Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
GEN_ERP_2025
Commits
7ba7402c
"lib/Screens/TransactionScreens/TransactionListScreen.dart" did not exist on "1a7abcc6c2054a95648130bc8cdbf9f1bcbff236"
Commit
7ba7402c
authored
Nov 21, 2025
by
Sai Srinivas
Committed by
Sai Srinivas
Nov 28, 2025
Browse files
Edit form and some fixes added
parent
d2939607
Changes
40
Show whitespace changes
Inline
Side-by-side
android/app/build.gradle.kts
View file @
7ba7402c
...
...
@@ -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
...
...
android/app/src/main/AndroidManifest.xml
View file @
7ba7402c
...
...
@@ -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"
/>
...
...
assets/svg/compliant_list_ic.svg
0 → 100644
View file @
7ba7402c
<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
lib/Models/FollowUpResponse.dart
View file @
7ba7402c
...
...
@@ -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
;
}
}
lib/Models/ServiceComplaintBillListResponse.dart
0 → 100644
View file @
7ba7402c
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
;
}
}
lib/Models/commonModels/EditCommonAccFormDetailsResponse.dart
0 → 100644
View file @
7ba7402c
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
;
}
}
lib/Notifiers/CheckInProvider.dart
View file @
7ba7402c
...
...
@@ -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
);
...
...
lib/Notifiers/HomeScreenNotifier.dart
View file @
7ba7402c
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"
;
...
...
lib/Notifiers/LogoutNotifier.dart
View file @
7ba7402c
...
...
@@ -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
,
...
...
lib/Notifiers/PendingComplaintsProvider.dart
View file @
7ba7402c
...
...
@@ -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
();
...
...
lib/Notifiers/QrProvider.dart
View file @
7ba7402c
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
;
}
}
}
lib/Notifiers/VisitDetailsProvider.dart
View file @
7ba7402c
...
...
@@ -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
;
n
otifyListeners
();
safeN
otifyListeners
();
}
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
;
n
otifyListeners
();
safeN
otifyListeners
();
}
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
;
n
otifyListeners
();
safeN
otifyListeners
();
}
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
());
}
}
}
lib/Notifiers/commonProvider/ValidationProvider.dart
View file @
7ba7402c
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
lib/Notifiers/commonProvider/accountDetailsProvider.dart
View file @
7ba7402c
...
...
@@ -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
)
{
...
...
lib/Notifiers/commonProvider/accountsListProvider.dart
View file @
7ba7402c
...
...
@@ -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
();
...
...
lib/Notifiers/commonProvider/editCommonAccountProvider.dart
0 → 100644
View file @
7ba7402c
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
();
}
}
lib/Notifiers/crmProvider/CrmNearByGeneratorsProvider.dart
0 → 100644
View file @
7ba7402c
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"
;
}
}
lib/Notifiers/financeProvider/RequesitionLidtDetailsProvider.dart
View file @
7ba7402c
...
...
@@ -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
)
>
...
...
lib/Notifiers/loginNotifier.dart
View file @
7ba7402c
...
...
@@ -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/Utils/backgroundServiceNew.dart
0 → 100644
View file @
7ba7402c
// 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
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment