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
Compare Revisions
5528042935da07e590b68b92d72d5d1b549c8f24...332a8e914c4aab70caf007a280d64c563822a035
Hide whitespace changes
Inline
Side-by-side
lib/screens/hrm/OrganizationStructureScreen.dart
0 → 100644
View file @
332a8e91
import
'package:flutter/material.dart'
;
class
OrganizationStructureScreen
extends
StatelessWidget
{
final
List
<
Department
>
departments
=
[
Department
(
name:
"Engineering"
,
teams:
[
Team
(
name:
"Mobile Team"
,
members:
[
"Mohit"
,
"Srinivas"
,
]),
Team
(
name:
"Backend Team"
,
members:
[
"Dheeraj"
,
"Satya"
,
"Sneha"
]),
],
),
Department
(
name:
"Sales & Marketing"
,
teams:
[
Team
(
name:
"Digital Marketing"
,
members:
[
"Kiran"
,
"Priya"
]),
Team
(
name:
"Field Sales"
,
members:
[
"Raj"
,
"Anjali"
]),
],
),
Department
(
name:
"HR & Admin"
,
teams:
[
Team
(
name:
"Recruitment"
,
members:
[
"Naresh"
]),
Team
(
name:
"Operations"
,
members:
[
"Suresh"
,
"Divya"
]),
],
),
];
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
title:
const
Text
(
"Organization Structure"
)),
body:
ListView
.
builder
(
padding:
const
EdgeInsets
.
all
(
16
),
itemCount:
departments
.
length
,
itemBuilder:
(
context
,
deptIndex
)
{
final
dept
=
departments
[
deptIndex
];
return
Card
(
margin:
const
EdgeInsets
.
only
(
bottom:
16
),
elevation:
2
,
child:
ExpansionTile
(
title:
Text
(
"
${dept.name}
not ready"
,
style:
const
TextStyle
(
fontSize:
18
,
fontWeight:
FontWeight
.
bold
),
),
children:
dept
.
teams
.
map
((
team
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
8
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
team
.
name
,
style:
const
TextStyle
(
fontSize:
16
,
fontWeight:
FontWeight
.
w600
),
),
const
SizedBox
(
height:
4
),
Wrap
(
spacing:
8
,
children:
team
.
members
.
map
((
member
)
{
return
Chip
(
label:
Text
(
member
),
backgroundColor:
Colors
.
blue
.
shade50
,
);
}).
toList
(),
),
const
SizedBox
(
height:
8
),
],
),
);
}).
toList
(),
),
);
},
),
);
}
}
class
Department
{
final
String
name
;
final
List
<
Team
>
teams
;
Department
({
required
this
.
name
,
required
this
.
teams
});
}
class
Team
{
final
String
name
;
final
List
<
String
>
members
;
Team
({
required
this
.
name
,
required
this
.
members
});
}
lib/screens/hrm/RewardListScreen.dart
0 → 100644
View file @
332a8e91
import
'package:dotted_line/dotted_line.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:generp/screens/hrm/RewardSearchScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Notifiers/hrmProvider/rewardListProvider.dart'
;
import
'../../Utils/app_colors.dart'
;
class
RewardListScreen
extends
StatefulWidget
{
const
RewardListScreen
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
RewardListScreen
>
createState
()
=>
_RewardListScreenState
();
}
class
_RewardListScreenState
extends
State
<
RewardListScreen
>
{
@override
Widget
build
(
BuildContext
context
)
{
return
ChangeNotifierProvider
(
create:
(
_
)
=>
RewardListProvider
()..
fetchRewardList
(
context
),
child:
Consumer
<
RewardListProvider
>(
builder:
(
context
,
provider
,
child
)
{
return
Scaffold
(
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
Colors
.
white
,
title:
Row
(
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
25
,
),
),
const
SizedBox
(
width:
10
),
Text
(
"Reward List"
,
style:
TextStyle
(
fontSize:
18
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
AppColors
.
semi_black
,
),
),
],
),
// actions: [
// InkResponse(
// onTap: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => RewardSearchScreen(),
// settings: const RouteSettings(
// name: 'AddLiveAttendanceScreen',
// ),
// ),
// ).then((_) {
// });
// },
// child: SvgPicture.asset(
// "assets/svg/search_ic.svg",
// height: 25,
// ),
// ),
// const SizedBox(width: 20),
// ],
),
backgroundColor:
Color
(
0xFFF6F6F8
),
body:
Builder
(
builder:
(
context
)
{
if
(
provider
.
isLoading
)
{
return
const
Center
(
child:
CircularProgressIndicator
(
color:
Colors
.
blue
,));
}
if
(
provider
.
errorMessage
!=
null
)
{
return
Center
(
child:
Text
(
provider
.
errorMessage
!));
}
if
(
provider
.
response
==
null
)
{
return
const
Center
(
child:
Text
(
"No details found"
));
}
final
rewardDetail
=
provider
.
response
!;
final
rewardResponse
=
provider
.
response
!;
final
rewards
=
rewardResponse
.
rewardsList
;
// main list object
final
achieved
=
rewardResponse
.
achievedAmount
??
"0"
;
final
disbursed
=
rewardResponse
.
disbursedAmount
??
"0"
;
final
balance
=
rewardResponse
.
balanceAmount
??
"0"
;
return
SingleChildScrollView
(
padding:
const
EdgeInsets
.
all
(
16
),
child:
Column
(
children:
[
/// --- Top Summary Cards ---
Stack
(
children:
[
Container
(
height:
110
,
width:
double
.
infinity
,
padding:
const
EdgeInsets
.
all
(
18
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xffd9ffd6
),
borderRadius:
BorderRadius
.
circular
(
18
),
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Text
(
"₹
${achieved}
"
,
// Achieved Amount from response
style:
const
TextStyle
(
fontSize:
20
,
color:
Color
(
0xff0D9C00
),
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w500
,
),
),
const
SizedBox
(
height:
10
),
const
Text
(
"Achievement Amount"
,
style:
TextStyle
(
fontSize:
14
,
color:
Color
(
0xff2D2D2D
),
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
,
),
),
],
),
),
// Positioned SVG Icon
Positioned
(
bottom:
8
,
right:
12
,
child:
Container
(
height:
42
,
width:
42
,
decoration:
BoxDecoration
(
shape:
BoxShape
.
circle
,
color:
const
Color
(
0xA0FFFFFF
),
// icon bg
),
child:
Center
(
child:
SvgPicture
.
asset
(
height:
25
,
width:
25
,
"assets/svg/hrm/achievement_ic.svg"
,
fit:
BoxFit
.
contain
,
),
),
),
),
],
),
const
SizedBox
(
height:
12
),
Row
(
children:
[
Expanded
(
child:
Container
(
height:
110
,
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xffe8ddff
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Stack
(
children:
[
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"₹
${disbursed}
"
,
// Disbursed Amount
style:
const
TextStyle
(
fontSize:
20
,
color:
Color
(
0xff493272
),
fontWeight:
FontWeight
.
w500
,
),
),
const
SizedBox
(
height:
8
),
const
Text
(
"Disbursed
\n
Amount"
,
style:
TextStyle
(
fontSize:
14
,
color:
Color
(
0xff2D2D2D
),
fontWeight:
FontWeight
.
w400
,
),
),
],
),
Positioned
(
bottom:
2
,
right:
2
,
child:
Container
(
height:
42
,
width:
42
,
decoration:
BoxDecoration
(
shape:
BoxShape
.
circle
,
color:
const
Color
(
0xA0FFFFFF
),
// icon bg
),
child:
Center
(
child:
SvgPicture
.
asset
(
height:
25
,
width:
25
,
"assets/svg/hrm/location_ic.svg"
,
fit:
BoxFit
.
contain
,
),
),
),
),
],
),
),
),
const
SizedBox
(
width:
12
),
Expanded
(
child:
Container
(
height:
110
,
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
const
Color
(
0xfffffbc3
),
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Stack
(
children:
[
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"₹
${balance}
"
,
// Balance Amount
style:
const
TextStyle
(
fontSize:
18
,
color:
Color
(
0xff605C00
),
),
),
const
SizedBox
(
height:
8
),
const
Text
(
"Balance
\n
Amount"
,
style:
TextStyle
(
fontSize:
14
,
color:
Color
(
0xff2D2D2D
),
fontWeight:
FontWeight
.
w400
,
),
),
],
),
Positioned
(
bottom:
2
,
right:
2
,
child:
Container
(
height:
42
,
width:
42
,
decoration:
BoxDecoration
(
shape:
BoxShape
.
circle
,
color:
const
Color
(
0xA0FFFFFF
),
// icon bg
),
child:
Center
(
child:
SvgPicture
.
asset
(
height:
25
,
width:
25
,
"assets/svg/hrm/ballance_ic.svg"
,
fit:
BoxFit
.
contain
,
),
),
),
),
],
),
),
),
],
),
const
SizedBox
(
height:
20
),
/// --- Reward List Card ---
if
(
rewards
!=
null
)
_rewardListCard
(
title:
rewards
.
description
??
"-"
,
// rewardsList fields
dateTime:
rewards
.
dateTime
??
"-"
,
achieved:
achieved
,
disbursed:
disbursed
,
balance:
balance
,
enteredBy:
rewards
.
enteredBy
??
"-"
,
)
else
const
Text
(
"No rewards available"
),
],
),
);
}
),
);
}
)
);
}
/// Reusable Reward Card Function
Widget
_rewardListCard
({
required
String
title
,
required
String
dateTime
,
required
String
achieved
,
required
String
disbursed
,
required
String
balance
,
required
String
enteredBy
,
})
{
return
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
16
),
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
grey
.
withOpacity
(
0.1
),
blurRadius:
6
,
offset:
const
Offset
(
0
,
3
),
)
],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
/// Header Row
Row
(
children:
[
CircleAvatar
(
radius:
22.5
,
backgroundColor:
Color
(
0xffEDF8FF
),
child:
SvgPicture
.
asset
(
height:
28
,
width:
28
,
"assets/svg/hrm/rewardList.svg"
,
fit:
BoxFit
.
contain
,
),
),
const
SizedBox
(
width:
8
),
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
title
,
style:
const
TextStyle
(
fontSize:
14.5
,
color:
Color
(
0xff2D2D2D
),
fontFamily:
"Plus Jakarta Sans"
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
),
),
Text
(
dateTime
,
style:
const
TextStyle
(
fontSize:
12.5
,
color:
Color
(
0xff818181
),
fontFamily:
"Plus Jakarta Sans"
,
fontStyle:
FontStyle
.
normal
,
fontWeight:
FontWeight
.
w400
),
),
],
),
),
],
),
const
SizedBox
(
height:
12
),
/// Amount Details
Padding
(
padding:
const
EdgeInsets
.
all
(
2.0
),
child:
Row
(
children:
[
const
Text
(
"Amount Details"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaSemiBold"
,
),
),
const
SizedBox
(
width:
10
),
Expanded
(
child:
DottedLine
(
dashGapLength:
4
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashLength:
2
,
lineThickness:
0.5
,
),
),
],
),
),
const
SizedBox
(
height:
6
),
_buildKeyValue
(
"Achieved Amount"
,
achieved
),
_buildKeyValue
(
"Disbursed Amount"
,
disbursed
),
_buildKeyValue
(
"Balance Amount"
,
balance
),
const
SizedBox
(
height:
10
),
/// Employee Details
Padding
(
padding:
const
EdgeInsets
.
all
(
2.0
),
child:
Row
(
children:
[
const
Text
(
"Employee Details"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaSemiBold"
,
),
),
const
SizedBox
(
width:
10
),
Expanded
(
child:
DottedLine
(
dashGapLength:
4
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashLength:
2
,
lineThickness:
0.5
,
),
),
],
),
),
_buildKeyValue
(
"Entered By"
,
enteredBy
),
],
),
);
}
/// Key-Value Row
Widget
_buildKeyValue
(
String
key
,
String
value
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
3.5
,
horizontal:
2
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
key
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
),
),
Text
(
value
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Color
(
0xFF818181
),
),
),
],
),
);
}
}
lib/screens/hrm/RewardSearchScreen.dart
0 → 100644
View file @
332a8e91
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'../../Utils/app_colors.dart'
;
class
RewardSearchScreen
extends
StatefulWidget
{
const
RewardSearchScreen
({
super
.
key
});
@override
State
<
RewardSearchScreen
>
createState
()
=>
_RewardSearchScreenState
();
}
class
_RewardSearchScreenState
extends
State
<
RewardSearchScreen
>
{
final
TextEditingController
_searchController
=
TextEditingController
();
// Dummy data
final
List
<
String
>
accounts
=
[
"Siddha Bank"
,
"Siddharth Shivam"
,
"Sidheshwar Temple"
,
"Axis Bank"
,
"SBI"
,
];
final
List
<
String
>
inquiries
=
[
"Inquiry Siddha Bank"
,
"Inquiry Sidharth"
,
"Inquiry Sidheshwar"
,
"Customer SBI"
,
];
final
List
<
String
>
leads
=
[
"Lead Siddha Bank"
,
"Lead Shivam"
,
"Lead Sidheshwar"
,
"Lead HDFC"
,
];
// Filtered data
String
query
=
""
;
@override
Widget
build
(
BuildContext
context
)
{
final
filteredAccounts
=
accounts
.
where
((
e
)
=>
e
.
toLowerCase
().
contains
(
query
.
toLowerCase
())).
toList
();
final
filteredInquiries
=
inquiries
.
where
((
e
)
=>
e
.
toLowerCase
().
contains
(
query
.
toLowerCase
())).
toList
();
final
filteredLeads
=
leads
.
where
((
e
)
=>
e
.
toLowerCase
().
contains
(
query
.
toLowerCase
())).
toList
();
return
Scaffold
(
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
const
Color
(
0xFFFFFFFF
),
title:
Row
(
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
25
,
),
),
const
SizedBox
(
width:
10
),
const
Text
(
"Search"
,
style:
TextStyle
(
fontSize:
18
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
],
),
),
backgroundColor:
Color
(
0xFFF6F6F8
),
body:
SingleChildScrollView
(
padding:
const
EdgeInsets
.
all
(
16
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
/// Search Field
TextField
(
controller:
_searchController
,
onChanged:
(
value
)
{
setState
(()
{
query
=
value
;
});
},
decoration:
InputDecoration
(
hintText:
"Search"
,
prefixIcon:
const
Icon
(
Icons
.
search
,
color:
Colors
.
black54
),
filled:
true
,
fillColor:
const
Color
(
0xffFFFFFF
),
contentPadding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
12
),
border:
OutlineInputBorder
(
borderRadius:
BorderRadius
.
circular
(
12
),
borderSide:
BorderSide
.
none
,
),
),
),
const
SizedBox
(
height:
20
),
if
(
query
.
isNotEmpty
)
Text
(
'Result for “
$query
”'
,
style:
const
TextStyle
(
fontSize:
18
,
color:
Color
(
0xff1487C9
),
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
),
),
const
SizedBox
(
height:
20
),
if
(
query
.
isNotEmpty
&&
filteredAccounts
.
isNotEmpty
)
_buildSection
(
"Accounts"
,
filteredAccounts
),
if
(
query
.
isNotEmpty
&&
filteredInquiries
.
isNotEmpty
)
_buildSection
(
"Inquiries"
,
filteredInquiries
),
if
(
query
.
isNotEmpty
&&
filteredLeads
.
isNotEmpty
)
_buildSection
(
"Leads"
,
filteredLeads
),
if
(
query
.
isNotEmpty
&&
filteredAccounts
.
isEmpty
&&
filteredInquiries
.
isEmpty
&&
filteredLeads
.
isEmpty
)
const
Center
(
child:
Text
(
"No results found"
,
style:
TextStyle
(
fontSize:
14
,
color:
Colors
.
grey
),
),
),
],
),
),
);
}
/// Reusable Section Widget
Widget
_buildSection
(
String
title
,
List
<
String
>
items
)
{
return
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
title
,
style:
const
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
fontFamily:
"Plus Jakarta Sans"
,
color:
Color
(
0xff2D2D2D
),
),
),
const
SizedBox
(
height:
10
),
Column
(
children:
items
.
map
((
e
)
=>
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
12
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
12
,
vertical:
12
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
grey
.
withOpacity
(
0.1
),
blurRadius:
5
,
offset:
const
Offset
(
0
,
3
),
)
],
),
child:
Row
(
children:
[
Container
(
height:
32
,
width:
32
,
decoration:
BoxDecoration
(
color:
const
Color
(
0xffE8F3FF
),
borderRadius:
BorderRadius
.
circular
(
8
),
),
child:
const
Icon
(
Icons
.
search
,
color:
Color
(
0xff0066FF
),
size:
20
),
),
const
SizedBox
(
width:
10
),
Expanded
(
child:
Text
(
e
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w400
,
color:
Color
(
0xff2D2D2D
),
),
overflow:
TextOverflow
.
ellipsis
,
),
),
],
),
))
.
toList
(),
)
],
);
}
}
lib/screens/hrm/TourExpensesDetailsScreen.dart
0 → 100644
View file @
332a8e91
import
'package:dotted_line/dotted_line.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Notifiers/hrmProvider/tourExpensesDetailsProvider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'../finance/FileViewer.dart'
;
class
TourExpensesDetailsScreen
extends
StatefulWidget
{
final
String
tourBillId
;
const
TourExpensesDetailsScreen
({
Key
?
key
,
required
this
.
tourBillId
})
:
super
(
key:
key
);
@override
State
<
TourExpensesDetailsScreen
>
createState
()
=>
_TourExpensesDetailsScreenState
();
}
class
_TourExpensesDetailsScreenState
extends
State
<
TourExpensesDetailsScreen
>{
@override
Widget
build
(
BuildContext
context
)
{
return
ChangeNotifierProvider
(
create:
(
_
)
=>
TourExpensesDetailsProvider
()
..
fetchTourExpensesDetails
(
context
,
widget
.
tourBillId
),
child:
Scaffold
(
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
Color
(
0xFFFFFFFF
),
title:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
25
,
),
),
SizedBox
(
width:
10
),
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
Text
(
"Tour Expenses"
,
style:
TextStyle
(
fontSize:
18
,
height:
1.1
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
AppColors
.
semi_black
,
),
),
),
],
),
),
backgroundColor:
AppColors
.
scaffold_bg_color
,
body:
Consumer
<
TourExpensesDetailsProvider
>(
builder:
(
context
,
provider
,
child
)
{
if
(
provider
.
isLoading
)
{
return
const
Center
(
child:
CircularProgressIndicator
());
}
if
(
provider
.
errorMessage
!=
null
)
{
return
Center
(
child:
Text
(
provider
.
errorMessage
!));
}
final
response
=
provider
.
response
;
if
(
response
==
null
)
{
return
const
Center
(
child:
Text
(
"No data available"
));
}
debugPrint
(
"==================requestDetails:
${response.requestDetails?.approvalStatus}
"
);
return
SingleChildScrollView
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
/// Header Card at the very top
_expenseHeaderCard
(
title:
response
.
requestDetails
?.
placeOfVisit
??
"Tour"
,
date:
response
.
tourExpenses
?.
fromDate
??
"-"
,
status:
(
response
.
requestDetails
?.
approvalStatus
?.
isNotEmpty
??
false
)
?
response
.
requestDetails
!.
approvalStatus
!
:
"No Status"
,
details:
[
{
"key"
:
"TL Pending Approval Amount"
,
"value"
:
"-"
},
{
"key"
:
"Total Approved Amount"
,
"value"
:
response
.
tourExpenses
?.
appliedAmount
??
"-"
},
{
"key"
:
"Total Balance Amount"
,
"value"
:
"-"
},
{
"key"
:
"HR Expiring Amount (Within 24Hrs)"
,
"value"
:
"-"
},
{
"key"
:
"HR Pending Approval Amount"
,
"value"
:
"-"
},
{
"key"
:
"Total Disbursed Amount"
,
"value"
:
"-"
},
],
),
const
SizedBox
(
height:
16
),
/// Tour Expense Card (Main Summary)
if
(
response
.
requestDetails
!=
null
&&
response
.
tourExpenses
!=
null
)
...[
const
SizedBox
(
height:
10
),
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
30.0
),
child:
Text
(
"Tour Summary"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
grey_thick
,
),
),
),
const
SizedBox
(
height:
8
),
SizedBox
(
height:
220
,
// adjust height to match your card
child:
ListView
(
scrollDirection:
Axis
.
horizontal
,
padding:
EdgeInsets
.
symmetric
(
// horizontal margin for centering
horizontal:
MediaQuery
.
of
(
context
).
size
.
width
*
0.05
,
),
children:
[
SizedBox
(
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.85
,
child:
_tourExpenseCard
(
employeeName:
response
.
requestDetails
?.
employeeName
??
"-"
,
placeOfVisit:
response
.
requestDetails
?.
placeOfVisit
??
"-"
,
daAmount:
response
.
tourExpenses
?.
da
??
"0"
,
totalAmount:
response
.
tourExpenses
?.
appliedAmount
??
"0"
,
fromDate:
response
.
tourExpenses
?.
fromDate
??
"-"
,
toDate:
response
.
tourExpenses
?.
toDate
??
"-"
,
remarks:
response
.
tourExpenses
?.
extraNote
??
"-"
,
),
),
],
),
),
],
const
SizedBox
(
height:
10
),
/// Travel Expenses Cards
if
(
response
.
travelExpenses
!=
null
&&
response
.
travelExpenses
!.
isNotEmpty
)
...[
const
SizedBox
(
height:
10
),
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
30.0
),
child:
Text
(
"Travel Expenses"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
grey_thick
,
),
),
),
const
SizedBox
(
height:
8
),
SizedBox
(
height:
216
,
child:
ListView
.
separated
(
scrollDirection:
Axis
.
horizontal
,
padding:
EdgeInsets
.
symmetric
(
horizontal:
MediaQuery
.
of
(
context
).
size
.
width
*
0.04
,
),
itemCount:
response
.
travelExpenses
!.
length
,
separatorBuilder:
(
_
,
__
)
=>
const
SizedBox
(
width:
12
),
itemBuilder:
(
context
,
index
)
{
final
t
=
response
.
travelExpenses
![
index
];
return
SizedBox
(
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.90
,
// card width
child:
_travelExpenseCard
(
travelType:
t
.
travelType
??
"-"
,
amount:
t
.
fare
??
"0"
,
from:
t
.
froma
??
"-"
,
to:
t
.
toa
??
"-"
,
onViewTap:
()
{
debugPrint
(
"Open:
${t.imageDirFilePath}
"
);
//Fileviewer(fileName: "", fileUrl: t.imageDirFilePath.toString())
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
Image
.
network
(
t
.
imageDirFilePath
.
toString
()),
// Fileviewer(fileName: label, fileUrl: "assets/images/capa.svg"),
),
);
},
),
);
},
),
)
],
const
SizedBox
(
height:
10
),
/// Hotel Expenses Cards
if
(
response
.
hotelExpenses
!=
null
&&
response
.
hotelExpenses
!.
isNotEmpty
)
...[
const
SizedBox
(
height:
10
),
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
30.0
),
child:
Text
(
"Hotel Expenses"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
grey_thick
,
),
),
),
const
SizedBox
(
height:
8
),
SizedBox
(
height:
216
,
child:
ListView
.
separated
(
scrollDirection:
Axis
.
horizontal
,
padding:
EdgeInsets
.
symmetric
(
horizontal:
MediaQuery
.
of
(
context
).
size
.
width
*
0.04
,
),
itemCount:
response
.
hotelExpenses
!.
length
,
separatorBuilder:
(
_
,
__
)
=>
const
SizedBox
(
width:
12
),
itemBuilder:
(
context
,
index
)
{
final
h
=
response
.
hotelExpenses
![
index
];
return
SizedBox
(
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.90
,
child:
_hotelExpenseCard
(
hotelName:
h
.
hotelName
??
"-"
,
amount:
h
.
amount
??
"0"
,
fromDate:
h
.
fromDate
??
"-"
,
toDate:
h
.
toDate
??
"-"
,
onViewTap:
()
{
debugPrint
(
"Open:
${h.imageDirFilePath}
"
);
showDialog
(
context:
context
,
builder:
(
_
)
=>
Dialog
(
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
12
),
child:
Image
.
network
(
h
.
imageDirFilePath
.
toString
())
),
),
);
},
),
);
},
),
),
],
const
SizedBox
(
height:
10
),
/// Other Expenses Cards
if
(
response
.
otherExpenses
!=
null
&&
response
.
otherExpenses
!.
isNotEmpty
)
...[
const
SizedBox
(
height:
10
),
Padding
(
padding:
const
EdgeInsets
.
only
(
left:
30.0
),
child:
Text
(
"Other Expenses"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
grey_thick
,
),
),
),
const
SizedBox
(
height:
8
),
SizedBox
(
height:
216
,
child:
ListView
.
separated
(
scrollDirection:
Axis
.
horizontal
,
padding:
EdgeInsets
.
symmetric
(
horizontal:
MediaQuery
.
of
(
context
).
size
.
width
*
0.04
,
),
itemCount:
response
.
otherExpenses
!.
length
,
separatorBuilder:
(
_
,
__
)
=>
const
SizedBox
(
width:
12
),
itemBuilder:
(
context
,
index
)
{
final
o
=
response
.
otherExpenses
![
index
];
return
SizedBox
(
width:
MediaQuery
.
of
(
context
).
size
.
width
*
0.90
,
child:
_otherExpenseCard
(
description:
o
.
otherDesc
??
"-"
,
amount:
o
.
otherAmount
??
"0"
,
date:
o
.
otherDate
??
"-"
,
onViewTap:
()
{
debugPrint
(
"Open:
${o.imageDirFilePath}
"
);
showDialog
(
context:
context
,
builder:
(
_
)
=>
Dialog
(
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
12
),
child:
Image
.
network
(
o
.
imageDirFilePath
.
toString
())
),
),
);
},
),
);
},
),
),
],
const
SizedBox
(
height:
25
),
],
),
);
},
),
),
);
}
/// Attach your reusable card functions here
Widget
_tourExpenseCard
({
required
String
employeeName
,
required
String
placeOfVisit
,
required
String
daAmount
,
required
String
totalAmount
,
required
String
fromDate
,
required
String
toDate
,
required
String
remarks
,
})
{
// paste your same implementation here
return
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
16
),
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
grey
.
withOpacity
(
0.1
),
blurRadius:
6
,
offset:
const
Offset
(
0
,
3
),
)
],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
children:
[
CircleAvatar
(
radius:
22.5
,
backgroundColor:
const
Color
(
0xffFFF3E0
),
child:
SvgPicture
.
asset
(
"assets/svg/hrm/travel_ic.svg"
,
),
),
const
SizedBox
(
width:
8
),
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
employeeName
,
style:
TextStyle
(
fontSize:
14.5
,
fontFamily:
"JakartaMedium"
,
fontWeight:
FontWeight
.
w600
,
color:
AppColors
.
semi_black
,
)
),
Text
(
placeOfVisit
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
app_blue
,
),
),
],
),
],
),
const
SizedBox
(
height:
12
),
_buildSectionHeader
(
"Amount Details"
),
_buildKeyValue
(
"DA Amount"
,
daAmount
),
_buildKeyValue
(
"Total Amount"
,
totalAmount
),
const
SizedBox
(
height:
10
),
_buildSectionHeader
(
"Tour Time"
),
_buildKeyValue
(
"From Date"
,
fromDate
),
_buildKeyValue
(
"To Date"
,
toDate
),
const
SizedBox
(
height:
10
),
_buildSectionHeader
(
"Remarks"
),
_buildKeyValue
(
"Extra Note"
,
remarks
),
],
),
);
}
Widget
_travelExpenseCard
({
required
String
travelType
,
required
String
amount
,
required
String
from
,
required
String
to
,
required
VoidCallback
onViewTap
,
})
{
// paste your travel card code here
return
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
16
),
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
grey
.
withOpacity
(
0.1
),
blurRadius:
6
,
offset:
const
Offset
(
0
,
3
),
)
],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Row
(
children:
[
CircleAvatar
(
radius:
20
,
backgroundColor:
const
Color
(
0xffFFF3E0
),
child:
SvgPicture
.
asset
(
"assets/svg/hrm/travel_ic.svg"
,
),
),
const
SizedBox
(
width:
8
),
Text
(
travelType
,
style:
TextStyle
(
fontSize:
14.5
,
fontFamily:
"JakartaMedium"
,
fontWeight:
FontWeight
.
w600
,
color:
AppColors
.
semi_black
,
)
),
],
),
Text
(
"₹
$amount
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
app_blue
,
),
),
],
),
const
SizedBox
(
height:
15
),
_buildSectionHeader
(
"Travel Details"
),
const
SizedBox
(
height:
4
),
_buildKeyValue
(
"From"
,
from
),
const
SizedBox
(
height:
2
),
_buildKeyValue
(
"To"
,
to
),
const
SizedBox
(
height:
2
),
_buildKeyValue
(
"Image"
,
"View"
,
isLink:
true
,
onTap:
onViewTap
),
],
),
);
}
Widget
_hotelExpenseCard
({
required
String
hotelName
,
required
String
amount
,
required
String
fromDate
,
required
String
toDate
,
required
VoidCallback
onViewTap
,
})
{
// paste your hotel card code here
return
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
16
),
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
grey
.
withOpacity
(
0.1
),
blurRadius:
6
,
offset:
const
Offset
(
0
,
3
),
)
],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Row
(
children:
[
CircleAvatar
(
radius:
20
,
backgroundColor:
const
Color
(
0xffFCE4EC
),
child:
SvgPicture
.
asset
(
"assets/svg/hrm/hotel_ic.svg"
,
),
),
const
SizedBox
(
width:
8
),
Text
(
hotelName
,
style:
TextStyle
(
fontSize:
14.5
,
fontFamily:
"JakartaMedium"
,
fontWeight:
FontWeight
.
w600
,
color:
AppColors
.
semi_black
,
)
),
],
),
Text
(
"₹
$amount
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
app_blue
,
),
),
],
),
const
SizedBox
(
height:
15
),
_buildSectionHeader
(
"Living Details"
),
const
SizedBox
(
height:
4
),
_buildKeyValue
(
"From"
,
fromDate
),
const
SizedBox
(
height:
2
),
_buildKeyValue
(
"To"
,
toDate
),
const
SizedBox
(
height:
2
),
_buildKeyValue
(
"Image"
,
"View"
,
isLink:
true
,
onTap:
onViewTap
),
],
),
);
}
Widget
_otherExpenseCard
({
required
String
description
,
required
String
amount
,
required
String
date
,
required
VoidCallback
onViewTap
,
})
{
// paste your other expense card code here
return
Container
(
margin:
const
EdgeInsets
.
only
(
bottom:
16
),
padding:
const
EdgeInsets
.
all
(
16
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
boxShadow:
[
BoxShadow
(
color:
Colors
.
grey
.
withOpacity
(
0.1
),
blurRadius:
6
,
offset:
const
Offset
(
0
,
3
),
)
],
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Row
(
children:
[
CircleAvatar
(
radius:
20
,
backgroundColor:
const
Color
(
0xffEDE7F6
),
child:
SvgPicture
.
asset
(
"assets/svg/hrm/books_ic.svg"
,
),
),
const
SizedBox
(
width:
8
),
Text
(
description
,
style:
TextStyle
(
fontSize:
14.5
,
fontFamily:
"JakartaMedium"
,
fontWeight:
FontWeight
.
w600
,
color:
AppColors
.
semi_black
,
)
),
],
),
Text
(
"₹
$amount
"
,
style:
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
AppColors
.
app_blue
,
),
),
],
),
const
SizedBox
(
height:
15
),
_buildSectionHeader
(
"Other Details"
),
const
SizedBox
(
height:
4
),
_buildKeyValue
(
"Date"
,
date
),
const
SizedBox
(
height:
2
),
_buildKeyValue
(
"Description"
,
description
),
const
SizedBox
(
height:
2
),
_buildKeyValue
(
"Image"
,
"View"
,
isLink:
true
,
onTap:
onViewTap
),
],
),
);
}
Widget
_buildSectionHeader
(
String
title
)
{
return
Row
(
children:
[
Text
(
title
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaSemiBold"
,
)
),
const
SizedBox
(
width:
16
),
Expanded
(
child:
DottedLine
(
dashGapLength:
3
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashLength:
2
,
lineThickness:
0.5
,
),
)
],
);
}
Widget
_buildKeyValue
(
String
key
,
String
value
,
{
bool
isLink
=
false
,
VoidCallback
?
onTap
})
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
3.5
,
horizontal:
2
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
key
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
),
),
isLink
?
GestureDetector
(
onTap:
onTap
,
child:
const
Text
(
"View"
,
style:
TextStyle
(
fontSize:
14
,
fontWeight:
FontWeight
.
w500
,
color:
Colors
.
blue
)),
)
:
Text
(
value
,
style:
const
TextStyle
(
fontSize:
14
,
color:
Color
(
0xFF818181
),
),
),
],
),
);
}
Widget
_expenseHeaderCard
({
required
String
title
,
required
String
date
,
required
status
,
required
List
<
Map
<
String
,
String
>>
details
,
})
{
bool
showMore
=
false
;
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
Card
(
margin:
EdgeInsets
.
symmetric
(
horizontal:
0
,
vertical:
1.2
),
shape:
const
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
only
(
bottomLeft:
Radius
.
circular
(
30
),
bottomRight:
Radius
.
circular
(
30
),
),
),
elevation:
2
,
child:
Container
(
decoration:
const
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
only
(
bottomLeft:
Radius
.
circular
(
30
),
bottomRight:
Radius
.
circular
(
30
),
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
12
,
horizontal:
14
),
child:
Column
(
children:
[
/// Header Row
Row
(
children:
[
Container
(
height:
45
,
width:
45
,
padding:
const
EdgeInsets
.
all
(
7.5
),
decoration:
const
BoxDecoration
(
color:
Color
(
0xFFE6F6FF
),
shape:
BoxShape
.
circle
,
),
child:
SvgPicture
.
asset
(
"assets/svg/hrm/tour_main_ic.svg"
),
),
const
SizedBox
(
width:
10
),
Expanded
(
flex:
5
,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
title
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaRegular"
,
color:
Color
(
0xff2D2D2D
)
)
),
const
SizedBox
(
height:
3
),
Text
(
date
,
style:
const
TextStyle
(
fontSize:
12
,
color:
Color
(
0xff818181
)
)
),
],
),
),
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
6
),
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
8
),
color:
_getStatusBgColor
(
status
),
),
child:
Text
(
status
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaRegular"
,
color:
_getStatusTxtColor
(
status
))),
)
],
),
const
SizedBox
(
height:
10
),
/// Expanded Section
if
(
showMore
)
...[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8
),
child:
Row
(
children:
[
const
Text
(
"Amount Details"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaSemiBold"
,
)
),
const
SizedBox
(
width:
10
),
Expanded
(
child:
DottedLine
(
dashGapLength:
4
,
dashGapColor:
Colors
.
white
,
dashColor:
AppColors
.
grey_semi
,
dashLength:
2
,
lineThickness:
0.5
,
),
),
],
),
),
const
SizedBox
(
height:
6
),
Column
(
children:
details
.
map
((
d
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Expanded
(
flex:
4
,
child:
Text
(
d
[
"key"
]
??
"-"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
semi_black
,
fontFamily:
"JakartaRegular"
,
)
)
),
Expanded
(
flex:
3
,
child:
Text
(
d
[
"value"
]
??
"-"
,
textAlign:
TextAlign
.
right
,
style:
const
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaRegular"
,
color:
Color
(
0xff818181
)
)
)
),
],
),
);
}).
toList
(),
),
],
/// Toggle Button
InkWell
(
onTap:
()
=>
setState
(()
=>
showMore
=
!
showMore
),
child:
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Text
(
showMore
?
"Hide Details"
:
"View Details"
,
style:
TextStyle
(
fontSize:
14
,
fontFamily:
"JakartaMedium"
,
fontWeight:
FontWeight
.
w500
,
color:
AppColors
.
app_blue
,
)
),
const
SizedBox
(
width:
6
),
Transform
.
flip
(
flipY:
showMore
,
child:
SvgPicture
.
asset
(
"assets/svg/arrow_dropdown.svg"
,
height:
25
,
width:
20
,
color:
AppColors
.
app_blue
,
),
)
],
),
),
)
],
),
),
);
},
);
}
/// Avatar color generator
Color
_getStatusBgColor
(
value
)
{
var
color
=
AppColors
.
approved_bg_color
;
switch
(
value
)
{
case
'HR Approved'
:
return
AppColors
.
approved_bg_color
;
case
'Expired at HR'
:
return
AppColors
.
rejected_bg_color
;
case
'Expired at TL'
:
return
AppColors
.
rejected_bg_color
;
}
return
color
;
}
Color
_getStatusTxtColor
(
value
)
{
var
color
=
AppColors
.
approved_text_color
;
switch
(
value
)
{
case
'HR Approved'
:
return
AppColors
.
approved_text_color
;
case
'Expired at HR'
:
return
AppColors
.
rejected_text_color
;
case
'Expired at TL'
:
return
AppColors
.
rejected_text_color
;
}
return
color
;
}
getText
(
value
)
{
switch
(
value
)
{
case
'HR Approved'
:
return
"A"
;
case
'Expired at HR'
:
return
"E"
;
case
'Expired at TL'
:
return
"E"
;
case
'Updated'
:
return
"U"
;
default
:
return
"Requested"
;
}
}
}
lib/screens/hrm/TourExpensesListScreen.dart
0 → 100644
View file @
332a8e91
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:generp/screens/hrm/TourExpensesDetailsScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'../../Models/hrmModels/tourExpensesListResponse.dart'
;
import
'../../Notifiers/hrmProvider/tourExpensesProvider.dart'
;
import
'AddTourExpBillScreen.dart'
;
class
TourExpensesListScreen
extends
StatefulWidget
{
const
TourExpensesListScreen
({
super
.
key
});
@override
State
<
TourExpensesListScreen
>
createState
()
=>
_TourExpensesListScreenState
();
}
class
_TourExpensesListScreenState
extends
State
<
TourExpensesListScreen
>
{
@override
Widget
build
(
BuildContext
context
)
{
return
SafeArea
(
top:
false
,
child:
ChangeNotifierProvider
(
create:
(
_
)
=>
TourExpensesProvider
()..
fetchTourExpenses
(
context
,
"1"
),
child:
Consumer
<
TourExpensesProvider
>(
builder:
(
context
,
provider
,
child
)
{
return
Scaffold
(
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
Colors
.
white
,
title:
Row
(
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
25
,
),
),
const
SizedBox
(
width:
10
),
const
Text
(
"Tour Expenses"
,
style:
TextStyle
(
fontSize:
18
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
],
),
),
backgroundColor:
const
Color
(
0xFFF6F6F8
),
body:
Column
(
children:
[
Expanded
(
child:
Builder
(
builder:
(
context
)
{
if
(
provider
.
isLoading
)
{
return
const
Center
(
child:
CircularProgressIndicator
(
color:
Colors
.
blue
));
}
if
(
provider
.
errorMessage
!=
null
)
{
return
Center
(
child:
Text
(
provider
.
errorMessage
!));
}
if
(
provider
.
response
?.
tourList
==
null
||
provider
.
response
!.
tourList
!.
isEmpty
)
{
return
const
Center
(
child:
Text
(
"No Tour Expenses Found"
));
}
final
list
=
provider
.
response
!.
tourList
!;
return
ListView
.
builder
(
padding:
const
EdgeInsets
.
all
(
12
),
itemCount:
list
.
length
,
itemBuilder:
(
context
,
index
)
{
final
TourList
item
=
list
[
index
];
return
InkWell
(
onTap:
()
{
/// navigation flow
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
TourExpensesDetailsScreen
(
tourBillId:
item
.
id
.
toString
(),
),
),
);
},
child:
Container
(
margin:
const
EdgeInsets
.
symmetric
(
vertical:
6
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
14
,
vertical:
12
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
),
child:
Row
(
children:
[
/// Left Avatar Circle
Container
(
height:
46
,
width:
46
,
decoration:
BoxDecoration
(
color:
_getAvatarColor
(
item
.
approvalStatus
),
shape:
BoxShape
.
circle
,
),
child:
Center
(
child:
Text
(
getText
(
item
.
approvalStatus
),
style:
TextStyle
(
fontSize:
15
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w500
,
color:
_getAvatarTxtColor
(
item
.
approvalStatus
),
),
),
),
),
const
SizedBox
(
width:
12
),
/// Middle Section
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
item
.
placeOfVisit
??
"-"
,
maxLines:
1
,
overflow:
TextOverflow
.
ellipsis
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
14
,
color:
AppColors
.
semi_black
,
),
),
Text
(
item
.
appliedDate
??
"-"
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
14
,
color:
AppColors
.
grey_semi
,
),
),
],
),
),
/// Right Section (Applied Amount)
Text
(
"₹
${item.appliedAmount ?? '0'}
"
,
style:
const
TextStyle
(
fontFamily:
"JakartaMedium"
,
fontSize:
14
,
color:
Color
(
0xff1487c9
),
)
),
],
),
),
);
},
);
},
),
),
],
),
floatingActionButtonLocation:
FloatingActionButtonLocation
.
centerFloat
,
floatingActionButton:
InkResponse
(
onTap:
()
{
HapticFeedback
.
selectionClick
();
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
const
AddBillScreen
(
pageTitleName:
"Add Bill"
,),
settings:
const
RouteSettings
(
name:
'AddTourExpBillScreen'
),
),
).
then
((
_
)
{
provider
.
fetchTourExpenses
(
context
,
"1"
);
});
// show add bill screen here
},
child:
Container
(
height:
45
,
alignment:
Alignment
.
center
,
margin:
EdgeInsets
.
symmetric
(
horizontal:
20
),
padding:
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
5
),
decoration:
BoxDecoration
(
color:
AppColors
.
app_blue
,
borderRadius:
BorderRadius
.
circular
(
15
),
),
child:
Text
(
"Add Bill"
,
style:
TextStyle
(
fontSize:
15
,
fontFamily:
"JakartaMedium"
,
color:
Colors
.
white
,
),
),
),
),
// /// Bottom Add Bill Button
// bottomNavigationBar: Container(
// padding: const EdgeInsets.all(18),
// color: Colors.white,
// child: ElevatedButton(
// style: ElevatedButton.styleFrom(
// backgroundColor: Color(0xff1487c9),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(15),
// ),
// padding: const EdgeInsets.symmetric(vertical: 14),
// ),
// onPressed: () {
// // to work
// },
// child: const Text(
// "Add Bill",
// style: TextStyle(
// fontSize: 16,
// fontFamily: "Plus Jakarta Sans",
// fontWeight: FontWeight.w500,
// color: Colors.white,
// ),
// ),
// ),
// ),
);
},
),
),
);
}
/// Avatar color generator
Color
_getAvatarColor
(
value
)
{
var
color
=
AppColors
.
approved_bg_color
;
switch
(
value
)
{
case
'HR Approved'
:
return
AppColors
.
approved_bg_color
;
case
'Expired at HR'
:
return
AppColors
.
rejected_bg_color
;
case
'Expired at TL'
:
return
AppColors
.
rejected_bg_color
;
}
return
color
;
}
Color
_getAvatarTxtColor
(
value
)
{
var
color
=
AppColors
.
approved_text_color
;
switch
(
value
)
{
case
'HR Approved'
:
return
AppColors
.
approved_text_color
;
case
'Expired at HR'
:
return
AppColors
.
rejected_text_color
;
case
'Expired at TL'
:
return
AppColors
.
rejected_text_color
;
}
return
color
;
}
getText
(
value
)
{
switch
(
value
)
{
case
'HR Approved'
:
return
"A"
;
case
'Expired at HR'
:
return
"E"
;
case
'Expired at TL'
:
return
"E"
;
case
'Updated'
:
return
"U"
;
default
:
return
"R"
;
}
}
}
lib/screens/notifierExports.dart
View file @
332a8e91
...
@@ -56,3 +56,12 @@ export 'package:generp/Notifiers/crmProvider/addProspectLeadsProvider.dart';
...
@@ -56,3 +56,12 @@ export 'package:generp/Notifiers/crmProvider/addProspectLeadsProvider.dart';
export
'package:generp/Notifiers/crmProvider/followUpUpdateProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/followUpUpdateProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/appointmentCalendarProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/appointmentCalendarProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/addNewLeadsandProspectsProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/addNewLeadsandProspectsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/attendanceListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/AttendanceDetailsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/tourExpensesProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/tourExpensesDetailsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/rewardListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationDetailsProvider.dart'
;
lib/screens/screensExports.dart
View file @
332a8e91
...
@@ -54,3 +54,5 @@ export 'package:generp/screens/crm/QuotationDetails.dart';
...
@@ -54,3 +54,5 @@ export 'package:generp/screens/crm/QuotationDetails.dart';
export
'package:generp/screens/crm/contactDetails.dart'
;
export
'package:generp/screens/crm/contactDetails.dart'
;
export
'package:generp/screens/crm/editAccountDetails.dart'
;
export
'package:generp/screens/crm/editAccountDetails.dart'
;
export
'package:generp/screens/crm/productDetails.dart'
;
export
'package:generp/screens/crm/productDetails.dart'
;
// hrm screen export
export
'package:generp/screens/hrm/Attendancelist.dart'
;
lib/services/api_calling.dart
View file @
332a8e91
...
@@ -25,12 +25,20 @@ import 'package:generp/Models/crmModels/crmProspectDetailsAddLeadsResponse.dart'
...
@@ -25,12 +25,20 @@ import 'package:generp/Models/crmModels/crmProspectDetailsAddLeadsResponse.dart'
import
'package:generp/Models/crmModels/crmProspectDetailsResponse.dart'
;
import
'package:generp/Models/crmModels/crmProspectDetailsResponse.dart'
;
import
'package:generp/Models/financeModels/addDirectPaymentResponse.dart'
;
import
'package:generp/Models/financeModels/addDirectPaymentResponse.dart'
;
import
'package:generp/Models/financeModels/paymentRequisitionPaymentsListResponse.dart'
;
import
'package:generp/Models/financeModels/paymentRequisitionPaymentsListResponse.dart'
;
import
'package:generp/Models/hrmModels/attendanceRequestListResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationDetailsResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationLIstResponse.dart'
;
import
'package:generp/Models/hrmModels/rewardListResponse.dart'
;
import
'package:generp/Models/hrmModels/tourExpensesAddViewResponse.dart'
;
import
'package:generp/Models/hrmModels/tourExpensesDetailsResponse.dart'
;
import
'package:generp/Models/hrmModels/tourExpensesListResponse.dart'
;
import
'package:generp/Models/ordersModels/PendingTPCAgentListResponse.dart'
;
import
'package:generp/Models/ordersModels/PendingTPCAgentListResponse.dart'
;
import
'package:generp/Models/ordersModels/TPCAgentDetailsResponse.dart'
;
import
'package:generp/Models/ordersModels/TPCAgentDetailsResponse.dart'
;
import
'package:generp/Models/ordersModels/TPCListResponse.dart'
;
import
'package:generp/Models/ordersModels/TPCListResponse.dart'
;
import
'package:generp/Models/ordersModels/orderDashboardResponse.dart'
;
import
'package:generp/Models/ordersModels/orderDashboardResponse.dart'
;
import
'package:generp/services/api_names.dart'
;
import
'package:generp/services/api_names.dart'
;
import
'package:generp/services/api_post_request.dart'
;
import
'package:generp/services/api_post_request.dart'
;
import
'package:http/http.dart'
as
http
;
import
'package:path_provider/path_provider.dart'
;
import
'package:path_provider/path_provider.dart'
;
import
'../Models/AccountSuggestionResponse.dart'
;
import
'../Models/AccountSuggestionResponse.dart'
;
...
@@ -92,6 +100,8 @@ import '../Models/financeModels/paymentRequisitionPaymentsDetailsResponse.dart';
...
@@ -92,6 +100,8 @@ import '../Models/financeModels/paymentRequisitionPaymentsDetailsResponse.dart';
import
'../Models/financeModels/paymentRequisitionPaymentsReceiptsDetailsResponse.dart'
;
import
'../Models/financeModels/paymentRequisitionPaymentsReceiptsDetailsResponse.dart'
;
import
'../Models/financeModels/paymentRequisitionPaymentsReceiptsListResponse.dart'
;
import
'../Models/financeModels/paymentRequisitionPaymentsReceiptsListResponse.dart'
;
import
'../Models/generatorComplaintResponse.dart'
;
import
'../Models/generatorComplaintResponse.dart'
;
import
'../Models/hrmModels/attendanceRequestDetailsResponse.dart'
;
import
'../Models/hrmModels/hrmAccessiblePagesResponse.dart'
;
import
'../Models/loadGeneratorDetailsResponse.dart'
;
import
'../Models/loadGeneratorDetailsResponse.dart'
;
import
'../Models/financeModels/financeDashboardPagesResponse.dart'
;
import
'../Models/financeModels/financeDashboardPagesResponse.dart'
;
import
'../Models/ordersModels/AddOrderPaymentSelectAccountResponse.dart'
;
import
'../Models/ordersModels/AddOrderPaymentSelectAccountResponse.dart'
;
...
@@ -116,6 +126,7 @@ import '../Models/ordersModels/paymentListByModeResponse.dart';
...
@@ -116,6 +126,7 @@ import '../Models/ordersModels/paymentListByModeResponse.dart';
import
'../Models/ordersModels/technicianAddPaymentResendOTPResponse.dart'
;
import
'../Models/ordersModels/technicianAddPaymentResendOTPResponse.dart'
;
import
'../Notifiers/financeProvider/approveRejectPaymentRequestResponse.dart'
;
import
'../Notifiers/financeProvider/approveRejectPaymentRequestResponse.dart'
;
import
'../Utils/commonServices.dart'
;
import
'../Utils/commonServices.dart'
;
import
'package:http_parser/http_parser.dart'
;
class
ApiCalling
{
class
ApiCalling
{
static
Future
download_files
(
empId
,
session
,
url
,
cntxt
)
async
{
static
Future
download_files
(
empId
,
session
,
url
,
cntxt
)
async
{
...
@@ -4898,6 +4909,453 @@ class ApiCalling {
...
@@ -4898,6 +4909,453 @@ class ApiCalling {
}
}
}
}
///hrm modules
///
///
static
Future
<
hrmAccessiblePagesResponse
?>
hrmAccessiblePagesAPI
(
empId
,
session
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
'session_id'
:
(
session
).
toString
(),
};
final
res
=
await
post
(
data
,
HrmAccessiblePagesUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
hrmAccessiblePagesResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
attendanceRequestListResponse
?>
attendanceRequestListAPI
(
empId
,
session
,
type
,
from
,
to
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
'session_id'
:
(
session
).
toString
(),
'type'
:
(
type
),
'from'
:
(
from
),
'to'
:
(
to
),
};
final
res
=
await
post
(
data
,
AttendanceRequestListUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
attendanceRequestListResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
attendanceRequestDetailsResponse
?>
attendanceRequestDetailAPI
(
empId
,
session
,
attendanceRequestId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'emp_id'
:
(
empId
).
toString
(),
'session_id'
:
(
session
).
toString
(),
'attendance_request_id'
:
(
attendanceRequestId
),
};
final
res
=
await
post
(
data
,
AttendanceRequestDetailsUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
attendanceRequestDetailsResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
CommonResponse
?>
addAttendanceRequestAPI
({
required
String
sessionId
,
required
String
empId
,
required
String
process
,
required
String
type
,
required
String
loc
,
required
String
checkDate
,
String
?
checkInTime
,
String
?
checkInLoc
,
File
?
checkInProof
,
String
?
checkOutTime
,
String
?
checkOutLoc
,
File
?
checkOutProof
,
String
?
note
,
})
async
{
try
{
var
request
=
http
.
MultipartRequest
(
'POST'
,
Uri
.
parse
(
AddAttendanceRequestUrl
));
// Add basic fields that are always required
Map
<
String
,
String
>
fields
=
{
"session_id"
:
sessionId
,
"emp_id"
:
empId
,
"process"
:
process
,
"type"
:
type
,
"loc"
:
loc
,
"check_date"
:
checkDate
,
"note"
:
note
??
""
,
};
// Conditionally add check-in fields based on type
if
(
type
==
"Check In"
||
type
==
"Check In/Out"
)
{
fields
[
"check_in_time"
]
=
checkInTime
??
""
;
fields
[
"check_in_loc"
]
=
checkInLoc
??
""
;
if
(
checkInProof
!=
null
)
{
request
.
files
.
add
(
await
http
.
MultipartFile
.
fromPath
(
"check_in_proof"
,
checkInProof
.
path
));
}
}
// Conditionally add check-out fields based on type
if
(
type
==
"Check Out"
||
type
==
"Check In/Out"
)
{
fields
[
"check_out_time"
]
=
checkOutTime
??
""
;
fields
[
"check_out_loc"
]
=
checkOutLoc
??
""
;
if
(
checkOutProof
!=
null
)
{
request
.
files
.
add
(
await
http
.
MultipartFile
.
fromPath
(
"check_out_proof"
,
checkOutProof
.
path
));
}
}
// Add all fields to the request
request
.
fields
.
addAll
(
fields
);
// Log the actual fields being sent
debugPrint
(
"addAttendanceRequestAPI - Type:
$type
"
);
debugPrint
(
"addAttendanceRequestAPI - Fields:
$fields
"
);
debugPrint
(
"addAttendanceRequestAPI - Files:
${request.files.map((f) => f.filename).toList()}
"
);
var
response
=
await
request
.
send
();
var
resBody
=
await
response
.
stream
.
bytesToString
();
debugPrint
(
"Server Response:
$resBody
"
);
if
(
response
.
statusCode
==
200
)
{
return
CommonResponse
.
fromJson
(
jsonDecode
(
resBody
));
}
else
{
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
"API Error:
$e
"
);
return
null
;
}
}
//reward list
static
Future
<
rewardListResponse
?>
rewardListAPI
(
empId
,
session
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
};
final
res
=
await
post
(
data
,
RewardListUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
rewardListResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
//tour exp
static
Future
<
tourExpensesListResponse
?>
tourExpensesListAPI
(
empId
,
session
,
pageNumber
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'page_number'
:
(
pageNumber
),
};
final
res
=
await
post
(
data
,
TourExpensesListUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
tourExpensesListResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
tourExpensesDetailsResponse
?>
tourExpensesDetailAPI
(
session
,
empId
,
tourBillId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'tour_bill_id'
:
(
tourBillId
),
};
final
res
=
await
post
(
data
,
TourExpensesDetailsUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
tourExpensesDetailsResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
tourExpensesAddViewResponse
?>
tourExpensesAddViewAPI
(
empId
,
session
,
tourBillId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'tour_bill_id'
:
(
tourBillId
),
};
final
res
=
await
post
(
data
,
TourExpensesAddViewUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
tourExpensesAddViewResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
CommonResponse
?>
addTourBillAPI
({
required
String
sessionId
,
required
String
empId
,
required
String
placeOfVisit
,
required
String
daAmount
,
required
String
tourType
,
required
String
tourDate
,
required
List
<
Map
<
String
,
dynamic
>>
travelExpenses
,
required
List
<
Map
<
String
,
dynamic
>>
hotelExpenses
,
required
List
<
Map
<
String
,
dynamic
>>
otherExpenses
,
List
<
File
>?
travelImages
,
List
<
File
>?
hotelImages
,
List
<
File
>?
otherImages
,
})
async
{
try
{
var
request
=
http
.
MultipartRequest
(
"POST"
,
Uri
.
parse
(
AddTourExpensesUrl
));
/// Add text fields
request
.
fields
[
'session_id'
]
=
sessionId
;
request
.
fields
[
'emp_id'
]
=
empId
;
request
.
fields
[
'place_of_visit'
]
=
placeOfVisit
;
request
.
fields
[
'da_amount'
]
=
daAmount
;
request
.
fields
[
'tour_type'
]
=
tourType
;
request
.
fields
[
'tour_date'
]
=
tourDate
;
/// Convert expense lists to JSON string
request
.
fields
[
'travel_expenses'
]
=
jsonEncode
(
travelExpenses
);
request
.
fields
[
'hotel_expenses'
]
=
jsonEncode
(
hotelExpenses
);
request
.
fields
[
'other_expenses'
]
=
jsonEncode
(
otherExpenses
);
/// Add hotel images
if
(
hotelImages
!.
isNotEmpty
)
{
for
(
var
file
in
hotelImages
)
{
if
(
file
.
path
.
isNotEmpty
)
{
request
.
files
.
add
(
await
http
.
MultipartFile
.
fromPath
(
"hotel_images[]"
,
file
.
path
,
),
);
}
}
}
/// Add travel images
if
(
travelImages
!.
isNotEmpty
)
{
for
(
var
file
in
travelImages
)
{
if
(
file
.
path
.
isNotEmpty
)
{
request
.
files
.
add
(
await
http
.
MultipartFile
.
fromPath
(
"travel_images[]"
,
file
.
path
,
),
);
}
}
}
/// Add other images
if
(
otherImages
!.
isNotEmpty
)
{
for
(
var
file
in
otherImages
)
{
if
(
file
.
path
.
isNotEmpty
)
{
request
.
files
.
add
(
await
http
.
MultipartFile
.
fromPath
(
"other_images[]"
,
file
.
path
,
),
);
}
}
}
/// Send request
var
response
=
await
request
.
send
();
var
resBody
=
await
response
.
stream
.
bytesToString
();
debugPrint
(
"Request Fields:
${request.fields}
"
);
debugPrint
(
"Response:
$resBody
"
);
if
(
response
.
statusCode
==
200
)
{
return
CommonResponse
.
fromJson
(
jsonDecode
(
resBody
));
}
else
{
debugPrint
(
"Error:
${response.statusCode}
-
$resBody
"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
"Error in addTourBillAPI:
$e
"
);
return
null
;
}
}
// Leave Application api
static
Future
<
leaveApplicationLIstResponse
?>
leaveApplicationListAPI
(
session
,
empId
,
dateFrom
,
dateTo
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'requested_date_from'
:
(
dateFrom
),
'requested_date_to'
:
(
dateTo
),
};
final
res
=
await
post
(
data
,
LeaveApplicationListUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
leaveApplicationLIstResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
static
Future
<
leaveApplicationDetailsResponse
?>
leaveApplicationDetailAPI
(
session
,
empId
,
leaveRequestId
,
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'leave_request_id'
:
(
leaveRequestId
),
};
final
res
=
await
post
(
data
,
LeaveApplicationDetailsUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
leaveApplicationDetailsResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
//add leave request
static
Future
<
CommonResponse
?>
leaveRequestAddAPI
(
session
,
empId
,
fromDate
,
fromTime
,
toDate
,
toTime
,
leaveType
,
reason
)
async
{
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
'from_date'
:
(
fromDate
).
toString
(),
'from_time'
:
(
fromTime
).
toString
(),
'to_date'
:
(
toDate
).
toString
(),
'to_time'
:
(
toTime
).
toString
(),
'leave_type'
:
(
leaveType
).
toString
(),
'reason'
:
(
reason
).
toString
(),
};
final
res
=
await
post
(
data
,
LeaveRequestAdditionUrl
,
{});
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
res
.
body
);
return
CommonResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'hello bev=bug
$e
'
);
return
null
;
}
}
// static Future<CommonResponse?> TpcIssueListApprovalAPI(
// static Future<CommonResponse?> TpcIssueListApprovalAPI(
// empId,
// empId,
// session,
// session,
...
...
lib/services/api_names.dart
View file @
332a8e91
...
@@ -178,6 +178,25 @@ const crmDashboardFollowUpUrl = "${baseUrl_test}crm_dashboard_followup_list";
...
@@ -178,6 +178,25 @@ const crmDashboardFollowUpUrl = "${baseUrl_test}crm_dashboard_followup_list";
const
crmDashboardQuotationsUrl
=
"
${baseUrl_test}
crm_dashboard_quotations_list"
;
const
crmDashboardQuotationsUrl
=
"
${baseUrl_test}
crm_dashboard_quotations_list"
;
///HRM
//Attendance
const
HrmAccessiblePagesUrl
=
"
${baseUrl_test}
hrm_accessible_pages"
;
const
AttendanceRequestListUrl
=
"
${baseUrl_test}
attendance_request_list"
;
const
AttendanceRequestDetailsUrl
=
"
${baseUrl_test}
attendance_request_details"
;
const
AddAttendanceRequestUrl
=
"
${baseUrl_test}
add_attendance_request"
;
// reward list
const
RewardListUrl
=
"
${baseUrl_test}
hrm_emp_self_rewards"
;
// Tour Expenses hrm_emp_self_rewards
const
TourExpensesListUrl
=
"
${baseUrl_test}
tour_bill_list"
;
const
TourExpensesDetailsUrl
=
"
${baseUrl_test}
tour_bill_details"
;
const
TourExpensesAddViewUrl
=
"
${baseUrl_test}
add_tour_bill_view"
;
const
AddTourExpensesUrl
=
"
${baseUrl_test}
add_tour_bill"
;
//leave applications
const
LeaveApplicationListUrl
=
"
${baseUrl_test}
leave_request_list"
;
const
LeaveApplicationDetailsUrl
=
"
${baseUrl_test}
leave_request_details"
;
const
LeaveRequestAdditionUrl
=
"
${baseUrl_test}
add_leave_request"
;
...
...
lib/services/api_post_request.dart
View file @
332a8e91
...
@@ -181,6 +181,76 @@ Future<String?> postImageNew(
...
@@ -181,6 +181,76 @@ Future<String?> postImageNew(
return
null
;
return
null
;
}
}
}
}
//travel_image
//hotel_image
//other_image
Future
<
String
?>
PostMultipleImagesNew
(
Map
<
String
,
String
>
body
,
String
urlLink
,
Map
<
String
,
String
>
headers
,
List
<
http
.
MultipartFile
>
newList
,
List
<
http
.
MultipartFile
>
newList1
,
List
<
http
.
MultipartFile
>
newList2
,
)
async
{
try
{
var
req
=
http
.
MultipartRequest
(
'POST'
,
Uri
.
parse
(
urlLink
));
req
.
headers
.
addAll
(
headers
);
req
.
files
.
addAll
(
newList
);
req
.
files
.
addAll
(
newList1
);
req
.
files
.
addAll
(
newList2
);
req
.
fields
.
addAll
(
body
);
var
res
=
await
req
.
send
();
final
resBody
=
await
res
.
stream
.
bytesToString
();
if
(
res
.
statusCode
>=
200
&&
res
.
statusCode
<
300
)
{
print
(
"****
$resBody
....
$res
"
);
return
resBody
;
}
else
{
print
(
"error:
${res.reasonPhrase}
"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
e
.
toString
());
return
null
;
}
}
Future
<
String
?>
PostMultipleImagesNew2
(
Map
<
String
,
String
>
body
,
String
urlLink
,
Map
<
String
,
String
>
headers
,
List
<
http
.
MultipartFile
>
newList
,
List
<
http
.
MultipartFile
>
newList1
,
)
async
{
try
{
var
req
=
http
.
MultipartRequest
(
'POST'
,
Uri
.
parse
(
urlLink
));
req
.
headers
.
addAll
(
headers
);
req
.
files
.
addAll
(
newList
);
req
.
files
.
addAll
(
newList1
);
req
.
fields
.
addAll
(
body
);
var
res
=
await
req
.
send
();
final
resBody
=
await
res
.
stream
.
bytesToString
();
if
(
res
.
statusCode
>=
200
&&
res
.
statusCode
<
300
)
{
print
(
"****
$resBody
....
$res
"
);
return
resBody
;
}
else
{
print
(
"error:
${res.reasonPhrase}
"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
e
.
toString
());
return
null
;
}
}
Future
<
String
?>
PostMultipleImages
(
Future
<
String
?>
PostMultipleImages
(
Map
<
String
,
String
>
body
,
Map
<
String
,
String
>
body
,
...
...
macos/Flutter/GeneratedPluginRegistrant.swift
View file @
332a8e91
...
@@ -8,6 +8,7 @@ import Foundation
...
@@ -8,6 +8,7 @@ import Foundation
import
app_settings
import
app_settings
import
connectivity_plus
import
connectivity_plus
import
device_info_plus
import
device_info_plus
import
file_picker
import
file_selector_macos
import
file_selector_macos
import
firebase_core
import
firebase_core
import
firebase_messaging
import
firebase_messaging
...
@@ -30,6 +31,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
...
@@ -30,6 +31,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppSettingsPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"AppSettingsPlugin"
))
AppSettingsPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"AppSettingsPlugin"
))
ConnectivityPlusPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"ConnectivityPlusPlugin"
))
ConnectivityPlusPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"ConnectivityPlusPlugin"
))
DeviceInfoPlusMacosPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"DeviceInfoPlusMacosPlugin"
))
DeviceInfoPlusMacosPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"DeviceInfoPlusMacosPlugin"
))
FilePickerPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FilePickerPlugin"
))
FileSelectorPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FileSelectorPlugin"
))
FileSelectorPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FileSelectorPlugin"
))
FLTFirebaseCorePlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FLTFirebaseCorePlugin"
))
FLTFirebaseCorePlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FLTFirebaseCorePlugin"
))
FLTFirebaseMessagingPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FLTFirebaseMessagingPlugin"
))
FLTFirebaseMessagingPlugin
.
register
(
with
:
registry
.
registrar
(
forPlugin
:
"FLTFirebaseMessagingPlugin"
))
...
...
pubspec.lock
View file @
332a8e91
...
@@ -465,6 +465,14 @@ packages:
...
@@ -465,6 +465,14 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "7.0.1"
version: "7.0.1"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: ab13ae8ef5580a411c458d6207b6774a6c237d77ac37011b13994879f68a8810
url: "https://pub.dev"
source: hosted
version: "8.3.7"
file_selector_linux:
file_selector_linux:
dependency: transitive
dependency: transitive
description:
description:
...
...
pubspec.yaml
View file @
332a8e91
...
@@ -89,6 +89,7 @@ dependencies:
...
@@ -89,6 +89,7 @@ dependencies:
pinput
:
^5.0.1
pinput
:
^5.0.1
build_runner
:
^2.4.0
build_runner
:
^2.4.0
build_web_compilers
:
^4.0.4
build_web_compilers
:
^4.0.4
file_picker
:
^8.0.0
dev_dependencies
:
dev_dependencies
:
flutter_test
:
flutter_test
:
...
@@ -126,6 +127,7 @@ flutter:
...
@@ -126,6 +127,7 @@ flutter:
-
assets/svg/service/
-
assets/svg/service/
-
assets/svg/crm/
-
assets/svg/crm/
-
assets/svg/order/
-
assets/svg/order/
-
assets/svg/hrm/
# An image asset can refer to one or more resolution-specific "variants", see
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# https://flutter.dev/to/resolution-aware-images
...
...
Prev
1
2
3
4
Next