Commit 7ba7402c authored by Sai Srinivas's avatar Sai Srinivas Committed by Sai Srinivas
Browse files

Edit form and some fixes added

parent d2939607
...@@ -42,7 +42,7 @@ android { ...@@ -42,7 +42,7 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "in.webgrid.generp" applicationId = "in.webgrid.generp"
minSdk = 23 minSdk = flutter.minSdkVersion
targetSdk = 36 targetSdk = 36
versionCode = flutter.versionCode versionCode = flutter.versionCode
versionName = flutter.versionName versionName = flutter.versionName
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application <application
android:name="${applicationName}" android:name="${applicationName}"
...@@ -77,6 +78,12 @@ ...@@ -77,6 +78,12 @@
</intent-filter> </intent-filter>
</activity> </activity>
<service
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
android:foregroundServiceType="location"
android:exported="false"/>
<meta-data <meta-data
android:name="flutter_deeplinking_enabled" android:name="flutter_deeplinking_enabled"
android:value="true" /> android:value="true" />
......
<svg id="Layer_1" enable-background="new 0 0 64 64" height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><g><g id="ARC_17_"><g><path d="m31.996 31.008c-3.292 0-6.583-1.09-9.33-3.271-.433-.344-.504-.973-.161-1.406.345-.432.973-.502 1.405-.16 4.761 3.783 11.412 3.783 16.171 0 .432-.344 1.062-.271 1.405.16.344.434.271 1.063-.161 1.406-2.746 2.181-6.038 3.271-9.329 3.271z"/></g></g><g id="ARC_18_"><g><path d="m16.307 41.711c-.455 0-.866-.313-.973-.773-1.432-6.156 1.748-12.424 7.561-14.904.509-.217 1.096.02 1.313.527.217.508-.02 1.096-.527 1.313-4.919 2.098-7.61 7.402-6.398 12.611.125.537-.209 1.074-.748 1.199-.077.019-.153.027-.228.027z"/></g></g><g id="ARC_19_"><g><path d="m47.684 41.711c-.075 0-.151-.008-.228-.027-.538-.125-.873-.662-.747-1.199 1.212-5.209-1.479-10.514-6.398-12.611-.508-.217-.744-.805-.527-1.313.217-.51.809-.744 1.313-.527 5.813 2.48 8.994 8.748 7.561 14.904-.109.46-.52.773-.974.773z"/></g></g><g id="CIRCLE_14_"><g><path d="m32.013 26.967c-2.701 0-5.284-.963-7.273-2.709-3.782-3.32-4.823-8.957-2.475-13.398 1.881-3.561 5.723-5.861 9.788-5.861.888 0 1.772.107 2.629.324 4.817 1.209 8.314 5.695 8.314 10.668 0 3.559-1.735 6.916-4.642 8.979-1.844 1.305-4.038 1.997-6.341 1.997zm.039-19.969c-3.333 0-6.48 1.881-8.019 4.795-1.92 3.635-1.068 8.244 2.026 10.963 1.624 1.426 3.738 2.211 5.954 2.211 1.888 0 3.68-.563 5.184-1.629 2.379-1.689 3.799-4.436 3.799-7.348 0-4.068-2.86-7.74-6.801-8.729-.699-.175-1.419-.263-2.143-.263z"/></g></g><g id="ARC_20_"><g><path d="m24.573 43.184c-.034 0-.067-.002-.102-.006-2.83-.287-5.66-.791-8.412-1.498-.535-.139-.857-.684-.719-1.219.137-.535.684-.857 1.217-.719 2.655.684 5.386 1.17 8.115 1.445.55.057.95.547.895 1.096-.052.516-.487.901-.994.901z"/></g></g><g id="ARC_21_"><g><path d="m39.418 43.184c-.507 0-.941-.385-.994-.9-.056-.549.345-1.039.895-1.096 2.73-.275 5.46-.762 8.115-1.445.529-.137 1.08.184 1.218.719s-.185 1.08-.72 1.219c-2.752.707-5.582 1.211-8.412 1.498-.035.003-.069.005-.102.005z"/></g></g><g id="LINE_65_"><g><path d="m31.995 53.99c-.195 0-.392-.057-.565-.176-.455-.313-.571-.936-.258-1.391l7.423-10.807c.312-.455.938-.57 1.391-.258.455.313.57.936.258 1.391l-7.424 10.808c-.194.283-.507.433-.825.433z"/></g></g><g id="LINE_66_"><g><path d="m31.997 53.99c-.318 0-.631-.15-.825-.434l-7.424-10.806c-.313-.455-.197-1.078.258-1.391.457-.314 1.078-.197 1.391.258l7.424 10.807c.312.455.197 1.078-.258 1.391-.174.119-.372.175-.566.175z"/></g></g><g id="LWPOLYLINE_14_"><g><path d="m32.453 59.002c-.709 0-1.429-.012-2.159-.037-4.484-.15-8.824-.424-12.622-2.088-.71-.311-2.386-1.189-2.613-2.623-.083-.527-.001-1.32.866-2.09 2.129-1.893 5.448-2.318 8.114-2.66l.896-.117c.541-.07 1.052.309 1.126.855s-.308 1.053-.855 1.127l-.913.119c-2.394.307-5.372.688-7.039 2.17-.177.156-.223.264-.22.283.034.213.553.715 1.44 1.104 3.473 1.521 7.604 1.777 11.886 1.922 4.494.148 8.578-.178 12.126-.98 3.9-.879 4.438-1.734 4.508-1.898.011-.025.029-.07-.06-.217-.367-.598-1.497-.996-2.245-1.26-1.851-.652-3.845-.959-5.896-1.242-.548-.074-.93-.578-.854-1.125.074-.547.577-.938 1.126-.855 2.157.297 4.262.621 6.289 1.336 1.014.357 2.548.898 3.285 2.102.518.846.393 1.576.196 2.041-.554 1.311-2.415 2.283-5.856 3.059-3.175.717-6.699 1.074-10.526 1.074z"/></g></g></g></svg>
\ No newline at end of file
...@@ -9,7 +9,7 @@ class FollowupListResponse { ...@@ -9,7 +9,7 @@ class FollowupListResponse {
if (json['list'] != null) { if (json['list'] != null) {
list = <Followuplist>[]; list = <Followuplist>[];
json['list'].forEach((v) { json['list'].forEach((v) {
list!.add(Followuplist.fromJson(v)); list!.add(new Followuplist.fromJson(v));
}); });
} }
error = json['error']; error = json['error'];
...@@ -17,12 +17,12 @@ class FollowupListResponse { ...@@ -17,12 +17,12 @@ class FollowupListResponse {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{}; final Map<String, dynamic> data = new Map<String, dynamic>();
if (list != null) { if (this.list != null) {
data['list'] = list!.map((v) => v.toJson()).toList(); data['list'] = this.list!.map((v) => v.toJson()).toList();
} }
data['error'] = error; data['error'] = this.error;
data['session_exists'] = sessionExists; data['session_exists'] = this.sessionExists;
return data; return data;
} }
} }
...@@ -42,8 +42,8 @@ class Followuplist { ...@@ -42,8 +42,8 @@ class Followuplist {
String? time; String? time;
String? ename; String? ename;
Followuplist({ Followuplist(
this.id, {this.id,
this.empId, this.empId,
this.compId, this.compId,
this.inTime, this.inTime,
...@@ -55,8 +55,7 @@ class Followuplist { ...@@ -55,8 +55,7 @@ class Followuplist {
this.fsrExt, this.fsrExt,
this.runningHrs, this.runningHrs,
this.time, this.time,
this.ename, this.ename});
});
Followuplist.fromJson(Map<String, dynamic> json) { Followuplist.fromJson(Map<String, dynamic> json) {
id = json['id']; id = json['id'];
...@@ -75,20 +74,20 @@ class Followuplist { ...@@ -75,20 +74,20 @@ class Followuplist {
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{}; final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = id; data['id'] = this.id;
data['emp_id'] = empId; data['emp_id'] = this.empId;
data['comp_id'] = compId; data['comp_id'] = this.compId;
data['in_time'] = inTime; data['in_time'] = this.inTime;
data['out_time'] = outTime; data['out_time'] = this.outTime;
data['feedback'] = feedback; data['feedback'] = this.feedback;
data['type'] = type; data['type'] = this.type;
data['date'] = date; data['date'] = this.date;
data['fsr_no'] = fsrNo; data['fsr_no'] = this.fsrNo;
data['fsr_ext'] = fsrExt; data['fsr_ext'] = this.fsrExt;
data['running_hrs'] = runningHrs; data['running_hrs'] = this.runningHrs;
data['time'] = time; data['time'] = this.time;
data['ename'] = ename; data['ename'] = this.ename;
return data; return data;
} }
} }
class ServiceComplaintBillListResponse {
List<ComplaintList>? complaintList;
int? error;
int? sessionExists;
ServiceComplaintBillListResponse(
{this.complaintList, this.error, this.sessionExists});
ServiceComplaintBillListResponse.fromJson(Map<String, dynamic> json) {
if (json['complaint_list'] != null) {
complaintList = <ComplaintList>[];
json['complaint_list'].forEach((v) {
complaintList!.add(new ComplaintList.fromJson(v));
});
}
error = json['error'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.complaintList != null) {
data['complaint_list'] =
this.complaintList!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['session_exists'] = this.sessionExists;
return data;
}
}
class ComplaintList {
String? billId;
String? totalAmount;
String? rawAmount;
String? narration;
String? billDate;
String? dueDate;
String? billPaid;
ComplaintList(
{this.billId,
this.totalAmount,
this.rawAmount,
this.narration,
this.billDate,
this.dueDate,
this.billPaid});
ComplaintList.fromJson(Map<String, dynamic> json) {
billId = json['bill_id'];
totalAmount = json['total_amount'];
rawAmount = json['raw_amount'];
narration = json['narration'];
billDate = json['bill_date'];
dueDate = json['due_date'];
billPaid = json['bill_paid'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['bill_id'] = this.billId;
data['total_amount'] = this.totalAmount;
data['raw_amount'] = this.rawAmount;
data['narration'] = this.narration;
data['bill_date'] = this.billDate;
data['due_date'] = this.dueDate;
data['bill_paid'] = this.billPaid;
return data;
}
}
class EditCommonAccFormDetailsResponse {
List<AccountList>? accountList;
String? error;
String? message;
int? sessionExists;
EditCommonAccFormDetailsResponse(
{this.accountList, this.error, this.message, this.sessionExists});
EditCommonAccFormDetailsResponse.fromJson(Map<String, dynamic> json) {
if (json['account_list'] != null) {
accountList = <AccountList>[];
json['account_list'].forEach((v) {
accountList!.add(new AccountList.fromJson(v));
});
}
error = json['error'];
message = json['message'];
sessionExists = json['session_exists'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.accountList != null) {
data['account_list'] = this.accountList!.map((v) => v.toJson()).toList();
}
data['error'] = this.error;
data['message'] = this.message;
data['session_exists'] = this.sessionExists;
return data;
}
}
class AccountList {
String? id;
String? isPaymentAccount;
String? createdEmployeeId;
String? type;
String? refId;
String? name;
String? subLocality;
String? district;
String? state;
String? address;
String? datetime;
String? empId;
String? bankName;
String? bankBranchName;
String? bankIfscCode;
String? bankAccountHolderName;
String? bankAccountNumber;
String? bankUpiId;
String? bankUpiName;
String? gstNumber;
Null? cashfreeAccountId;
String? isGstNumberVerified;
String? isBankAccountVerified;
String? remarks;
String? isExists;
String? createdDatetime;
String? updatedDatetime;
String? mob1;
String? email;
String? contactName;
AccountList(
{this.id,
this.isPaymentAccount,
this.createdEmployeeId,
this.type,
this.refId,
this.name,
this.subLocality,
this.district,
this.state,
this.address,
this.datetime,
this.empId,
this.bankName,
this.bankBranchName,
this.bankIfscCode,
this.bankAccountHolderName,
this.bankAccountNumber,
this.bankUpiId,
this.bankUpiName,
this.gstNumber,
this.cashfreeAccountId,
this.isGstNumberVerified,
this.isBankAccountVerified,
this.remarks,
this.isExists,
this.createdDatetime,
this.updatedDatetime,
this.mob1,
this.email,
this.contactName});
AccountList.fromJson(Map<String, dynamic> json) {
id = json['id'];
isPaymentAccount = json['is_payment_account'];
createdEmployeeId = json['created_employee_id'];
type = json['type'];
refId = json['ref_id'];
name = json['name'];
subLocality = json['sub_locality'];
district = json['district'];
state = json['state'];
address = json['address'];
datetime = json['datetime'];
empId = json['emp_id'];
bankName = json['bank_name'];
bankBranchName = json['bank_branch_name'];
bankIfscCode = json['bank_ifsc_code'];
bankAccountHolderName = json['bank_account_holder_name'];
bankAccountNumber = json['bank_account_number'];
bankUpiId = json['bank_upi_id'];
bankUpiName = json['bank_upi_name'];
gstNumber = json['gst_number'];
cashfreeAccountId = json['cashfree_account_id'];
isGstNumberVerified = json['is_gst_number_verified'];
isBankAccountVerified = json['is_bank_account_verified'];
remarks = json['remarks'];
isExists = json['is_exists'];
createdDatetime = json['created_datetime'];
updatedDatetime = json['updated_datetime'];
mob1 = json['mob1'];
email = json['email'];
contactName = json['contact_name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['is_payment_account'] = this.isPaymentAccount;
data['created_employee_id'] = this.createdEmployeeId;
data['type'] = this.type;
data['ref_id'] = this.refId;
data['name'] = this.name;
data['sub_locality'] = this.subLocality;
data['district'] = this.district;
data['state'] = this.state;
data['address'] = this.address;
data['datetime'] = this.datetime;
data['emp_id'] = this.empId;
data['bank_name'] = this.bankName;
data['bank_branch_name'] = this.bankBranchName;
data['bank_ifsc_code'] = this.bankIfscCode;
data['bank_account_holder_name'] = this.bankAccountHolderName;
data['bank_account_number'] = this.bankAccountNumber;
data['bank_upi_id'] = this.bankUpiId;
data['bank_upi_name'] = this.bankUpiName;
data['gst_number'] = this.gstNumber;
data['cashfree_account_id'] = this.cashfreeAccountId;
data['is_gst_number_verified'] = this.isGstNumberVerified;
data['is_bank_account_verified'] = this.isBankAccountVerified;
data['remarks'] = this.remarks;
data['is_exists'] = this.isExists;
data['created_datetime'] = this.createdDatetime;
data['updated_datetime'] = this.updatedDatetime;
data['mob1'] = this.mob1;
data['email'] = this.email;
data['contact_name'] = this.contactName;
return data;
}
}
...@@ -14,6 +14,7 @@ import 'package:provider/provider.dart'; ...@@ -14,6 +14,7 @@ import 'package:provider/provider.dart';
import '../Utils/BackgroundLocationService.dart'; import '../Utils/BackgroundLocationService.dart';
import '../Utils/SharedpreferencesService.dart'; import '../Utils/SharedpreferencesService.dart';
import '../Utils/backgroundServiceNew.dart';
import '../Utils/background_service.dart'; import '../Utils/background_service.dart';
import '../Utils/commonServices.dart'; import '../Utils/commonServices.dart';
import '../services/api_calling.dart'; import '../services/api_calling.dart';
...@@ -229,6 +230,8 @@ class CheckInOutProvider with ChangeNotifier { ...@@ -229,6 +230,8 @@ class CheckInOutProvider with ChangeNotifier {
if (data.error == 0) { if (data.error == 0) {
toast(context, "CheckedIn Successfully"); toast(context, "CheckedIn Successfully");
await BackgroundLocationService.startLocationService(context); await BackgroundLocationService.startLocationService(context);
await BackgroundLocationServiceNew.init();
await BackgroundLocationServiceNew.start();
locationController.clear(); locationController.clear();
dispose(); dispose();
Navigator.pop(context, true); Navigator.pop(context, true);
...@@ -266,6 +269,7 @@ class CheckInOutProvider with ChangeNotifier { ...@@ -266,6 +269,7 @@ class CheckInOutProvider with ChangeNotifier {
if (data.error == 0) { if (data.error == 0) {
toast(context, "Check-Out Successful"); toast(context, "Check-Out Successful");
await BackgroundLocationService.stopLocationService(); await BackgroundLocationService.stopLocationService();
await BackgroundLocationServiceNew.stop();
locationController.clear(); locationController.clear();
dispose(); dispose();
Navigator.pop(context, true); Navigator.pop(context, true);
......
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:generp/Utils/SharedpreferencesService.dart'; import 'package:generp/Utils/SharedpreferencesService.dart';
import 'package:generp/Utils/backgroundServiceNew.dart';
import 'package:generp/screens/LoginScreen.dart'; import 'package:generp/screens/LoginScreen.dart';
import 'package:generp/services/api_calling.dart'; import 'package:generp/services/api_calling.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
...@@ -77,6 +78,8 @@ class HomescreenNotifier extends ChangeNotifier { ...@@ -77,6 +78,8 @@ class HomescreenNotifier extends ChangeNotifier {
var lastLocationTime = await SharedpreferencesService().getString( var lastLocationTime = await SharedpreferencesService().getString(
"lastLocationTime", "lastLocationTime",
); );
notifyListeners(); notifyListeners();
print("lastLocationTime:$lastLocationTime"); print("lastLocationTime:$lastLocationTime");
...@@ -112,6 +115,7 @@ class HomescreenNotifier extends ChangeNotifier { ...@@ -112,6 +115,7 @@ class HomescreenNotifier extends ChangeNotifier {
if (_att_status == 0) { if (_att_status == 0) {
webSocketManager.close(); webSocketManager.close();
await BackgroundLocationService.stopLocationService(); await BackgroundLocationService.stopLocationService();
BackgroundLocationServiceNew.stop();
_onlineStatus = "Offline"; _onlineStatus = "Offline";
...@@ -151,11 +155,14 @@ class HomescreenNotifier extends ChangeNotifier { ...@@ -151,11 +155,14 @@ class HomescreenNotifier extends ChangeNotifier {
// print("Status knlknn offine"); // print("Status knlknn offine");
} }
await BackgroundLocationService.startLocationService(context); await BackgroundLocationService.startLocationService(context);
await BackgroundLocationServiceNew.init();
await BackgroundLocationServiceNew.start();
// print("setstatus:$setstatus"); // print("setstatus:$setstatus");
} else if (_att_status == 2) { } else if (_att_status == 2) {
// print("att_status:$att_status"); // print("att_status:$att_status");
webSocketManager.close(); webSocketManager.close();
await BackgroundLocationService.stopLocationService(); await BackgroundLocationService.stopLocationService();
await BackgroundLocationServiceNew.stop();
_onlineStatus = "Offline"; _onlineStatus = "Offline";
......
...@@ -5,6 +5,7 @@ import 'package:generp/screens/LoginScreen.dart'; ...@@ -5,6 +5,7 @@ import 'package:generp/screens/LoginScreen.dart';
import 'package:generp/services/api_calling.dart'; import 'package:generp/services/api_calling.dart';
import '../Utils/BackgroundLocationService.dart'; import '../Utils/BackgroundLocationService.dart';
import '../Utils/backgroundServiceNew.dart';
class LogoutNotifier extends ChangeNotifier { class LogoutNotifier extends ChangeNotifier {
bool _logoutButtonClicked = false; bool _logoutButtonClicked = false;
...@@ -33,6 +34,8 @@ class LogoutNotifier extends ChangeNotifier { ...@@ -33,6 +34,8 @@ class LogoutNotifier extends ChangeNotifier {
_isLoading = false; _isLoading = false;
_logoutButtonClicked = false; _logoutButtonClicked = false;
await BackgroundLocationService.stopLocationService(); await BackgroundLocationService.stopLocationService();
await BackgroundLocationServiceNew.stop();
SharedpreferencesService().clearPreferences(); SharedpreferencesService().clearPreferences();
Navigator.push( Navigator.push(
context, context,
......
...@@ -17,6 +17,7 @@ import '../Utils/commonServices.dart'; ...@@ -17,6 +17,7 @@ import '../Utils/commonServices.dart';
import '../screens/splash.dart'; import '../screens/splash.dart';
class Pendingcomplaintsprovider extends ChangeNotifier { class Pendingcomplaintsprovider extends ChangeNotifier {
TextEditingController fsrNumberController = TextEditingController(); TextEditingController fsrNumberController = TextEditingController();
TextEditingController runningHoursController = TextEditingController(); TextEditingController runningHoursController = TextEditingController();
TextEditingController feedbackController = TextEditingController(); TextEditingController feedbackController = TextEditingController();
......
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../Models/ordersModels/commonResponse.dart'; import '../Models/ordersModels/commonResponse.dart';
import '../Utils/custom_snackbar.dart'; import '../Utils/custom_snackbar.dart';
import '../services/api_calling.dart'; import '../services/api_calling.dart';
class QrProvider extends ChangeNotifier { class QrProvider extends ChangeNotifier {
CommonResponse? _qrResponse; CommonResponse? _qrResponse;
bool _isLoading = false; bool _isLoading = false;
...@@ -19,7 +17,6 @@ class QrProvider extends ChangeNotifier { ...@@ -19,7 +17,6 @@ class QrProvider extends ChangeNotifier {
Timer? _timer; Timer? _timer;
/// Fetch Razorpay QR API
Future<void> fetchRazorpayQr({ Future<void> fetchRazorpayQr({
required String sessionId, required String sessionId,
required String empId, required String empId,
...@@ -54,7 +51,6 @@ class QrProvider extends ChangeNotifier { ...@@ -54,7 +51,6 @@ class QrProvider extends ChangeNotifier {
} }
} }
/// Start 2-minute countdown
void _startTimer() { void _startTimer() {
_secondsLeft = 120; _secondsLeft = 120;
_timer?.cancel(); _timer?.cancel();
...@@ -68,12 +64,12 @@ class QrProvider extends ChangeNotifier { ...@@ -68,12 +64,12 @@ class QrProvider extends ChangeNotifier {
}); });
} }
/// Dispose timer properly
@override @override
void dispose() { void dispose() {
_timer?.cancel(); _timer?.cancel();
super.dispose(); super.dispose();
} }
bool _isPaymentUpdating = false; bool _isPaymentUpdating = false;
bool get isPaymentUpdating => _isPaymentUpdating; bool get isPaymentUpdating => _isPaymentUpdating;
...@@ -83,6 +79,7 @@ class QrProvider extends ChangeNotifier { ...@@ -83,6 +79,7 @@ class QrProvider extends ChangeNotifier {
} }
/// Fetch Razorpay QR Payment Status /// Fetch Razorpay QR Payment Status
/// NOTE: This method no longer shows snackbars itself. It simply returns the response.
Future<CommonResponse?> fetchRazorpayUpiQrStatus({ Future<CommonResponse?> fetchRazorpayUpiQrStatus({
required BuildContext context, required BuildContext context,
required String sessionId, required String sessionId,
...@@ -100,25 +97,22 @@ class QrProvider extends ChangeNotifier { ...@@ -100,25 +97,22 @@ class QrProvider extends ChangeNotifier {
if (response != null) { if (response != null) {
if (response.sessionExists == 1 && response.error == "0") { if (response.sessionExists == 1 && response.error == "0") {
debugPrint(" Payment Status: ${response.message}"); debugPrint("Payment Status: ${response.message}");
} else { } else {
CustomSnackBar.showWarning( // IMPORTANT: do not show UI here (no repeated warnings).
context: context, // The caller (screen) should decide when to show failure messages.
message: "⚠️ Payment not yet completed or failed" debugPrint("Payment still pending or failed: ${response.message}");
);
debugPrint("⚠️ Payment not yet completed or failed");
} }
} else { } else {
debugPrint("Null response from Razorpay QR Status API"); debugPrint("Null response from Razorpay QR Status API");
} }
return response; // return here return response;
} catch (e) { } catch (e) {
debugPrint("fetchRazorpayUpiQrStatus error: $e"); debugPrint("fetchRazorpayUpiQrStatus error: $e");
return null; return null;
} finally { } finally {
isPaymentUpdating = false; isPaymentUpdating = false;
} }
} }
} }
...@@ -4,6 +4,7 @@ import 'package:generp/services/api_calling.dart'; ...@@ -4,6 +4,7 @@ import 'package:generp/services/api_calling.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../Models/FollowUpResponse.dart'; import '../Models/FollowUpResponse.dart';
import '../Models/ServiceComplaintBillListResponse.dart';
import '../Models/ViewVisitDetailsResponseNew.dart'; import '../Models/ViewVisitDetailsResponseNew.dart';
import '../Utils/commonServices.dart'; import '../Utils/commonServices.dart';
...@@ -14,26 +15,79 @@ class Visitdetailsprovider extends ChangeNotifier { ...@@ -14,26 +15,79 @@ class Visitdetailsprovider extends ChangeNotifier {
GeneratorDetails _generatorDetails = GeneratorDetails(); GeneratorDetails _generatorDetails = GeneratorDetails();
ComplaintDetailsNew _complaintDetailsNew = ComplaintDetailsNew(); ComplaintDetailsNew _complaintDetailsNew = ComplaintDetailsNew();
List<Followuplist> _followupList = []; List<Followuplist> _followupList = [];
List<ComplaintList> _complaintList = [];
bool _isLoading = false; bool _isLoading = false;
CustomerDetails get customerDetails => _customerDetails; CustomerDetails get customerDetails => _customerDetails;
GeneratorDetails get generatorDetails => _generatorDetails; GeneratorDetails get generatorDetails => _generatorDetails;
ComplaintDetailsNew get complaintDetailsNew => _complaintDetailsNew; ComplaintDetailsNew get complaintDetailsNew => _complaintDetailsNew;
List<Followuplist> get followUpList => _followupList; List<Followuplist> get followUpList => _followupList;
List<ComplaintList> get complaintList => _complaintList;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
bool get showMoreDetails => _showMoreDetails; bool get showMoreDetails => _showMoreDetails;
// ==== FIX FOR THE CRASH ====
bool _disposed = false;
@override
void dispose() {
_disposed = true;
super.dispose();
}
void safeNotifyListeners() {
if (!_disposed) notifyListeners();
}
// ===========================
set showMoreDetails(bool value) { set showMoreDetails(bool value) {
_showMoreDetails = value; _showMoreDetails = value;
notifyListeners(); safeNotifyListeners();
} }
Future<void> LoadVisitDetailsAPI(BuildContext context, ComplaintID) async { ServiceComplaintBillListResponse? complaintBillListResponse;
String? error;
Future<void> serviceComplaintBillList(BuildContext context, String complaintId) async {
try { try {
var HomeProvider = Provider.of<HomescreenNotifier>( var homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
context,
listen: false, _isLoading = true;
safeNotifyListeners();
final data = await ApiCalling.serviceComplaintBillListAPI(
homeProvider.empId,
homeProvider.session,
complaintId,
); );
if (data != null) {
if (data.error == 0) {
_complaintList = data.complaintList ?? [];
_isLoading = false;
safeNotifyListeners();
} else {
toast(context, "Something Went Wrong, Please try again!");
}
} else {
toast(context, "No response From the server, Please try Again!");
}
complaintBillListResponse = data;
error = null;
} catch (e) {
error = e.toString();
complaintBillListResponse = null;
} finally {
_isLoading = false;
safeNotifyListeners();
}
}
Future<void> LoadVisitDetailsAPI(BuildContext context, ComplaintID) async {
try {
var HomeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.loadVisitDetailsAPI( final data = await ApiCalling.loadVisitDetailsAPI(
HomeProvider.empId, HomeProvider.empId,
HomeProvider.session, HomeProvider.session,
...@@ -42,31 +96,26 @@ class Visitdetailsprovider extends ChangeNotifier { ...@@ -42,31 +96,26 @@ class Visitdetailsprovider extends ChangeNotifier {
if (data != null) { if (data != null) {
if (data.error == 0) { if (data.error == 0) {
// complaintdetails = data.complaintDetails!;
_customerDetails = data.customerDetails!; _customerDetails = data.customerDetails!;
_generatorDetails = data.generatorDetails!; _generatorDetails = data.generatorDetails!;
_complaintDetailsNew = data.complaintDetailsNew!; _complaintDetailsNew = data.complaintDetailsNew!;
_isLoading = false; _isLoading = false;
notifyListeners(); safeNotifyListeners();
} else { } else {
toast(context, "Something Went Wrong, Please try again!"); toast(context, "Something Went Wrong, Please try again!");
print("error");
} }
} else { } else {
toast(context, "No response From the server, Please try Again!"); toast(context, "No response From the server, Please try Again!");
print("error2");
} }
} on Error catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
} }
} }
Future<void> LoadFollowupListAPI(BuildContext context, ComplaintID) async { Future<void> LoadFollowupListAPI(BuildContext context, ComplaintID) async {
try { try {
var HomeProvider = Provider.of<HomescreenNotifier>( var HomeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
context,
listen: false,
);
final data = await ApiCalling.loadFollowupListAPI( final data = await ApiCalling.loadFollowupListAPI(
HomeProvider.empId, HomeProvider.empId,
HomeProvider.session, HomeProvider.session,
...@@ -75,20 +124,19 @@ class Visitdetailsprovider extends ChangeNotifier { ...@@ -75,20 +124,19 @@ class Visitdetailsprovider extends ChangeNotifier {
if (data != null) { if (data != null) {
if (data.error == 0) { if (data.error == 0) {
// complaintdetails = data.complaintDetails!;
_followupList = data.list ?? []; _followupList = data.list ?? [];
_isLoading = false; _isLoading = false;
notifyListeners(); safeNotifyListeners();
} else { } else {
toast(context, "Something Went Wrong, Please try again!"); toast(context, "Something Went Wrong, Please try again!");
print("error");
} }
} else { } else {
toast(context, "No response From the server, Please try Again!"); toast(context, "No response From the server, Please try Again!");
print("error2");
} }
} on Error catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
} }
} }
} }
import 'package:flutter/material.dart'; //
import 'package:generp/services/api_calling.dart'; //
// import 'package:flutter/cupertino.dart';
import '../../Models/financeModels/ValidateBankAccountDetailsResponse.dart'; // import 'package:generp/Models/ordersModels/commonResponse.dart';
import '../../Models/financeModels/ValidateGstNumResponse.dart'; // import 'package:generp/services/api_calling.dart';
//
// class EditCommonAccountProvider extends ChangeNotifier{
class ValidationProvider extends ChangeNotifier { // bool isLoading = false;
bool isLoading = false; // String? errorMessage;
// CommonResponse? updateResponse;
ValidateGstNumResponse? gstResponse; //
ValidateBankAccountDetailsResponse? bankResponse; // Future<void> updateAccountForm() async{
//
String? errorMessage; // try{
// isLoading = true;
// errorMessage = null;
/// Validate GST Number // notifyListeners();
/// ----------------------------- //
Future<void> validateGstNumber( // updateResponse = await ApiCalling.commonUpdateAccountDetailsAPI(
String empId, String sessionId, String gstNumber) async { // empId,
try { // sessionId,
isLoading = true; // type,
errorMessage = null; // name,
notifyListeners(); // mob1,
// mob2,
gstResponse = await ApiCalling.validateGstNumberApi( // tel,
empId, // email,
sessionId, // designation,
gstNumber, // address,
); // state,
// district,
if (gstResponse == null) { // subLocality,
errorMessage = "Failed to validate GST number"; // bankName,
} // branchName,
// bankIfscCode,
} catch (e) { // accHolderName,
errorMessage = e.toString(); // bankAccNumber,
} // bankUpiId
// );
isLoading = false; //
notifyListeners(); // if (updateResponse == null){
} // errorMessage = "No Response from server";
// }
// }
/// Validate Bank Account Details //
/// ----------------------------- //
Future<void> validateBankDetails( // }
String empId, String sessionId, String accountNumber) async { //
try { // }
isLoading = true; \ No newline at end of file
errorMessage = null;
notifyListeners();
bankResponse = await ApiCalling.validateBankAccountDetailsApi(
empId,
sessionId,
accountNumber,
""
);
if (bankResponse == null) {
errorMessage = "Failed to validate bank account";
}
} catch (e) {
errorMessage = e.toString();
}
isLoading = false;
notifyListeners();
}
/// Reset before calling again
void clear() {
gstResponse = null;
bankResponse = null;
errorMessage = null;
notifyListeners();
}
}
...@@ -7,6 +7,8 @@ import '../../Models/commonModels/commonAccountdetailsResponse.dart'; ...@@ -7,6 +7,8 @@ import '../../Models/commonModels/commonAccountdetailsResponse.dart';
class Accountdetailsprovider extends ChangeNotifier { class Accountdetailsprovider extends ChangeNotifier {
bool _showMoreDetails = false; bool _showMoreDetails = false;
bool _isLoading = false;
bool get isLoading => _isLoading;
AccountDetails _accountDetails = AccountDetails(); AccountDetails _accountDetails = AccountDetails();
BalanceDetails _balanceDetails = BalanceDetails(); BalanceDetails _balanceDetails = BalanceDetails();
...@@ -27,6 +29,8 @@ class Accountdetailsprovider extends ChangeNotifier { ...@@ -27,6 +29,8 @@ class Accountdetailsprovider extends ChangeNotifier {
} }
Future<void> accountdetailsAPIFunction(context, accountID) async { Future<void> accountdetailsAPIFunction(context, accountID) async {
_isLoading = true;
notifyListeners();
try { try {
var prov = Provider.of<HomescreenNotifier>(context, listen: false); var prov = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.commonAccountDetailsAPI( final data = await ApiCalling.commonAccountDetailsAPI(
...@@ -56,6 +60,8 @@ class Accountdetailsprovider extends ChangeNotifier { ...@@ -56,6 +60,8 @@ class Accountdetailsprovider extends ChangeNotifier {
} }
} }
} catch (e) {} } catch (e) {}
_isLoading = false;
notifyListeners();
} }
Map<String, List<LedgerList>> groupByDate(List<LedgerList> list) { Map<String, List<LedgerList>> groupByDate(List<LedgerList> list) {
......
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:generp/Models/ordersModels/commonResponse.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.dart'; import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/Utils/commonServices.dart'; import 'package:generp/Utils/commonServices.dart';
import 'package:generp/Utils/custom_snackbar.dart';
import 'package:generp/screens/commom/accountsListDetails.dart'; import 'package:generp/screens/commom/accountsListDetails.dart';
import 'package:generp/screens/finance/financeDashboard.dart'; import 'package:generp/screens/finance/financeDashboard.dart';
import 'package:generp/services/api_calling.dart'; import 'package:generp/services/api_calling.dart';
...@@ -103,6 +105,7 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -103,6 +105,7 @@ class Accountslistprovider extends ChangeNotifier {
} }
ValidateGstNumResponse? gstResponse; ValidateGstNumResponse? gstResponse;
commonAddAccountsViewResponse? commonResponse;
ValidateBankAccountDetailsResponse? bankResponse; ValidateBankAccountDetailsResponse? bankResponse;
String? errorMessage; String? errorMessage;
...@@ -284,6 +287,7 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -284,6 +287,7 @@ class Accountslistprovider extends ChangeNotifier {
type, type,
value, value,
); );
commonResponse =data;
if (data != null) { if (data != null) {
if (data.error == "0") { if (data.error == "0") {
nameError = null; nameError = null;
...@@ -425,6 +429,181 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -425,6 +429,181 @@ class Accountslistprovider extends ChangeNotifier {
} }
} }
Future<void> checkAndApplyGst(BuildContext context, String gstNumber) async {
// clear previous GST error when user actively changed
gstNumberError = null;
notifyListeners();
final trimmed = gstNumber.trim();
if (trimmed.isEmpty) {
// user cleared GST: clear response + errors
gstResponse = null;
gstNumberError = null;
notifyListeners();
return;
}
try {
isLoading = true;
final homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final resp = await ApiCalling.validateGstNumberApi(
homeProv.empId,
homeProv.session,
trimmed,
);
gstResponse = resp;
if (resp == null) {
gstNumberError = "Failed to validate GST number";
notifyListeners();
return;
}
if (resp.error == "0") {
// success -> autofill address and compare company name
// Use response field names you mentioned: legal_name_of_business and address
final apiName = (resp.legalNameOfBusiness ?? "").trim();
final apiAddress = (resp.address ?? "").trim();
// Autofill/override address in Step 2
if (apiAddress.isNotEmpty) {
// Only override if response contains useful address
addressController.text = apiAddress;
}
// Compare company name vs gst name
final enteredName = (nameController.text ?? "").trim();
debugPrint("################# Entered text: $enteredName \n response name: $apiName");
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
// Set error on step 1
nameError = "Company name does not match GST record ('$apiName'). Please correct.";
} else {
nameError = null;
}
}
gstNumberError = null;
notifyListeners();
return;
} else {
// API returned invalid GST
gstNumberError = resp.message ?? "Invalid GST number";
notifyListeners();
return;
}
} catch (e) {
gstNumberError = "Error validating GST";
if (kDebugMode) debugPrint("checkAndApplyGst error: $e");
notifyListeners();
return;
} finally {
isLoading = false;
notifyListeners();
}
}
void recheckNameWithGst() {
if (gstResponse == null) return;
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
nameError = "Company name does not match GST record ('$apiName')";
} else {
nameError = null;
}
}
notifyListeners();
}
/// New helper: check bank account + ifsc and call bank API when both present.
/// Called by UI when user finishes account/ifsc input or when IFSC changes.
Future<void> checkAndApplyBank(BuildContext context, String accountNumber) async {
bankAcNumberError = null;
bankIFSCError = null;
notifyListeners();
final acc = accountNumber.trim();
final ifsc = bankIfscCotroller.text.trim();
if (acc.isEmpty && ifsc.isEmpty) {
// user cleared both
bankResponse = null;
bankAcNumberError = null;
bankIFSCError = null;
notifyListeners();
return;
}
// If account entered, IFSC required
if (acc.isNotEmpty && ifsc.isEmpty) {
bankIFSCError = "IFSC is required when account number is entered";
notifyListeners();
return;
}
// validate IFSC format (basic)
final ifscReg = RegExp(r'^[A-Za-z]{4}0[A-Za-z0-9]{6}$');
if (ifsc.isNotEmpty && !ifscReg.hasMatch(ifsc)) {
bankIFSCError = "Invalid IFSC format";
notifyListeners();
return;
}
if (acc.isNotEmpty && ifsc.isNotEmpty) {
try {
isLoading = true;
final homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final resp = await ApiCalling.validateBankAccountDetailsApi(
homeProv.empId,
homeProv.session,
acc,
ifsc,
);
bankResponse = resp;
if (resp == null) {
bankAcNumberError = "Failed to validate bank details";
notifyListeners();
return;
}
if (resp.error == "0") {
// success -> autofill bank fields
bankNameController.text = resp.bankName ?? bankNameController.text;
branchNameController.text = resp.branch ?? branchNameController.text;
bankHolderNameController.text = resp.nameAtBank ?? bankHolderNameController.text;
// clear errors
bankAcNumberError = null;
bankIFSCError = null;
banknameError = null;
bankBranchError = null;
bankHolderNameError = null;
notifyListeners();
return;
} else {
bankAcNumberError = resp.message ?? "Invalid account details";
notifyListeners();
return;
}
} catch (e) {
bankAcNumberError = "Error validating bank: ${e.toString()}";
if (kDebugMode) debugPrint("checkAndApplyBank error: $e");
notifyListeners();
return;
} finally {
isLoading = false;
notifyListeners();
}
}
}
bool hasFilledAdditionalDetails = false; bool hasFilledAdditionalDetails = false;
bool _submitClicked = false; bool _submitClicked = false;
...@@ -504,7 +683,7 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -504,7 +683,7 @@ class Accountslistprovider extends ChangeNotifier {
} }
} }
bool validateStep1() { bool validateStep1(BuildContext context) {
accountError = null; accountError = null;
nameError = null; nameError = null;
mobileError = null; mobileError = null;
...@@ -518,10 +697,53 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -518,10 +697,53 @@ class Accountslistprovider extends ChangeNotifier {
nameError = "Please Enter a Name"; nameError = "Please Enter a Name";
isValid = false; isValid = false;
} }
if (nameError != null && nameError != "") {
isValid = false;
}
if (mobileController.text.trim().isNotEmpty && mobileController.text.length < 10) { if (mobileController.text.trim().isNotEmpty && mobileController.text.length < 10) {
mobileError = "Mobile Number should be 10 digits"; mobileError = "Mobile Number should be 10 digits";
isValid = false; isValid = false;
} }
if (gstResponse != null){
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
final msg = "Company name does not match GST record ('$apiName')";
CustomSnackBar.showWarning(context: context, message: msg);
isValid = false;
} else {
isValid = true;
nameError = null;
}
}
}
if (commonResponse != null){
final message = (commonResponse?.message ?? "").trim();
final enteredName = nameController.text.trim();
if (message != "Can Proceed" ) {
isValid = false;
CustomSnackBar.showWarning(context: context, message: message);
} else {
isValid = true;
}
}
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
nameError = "Company name does not match GST record ('$apiName')";
} else {
nameError = null;
}
}
if (mobileController.text.trim().isEmpty) { if (mobileController.text.trim().isEmpty) {
mobileError = "Please Enter Mobile Number"; mobileError = "Please Enter Mobile Number";
isValid = false; isValid = false;
...@@ -535,6 +757,8 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -535,6 +757,8 @@ class Accountslistprovider extends ChangeNotifier {
return isValid; return isValid;
} }
bool validateStep2() { bool validateStep2() {
stateError = null; stateError = null;
districtError = null; districtError = null;
...@@ -547,7 +771,7 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -547,7 +771,7 @@ class Accountslistprovider extends ChangeNotifier {
return isValid; return isValid;
} }
bool validateStep3() { bool validateStep3(BuildContext context) {
banknameError = null; banknameError = null;
bankBranchError = null; bankBranchError = null;
bankIFSCError = null; bankIFSCError = null;
...@@ -557,6 +781,21 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -557,6 +781,21 @@ class Accountslistprovider extends ChangeNotifier {
gstNumberError = null; gstNumberError = null;
bool isValid = true; bool isValid = true;
_submitClicked = false; _submitClicked = false;
if (gstResponse != null){
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
final msg = "Company name does not match GST record ('$apiName')";
CustomSnackBar.showWarning(context: context, message: msg);
isValid = false;
} else {
isValid = true;
nameError = null;
}
}
}
notifyListeners(); notifyListeners();
return isValid; return isValid;
} }
...@@ -564,6 +803,20 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -564,6 +803,20 @@ class Accountslistprovider extends ChangeNotifier {
bool validateStep4() { bool validateStep4() {
bool isValid = true; bool isValid = true;
_submitClicked = false; _submitClicked = false;
if (gstResponse != null){
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
isValid = false;
} else {
isValid = true;
nameError = null;
}
}
}
notifyListeners(); notifyListeners();
return isValid; return isValid;
} }
...@@ -607,6 +860,31 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -607,6 +860,31 @@ class Accountslistprovider extends ChangeNotifier {
isValid = false; isValid = false;
} }
if (commonResponse != null){
final message = (commonResponse?.message ?? "").trim();
final enteredName = nameController.text.trim();
if (message != "Can Proceed" ) {
isValid = false;
CustomSnackBar.showWarning(context: context, message: message);
} else {
isValid = true;
}
}
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
isValid = false;
CustomSnackBar.showWarning(context: context, message: "Company name does not match GST record ('$apiName')");
nameError = "Company name does not match GST record ('$apiName')";
} else {
isValid = true;
nameError = null;
}
}
_submitClicked = false; _submitClicked = false;
notifyListeners(); notifyListeners();
return isValid; return isValid;
...@@ -633,13 +911,13 @@ class Accountslistprovider extends ChangeNotifier { ...@@ -633,13 +911,13 @@ class Accountslistprovider extends ChangeNotifier {
} }
/// simplified update - kept for compatibility if UI uses it /// simplified update - kept for compatibility if UI uses it
Future<void> updateGSTNumber(BuildContext context, String value) async { void updateGSTNumber(String value) {
// We won't call the GST API here — UI flow calls validateGstNumber explicitly. // just clear the error when user edits GST
// This function simply clears previous error on typing.
gstNumberError = null; gstNumberError = null;
notifyListeners(); notifyListeners();
} }
void updateBankBranch(String value) { void updateBankBranch(String value) {
bankBranchError = null; bankBranchError = null;
notifyListeners(); notifyListeners();
......
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/services/api_calling.dart';
import 'package:generp/Utils/commonServices.dart';
import 'package:provider/provider.dart';
import '../../Models/commonModels/DistrictsResponse.dart';
import '../../Models/commonModels/EditCommonAccFormDetailsResponse.dart';
import '../../Models/commonModels/SubLocationsResponse.dart';
import '../../Models/financeModels/ValidateBankAccountDetailsResponse.dart';
import '../../Models/financeModels/ValidateGstNumResponse.dart';
import '../../Models/commonModels/commonAddAccountsViewResponse.dart';
class EditCommonAccountProvider extends ChangeNotifier {
// --- Text controllers used by edit form (only required ones) ---
final TextEditingController nameController = TextEditingController();
final TextEditingController mobileController = TextEditingController();
final TextEditingController addressController = TextEditingController();
final TextEditingController bankNameController = TextEditingController();
final TextEditingController branchNameController = TextEditingController();
final TextEditingController bankIfscCotroller = TextEditingController();
final TextEditingController bankHolderNameController = TextEditingController();
final TextEditingController gstNumberController = TextEditingController();
final TextEditingController bankAcNumberController = TextEditingController();
final TextEditingController bankUpiController = TextEditingController();
// contact person details (kept because your form uses them)
final TextEditingController contactPersonController = TextEditingController();
// final TextEditingController contectPersonDesignationController = TextEditingController();
// final TextEditingController contectPersonAltMobController = TextEditingController();
// final TextEditingController contectPersonTeleController = TextEditingController();
final TextEditingController contectPersonMailController = TextEditingController();
// small search controllers for dropdown search widgets
final TextEditingController stateSearchController = TextEditingController();
final TextEditingController districtSearchController = TextEditingController();
final TextEditingController subLocSearchController = TextEditingController();
// --- simple error strings for UI ---
String? accountError;
String? nameError;
String? mobileError;
String? stateError;
String? districtError;
String? localityError;
String? addressError;
String? gstNumberError;
String? banknameError;
String? bankBranchError;
String? bankIFSCError;
String? bankHolderNameError;
String? bankAcNumberError;
String? upiError;
String? contactPersonError;
String? desigantionError;
String? altMobError;
String? teleError;
String? mailError;
String? addMoreDetailsError;
// --- dropdown lists (populated from addCommonAccountView API) ---
List<String> _accountTypes = [];
List<States> _states = [];
List<Districts> _districts = [];
List<SubLocations> _subLocations = [];
// selection holders
String? _selectedAccountType;
States? _selectedState;
Districts? _selectedDistricts;
SubLocations? _selectedSubLocations;
// IDs / values (strings) used when sending API
String? _selectedStateID;
String? _selectedDistrictID;
String? _selectedSubLocID;
// responses from validation APIs
ValidateGstNumResponse? gstResponse;
ValidateBankAccountDetailsResponse? bankResponse;
commonAddAccountsViewResponse? commonResponse;
// loading & submit state
bool _isLoading = false;
bool _isSubmitting = false;
String? updateErrorMessage;
// getters
bool get isLoading => _isLoading;
bool get isSubmitting => _isSubmitting;
List<States> get states => _states;
List<Districts> get districts => _districts;
List<SubLocations> get subLocations => _subLocations;
String? get selectedAccountType => _selectedAccountType;
States? get selectedState => _selectedState;
Districts? get selectedDistricts => _selectedDistricts;
SubLocations? get selectedSubLocations => _selectedSubLocations;
String? get selectedStateID => _selectedStateID;
String? get selectedDistrictId => _selectedDistrictID;
String? get selectedSubLocID => _selectedSubLocID;
bool _submitClicked = false;
bool get submitClickced => _submitClicked;
set submitClickced(bool value) {
_submitClicked = value;
notifyListeners();
}
// --- setters that clear corresponding errors and notify ---
set selectedAccountType(String? v) {
_selectedAccountType = v;
accountError = null;
notifyListeners();
}
set selectedState(States? v) {
_selectedState = v;
_selectedStateID = v?.id;
stateError = null;
// clear dependent district/subLocation when state changes
_districts.clear();
_selectedDistricts = null;
_selectedDistrictID = null;
_subLocations.clear();
_selectedSubLocations = null;
_selectedSubLocID = null;
notifyListeners();
}
set selectedDistricts(Districts? v) {
_selectedDistricts = v;
_selectedDistrictID = v?.id;
districtError = null;
_subLocations.clear();
_selectedSubLocations = null;
_selectedSubLocID = null;
notifyListeners();
}
set selectedSubLocations(SubLocations? v) {
_selectedSubLocations = v;
_selectedSubLocID = v?.id;
localityError = null;
notifyListeners();
}
set isLoading(bool v) {
_isLoading = v;
notifyListeners();
}
EditCommonAccFormDetailsResponse? detailsListResponse;
// LOAD ACCOUNT DETAILS + PREFILL ALL FIELDS
// ==========================================================
Future<bool> loadAccountDetailsForEdit(
BuildContext context,
String accountId,
) async {
try {
isLoading = true;
notifyListeners();
final homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.commonAccountDetailsListAPI(
homeProv.empId,
homeProv.session,
accountId,
);
detailsListResponse =data;
if (data == null || data.error != "0") {
updateErrorMessage = data?.message ?? "Failed to load account details";
isLoading = false;
notifyListeners();
return false;
}
// Expecting at least one account in the list; take the first.
if (data.accountList == null || data.accountList!.isEmpty) {
updateErrorMessage = "No account data returned";
isLoading = false;
notifyListeners();
return false;
}
final acc = data.accountList!.first;
// 1) PREFILL TEXT CONTROLLERS
// ---------------------------
nameController.text = acc.name ?? "";
mobileController.text = acc.mob1 ?? "";
addressController.text = acc.address ?? "";
bankNameController.text = acc.bankName ?? "";
branchNameController.text = acc.bankBranchName ?? "";
bankIfscCotroller.text = acc.bankIfscCode ?? "";
bankHolderNameController.text = acc.bankAccountHolderName ?? "";
bankAcNumberController.text = acc.bankAccountNumber ?? "";
bankUpiController.text = acc.bankUpiId ?? "";
gstNumberController.text = acc.gstNumber ?? "";
// contact person (if API has contact_name)
contactPersonController.text = acc.contactName ?? "";
// Other contact fields in API aren't present — keep empty or preserve existing
contectPersonMailController.text = acc.email ?? "";
// ---------------------------
// 2) PREFILL ACCOUNT TYPE
// ---------------------------
selectedAccountType = acc.type;
// ---------------------------
// 3) LOAD DROPDOWNS (account types, states)
// ---------------------------
await addCommonAccountViewAPI(context);
// ---------------------------
// 4) SELECT STATE (by name)
// ---------------------------
if (acc.state != null && acc.state!.trim().isNotEmpty) {
final matchState = _states.firstWhere(
(s) => (s.name ?? "").toLowerCase() == acc.state!.trim().toLowerCase(),
orElse: () => States(id: null, name: null),
);
if (matchState.id != null) {
// use setter so it clears errors and resets dependent lists
selectedState = matchState;
_selectedStateID = matchState.id;
// load districts for this state
await getDistrictAPI(context, matchState.id);
}
}
// ---------------------------
// 5) SELECT DISTRICT (by name)
// ---------------------------
if (acc.district != null && acc.district!.trim().isNotEmpty && _districts.isNotEmpty) {
final matchDist = _districts.firstWhere(
(d) => (d.district ?? "").toLowerCase() == acc.district!.trim().toLowerCase(),
orElse: () => Districts(id: null, district: null),
);
if (matchDist.id != null) {
selectedDistricts = matchDist;
_selectedDistrictID = matchDist.id;
// load sub-localities for this district
await getSubLocationAPI(context, matchDist.id);
}
}
// ---------------------------
// 6) SELECT SUB-LOCALITY (by name)
// ---------------------------
if (acc.subLocality != null && acc.subLocality!.trim().isNotEmpty && _subLocations.isNotEmpty) {
final matchSub = _subLocations.firstWhere(
(s) => (s.subLocality ?? "").toLowerCase() == acc.subLocality!.trim().toLowerCase(),
orElse: () => SubLocations(id: null, subLocality: null),
);
if (matchSub.id != null) {
selectedSubLocations = matchSub;
_selectedSubLocID = matchSub.id;
}
}
// everything loaded
isLoading = false;
notifyListeners();
return true;
} catch (e, s) {
if (kDebugMode) debugPrint("loadAccountDetailsForEdit ERROR => $e\n$s");
updateErrorMessage = e.toString();
isLoading = false;
notifyListeners();
return false;
}
}
Future<void> getDistrictAPI(context, stateID) async {
try {
var homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
_districts.clear();
notifyListeners();
final data = await ApiCalling.commonAddAccountViewDistrictAPI(
homeProv.empId,
homeProv.session,
stateID,
);
if (data != null) {
if (data.error == "0") {
_districts = data.districts ?? [];
notifyListeners();
}
}
} catch (e) {
if (kDebugMode) debugPrint('getDistrictAPI error: $e');
}
}
Future<void> getSubLocationAPI(context, districtID) async {
try {
var homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
_subLocations.clear();
notifyListeners();
final data = await ApiCalling.commonAddAccountViewSubLocationAPI(
homeProv.empId,
homeProv.session,
districtID,
);
if (data != null) {
if (data.error == "0") {
_subLocations = data.subLocations ?? [];
notifyListeners();
}
}
} catch (e) {
if (kDebugMode) debugPrint('getSubLocationAPI error: $e');
}
}
// --- API: load data needed to populate dropdowns (account types, states) ---
Future<void> addCommonAccountViewAPI(BuildContext context) async {
try {
isLoading = true;
var homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.commonAddAccountViewAPI(homeProv.empId, homeProv.session);
_accountTypes.clear();
_states.clear();
if (data != null && data.error == "0") {
_accountTypes = data.accountTypes ?? [];
_states = data.states ?? [];
commonResponse = data;
}
} catch (e) {
if (kDebugMode) debugPrint('addCommonAccountViewAPI error: $e');
} finally {
isLoading = false;
notifyListeners();
}
}
// --- GST validation: calls API and sets gstResponse; returns true if valid ---
Future<bool> validateGstNumber(String empId, String sessionId, String gstNumber) async {
if (gstNumber.trim().isEmpty) {
gstResponse = null;
gstNumberError = null;
notifyListeners();
return false;
}
try {
isLoading = true;
final response = await ApiCalling.validateGstNumberApi(empId, sessionId, gstNumber.trim());
gstResponse = response;
if (response == null) {
gstNumberError = "Failed to validate GST number";
notifyListeners();
return false;
}
if (response.error == "0") {
gstNumberError = null;
notifyListeners();
return true;
} else {
gstNumberError = response.message ?? "Invalid GST number";
notifyListeners();
return false;
}
} catch (e) {
gstNumberError = "Error validating GST: ${e.toString()}";
if (kDebugMode) debugPrint('validateGstNumber error: $e');
notifyListeners();
return false;
} finally {
isLoading = false;
notifyListeners();
}
}
// --- Bank validation: requires both account number and IFSC ---
Future<bool> validateBankDetails(String empId, String sessionId, String accountNumber) async {
final ifsc = bankIfscCotroller.text.trim();
final accList = detailsListResponse?.accountList!.first;
if (accountNumber.trim().isEmpty || ifsc.isEmpty) {
bankResponse = null;
bankAcNumberError = null;
bankIFSCError = null;
bankNameController.text = "";
branchNameController.text = "";
bankHolderNameController.text = "";
bankNameController.text = accList?.bankName ?? "";
branchNameController.text = accList?.bankBranchName ?? "";
bankHolderNameController.text = accList?.bankAccountHolderName ?? "";
notifyListeners();
return false;
}
if (bankAcNumberController.text.isEmpty || bankIfscCotroller.text.isEmpty) {
bankNameController.text = "";
branchNameController.text = "";
bankHolderNameController.text = "";
bankNameController.text = accList?.bankName ?? "";
branchNameController.text = accList?.bankBranchName ?? "";
bankHolderNameController.text = accList?.bankAccountHolderName ?? "";
notifyListeners();
return false;
}
final reg = RegExp(r'^[A-Za-z]{4}0[A-Za-z0-9]{6}$');
if (!reg.hasMatch(ifsc)) {
bankIFSCError = "Invalid IFSC format";
notifyListeners();
return false;
}
try {
isLoading = true;
final response = await ApiCalling.validateBankAccountDetailsApi(empId, sessionId, accountNumber.trim(), ifsc);
bankResponse = response;
if (response == null) {
bankAcNumberError = "Failed to validate bank account";
notifyListeners();
return false;
}
if (response.error == "0") {
bankAcNumberError = null;
bankIFSCError = null;
notifyListeners();
return true;
} else {
bankAcNumberError = response.message ?? "Invalid account details";
notifyListeners();
return false;
}
} catch (e) {
bankAcNumberError = "Error validating account: ${e.toString()}";
if (kDebugMode) debugPrint('validateBankDetails error: $e');
notifyListeners();
return false;
} finally {
isLoading = false;
notifyListeners();
}
}
// --- Combines validation and applies response (autofill) for GST ---
Future<void> checkAndApplyGst(BuildContext context, String gstNumber) async {
gstNumberError = null;
notifyListeners();
final trimmed = gstNumber.trim();
if (trimmed.isEmpty) {
gstResponse = null;
gstNumberError = null;
notifyListeners();
return;
}
try {
isLoading = true;
final homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final resp = await ApiCalling.validateGstNumberApi(homeProv.empId, homeProv.session, trimmed);
gstResponse = resp;
if (resp == null) {
gstNumberError = "Failed to validate GST number";
notifyListeners();
return;
}
if (resp.error == "0") {
// autofill address if available
final apiAddress = (resp.address ?? "").trim();
final apiName = (resp.legalNameOfBusiness ?? "").trim();
if (apiAddress.isNotEmpty) {
addressController.text = apiAddress;
}
// compare company name and set error if mismatch
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
nameError = "Name Does not match with GST Legal Name : ('$apiName').";
} else {
nameError = null;
}
}
gstNumberError = null;
notifyListeners();
return;
} else {
_submitClicked = false;
gstNumberError = resp.message ?? "Invalid GST number";
notifyListeners();
return;
}
} catch (e) {
gstNumberError = "Error validating GST";
if (kDebugMode) debugPrint("checkAndApplyGst error: $e");
notifyListeners();
return;
} finally {
isLoading = false;
notifyListeners();
}
}
// --- Combines validation and applies response (autofill) for Bank ---
Future<void> checkAndApplyBank(BuildContext context, String accountNumber) async {
bankAcNumberError = null;
bankIFSCError = null;
notifyListeners();
final acc = accountNumber.trim();
final ifsc = bankIfscCotroller.text.trim();
if (acc.isEmpty && ifsc.isEmpty) {
bankResponse = null;
bankAcNumberError = null;
bankIFSCError = null;
notifyListeners();
return;
}
// If account entered, IFSC required
if (acc.isNotEmpty && ifsc.isEmpty) {
bankIFSCError = "IFSC is required when account number is entered";
notifyListeners();
return;
}
// validate IFSC format
final ifscReg = RegExp(r'^[A-Za-z]{4}0[A-Za-z0-9]{6}$');
if (ifsc.isNotEmpty && !ifscReg.hasMatch(ifsc)) {
bankIFSCError = "Invalid IFSC format";
notifyListeners();
return;
}
if (acc.isNotEmpty && ifsc.isNotEmpty) {
try {
isLoading = true;
final homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final resp = await ApiCalling.validateBankAccountDetailsApi(homeProv.empId, homeProv.session, acc, ifsc);
bankResponse = resp;
if (resp == null) {
bankAcNumberError = "Failed to validate bank details";
notifyListeners();
return;
}
if (resp.error == "0") {
// autofill bank fields from response
bankNameController.text = resp.bankName ?? bankNameController.text;
branchNameController.text = resp.branch ?? branchNameController.text;
bankHolderNameController.text = resp.nameAtBank ?? bankHolderNameController.text;
bankAcNumberError = null;
bankIFSCError = null;
banknameError = null;
bankBranchError = null;
bankHolderNameError = null;
notifyListeners();
return;
} else {
bankAcNumberError = resp.message ?? "Invalid account details";
notifyListeners();
return;
}
} catch (e) {
bankAcNumberError = "Error validating bank: ${e.toString()}";
if (kDebugMode) debugPrint("checkAndApplyBank error: $e");
notifyListeners();
return;
} finally {
isLoading = false;
notifyListeners();
}
}
}
// --- Re-compare company name with GST (UI calls this on name change) ---
void recheckNameWithGst() {
if (gstResponse == null) return;
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
nameError = "Name Does not match with GST Legal Name : ('$apiName').";
} else {
nameError = null;
}
}
notifyListeners();
}
Future<void> checkInputsAPI(context, type, value) async {
try {
var homeProv = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.commonAddAccountCheckInputsAPI(
homeProv.empId,
homeProv.session,
type,
value,
);
commonResponse =data;
if (data != null) {
if (data.error == "0") {
nameError = null;
mobileError = null;
notifyListeners();
} else if (data.error == "1") {
if (data.message?.contains("name already exists") ?? false) {
nameError = data.message ?? "";
} else {
mobileError = data.message ?? "";
}
notifyListeners();
}
}
} catch (e) {
if (kDebugMode) debugPrint('checkInputsAPI error: $e');
}
}
// --- Submit (update) API function (calls your existing commonUpdateAccountDetailsAPI) ---
Future<bool> updateAccountDetailsAPIFunction(
BuildContext context, {
required String accId,
required String name,
required String mob1,
String? mob2,
String? tel,
String? email,
String? designation,
String? address,
String? state,
String? district,
String? subLocality,
String? bankName,
String? branchName,
String? bankIfscCode,
String? accHolderName,
String? bankAccNumber,
String? bankUpiId,
}) async {
try {
_isSubmitting = true;
updateErrorMessage = null;
notifyListeners();
var prov = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.commonUpdateAccountDetailsAPI(
prov.empId,
prov.session,
accId,
name,
mob1,
mob2 ?? '',
tel ?? '',
email ?? '',
designation ?? '',
address ?? '',
state ?? '',
district ?? '',
subLocality ?? '',
bankName ?? '',
branchName ?? '',
bankIfscCode ?? '',
accHolderName ?? '',
bankAccNumber ?? '',
bankUpiId ?? '',
);
if (data == null) {
updateErrorMessage = "No response from server";
_isSubmitting = false;
notifyListeners();
return false;
}
if (data.error == "0" || data.error == 0) {
toast(context, data.message ?? "Updated successfully");
_isSubmitting = false;
notifyListeners();
return true;
} else {
updateErrorMessage = data.message ?? "Failed to update account";
_isSubmitting = false;
notifyListeners();
return false;
}
} catch (e, s) {
if (kDebugMode) debugPrint("updateAccountDetailsAPIFunction error: $e\n$s");
updateErrorMessage = e.toString();
_isSubmitting = false;
notifyListeners();
return false;
}
}
bool _isGstValidFormat(String gst) {
gst = gst.trim().toUpperCase();
final reg = RegExp(r'^[0-3][0-9][A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$');
return reg.hasMatch(gst);
}
// --- Simple validation (keeps same logic as your UI expects) ---
bool validateStep1(BuildContext context) {
accountError = null;
nameError = null;
mobileError = null;
gstNumberError = null;
contactPersonError = null;
bool isValid = true;
if (_selectedAccountType == null || _selectedAccountType!.isEmpty) {
accountError = "Please select an Account";
isValid = false;
}
if (nameController.text.trim().isEmpty) {
nameError = "Please Enter a Name";
isValid = false;
}
if(gstNumberController.text.trim().isNotEmpty){
final gst = gstNumberController.text.trim();
if (!_isGstValidFormat(gst)) {
gstNumberError = "Invalid GST format";notifyListeners();
isValid = false;
}
}
if(gstNumberController.text.isEmpty){
final accList = detailsListResponse?.accountList!.first;
final gst = gstNumberController.text.trim();
addressController.text = accList?.address ?? "";
}
if (nameError != null && nameError!.isNotEmpty) {
isValid = false;
}
if (mobileController.text.trim().isNotEmpty && mobileController.text.length < 10) {
mobileError = "Mobile Number should be 10 digits";
isValid = false;
}
if (mobileController.text.trim().isEmpty) {
mobileError = "Please Enter Mobile Number";
isValid = false;
}
if (contactPersonController.text.trim().isEmpty) {
contactPersonError = "Please Enter Contact Person Name";
isValid = false;
}
// GST vs name check if gstResponse present
if (gstResponse != null) {
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
nameError = "Company name does not match GST record ('$apiName')";
isValid = false;
} else {
nameError = null;
}
}
}
notifyListeners();
return isValid;
}
bool validateStep() {
final accList = detailsListResponse?.accountList!.first;
if (gstNumberController.text.isEmpty) {
final gst = gstNumberController.text.trim();
addressController.text = accList?.address ?? "";
}
notifyListeners();
return false;
}
bool validateStep3() {
final accList = detailsListResponse?.accountList!.first;
if (bankAcNumberController.text.isEmpty || bankIfscCotroller.text.isEmpty) {
bankNameController.text = "";
branchNameController.text = "";
bankHolderNameController.text = "";
bankNameController.text = accList?.bankName ?? "";
branchNameController.text = accList?.bankBranchName ?? "";
bankHolderNameController.text = accList?.bankAccountHolderName ?? "";
notifyListeners();
return false;
}
bool isValid = true;
// optional step — you commented it optional. Keep commented validations deactivated.
_submitClicked = false;
notifyListeners();
return isValid;
}
// Full form final validation before submit
bool validatereceiptForm(BuildContext context) {
// reset error holders
accountError = null; nameError = null; mobileError = null;
stateError = null; districtError = null; localityError = null; addressError = null;
banknameError = null; gstNumberError = null; bankBranchError = null; bankIFSCError = null;
bankHolderNameError = null; bankAcNumberError = null; upiError = null;
contactPersonError = null; desigantionError = null; altMobError = null; teleError = null; mailError = null;
bool isValid = true;
if (_selectedAccountType == null || _selectedAccountType!.isEmpty) {
accountError = "Please select an Account";
isValid = false;
}
if (nameController.text.trim().isEmpty) {
nameError = "Please Enter a Name";
isValid = false;
}
if (mobileController.text.trim().isEmpty) {
mobileError = "Please Enter Mobile Number";
isValid = false;
}
if (contactPersonController.text.trim().isEmpty) {
contactPersonError = "Please Enter Contact Person Name";
isValid = false;
}
// GST check
final apiName = (gstResponse?.legalNameOfBusiness ?? "").trim();
final enteredName = nameController.text.trim();
if (apiName.isNotEmpty && enteredName.isNotEmpty) {
if (apiName.toLowerCase() != enteredName.toLowerCase()) {
isValid = false;
nameError = "Company name does not match GST record ('$apiName')";
}
}
notifyListeners();
return isValid;
}
// --- update helper setters to clear errors on edit ---
void updateName(String value) {
nameError = null;
notifyListeners();
}
void updateMobile(String value) {
mobileError = null;
notifyListeners();
}
void updateAddress(String value) {
addressError = null;
notifyListeners();
}
void updateBankName(String value) {
banknameError = null;
notifyListeners();
}
void updateGSTNumber(String value) {
gstNumberError = null;
notifyListeners();
}
void updateBankBranch(String value) {
bankBranchError = null;
notifyListeners();
}
void updateIFSC(String value) {
bankIFSCError = null;
notifyListeners();
}
void updateHolder(String value) {
bankHolderNameError = null;
notifyListeners();
}
void updateNumber(String value) {
bankAcNumberError = null;
notifyListeners();
}
void updateUPI(String value) {
upiError = null;
notifyListeners();
}
void updateContactPerson(String value) {
contactPersonError = null;
notifyListeners();
}
void updateDesignation(String value) {
desigantionError = null;
notifyListeners();
}
void updateAltMobile(String value) {
altMobError = null;
notifyListeners();
}
void updateTeleMobile(String value) {
teleError = null;
notifyListeners();
}
void updateMail(String value) {
mailError = null;
notifyListeners();
}
// --- Reset values used by Edit form (clears controllers + errors + selections) ---
void resetValues() {
_selectedAccountType = null;
_selectedState = null;
_selectedDistricts = null;
_selectedSubLocations = null;
_selectedStateID = null;
_selectedDistrictID = null;
_selectedSubLocID = null;
gstResponse = null;
bankResponse = null;
commonResponse = null;
updateErrorMessage = null;
_isLoading = false;
_isSubmitting = false;
stateSearchController.clear();
districtSearchController.clear();
subLocSearchController.clear();
nameController.clear();
mobileController.clear();
addressController.clear();
bankNameController.clear();
branchNameController.clear();
bankIfscCotroller.clear();
bankHolderNameController.clear();
bankAcNumberController.clear();
bankUpiController.clear();
contactPersonController.clear();
contectPersonMailController.clear();
accountError = null;
nameError = null;
mobileError = null;
stateError = null;
districtError = null;
localityError = null;
addressError = null;
banknameError = null;
gstNumberError = null;
bankBranchError = null;
bankIFSCError = null;
bankHolderNameError = null;
bankAcNumberError = null;
upiError = null;
contactPersonError = null;
desigantionError = null;
altMobError = null;
teleError = null;
mailError = null;
addMoreDetailsError = null;
notifyListeners();
}
// dispose controllers when provider is disposed (optional)
@override
void dispose() {
nameController.dispose();
mobileController.dispose();
addressController.dispose();
bankNameController.dispose();
branchNameController.dispose();
bankIfscCotroller.dispose();
bankHolderNameController.dispose();
gstNumberController.dispose();
bankAcNumberController.dispose();
bankUpiController.dispose();
contactPersonController.dispose();
contectPersonMailController.dispose();
stateSearchController.dispose();
districtSearchController.dispose();
subLocSearchController.dispose();
super.dispose();
}
}
import 'dart:async';
import 'dart:io';
import 'dart:ui' as ui;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/Utils/SharedpreferencesService.dart';
import 'package:generp/screens/LoginScreen.dart';
import 'package:generp/services/api_calling.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:geocoding/geocoding.dart' as geocoding;
import 'package:location/location.dart' as Location;
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';
import '../../Models/NearbyGeneratorsResponse.dart';
import '../../Utils/commonServices.dart';
class CrmNearByGeneratorsProvider extends ChangeNotifier {
final ImagePicker _picker = ImagePicker();
List<Nearbygenerators> _generatorslist = [];
final TextEditingController _locationController = TextEditingController();
final String _googleApikey = "AIzaSyBGzvgMMKwPBAANTwaoRsAnrCpiWCj8wVs";
GoogleMapController? _mapController;
CameraPosition? _cameraPosition;
final LatLng _startLocation = const LatLng(
17.439112226708446,
78.43292499146135,
);
String _latlongs = "";
List<Marker> _markers = [];
List<String> _addresses = [];
Location.LocationData? _currentLocation;
bool _isLocationEnabled = false;
bool _hasLocationPermission = false;
Timer? _timer;
File? _image;
bool _isLoading = true;
String _selectedItem = 'Active';
double _currentValue = 1.0;
Timer? _debounceTimer;
List<Nearbygenerators> get generatorsList => _generatorslist;
TextEditingController get LocationController => _locationController;
String get googleAPIKey => _googleApikey;
GoogleMapController? get mapController => _mapController;
CameraPosition? get cameraPosition => _cameraPosition;
LatLng get startLocation => _startLocation;
String get latlongs => _latlongs;
List<Marker> get markers => _markers;
List<String> get addresses => _addresses;
Location.LocationData? get currentLocation => _currentLocation;
bool get isLocationEnabled => _isLocationEnabled;
bool get hasLocationPermission => _hasLocationPermission;
bool get isLoading => _isLoading;
Timer? get timer => _timer;
File? get image => _image;
String get selectedItem => _selectedItem;
double get currentValue => _currentValue;
set currentValue(value) {
_currentValue = value;
notifyListeners();
}
set selectedItem(String value) {
_selectedItem = value;
notifyListeners();
}
set markers(List<Marker> value) {
_markers = value;
notifyListeners();
}
set mapController(value) {
_mapController = value;
notifyListeners();
}
void resetAll() {
_currentValue = 1.0;
_selectedItem = "";
_markers = [];
_addresses = [];
}
Future<void> getLocationPermission(context) async {
// Check if location services are enabled
_isLocationEnabled = await Geolocator.isLocationServiceEnabled();
// Check if the app has been granted location permission
LocationPermission permission = await Geolocator.checkPermission();
_hasLocationPermission =
permission == LocationPermission.always ||
permission == LocationPermission.whileInUse;
final Location.Location location = Location.Location();
bool serviceEnabled;
Location.PermissionStatus permissionGranted;
serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) {
return;
}
}
_isLoading = false;
permissionGranted = (await location.hasPermission());
if (permissionGranted == PermissionStatus) {
permissionGranted = (await location.requestPermission());
if (permissionGranted != PermissionStatus) {
return;
}
}
final Location.LocationData locData = await location.getLocation();
_currentLocation = locData;
if (_currentLocation != null) {
_mapController?.animateCamera(
CameraUpdate.newLatLng(
LatLng(_currentLocation!.latitude!, _currentLocation!.longitude!),
),
);
final lat = _currentLocation!.latitude;
final lang = _currentLocation!.longitude!;
_latlongs = '$lat,$lang';
LoadNearbyGeneratorsAPI(context, _currentValue);
}
}
void onCameraMove(context, CameraPosition position) {
_timer?.cancel(); // Cancel any previous timer
_timer = Timer(Duration(seconds: 1), () {
getLocationPermission(context);
});
}
void debounce(VoidCallback callback, Duration duration) {
_debounceTimer?.cancel();
_debounceTimer = Timer(duration, callback);
}
Future<void> LoadNearbyGeneratorsAPI(BuildContext context, radius) async {
if (_latlongs.isEmpty || _currentValue <= 0) {
print(
"Invalid parameters: latlongs=$_latlongs, currentValue=$_currentValue",
);
return;
}
try {
var provider = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.loadCrmNearbyGeneratorsAPI(
provider.empId,
provider.session,
_latlongs,
_currentValue,
_selectedItem,
);
if (data != null) {
if (data.sessionExists == 1) {
if (data.error == 0) {
_generatorslist = data.list!;
await updateMarkersFromApiResponse(context, data.list!);
_isLoading = false;
notifyListeners();
} else {}
} else {
// SharedpreferencesService().clearPreferences();
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => LoginScreen()),
// );
}
} else {
toast(context, "Something went wrong, Please try again.");
}
} on Exception catch (e) {
print("$e");
}
}
Future<void> updateMarkersFromApiResponse(
BuildContext context,
List<Nearbygenerators> generatorslist,
) async {
_markers = await createMarkersFromApiResponse(context, generatorslist);
_addresses.clear();
await Future.forEach(generatorslist, (store) async {
String address = await _getAddressFromLatLng(store.loc);
_addresses.add(address);
});
notifyListeners();
// for (int i = 0; i < _addresses.length; i++) {
// //print('List of Addresses:' "${addresses[i]}");
// // print('List of Addresses:' "${addresses[1]}" );
// }
}
Future<List<Marker>> createMarkersFromApiResponse(
BuildContext context,
List<Nearbygenerators> generatorslist,
) async {
List<Marker> markers = [];
// print("Hello Nutsby!");
ByteData data = await rootBundle.load("assets/images/dg_set.png");
Uint8List bytes = data.buffer.asUint8List();
await Future.forEach(generatorslist, (generator) async {
ui.Codec codec = await ui.instantiateImageCodec(
bytes,
targetWidth: 75,
targetHeight: 95,
);
ui.FrameInfo fi = await codec.getNextFrame();
Uint8List resizedBytes =
(await fi.image.toByteData(
format: ui.ImageByteFormat.png,
))!.buffer.asUint8List();
markers.add(
Marker(
markerId: MarkerId(generator.generatorId.toString()),
position: _parseLatLng(generator.loc),
icon: BitmapDescriptor.fromBytes(resizedBytes),
infoWindow: InfoWindow(
onTap: () {
print("INFO WINDOW TAP");
},
title: "Customer Name: ${generator.accName}",
snippet: "Product Name: ${generator.productName}",
),
zIndex: 100,
),
);
});
return markers;
}
LatLng _parseLatLng(String? location) {
if (location != null) {
List<String> parts = location.split(',');
if (parts.length == 2) {
double lat = double.tryParse(parts[0]) ?? 0.0;
double lng = double.tryParse(parts[1]) ?? 0.0;
return LatLng(lat, lng);
}
}
return const LatLng(0.0, 0.0);
}
Future<String> _getAddressFromLatLng(String? location) async {
if (location != null) {
List<String> parts = location.split(',');
if (parts.length == 2) {
double lat = double.tryParse(parts[0]) ?? 0.0;
double lng = double.tryParse(parts[1]) ?? 0.0;
List<geocoding.Placemark> placemarks = await geocoding
.placemarkFromCoordinates(lat, lng);
if (placemarks.isNotEmpty) {
final placemark = placemarks.first;
String address =
'${placemark.street ?? ''}, '
'${placemark.thoroughfare ?? ''} '
// '${placemark.subThoroughfare ?? ''}, '
// '${placemark.name ?? ''}, '
'${placemark.subLocality ?? ''}, '
'${placemark.locality ?? ''}, '
'${placemark.administrativeArea ?? ''}, '
'${placemark.subAdministrativeArea ?? ''} '
'${placemark.postalCode ?? ''}, '
'${placemark.country ?? ''}';
return address.trim();
}
}
}
return "Address not found";
}
}
...@@ -302,27 +302,45 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -302,27 +302,45 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
} catch (e) {} } catch (e) {}
} }
preValues() { preValues() {// safeNormalizeAmount()
print("here 212ssass1"); print("here 212ssass1");
requestedAmount.text = _requestDetails.requestedAmount ?? "-"; requestedAmount.text = safeNormalizeAmount(_requestDetails.requestedAmount);
proposedPaymentAccount.text = _requestDetails.proposedAccount ?? "-"; proposedPaymentAccount.text = _requestDetails.proposedAccount ?? "-";
approvedAmountReadonly.text = _requestDetails.formattedAmount ?? "-"; approvedAmountReadonly.text = safeNormalizeAmount(_requestDetails.amount);
approvedAmount.text = _requestDetails.amount ?? "-"; approvedAmount.text = safeNormalizeAmount(_requestDetails.amount);
accountName.text = _requestDetails.accountName ?? "-"; accountName.text = _requestDetails.accountName ?? "";
branch.text = _requestDetails.branch ?? "-"; branch.text = _requestDetails.branch ?? "";
requestingPurpose.text = _requestDetails.requestingPurpose ?? "-"; requestingPurpose.text = _requestDetails.requestingPurpose ?? "";
description.text = _requestDetails.description ?? "-"; description.text = _requestDetails.description ?? "";
amount.text = _requestDetails.amount ?? "-"; amount.text = safeNormalizeAmount(_requestDetails.amount);
paymentMode.text = _requestDetails.requestMode ?? "-"; paymentMode.text = _requestDetails.requestMode ?? "";
bankUpiID.text = _requestDetails.bankUpiId ?? "-"; bankUpiID.text = _requestDetails.bankUpiId ?? "";
bankName.text = _requestDetails.bankName ?? "-"; bankName.text = _requestDetails.bankName ?? "";
bankBranchName.text = _requestDetails.bankBranchname ?? "-"; bankBranchName.text = _requestDetails.bankBranchname ?? "";
bankAccountNumber.text = _requestDetails.bankAccountNumber ?? "-"; bankAccountNumber.text = _requestDetails.bankAccountNumber ?? "";
bankIfscCode.text = _requestDetails.bankIfscCode ?? "-"; bankIfscCode.text = _requestDetails.bankIfscCode ?? "";
bankHolderName.text = _requestDetails.bankAccountHolderName ?? "-"; bankHolderName.text = _requestDetails.bankAccountHolderName ?? "";
notifyListeners(); notifyListeners();
} }
String safeNormalizeAmount(String? input) {
if (input == null || input.trim().isEmpty) return "0";
// Remove currency symbols, commas and spaces - keep digits and dots
String cleaned = input.replaceAll(RegExp(r'[^0-9.]'), '');
// Handle multiple decimal points: keep only first dot
int firstDot = cleaned.indexOf('.');
if (firstDot != -1) {
String before = cleaned.substring(0, firstDot + 1);
String after = cleaned.substring(firstDot + 1).replaceAll('.', '');
cleaned = before + after;
}
return cleaned.isEmpty ? "0" : cleaned;
}
Future<void> approveRejectPaymentRequestAPIFunction( Future<void> approveRejectPaymentRequestAPIFunction(
context, context,
paymentRequestId, paymentRequestId,
...@@ -363,31 +381,31 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -363,31 +381,31 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
paymentRequestId, paymentRequestId,
approveRemarks, approveRemarks,
) async { ) async {
print("🎯 === REJECT PROVIDER METHOD STARTED ==="); print(" === REJECT PROVIDER METHOD STARTED ===");
// Set loading to true at the start // Set loading to true at the start
_isLoading = true; _isLoading = true;
notifyListeners(); notifyListeners();
print("🔄 Loading set to TRUE in reject method"); print(" Loading set to TRUE in reject method");
bool success = false; bool success = false;
try { try {
print("🔍 Starting validation for rejection..."); print(" Starting validation for rejection...");
if (approveRemarks.toString().trim().isEmpty) { // if (approveRemarks.toString().trim().isEmpty) {
print(" Remarks validation failed"); // print(" Remarks validation failed");
remarksError = "Please Enter Remarks"; // remarksError = "Please Enter Remarks";
_isLoading = false; // _isLoading = false;
notifyListeners(); // notifyListeners();
return false; // return false;
} // }
print(" Validation passed"); print(" Validation passed");
var provider = Provider.of<HomescreenNotifier>(context, listen: false); var provider = Provider.of<HomescreenNotifier>(context, listen: false);
print("🌐 Calling reject API..."); print(" Calling reject API...");
final data = await ApiCalling.RejectPaymentRequestSubmitAPI( final data = await ApiCalling.RejectPaymentRequestSubmitAPI(
provider.empId, provider.empId,
provider.session, provider.session,
...@@ -395,36 +413,36 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -395,36 +413,36 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
paymentRequestId, paymentRequestId,
approveRemarks, approveRemarks,
); );
print("🌐 Reject API call completed"); print(" Reject API call completed");
if (data != null) { if (data != null) {
print("📡 Reject API Response: error=${data.error}, message=${data.message}"); print(" Reject API Response: error=${data.error}, message=${data.message}");
if (data.error == "0") { if (data.error == "0") {
print(" Reject API SUCCESS"); print(" Reject API SUCCESS");
success = true; success = true;
if (context.mounted) { if (context.mounted) {
print("🎯 Context mounted - performing UI operations"); print(" Context mounted - performing UI operations");
paymentRequesitionDetails(context, paymentRequestId); paymentRequesitionDetails(context, paymentRequestId);
resetAll(); resetAll();
toast(context, data.message); toast(context, data.message);
Navigator.pop(context, true); // Pass true to indicate success Navigator.pop(context, true); // Pass true to indicate success
} }
} else { } else {
print(" Reject API returned error: ${data.message}"); print(" Reject API returned error: ${data.message}");
if (context.mounted) { if (context.mounted) {
toast(context, data.message ?? "Rejection failed"); toast(context, data.message ?? "Rejection failed");
} }
} }
} else { } else {
print(" NULL response from reject API"); print(" NULL response from reject API");
if (context.mounted) { if (context.mounted) {
toast(context, "No response from server"); toast(context, "No response from server");
} }
} }
} catch (e) { } catch (e) {
print("💥 EXCEPTION in reject provider method: $e"); print(" EXCEPTION in reject provider method: $e");
if (context.mounted) { if (context.mounted) {
toast(context, "Error: ${e.toString()}"); toast(context, "Error: ${e.toString()}");
} }
...@@ -433,10 +451,10 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -433,10 +451,10 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
print("🔄 Loading set to FALSE in reject method finally block"); print(" Loading set to FALSE in reject method finally block");
} }
print("🎯 === REJECT PROVIDER METHOD COMPLETED ==="); print(" === REJECT PROVIDER METHOD COMPLETED ===");
return success; return success;
} }
...@@ -457,27 +475,27 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -457,27 +475,27 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
String approve_remarks, String approve_remarks,
String proposed_payment_account_id, String proposed_payment_account_id,
) async { ) async {
print("🎯 === PROVIDER METHOD STARTED ==="); print(" === PROVIDER METHOD STARTED ===");
// Set loading to true at the start // Set loading to true at the start
_isLoading = true; _isLoading = true;
notifyListeners(); notifyListeners();
try { try {
print("🔍 Starting validation..."); print(" Starting validation...");
if (!validateApproval(approved_amount, approve_remarks, proposed_payment_account_id)) { if (!validateApproval(approved_amount, approve_remarks, proposed_payment_account_id)) {
print(" VALIDATION FAILED - Stopping execution"); print(" VALIDATION FAILED - Stopping execution");
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
return; return;
} }
print(" Validation passed"); print(" Validation passed");
print("👤 Getting home provider..."); print(" Getting home provider...");
var homeProvider = Provider.of<HomescreenNotifier>(context, listen: false); var homeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
print("👤 Emp ID: ${homeProvider.empId}, Session: ${homeProvider.session}"); print(" Emp ID: ${homeProvider.empId}, Session: ${homeProvider.session}");
print("🌐 Calling API..."); print(" Calling API...");
final data = await ApiCalling.ApprovePaymentRequestSubmitAPI( final data = await ApiCalling.ApprovePaymentRequestSubmitAPI(
homeProvider.empId, homeProvider.empId,
homeProvider.session, homeProvider.session,
...@@ -487,43 +505,43 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -487,43 +505,43 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
approve_remarks, approve_remarks,
proposed_payment_account_id, proposed_payment_account_id,
); );
print("🌐 API call completed"); print(" API call completed");
if (data != null) { if (data != null) {
print("📡 API Response: error=${data.error}, message=${data.message}"); print(" API Response: error=${data.error}, message=${data.message}");
if (data.error == "0") { if (data.error == "0") {
print(" API SUCCESS - Processing..."); print(" API SUCCESS - Processing...");
// Check if context is still valid before UI operations // Check if context is still valid before UI operations
if (context.mounted) { if (context.mounted) {
print("🎯 Context mounted - performing UI operations"); print(" Context mounted - performing UI operations");
paymentRequesitionDetails(context, payment_request_id); paymentRequesitionDetails(context, payment_request_id);
resetAll(); resetAll();
toast(context, data.message); toast(context, data.message);
Navigator.pop(context, true); Navigator.pop(context, true);
print(" UI operations completed"); print(" UI operations completed");
} else { } else {
print("️ Context not mounted - skipping UI operations"); print("️ Context not mounted - skipping UI operations");
} }
notifyListeners(); notifyListeners();
print(" Notify listeners called"); print(" Notify listeners called");
} else { } else {
print(" API returned error: ${data.message}"); print(" API returned error: ${data.message}");
if (context.mounted) { if (context.mounted) {
toast(context, data.message ?? "Submission failed"); toast(context, data.message ?? "Submission failed");
} }
} }
} else { } else {
print(" NULL response from API"); print(" NULL response from API");
if (context.mounted) { if (context.mounted) {
toast(context, "No response from server"); toast(context, "No response from server");
} }
} }
} catch (e, s) { } catch (e, s) {
print("💥 EXCEPTION in provider method: $e"); print(" EXCEPTION in provider method: $e");
print("📋 Stack trace: $s"); print(" Stack trace: $s");
// Show error to user // Show error to user
if (context.mounted) { if (context.mounted) {
toast(context, "Error: ${e.toString()}"); toast(context, "Error: ${e.toString()}");
...@@ -532,10 +550,10 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -532,10 +550,10 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
// Set loading to false when everything is done (success or error) // Set loading to false when everything is done (success or error)
_isLoading = false; _isLoading = false;
notifyListeners(); notifyListeners();
print("🔄 Loading state set to false"); print(" Loading state set to false");
} }
print("🎯 === PROVIDER METHOD COMPLETED ==="); print(" === PROVIDER METHOD COMPLETED ===");
} }
...@@ -640,11 +658,11 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -640,11 +658,11 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
} }
bool validateApproval( bool validateApproval(
String approvedAmount, // Add type for clarity String approvedAmount, //
String approveRemarks, // Add type for clarity String approveRemarks, //
String proposedPaymentAccountId, // Add type for clarity String proposedPaymentAccountId, //
) { ) {
print("🔍 === VALIDATION STARTED ==="); print(" === VALIDATION STARTED ===");
print(" Approved Amount: '$approvedAmount'"); print(" Approved Amount: '$approvedAmount'");
print(" Requested Amount: '${requestedAmount.text}'"); print(" Requested Amount: '${requestedAmount.text}'");
print(" Remarks: '$approveRemarks'"); print(" Remarks: '$approveRemarks'");
...@@ -664,11 +682,11 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -664,11 +682,11 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
} }
// Fix 2: Use the String parameter directly (no .text) // Fix 2: Use the String parameter directly (no .text)
if (approveRemarks.trim().isEmpty) { // if (approveRemarks.trim().isEmpty) {
remarksError = "Please Enter Remarks"; // remarksError = "Please Enter Remarks";
isValid = false; // isValid = false;
print("❌ Remarks are empty"); // print("❌ Remarks are empty");
} // }
// Fix 3: Parse the String parameters, not .text // Fix 3: Parse the String parameters, not .text
if (approvedAmount.trim().isNotEmpty && requestedAmount.text.trim().isNotEmpty) { if (approvedAmount.trim().isNotEmpty && requestedAmount.text.trim().isNotEmpty) {
...@@ -677,35 +695,35 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -677,35 +695,35 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
double approved = numberFormat.parse(approvedAmount.trim()).toDouble(); double approved = numberFormat.parse(approvedAmount.trim()).toDouble();
double requested = numberFormat.parse(requestedAmount.text.trim()).toDouble(); double requested = numberFormat.parse(requestedAmount.text.trim()).toDouble();
print("💰 Amount Comparison: Approved: $approved, Requested: $requested"); print(" Amount Comparison: Approved: $approved, Requested: $requested");
if (approved > requested) { if (approved > requested) {
ApprovedAmountError = "Approved Amount should not be greater than requested amount"; ApprovedAmountError = "Approved Amount should not be greater than requested amount";
isValid = false; isValid = false;
print(" Approved amount exceeds requested amount"); print(" Approved amount exceeds requested amount");
} }
} catch (e) { } catch (e) {
print("💥 Error parsing amounts: $e"); print(" Error parsing amounts: $e");
ApprovedAmountError = "Invalid amount format"; ApprovedAmountError = "Invalid amount format";
isValid = false; isValid = false;
} }
} }
// Fix 4: Use the parameter OR check both for consistency // Fix 4: Use the parameter OR check both for consistency
if (proposedPaymentAccountId.isEmpty && _selectedID.isEmpty) { // if (proposedPaymentAccountId.isEmpty && _selectedID.isEmpty) {
selectpaymentAccountError = "Please select an account"; // selectpaymentAccountError = "Please select an account";
isValid = false; // isValid = false;
print(" No payment account selected"); // // print(" No payment account selected");
} else if (proposedPaymentAccountId.isNotEmpty && _selectedID.isEmpty) { // } else if (proposedPaymentAccountId.isNotEmpty && _selectedID.isEmpty) {
// If parameter has value but _selectedID doesn't, sync them // // If parameter has value but _selectedID doesn't, sync them
_selectedID = proposedPaymentAccountId; // _selectedID = proposedPaymentAccountId;
print("🔄 Synced selected ID from parameter: $_selectedID"); // // print(" Synced selected ID from parameter: $_selectedID");
} // }
_submitClicked = false; _submitClicked = false;
notifyListeners(); notifyListeners();
print("🔍 === VALIDATION RESULT: $isValid ==="); // print(" === VALIDATION RESULT: $isValid ===");
return isValid; return isValid;
} }
...@@ -779,6 +797,12 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier { ...@@ -779,6 +797,12 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
resetRequired() {
remarksError = null;
selectpaymentAccountError = null;
notifyListeners();
}
onChangeApprov(value) { onChangeApprov(value) {
final numberFormat = NumberFormat.decimalPattern(); final numberFormat = NumberFormat.decimalPattern();
if (numberFormat.parse(approvedAmount.text) > if (numberFormat.parse(approvedAmount.text) >
......
...@@ -184,6 +184,12 @@ class Loginnotifier extends ChangeNotifier { ...@@ -184,6 +184,12 @@ class Loginnotifier extends ChangeNotifier {
SharedpreferencesService().saveString("UserName", data.name!); SharedpreferencesService().saveString("UserName", data.name!);
SharedpreferencesService().saveString("UserEmail", data.emailId!); SharedpreferencesService().saveString("UserEmail", data.emailId!);
SharedpreferencesService().saveString("Session_id", data.sessionId!); SharedpreferencesService().saveString("Session_id", data.sessionId!);
SharedpreferencesService().saveString("user", data.userId!);
SharedpreferencesService().saveString("session", data.sessionId!);
print("USER ID : ${data.userId}");
print("SESSISON ID: ${data.sessionId}");
var roles = data.permissions!.toString(); var roles = data.permissions!.toString();
SharedpreferencesService().saveString("roles", roles); SharedpreferencesService().saveString("roles", roles);
......
// lib/services/background_location_service.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'package:geolocator/geolocator.dart';
import 'package:provider/provider.dart';
import '../Notifiers/HomeScreenNotifier.dart';
import '../services/api_calling.dart';
import 'SharedpreferencesService.dart';
@pragma('vm:entry-point')
void startCallback() {
FlutterForegroundTask.setTaskHandler(LocationTaskHandler());
}
class LocationTaskHandler extends TaskHandler {
StreamSubscription<Position>? _stream;
String? _empId;
String? _sessionId;
@override
Future<void> onStart(DateTime timestamp, TaskStarter starter) async {
// Load user data
_empId = await SharedpreferencesService().getString("user");
_sessionId = await SharedpreferencesService().getString("session");
// var prov = Provider.of<HomescreenNotifier>(context, listen: false);
// _empId = prov.empId;
// _sessionId = prov.session;
print("DATA : ${_empId}");
print("DATA : ${_sessionId}");
if (_empId == null || _sessionId == null) {
FlutterForegroundTask.updateService(
notificationTitle: "GEN ERP",
notificationText: "Please login first",
);
return;
}
// Start real-time location stream (when moving)
_stream = Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 20, // Only send if moved 20 meters
),
).listen((position) {
_sendLocationToApi(position);
});
// Send first location immediately
_sendCurrentLocationOnce();
FlutterForegroundTask.updateService(
notificationTitle: "GEN ERP",
notificationText: "Live tracking active",
);
}
Future<void> _sendCurrentLocationOnce() async {
try {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: const Duration(seconds: 15),
);
await _sendLocationToApi(position);
} catch (e) {
if (kDebugMode) print("Initial location failed: $e");
}
}
Future<void> _sendLocationToApi(Position position) async {
final location = "${position.latitude},${position.longitude}";
_empId = await SharedpreferencesService().getString("user");
_sessionId = await SharedpreferencesService().getString("session");
print("DATA111 : ${_empId}");
print("DATA111 : ${_sessionId}");
try {
final result = await ApiCalling.trackLiveLocationEmpolyeeAPI(
_empId!,
_sessionId!,
location,
);
if (result != null && result.error == "0") {
FlutterForegroundTask.updateService(
notificationTitle: "GEN ERP",
notificationText: "Location sent • ${DateTime.now().toString().substring(11, 19)}",
);
} else {
FlutterForegroundTask.updateService(
notificationText: "Sync failed • Retrying...",
);
}
} catch (e) {
FlutterForegroundTask.updateService(
notificationText: "No network • Retrying...",
);
}
// Save last sent time
final time = DateTime.now().toString().substring(11, 19);
SharedpreferencesService().saveString("lastLocationTime", time);
}
// This runs every 6 minutes (fallback when not moving)
@override
void onRepeatEvent(DateTime timestamp) {
_sendCurrentLocationOnce();
}
@override
Future<void> onDestroy(DateTime timestamp, bool isTimeout) async {
_stream?.cancel();
}
}
// Main Service Controller
class BackgroundLocationServiceNew {
static Future<void> init() async {
FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'gen_erp_location_channel',
channelName: 'GEN ERP Tracking',
channelDescription: 'Sends location every 6 minutes',
channelImportance: NotificationChannelImportance.HIGH,
priority: NotificationPriority.HIGH,
showBadge: true,
visibility: NotificationVisibility.VISIBILITY_SECRET
),
iosNotificationOptions: const IOSNotificationOptions(),
foregroundTaskOptions: ForegroundTaskOptions(
eventAction: ForegroundTaskEventAction.repeat(360000), // Every 6 minutes
autoRunOnBoot: false, // Prevents crash on boot
allowWakeLock: true,
allowWifiLock: true,
),
);
}
static Future<bool> get isRunning => FlutterForegroundTask.isRunningService;
static Future<void> start() async {
if (await isRunning) {
await FlutterForegroundTask.restartService();
} else {
await FlutterForegroundTask.startService(
notificationTitle: 'GEN ERP',
notificationText: 'Starting location tracking...',
callback: startCallback,
);
}
}
static Future<void> stop() async {
await FlutterForegroundTask.stopService();
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment