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 {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "in.webgrid.generp"
minSdk = 23
minSdk = flutter.minSdkVersion
targetSdk = 36
versionCode = flutter.versionCode
versionName = flutter.versionName
......
......@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name="${applicationName}"
......@@ -77,6 +78,12 @@
</intent-filter>
</activity>
<service
android:name="com.pravera.flutter_foreground_task.service.ForegroundService"
android:foregroundServiceType="location"
android:exported="false"/>
<meta-data
android:name="flutter_deeplinking_enabled"
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 {
if (json['list'] != null) {
list = <Followuplist>[];
json['list'].forEach((v) {
list!.add(Followuplist.fromJson(v));
list!.add(new Followuplist.fromJson(v));
});
}
error = json['error'];
......@@ -17,12 +17,12 @@ class FollowupListResponse {
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (list != null) {
data['list'] = list!.map((v) => v.toJson()).toList();
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.list != null) {
data['list'] = this.list!.map((v) => v.toJson()).toList();
}
data['error'] = error;
data['session_exists'] = sessionExists;
data['error'] = this.error;
data['session_exists'] = this.sessionExists;
return data;
}
}
......@@ -42,8 +42,8 @@ class Followuplist {
String? time;
String? ename;
Followuplist({
this.id,
Followuplist(
{this.id,
this.empId,
this.compId,
this.inTime,
......@@ -55,8 +55,7 @@ class Followuplist {
this.fsrExt,
this.runningHrs,
this.time,
this.ename,
});
this.ename});
Followuplist.fromJson(Map<String, dynamic> json) {
id = json['id'];
......@@ -75,20 +74,20 @@ class Followuplist {
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['emp_id'] = empId;
data['comp_id'] = compId;
data['in_time'] = inTime;
data['out_time'] = outTime;
data['feedback'] = feedback;
data['type'] = type;
data['date'] = date;
data['fsr_no'] = fsrNo;
data['fsr_ext'] = fsrExt;
data['running_hrs'] = runningHrs;
data['time'] = time;
data['ename'] = ename;
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['emp_id'] = this.empId;
data['comp_id'] = this.compId;
data['in_time'] = this.inTime;
data['out_time'] = this.outTime;
data['feedback'] = this.feedback;
data['type'] = this.type;
data['date'] = this.date;
data['fsr_no'] = this.fsrNo;
data['fsr_ext'] = this.fsrExt;
data['running_hrs'] = this.runningHrs;
data['time'] = this.time;
data['ename'] = this.ename;
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';
import '../Utils/BackgroundLocationService.dart';
import '../Utils/SharedpreferencesService.dart';
import '../Utils/backgroundServiceNew.dart';
import '../Utils/background_service.dart';
import '../Utils/commonServices.dart';
import '../services/api_calling.dart';
......@@ -229,6 +230,8 @@ class CheckInOutProvider with ChangeNotifier {
if (data.error == 0) {
toast(context, "CheckedIn Successfully");
await BackgroundLocationService.startLocationService(context);
await BackgroundLocationServiceNew.init();
await BackgroundLocationServiceNew.start();
locationController.clear();
dispose();
Navigator.pop(context, true);
......@@ -266,6 +269,7 @@ class CheckInOutProvider with ChangeNotifier {
if (data.error == 0) {
toast(context, "Check-Out Successful");
await BackgroundLocationService.stopLocationService();
await BackgroundLocationServiceNew.stop();
locationController.clear();
dispose();
Navigator.pop(context, true);
......
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:generp/Utils/SharedpreferencesService.dart';
import 'package:generp/Utils/backgroundServiceNew.dart';
import 'package:generp/screens/LoginScreen.dart';
import 'package:generp/services/api_calling.dart';
import 'package:intl/intl.dart';
......@@ -77,6 +78,8 @@ class HomescreenNotifier extends ChangeNotifier {
var lastLocationTime = await SharedpreferencesService().getString(
"lastLocationTime",
);
notifyListeners();
print("lastLocationTime:$lastLocationTime");
......@@ -112,6 +115,7 @@ class HomescreenNotifier extends ChangeNotifier {
if (_att_status == 0) {
webSocketManager.close();
await BackgroundLocationService.stopLocationService();
BackgroundLocationServiceNew.stop();
_onlineStatus = "Offline";
......@@ -151,11 +155,14 @@ class HomescreenNotifier extends ChangeNotifier {
// print("Status knlknn offine");
}
await BackgroundLocationService.startLocationService(context);
await BackgroundLocationServiceNew.init();
await BackgroundLocationServiceNew.start();
// print("setstatus:$setstatus");
} else if (_att_status == 2) {
// print("att_status:$att_status");
webSocketManager.close();
await BackgroundLocationService.stopLocationService();
await BackgroundLocationServiceNew.stop();
_onlineStatus = "Offline";
......
......@@ -5,6 +5,7 @@ import 'package:generp/screens/LoginScreen.dart';
import 'package:generp/services/api_calling.dart';
import '../Utils/BackgroundLocationService.dart';
import '../Utils/backgroundServiceNew.dart';
class LogoutNotifier extends ChangeNotifier {
bool _logoutButtonClicked = false;
......@@ -33,6 +34,8 @@ class LogoutNotifier extends ChangeNotifier {
_isLoading = false;
_logoutButtonClicked = false;
await BackgroundLocationService.stopLocationService();
await BackgroundLocationServiceNew.stop();
SharedpreferencesService().clearPreferences();
Navigator.push(
context,
......
......@@ -17,6 +17,7 @@ import '../Utils/commonServices.dart';
import '../screens/splash.dart';
class Pendingcomplaintsprovider extends ChangeNotifier {
TextEditingController fsrNumberController = TextEditingController();
TextEditingController runningHoursController = TextEditingController();
TextEditingController feedbackController = TextEditingController();
......
import 'dart:async';
import 'package:flutter/material.dart';
import '../Models/ordersModels/commonResponse.dart';
import '../Utils/custom_snackbar.dart';
import '../services/api_calling.dart';
class QrProvider extends ChangeNotifier {
CommonResponse? _qrResponse;
bool _isLoading = false;
......@@ -19,7 +17,6 @@ class QrProvider extends ChangeNotifier {
Timer? _timer;
/// Fetch Razorpay QR API
Future<void> fetchRazorpayQr({
required String sessionId,
required String empId,
......@@ -54,7 +51,6 @@ class QrProvider extends ChangeNotifier {
}
}
/// Start 2-minute countdown
void _startTimer() {
_secondsLeft = 120;
_timer?.cancel();
......@@ -68,12 +64,12 @@ class QrProvider extends ChangeNotifier {
});
}
/// Dispose timer properly
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
bool _isPaymentUpdating = false;
bool get isPaymentUpdating => _isPaymentUpdating;
......@@ -83,6 +79,7 @@ class QrProvider extends ChangeNotifier {
}
/// Fetch Razorpay QR Payment Status
/// NOTE: This method no longer shows snackbars itself. It simply returns the response.
Future<CommonResponse?> fetchRazorpayUpiQrStatus({
required BuildContext context,
required String sessionId,
......@@ -100,25 +97,22 @@ class QrProvider extends ChangeNotifier {
if (response != null) {
if (response.sessionExists == 1 && response.error == "0") {
debugPrint(" Payment Status: ${response.message}");
debugPrint("Payment Status: ${response.message}");
} else {
CustomSnackBar.showWarning(
context: context,
message: "⚠️ Payment not yet completed or failed"
);
debugPrint("⚠️ Payment not yet completed or failed");
// IMPORTANT: do not show UI here (no repeated warnings).
// The caller (screen) should decide when to show failure messages.
debugPrint("Payment still pending or failed: ${response.message}");
}
} 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) {
debugPrint("fetchRazorpayUpiQrStatus error: $e");
debugPrint("fetchRazorpayUpiQrStatus error: $e");
return null;
} finally {
isPaymentUpdating = false;
}
}
}
......@@ -4,6 +4,7 @@ import 'package:generp/services/api_calling.dart';
import 'package:provider/provider.dart';
import '../Models/FollowUpResponse.dart';
import '../Models/ServiceComplaintBillListResponse.dart';
import '../Models/ViewVisitDetailsResponseNew.dart';
import '../Utils/commonServices.dart';
......@@ -14,26 +15,79 @@ class Visitdetailsprovider extends ChangeNotifier {
GeneratorDetails _generatorDetails = GeneratorDetails();
ComplaintDetailsNew _complaintDetailsNew = ComplaintDetailsNew();
List<Followuplist> _followupList = [];
List<ComplaintList> _complaintList = [];
bool _isLoading = false;
CustomerDetails get customerDetails => _customerDetails;
GeneratorDetails get generatorDetails => _generatorDetails;
ComplaintDetailsNew get complaintDetailsNew => _complaintDetailsNew;
List<Followuplist> get followUpList => _followupList;
List<ComplaintList> get complaintList => _complaintList;
bool get isLoading => _isLoading;
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) {
_showMoreDetails = value;
notifyListeners();
safeNotifyListeners();
}
Future<void> LoadVisitDetailsAPI(BuildContext context, ComplaintID) async {
ServiceComplaintBillListResponse? complaintBillListResponse;
String? error;
Future<void> serviceComplaintBillList(BuildContext context, String complaintId) async {
try {
var HomeProvider = Provider.of<HomescreenNotifier>(
context,
listen: false,
var homeProvider = Provider.of<HomescreenNotifier>(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(
HomeProvider.empId,
HomeProvider.session,
......@@ -42,31 +96,26 @@ class Visitdetailsprovider extends ChangeNotifier {
if (data != null) {
if (data.error == 0) {
// complaintdetails = data.complaintDetails!;
_customerDetails = data.customerDetails!;
_generatorDetails = data.generatorDetails!;
_complaintDetailsNew = data.complaintDetailsNew!;
_isLoading = false;
notifyListeners();
safeNotifyListeners();
} else {
toast(context, "Something Went Wrong, Please try again!");
print("error");
}
} else {
toast(context, "No response From the server, Please try Again!");
print("error2");
}
} on Error catch (e) {
} catch (e) {
print(e.toString());
}
}
Future<void> LoadFollowupListAPI(BuildContext context, ComplaintID) async {
try {
var HomeProvider = Provider.of<HomescreenNotifier>(
context,
listen: false,
);
var HomeProvider = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.loadFollowupListAPI(
HomeProvider.empId,
HomeProvider.session,
......@@ -75,20 +124,19 @@ class Visitdetailsprovider extends ChangeNotifier {
if (data != null) {
if (data.error == 0) {
// complaintdetails = data.complaintDetails!;
_followupList = data.list ?? [];
_isLoading = false;
notifyListeners();
safeNotifyListeners();
} else {
toast(context, "Something Went Wrong, Please try again!");
print("error");
}
} else {
toast(context, "No response From the server, Please try Again!");
print("error2");
}
} on Error catch (e) {
} catch (e) {
print(e.toString());
}
}
}
import 'package:flutter/material.dart';
import 'package:generp/services/api_calling.dart';
import '../../Models/financeModels/ValidateBankAccountDetailsResponse.dart';
import '../../Models/financeModels/ValidateGstNumResponse.dart';
class ValidationProvider extends ChangeNotifier {
bool isLoading = false;
ValidateGstNumResponse? gstResponse;
ValidateBankAccountDetailsResponse? bankResponse;
String? errorMessage;
/// Validate GST Number
/// -----------------------------
Future<void> validateGstNumber(
String empId, String sessionId, String gstNumber) async {
try {
isLoading = true;
errorMessage = null;
notifyListeners();
gstResponse = await ApiCalling.validateGstNumberApi(
empId,
sessionId,
gstNumber,
);
if (gstResponse == null) {
errorMessage = "Failed to validate GST number";
}
} catch (e) {
errorMessage = e.toString();
}
isLoading = false;
notifyListeners();
}
/// Validate Bank Account Details
/// -----------------------------
Future<void> validateBankDetails(
String empId, String sessionId, String accountNumber) async {
try {
isLoading = true;
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();
}
}
//
//
// import 'package:flutter/cupertino.dart';
// import 'package:generp/Models/ordersModels/commonResponse.dart';
// import 'package:generp/services/api_calling.dart';
//
// class EditCommonAccountProvider extends ChangeNotifier{
// bool isLoading = false;
// String? errorMessage;
// CommonResponse? updateResponse;
//
// Future<void> updateAccountForm() async{
//
// try{
// isLoading = true;
// errorMessage = null;
// notifyListeners();
//
// updateResponse = await ApiCalling.commonUpdateAccountDetailsAPI(
// empId,
// sessionId,
// type,
// name,
// mob1,
// mob2,
// tel,
// email,
// designation,
// address,
// state,
// district,
// subLocality,
// bankName,
// branchName,
// bankIfscCode,
// accHolderName,
// bankAccNumber,
// bankUpiId
// );
//
// if (updateResponse == null){
// errorMessage = "No Response from server";
// }
// }
//
//
// }
//
// }
\ No newline at end of file
......@@ -7,6 +7,8 @@ import '../../Models/commonModels/commonAccountdetailsResponse.dart';
class Accountdetailsprovider extends ChangeNotifier {
bool _showMoreDetails = false;
bool _isLoading = false;
bool get isLoading => _isLoading;
AccountDetails _accountDetails = AccountDetails();
BalanceDetails _balanceDetails = BalanceDetails();
......@@ -27,6 +29,8 @@ class Accountdetailsprovider extends ChangeNotifier {
}
Future<void> accountdetailsAPIFunction(context, accountID) async {
_isLoading = true;
notifyListeners();
try {
var prov = Provider.of<HomescreenNotifier>(context, listen: false);
final data = await ApiCalling.commonAccountDetailsAPI(
......@@ -56,6 +60,8 @@ class Accountdetailsprovider extends ChangeNotifier {
}
}
} catch (e) {}
_isLoading = false;
notifyListeners();
}
Map<String, List<LedgerList>> groupByDate(List<LedgerList> list) {
......
......@@ -2,8 +2,10 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:generp/Models/ordersModels/commonResponse.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.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/finance/financeDashboard.dart';
import 'package:generp/services/api_calling.dart';
......@@ -103,6 +105,7 @@ class Accountslistprovider extends ChangeNotifier {
}
ValidateGstNumResponse? gstResponse;
commonAddAccountsViewResponse? commonResponse;
ValidateBankAccountDetailsResponse? bankResponse;
String? errorMessage;
......@@ -284,6 +287,7 @@ class Accountslistprovider extends ChangeNotifier {
type,
value,
);
commonResponse =data;
if (data != null) {
if (data.error == "0") {
nameError = null;
......@@ -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 _submitClicked = false;
......@@ -504,7 +683,7 @@ class Accountslistprovider extends ChangeNotifier {
}
}
bool validateStep1() {
bool validateStep1(BuildContext context) {
accountError = null;
nameError = null;
mobileError = null;
......@@ -518,10 +697,53 @@ class Accountslistprovider extends ChangeNotifier {
nameError = "Please Enter a Name";
isValid = false;
}
if (nameError != null && nameError != "") {
isValid = false;
}
if (mobileController.text.trim().isNotEmpty && mobileController.text.length < 10) {
mobileError = "Mobile Number should be 10 digits";
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) {
mobileError = "Please Enter Mobile Number";
isValid = false;
......@@ -535,6 +757,8 @@ class Accountslistprovider extends ChangeNotifier {
return isValid;
}
bool validateStep2() {
stateError = null;
districtError = null;
......@@ -547,7 +771,7 @@ class Accountslistprovider extends ChangeNotifier {
return isValid;
}
bool validateStep3() {
bool validateStep3(BuildContext context) {
banknameError = null;
bankBranchError = null;
bankIFSCError = null;
......@@ -557,6 +781,21 @@ class Accountslistprovider extends ChangeNotifier {
gstNumberError = null;
bool isValid = true;
_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();
return isValid;
}
......@@ -564,6 +803,20 @@ class Accountslistprovider extends ChangeNotifier {
bool validateStep4() {
bool isValid = true;
_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();
return isValid;
}
......@@ -607,6 +860,31 @@ class Accountslistprovider extends ChangeNotifier {
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;
notifyListeners();
return isValid;
......@@ -633,13 +911,13 @@ class Accountslistprovider extends ChangeNotifier {
}
/// simplified update - kept for compatibility if UI uses it
Future<void> updateGSTNumber(BuildContext context, String value) async {
// We won't call the GST API here — UI flow calls validateGstNumber explicitly.
// This function simply clears previous error on typing.
void updateGSTNumber(String value) {
// just clear the error when user edits GST
gstNumberError = null;
notifyListeners();
}
void updateBankBranch(String value) {
bankBranchError = null;
notifyListeners();
......
This diff is collapsed.
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 {
} catch (e) {}
}
preValues() {
preValues() {// safeNormalizeAmount()
print("here 212ssass1");
requestedAmount.text = _requestDetails.requestedAmount ?? "-";
requestedAmount.text = safeNormalizeAmount(_requestDetails.requestedAmount);
proposedPaymentAccount.text = _requestDetails.proposedAccount ?? "-";
approvedAmountReadonly.text = _requestDetails.formattedAmount ?? "-";
approvedAmount.text = _requestDetails.amount ?? "-";
accountName.text = _requestDetails.accountName ?? "-";
branch.text = _requestDetails.branch ?? "-";
requestingPurpose.text = _requestDetails.requestingPurpose ?? "-";
description.text = _requestDetails.description ?? "-";
amount.text = _requestDetails.amount ?? "-";
paymentMode.text = _requestDetails.requestMode ?? "-";
bankUpiID.text = _requestDetails.bankUpiId ?? "-";
bankName.text = _requestDetails.bankName ?? "-";
bankBranchName.text = _requestDetails.bankBranchname ?? "-";
bankAccountNumber.text = _requestDetails.bankAccountNumber ?? "-";
bankIfscCode.text = _requestDetails.bankIfscCode ?? "-";
bankHolderName.text = _requestDetails.bankAccountHolderName ?? "-";
approvedAmountReadonly.text = safeNormalizeAmount(_requestDetails.amount);
approvedAmount.text = safeNormalizeAmount(_requestDetails.amount);
accountName.text = _requestDetails.accountName ?? "";
branch.text = _requestDetails.branch ?? "";
requestingPurpose.text = _requestDetails.requestingPurpose ?? "";
description.text = _requestDetails.description ?? "";
amount.text = safeNormalizeAmount(_requestDetails.amount);
paymentMode.text = _requestDetails.requestMode ?? "";
bankUpiID.text = _requestDetails.bankUpiId ?? "";
bankName.text = _requestDetails.bankName ?? "";
bankBranchName.text = _requestDetails.bankBranchname ?? "";
bankAccountNumber.text = _requestDetails.bankAccountNumber ?? "";
bankIfscCode.text = _requestDetails.bankIfscCode ?? "";
bankHolderName.text = _requestDetails.bankAccountHolderName ?? "";
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(
context,
paymentRequestId,
......@@ -363,31 +381,31 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
paymentRequestId,
approveRemarks,
) async {
print("🎯 === REJECT PROVIDER METHOD STARTED ===");
print(" === REJECT PROVIDER METHOD STARTED ===");
// Set loading to true at the start
_isLoading = true;
notifyListeners();
print("🔄 Loading set to TRUE in reject method");
print(" Loading set to TRUE in reject method");
bool success = false;
try {
print("🔍 Starting validation for rejection...");
print(" Starting validation for rejection...");
if (approveRemarks.toString().trim().isEmpty) {
print(" Remarks validation failed");
remarksError = "Please Enter Remarks";
_isLoading = false;
notifyListeners();
return false;
}
// if (approveRemarks.toString().trim().isEmpty) {
// print(" Remarks validation failed");
// remarksError = "Please Enter Remarks";
// _isLoading = false;
// notifyListeners();
// return false;
// }
print(" Validation passed");
print(" Validation passed");
var provider = Provider.of<HomescreenNotifier>(context, listen: false);
print("🌐 Calling reject API...");
print(" Calling reject API...");
final data = await ApiCalling.RejectPaymentRequestSubmitAPI(
provider.empId,
provider.session,
......@@ -395,36 +413,36 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
paymentRequestId,
approveRemarks,
);
print("🌐 Reject API call completed");
print(" Reject API call completed");
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") {
print(" Reject API SUCCESS");
print(" Reject API SUCCESS");
success = true;
if (context.mounted) {
print("🎯 Context mounted - performing UI operations");
print(" Context mounted - performing UI operations");
paymentRequesitionDetails(context, paymentRequestId);
resetAll();
toast(context, data.message);
Navigator.pop(context, true); // Pass true to indicate success
}
} else {
print(" Reject API returned error: ${data.message}");
print(" Reject API returned error: ${data.message}");
if (context.mounted) {
toast(context, data.message ?? "Rejection failed");
}
}
} else {
print(" NULL response from reject API");
print(" NULL response from reject API");
if (context.mounted) {
toast(context, "No response from server");
}
}
} catch (e) {
print("💥 EXCEPTION in reject provider method: $e");
print(" EXCEPTION in reject provider method: $e");
if (context.mounted) {
toast(context, "Error: ${e.toString()}");
}
......@@ -433,10 +451,10 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
_isLoading = false;
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;
}
......@@ -457,27 +475,27 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
String approve_remarks,
String proposed_payment_account_id,
) async {
print("🎯 === PROVIDER METHOD STARTED ===");
print(" === PROVIDER METHOD STARTED ===");
// Set loading to true at the start
_isLoading = true;
notifyListeners();
try {
print("🔍 Starting validation...");
print(" Starting validation...");
if (!validateApproval(approved_amount, approve_remarks, proposed_payment_account_id)) {
print(" VALIDATION FAILED - Stopping execution");
print(" VALIDATION FAILED - Stopping execution");
_isLoading = false;
notifyListeners();
return;
}
print(" Validation passed");
print(" Validation passed");
print("👤 Getting home provider...");
print(" Getting home provider...");
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(
homeProvider.empId,
homeProvider.session,
......@@ -487,43 +505,43 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
approve_remarks,
proposed_payment_account_id,
);
print("🌐 API call completed");
print(" API call completed");
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") {
print(" API SUCCESS - Processing...");
print(" API SUCCESS - Processing...");
// Check if context is still valid before UI operations
if (context.mounted) {
print("🎯 Context mounted - performing UI operations");
print(" Context mounted - performing UI operations");
paymentRequesitionDetails(context, payment_request_id);
resetAll();
toast(context, data.message);
Navigator.pop(context, true);
print(" UI operations completed");
print(" UI operations completed");
} else {
print("️ Context not mounted - skipping UI operations");
print("️ Context not mounted - skipping UI operations");
}
notifyListeners();
print(" Notify listeners called");
print(" Notify listeners called");
} else {
print(" API returned error: ${data.message}");
print(" API returned error: ${data.message}");
if (context.mounted) {
toast(context, data.message ?? "Submission failed");
}
}
} else {
print(" NULL response from API");
print(" NULL response from API");
if (context.mounted) {
toast(context, "No response from server");
}
}
} catch (e, s) {
print("💥 EXCEPTION in provider method: $e");
print("📋 Stack trace: $s");
print(" EXCEPTION in provider method: $e");
print(" Stack trace: $s");
// Show error to user
if (context.mounted) {
toast(context, "Error: ${e.toString()}");
......@@ -532,10 +550,10 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
// Set loading to false when everything is done (success or error)
_isLoading = false;
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 {
}
bool validateApproval(
String approvedAmount, // Add type for clarity
String approveRemarks, // Add type for clarity
String proposedPaymentAccountId, // Add type for clarity
String approvedAmount, //
String approveRemarks, //
String proposedPaymentAccountId, //
) {
print("🔍 === VALIDATION STARTED ===");
print(" === VALIDATION STARTED ===");
print(" Approved Amount: '$approvedAmount'");
print(" Requested Amount: '${requestedAmount.text}'");
print(" Remarks: '$approveRemarks'");
......@@ -664,11 +682,11 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
}
// Fix 2: Use the String parameter directly (no .text)
if (approveRemarks.trim().isEmpty) {
remarksError = "Please Enter Remarks";
isValid = false;
print("❌ Remarks are empty");
}
// if (approveRemarks.trim().isEmpty) {
// remarksError = "Please Enter Remarks";
// isValid = false;
// print("❌ Remarks are empty");
// }
// Fix 3: Parse the String parameters, not .text
if (approvedAmount.trim().isNotEmpty && requestedAmount.text.trim().isNotEmpty) {
......@@ -677,35 +695,35 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
double approved = numberFormat.parse(approvedAmount.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) {
ApprovedAmountError = "Approved Amount should not be greater than requested amount";
isValid = false;
print(" Approved amount exceeds requested amount");
print(" Approved amount exceeds requested amount");
}
} catch (e) {
print("💥 Error parsing amounts: $e");
print(" Error parsing amounts: $e");
ApprovedAmountError = "Invalid amount format";
isValid = false;
}
}
// Fix 4: Use the parameter OR check both for consistency
if (proposedPaymentAccountId.isEmpty && _selectedID.isEmpty) {
selectpaymentAccountError = "Please select an account";
isValid = false;
print(" No payment account selected");
} else if (proposedPaymentAccountId.isNotEmpty && _selectedID.isEmpty) {
// If parameter has value but _selectedID doesn't, sync them
_selectedID = proposedPaymentAccountId;
print("🔄 Synced selected ID from parameter: $_selectedID");
}
// if (proposedPaymentAccountId.isEmpty && _selectedID.isEmpty) {
// selectpaymentAccountError = "Please select an account";
// isValid = false;
// // print(" No payment account selected");
// } else if (proposedPaymentAccountId.isNotEmpty && _selectedID.isEmpty) {
// // If parameter has value but _selectedID doesn't, sync them
// _selectedID = proposedPaymentAccountId;
// // print(" Synced selected ID from parameter: $_selectedID");
// }
_submitClicked = false;
notifyListeners();
print("🔍 === VALIDATION RESULT: $isValid ===");
// print(" === VALIDATION RESULT: $isValid ===");
return isValid;
}
......@@ -779,6 +797,12 @@ class Requesitionlidtdetailsprovider extends ChangeNotifier {
notifyListeners();
}
resetRequired() {
remarksError = null;
selectpaymentAccountError = null;
notifyListeners();
}
onChangeApprov(value) {
final numberFormat = NumberFormat.decimalPattern();
if (numberFormat.parse(approvedAmount.text) >
......
......@@ -184,6 +184,12 @@ class Loginnotifier extends ChangeNotifier {
SharedpreferencesService().saveString("UserName", data.name!);
SharedpreferencesService().saveString("UserEmail", data.emailId!);
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();
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