checkin status v1, working"
"
This commit is contained in:
@@ -10,6 +10,7 @@ class ClockInAdapter {
|
|||||||
DateTime? checkInTime,
|
DateTime? checkInTime,
|
||||||
DateTime? checkOutTime,
|
DateTime? checkOutTime,
|
||||||
String? activeShiftId,
|
String? activeShiftId,
|
||||||
|
String? activeApplicationId,
|
||||||
}) {
|
}) {
|
||||||
final bool isCheckedIn = status == 'CHECKED_IN' || status == 'LATE'; // Assuming LATE is also checked in?
|
final bool isCheckedIn = status == 'CHECKED_IN' || status == 'LATE'; // Assuming LATE is also checked in?
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ class ClockInAdapter {
|
|||||||
checkInTime: checkInTime,
|
checkInTime: checkInTime,
|
||||||
checkOutTime: checkOutTime,
|
checkOutTime: checkOutTime,
|
||||||
activeShiftId: activeShiftId,
|
activeShiftId: activeShiftId,
|
||||||
|
activeApplicationId: activeApplicationId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,22 @@ class AttendanceStatus extends Equatable {
|
|||||||
final DateTime? checkInTime;
|
final DateTime? checkInTime;
|
||||||
final DateTime? checkOutTime;
|
final DateTime? checkOutTime;
|
||||||
final String? activeShiftId;
|
final String? activeShiftId;
|
||||||
|
final String? activeApplicationId;
|
||||||
|
|
||||||
const AttendanceStatus({
|
const AttendanceStatus({
|
||||||
this.isCheckedIn = false,
|
this.isCheckedIn = false,
|
||||||
this.checkInTime,
|
this.checkInTime,
|
||||||
this.checkOutTime,
|
this.checkOutTime,
|
||||||
this.activeShiftId,
|
this.activeShiftId,
|
||||||
|
this.activeApplicationId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [isCheckedIn, checkInTime, checkOutTime, activeShiftId];
|
List<Object?> get props => [
|
||||||
|
isCheckedIn,
|
||||||
|
checkInTime,
|
||||||
|
checkOutTime,
|
||||||
|
activeShiftId,
|
||||||
|
activeApplicationId,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import '../../domain/repositories/clock_in_repository_interface.dart';
|
|||||||
class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
||||||
final dc.ExampleConnector _dataConnect;
|
final dc.ExampleConnector _dataConnect;
|
||||||
final Map<String, String> _shiftToApplicationId = {};
|
final Map<String, String> _shiftToApplicationId = {};
|
||||||
|
String? _activeApplicationId;
|
||||||
|
|
||||||
ClockInRepositoryImpl({
|
ClockInRepositoryImpl({
|
||||||
required dc.ExampleConnector dataConnect,
|
required dc.ExampleConnector dataConnect,
|
||||||
@@ -187,16 +188,34 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
|||||||
return const AttendanceStatus(isCheckedIn: false);
|
return const AttendanceStatus(isCheckedIn: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
final dc.GetApplicationsByStaffIdApplications? activeApp =
|
dc.GetApplicationsByStaffIdApplications? activeApp;
|
||||||
_getActiveApplication(apps);
|
for (final app in apps) {
|
||||||
final dc.GetApplicationsByStaffIdApplications app =
|
if (app.checkInTime != null && app.checkOutTime == null) {
|
||||||
activeApp ?? apps.last;
|
if (activeApp == null) {
|
||||||
|
activeApp = app;
|
||||||
|
} else {
|
||||||
|
final DateTime? current = _toDateTime(activeApp.checkInTime);
|
||||||
|
final DateTime? next = _toDateTime(app.checkInTime);
|
||||||
|
if (current == null || (next != null && next.isAfter(current))) {
|
||||||
|
activeApp = app;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ClockInAdapter.toAttendanceStatus(
|
if (activeApp == null) {
|
||||||
status: app.status.stringValue,
|
_activeApplicationId = null;
|
||||||
checkInTime: _toDateTime(app.checkInTime),
|
return const AttendanceStatus(isCheckedIn: false);
|
||||||
checkOutTime: _toDateTime(app.checkOutTime),
|
}
|
||||||
activeShiftId: app.shiftId,
|
|
||||||
|
_activeApplicationId = activeApp.id;
|
||||||
|
print('Active check-in appId=$_activeApplicationId');
|
||||||
|
return AttendanceStatus(
|
||||||
|
isCheckedIn: true,
|
||||||
|
checkInTime: _toDateTime(activeApp.checkInTime),
|
||||||
|
checkOutTime: _toDateTime(activeApp.checkOutTime),
|
||||||
|
activeShiftId: activeApp.shiftId,
|
||||||
|
activeApplicationId: activeApp.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +246,7 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
|||||||
)
|
)
|
||||||
.checkInTime(checkInTs)
|
.checkInTime(checkInTs)
|
||||||
.execute();
|
.execute();
|
||||||
|
_activeApplicationId = app.id;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('ClockIn updateApplicationStatus error: $e');
|
print('ClockIn updateApplicationStatus error: $e');
|
||||||
print('ClockIn error type: ${e.runtimeType}');
|
print('ClockIn error type: ${e.runtimeType}');
|
||||||
@@ -245,22 +265,43 @@ class ClockInRepositoryImpl implements ClockInRepositoryInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<AttendanceStatus> clockOut({String? notes, int? breakTimeMinutes}) async {
|
Future<AttendanceStatus> clockOut({
|
||||||
|
String? notes,
|
||||||
|
int? breakTimeMinutes,
|
||||||
|
String? applicationId,
|
||||||
|
}) async {
|
||||||
final String staffId = await _getStaffId();
|
final String staffId = await _getStaffId();
|
||||||
|
|
||||||
final List<dc.GetApplicationsByStaffIdApplications> apps =
|
print(
|
||||||
await _getTodaysApplications(staffId);
|
'ClockOut request: applicationId=$applicationId '
|
||||||
final dc.GetApplicationsByStaffIdApplications? app =
|
'activeApplicationId=$_activeApplicationId',
|
||||||
_getActiveApplication(apps);
|
);
|
||||||
if (app == null) throw Exception('No active shift found to clock out');
|
final String? targetAppId = applicationId ?? _activeApplicationId;
|
||||||
|
if (targetAppId == null || targetAppId.isEmpty) {
|
||||||
|
throw Exception('No active application id for checkout');
|
||||||
|
}
|
||||||
|
final appResult = await _dataConnect
|
||||||
|
.getApplicationById(id: targetAppId)
|
||||||
|
.execute();
|
||||||
|
final app = appResult.data.application;
|
||||||
|
print(
|
||||||
|
'ClockOut getApplicationById: id=${app?.id} '
|
||||||
|
'checkIn=${app?.checkInTime?.toJson()} '
|
||||||
|
'checkOut=${app?.checkOutTime?.toJson()}',
|
||||||
|
);
|
||||||
|
if (app == null) {
|
||||||
|
throw Exception('Application not found for checkout');
|
||||||
|
}
|
||||||
|
if (app.checkInTime == null || app.checkOutTime != null) {
|
||||||
|
throw Exception('No active shift found to clock out');
|
||||||
|
}
|
||||||
|
|
||||||
await _dataConnect
|
await _dataConnect
|
||||||
.updateApplicationStatus(
|
.updateApplicationStatus(
|
||||||
id: app.id,
|
id: targetAppId,
|
||||||
)
|
)
|
||||||
.status(dc.ApplicationStatus.CHECKED_OUT)
|
.checkOutTime(_fromDateTime(DateTime.now()))
|
||||||
.checkOutTime(_fromDateTime(DateTime.now()))
|
.execute();
|
||||||
.execute();
|
|
||||||
|
|
||||||
return getAttendanceStatus();
|
return getAttendanceStatus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ class ClockOutArguments extends UseCaseArgument {
|
|||||||
/// Optional break time in minutes.
|
/// Optional break time in minutes.
|
||||||
final int? breakTimeMinutes;
|
final int? breakTimeMinutes;
|
||||||
|
|
||||||
|
/// Optional application id for checkout.
|
||||||
|
final String? applicationId;
|
||||||
|
|
||||||
/// Creates a [ClockOutArguments] instance.
|
/// Creates a [ClockOutArguments] instance.
|
||||||
const ClockOutArguments({
|
const ClockOutArguments({
|
||||||
this.notes,
|
this.notes,
|
||||||
this.breakTimeMinutes,
|
this.breakTimeMinutes,
|
||||||
|
this.applicationId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [notes, breakTimeMinutes];
|
List<Object?> get props => [notes, breakTimeMinutes, applicationId];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,5 +17,9 @@ abstract class ClockInRepositoryInterface {
|
|||||||
|
|
||||||
/// Checks the user out for the currently active shift.
|
/// Checks the user out for the currently active shift.
|
||||||
/// Optionally accepts [breakTimeMinutes] if tracked.
|
/// Optionally accepts [breakTimeMinutes] if tracked.
|
||||||
Future<AttendanceStatus> clockOut({String? notes, int? breakTimeMinutes});
|
Future<AttendanceStatus> clockOut({
|
||||||
|
String? notes,
|
||||||
|
int? breakTimeMinutes,
|
||||||
|
String? applicationId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class ClockOutUseCase implements UseCase<ClockOutArguments, AttendanceStatus> {
|
|||||||
return _repository.clockOut(
|
return _repository.clockOut(
|
||||||
notes: arguments.notes,
|
notes: arguments.notes,
|
||||||
breakTimeMinutes: arguments.breakTimeMinutes,
|
breakTimeMinutes: arguments.breakTimeMinutes,
|
||||||
|
applicationId: arguments.applicationId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ class ClockInBloc extends Bloc<ClockInEvent, ClockInState> {
|
|||||||
ClockOutArguments(
|
ClockOutArguments(
|
||||||
notes: event.notes,
|
notes: event.notes,
|
||||||
breakTimeMinutes: 0, // Should be passed from event if supported
|
breakTimeMinutes: 0, // Should be passed from event if supported
|
||||||
|
applicationId: state.attendance.activeApplicationId,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
emit(state.copyWith(
|
emit(state.copyWith(
|
||||||
|
|||||||
Reference in New Issue
Block a user