attendence records, extra hours , rewards and punishment funnctionality have been added
This commit is contained in:
@@ -3,6 +3,10 @@ import 'package:dio/dio.dart';
|
||||
import '../../core/error/exceptions.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
import '../dto/attendance_response_dto.dart';
|
||||
import '../dto/attendance_record_dto.dart';
|
||||
import '../dto/overtime_dto.dart';
|
||||
import '../dto/reward_dto.dart';
|
||||
import '../dto/punishment_dto.dart';
|
||||
|
||||
abstract class AttendanceRemoteDataSource {
|
||||
Future<AttendanceResponseDto> login({
|
||||
@@ -14,6 +18,13 @@ abstract class AttendanceRemoteDataSource {
|
||||
required String employeeId,
|
||||
required File faceImage,
|
||||
});
|
||||
|
||||
Future<List<AttendanceRecordDto>> getAttendanceRecords({
|
||||
required String employeeId,
|
||||
});
|
||||
Future<List<OvertimeDto>> getExtraHours({required String employeeId});
|
||||
Future<List<RewardDto>> getRewards({required String employeeId});
|
||||
Future<List<PunishmentDto>> getPunishments({required String employeeId});
|
||||
}
|
||||
|
||||
class AttendanceRemoteDataSourceImpl implements AttendanceRemoteDataSource {
|
||||
@@ -140,9 +151,138 @@ class AttendanceRemoteDataSourceImpl implements AttendanceRemoteDataSource {
|
||||
throw NetworkException(message: 'خطأ في الانترنيت يرجى المحاولة لاحقا');
|
||||
}
|
||||
} catch (e) {
|
||||
if (e is ServerException || e is NetworkException) {
|
||||
rethrow;
|
||||
throw ServerException(message: 'خطأ غير متوقع');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<AttendanceRecordDto>> getAttendanceRecords({
|
||||
required String employeeId,
|
||||
}) async {
|
||||
try {
|
||||
final response = await apiClient.get(
|
||||
'/Attendance',
|
||||
queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data;
|
||||
if (data is Map<String, dynamic> &&
|
||||
data['data'] != null &&
|
||||
data['data']['items'] is List) {
|
||||
final items = data['data']['items'] as List;
|
||||
return items.map((e) => AttendanceRecordDto.fromJson(e)).toList();
|
||||
}
|
||||
return [];
|
||||
} else {
|
||||
throw ServerException(
|
||||
message: 'فشل في جلب البيانات',
|
||||
statusCode: response.statusCode,
|
||||
);
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
throw ServerException(
|
||||
message: e.message ?? 'Unknown error',
|
||||
statusCode: e.response?.statusCode,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ServerException(message: 'خطأ غير متوقع');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<OvertimeDto>> getExtraHours({required String employeeId}) async {
|
||||
try {
|
||||
final response = await apiClient.get(
|
||||
'/ExtraHours',
|
||||
queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = response.data;
|
||||
|
||||
if (responseData is Map<String, dynamic>) {
|
||||
return OvertimeListResponseDto.fromJson(responseData).items;
|
||||
} else {
|
||||
throw ServerException(
|
||||
message: 'استجابة غير صحيحة من الخادم',
|
||||
statusCode: response.statusCode,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw ServerException(
|
||||
message: 'فشل في جلب البيانات',
|
||||
statusCode: response.statusCode,
|
||||
);
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
throw ServerException(
|
||||
message: e.message ?? 'Unknown error',
|
||||
statusCode: e.response?.statusCode,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ServerException(message: 'خطأ غير متوقع');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<RewardDto>> getRewards({required String employeeId}) async {
|
||||
try {
|
||||
final response = await apiClient.get(
|
||||
'/Reward',
|
||||
queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = response.data;
|
||||
if (responseData is Map<String, dynamic>) {
|
||||
return RewardListResponseDto.fromJson(responseData).items;
|
||||
}
|
||||
return [];
|
||||
} else {
|
||||
throw ServerException(
|
||||
message: 'فشل في جلب المكافآت',
|
||||
statusCode: response.statusCode,
|
||||
);
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
throw ServerException(
|
||||
message: e.message ?? 'Unknown error',
|
||||
statusCode: e.response?.statusCode,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ServerException(message: 'خطأ غير متوقع');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<PunishmentDto>> getPunishments({
|
||||
required String employeeId,
|
||||
}) async {
|
||||
try {
|
||||
final response = await apiClient.get(
|
||||
'/Punishment',
|
||||
queryParameters: {'IsDeleted': false, 'EmployeeId': employeeId},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final responseData = response.data;
|
||||
if (responseData is Map<String, dynamic>) {
|
||||
return PunishmentListResponseDto.fromJson(responseData).items;
|
||||
}
|
||||
return [];
|
||||
} else {
|
||||
throw ServerException(
|
||||
message: 'فشل في جلب البيانات',
|
||||
statusCode: response.statusCode,
|
||||
);
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
throw ServerException(
|
||||
message: e.message ?? 'Unknown error',
|
||||
statusCode: e.response?.statusCode,
|
||||
);
|
||||
} catch (e) {
|
||||
throw ServerException(message: 'خطأ غير متوقع');
|
||||
}
|
||||
}
|
||||
|
||||
45
lib/data/dto/attendance_record_dto.dart
Normal file
45
lib/data/dto/attendance_record_dto.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
class AttendanceRecordDto {
|
||||
final String id;
|
||||
final String employeeId;
|
||||
final DateTime? login;
|
||||
final DateTime? logout;
|
||||
final String? reason;
|
||||
final DateTime? createdAt;
|
||||
final bool isDeleted;
|
||||
|
||||
AttendanceRecordDto({
|
||||
required this.id,
|
||||
required this.employeeId,
|
||||
this.login,
|
||||
this.logout,
|
||||
this.reason,
|
||||
this.createdAt,
|
||||
required this.isDeleted,
|
||||
});
|
||||
|
||||
factory AttendanceRecordDto.fromJson(Map<String, dynamic> json) {
|
||||
return AttendanceRecordDto(
|
||||
id: json['id']?.toString() ?? '',
|
||||
employeeId: json['employeeId']?.toString() ?? '',
|
||||
login: _parseDateTime(json['login']),
|
||||
logout: _parseDateTime(json['logout']),
|
||||
reason: json['reason'],
|
||||
createdAt: _parseDateTime(json['createdAt']),
|
||||
isDeleted: json['isDeleted'] ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
static DateTime? _parseDateTime(dynamic value) {
|
||||
if (value == null) return null;
|
||||
if (value is DateTime) return value;
|
||||
if (value is String) {
|
||||
if (value.isEmpty) return null;
|
||||
try {
|
||||
return DateTime.parse(value);
|
||||
} catch (e) {
|
||||
return null; // Handle parse error gracefully
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
49
lib/data/dto/extra_payment_dto.dart
Normal file
49
lib/data/dto/extra_payment_dto.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
class ExtraPaymentDto {
|
||||
final String id;
|
||||
final DateTime date;
|
||||
final double amount;
|
||||
final String? reason;
|
||||
final String? note;
|
||||
final String employeeId;
|
||||
final bool isDeleted;
|
||||
|
||||
ExtraPaymentDto({
|
||||
required this.id,
|
||||
required this.date,
|
||||
required this.amount,
|
||||
this.reason,
|
||||
this.note,
|
||||
required this.employeeId,
|
||||
required this.isDeleted,
|
||||
});
|
||||
|
||||
factory ExtraPaymentDto.fromJson(Map<String, dynamic> json) {
|
||||
return ExtraPaymentDto(
|
||||
id: json['id']?.toString() ?? '',
|
||||
date:
|
||||
json['date'] != null ? DateTime.parse(json['date']) : DateTime.now(),
|
||||
amount: (json['amount'] as num?)?.toDouble() ?? 0.0,
|
||||
reason: json['reason'],
|
||||
note: json['note'],
|
||||
employeeId: json['employeeId']?.toString() ?? '',
|
||||
isDeleted: json['isDeleted'] ?? false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExtraPaymentListResponseDto {
|
||||
final List<ExtraPaymentDto> items;
|
||||
|
||||
ExtraPaymentListResponseDto({required this.items});
|
||||
|
||||
factory ExtraPaymentListResponseDto.fromJson(Map<String, dynamic> json) {
|
||||
final data = json['data'];
|
||||
if (data == null || data is! Map<String, dynamic>) {
|
||||
return ExtraPaymentListResponseDto(items: []);
|
||||
}
|
||||
final itemsJson = data['items'] as List? ?? [];
|
||||
return ExtraPaymentListResponseDto(
|
||||
items: itemsJson.map((e) => ExtraPaymentDto.fromJson(e)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
46
lib/data/dto/overtime_dto.dart
Normal file
46
lib/data/dto/overtime_dto.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
class OvertimeDto {
|
||||
final String id;
|
||||
final DateTime date;
|
||||
final double hours;
|
||||
final double hourlyRateAtTheTime;
|
||||
final String employeeId;
|
||||
final bool isDeleted;
|
||||
|
||||
OvertimeDto({
|
||||
required this.id,
|
||||
required this.employeeId,
|
||||
required this.date,
|
||||
required this.hours,
|
||||
required this.hourlyRateAtTheTime,
|
||||
required this.isDeleted,
|
||||
});
|
||||
|
||||
factory OvertimeDto.fromJson(Map<String, dynamic> json) {
|
||||
return OvertimeDto(
|
||||
id: json['id']?.toString() ?? '',
|
||||
date: DateTime.parse(json['date']),
|
||||
hours: (json['hours'] as num?)?.toDouble() ?? 0.0,
|
||||
hourlyRateAtTheTime:
|
||||
(json['hourlyRateAtTheTime'] as num?)?.toDouble() ?? 0.0,
|
||||
employeeId: json['employeeId']?.toString() ?? '',
|
||||
isDeleted: json['isDeleted'] ?? false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class OvertimeListResponseDto {
|
||||
final List<OvertimeDto> items;
|
||||
|
||||
OvertimeListResponseDto({required this.items});
|
||||
|
||||
factory OvertimeListResponseDto.fromJson(Map<String, dynamic> json) {
|
||||
final data = json['data'];
|
||||
if (data == null || data is! Map<String, dynamic>) {
|
||||
return OvertimeListResponseDto(items: []);
|
||||
}
|
||||
final itemsJson = data['items'] as List? ?? [];
|
||||
return OvertimeListResponseDto(
|
||||
items: itemsJson.map((e) => OvertimeDto.fromJson(e)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
46
lib/data/dto/punishment_dto.dart
Normal file
46
lib/data/dto/punishment_dto.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
class PunishmentDto {
|
||||
final String id;
|
||||
final DateTime date;
|
||||
final double amount;
|
||||
final String? reason;
|
||||
final String? note;
|
||||
final String employeeId;
|
||||
|
||||
PunishmentDto({
|
||||
required this.id,
|
||||
required this.date,
|
||||
required this.amount,
|
||||
this.reason,
|
||||
this.note,
|
||||
required this.employeeId,
|
||||
});
|
||||
|
||||
factory PunishmentDto.fromJson(Map<String, dynamic> json) {
|
||||
return PunishmentDto(
|
||||
id: json['id']?.toString() ?? '',
|
||||
date:
|
||||
json['date'] != null ? DateTime.parse(json['date']) : DateTime.now(),
|
||||
amount: (json['amount'] as num?)?.toDouble() ?? 0.0,
|
||||
reason: json['reason'],
|
||||
note: json['note'],
|
||||
employeeId: json['employeeId']?.toString() ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PunishmentListResponseDto {
|
||||
final List<PunishmentDto> items;
|
||||
|
||||
PunishmentListResponseDto({required this.items});
|
||||
|
||||
factory PunishmentListResponseDto.fromJson(Map<String, dynamic> json) {
|
||||
final data = json['data'];
|
||||
if (data == null || data is! Map<String, dynamic>) {
|
||||
return PunishmentListResponseDto(items: []);
|
||||
}
|
||||
final itemsJson = data['items'] as List? ?? [];
|
||||
return PunishmentListResponseDto(
|
||||
items: itemsJson.map((e) => PunishmentDto.fromJson(e)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
46
lib/data/dto/reward_dto.dart
Normal file
46
lib/data/dto/reward_dto.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
class RewardDto {
|
||||
final String id;
|
||||
final DateTime date;
|
||||
final double amount;
|
||||
final String? reason;
|
||||
final String? note;
|
||||
final String employeeId;
|
||||
|
||||
RewardDto({
|
||||
required this.id,
|
||||
required this.date,
|
||||
required this.amount,
|
||||
this.reason,
|
||||
this.note,
|
||||
required this.employeeId,
|
||||
});
|
||||
|
||||
factory RewardDto.fromJson(Map<String, dynamic> json) {
|
||||
return RewardDto(
|
||||
id: json['id']?.toString() ?? '',
|
||||
date:
|
||||
json['date'] != null ? DateTime.parse(json['date']) : DateTime.now(),
|
||||
amount: (json['amount'] as num?)?.toDouble() ?? 0.0,
|
||||
reason: json['reason'],
|
||||
note: json['note'],
|
||||
employeeId: json['employeeId']?.toString() ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RewardListResponseDto {
|
||||
final List<RewardDto> items;
|
||||
|
||||
RewardListResponseDto({required this.items});
|
||||
|
||||
factory RewardListResponseDto.fromJson(Map<String, dynamic> json) {
|
||||
final data = json['data'];
|
||||
if (data == null || data is! Map<String, dynamic>) {
|
||||
return RewardListResponseDto(items: []);
|
||||
}
|
||||
final itemsJson = data['items'] as List? ?? [];
|
||||
return RewardListResponseDto(
|
||||
items: itemsJson.map((e) => RewardDto.fromJson(e)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import '../../domain/models/attendance_login_request.dart';
|
||||
import '../../domain/models/attendance_logout_request.dart';
|
||||
import '../../domain/models/attendance_response_model.dart';
|
||||
import '../../domain/models/attendance_model.dart';
|
||||
import '../../domain/models/overtime_model.dart';
|
||||
import '../../domain/models/extra_payment_model.dart';
|
||||
import '../../domain/repositories/attendance_repository.dart';
|
||||
import '../datasources/attendance_remote_data_source.dart';
|
||||
|
||||
@@ -38,4 +41,94 @@ class AttendanceRepositoryImpl implements AttendanceRepository {
|
||||
logout: dto.logout,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<AttendanceModel>> getAttendanceRecords({
|
||||
required String employeeId,
|
||||
}) async {
|
||||
final dtos = await remoteDataSource.getAttendanceRecords(
|
||||
employeeId: employeeId,
|
||||
);
|
||||
|
||||
return dtos.map((dto) {
|
||||
int? hours;
|
||||
if (dto.login != null && dto.logout != null) {
|
||||
hours = dto.logout!.difference(dto.login!).inHours;
|
||||
}
|
||||
|
||||
return AttendanceModel(
|
||||
id: dto.id,
|
||||
employeeId: dto.employeeId,
|
||||
date: dto.createdAt ?? dto.login,
|
||||
loginTime: dto.login,
|
||||
logoutTime: dto.logout,
|
||||
workHours: hours,
|
||||
createdAt: dto.createdAt ?? dto.login,
|
||||
reason: dto.reason,
|
||||
isDeleted: dto.isDeleted,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<OvertimeModel>> getExtraHours({
|
||||
required String employeeId,
|
||||
}) async {
|
||||
final dtos = await remoteDataSource.getExtraHours(employeeId: employeeId);
|
||||
|
||||
return dtos
|
||||
.map(
|
||||
(dto) => OvertimeModel(
|
||||
id: dto.id,
|
||||
employeeId: dto.employeeId,
|
||||
date: dto.date,
|
||||
hours: dto.hours,
|
||||
hourlyRateAtTheTime: dto.hourlyRateAtTheTime,
|
||||
totalAmount: dto.hours * dto.hourlyRateAtTheTime,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ExtraPaymentModel>> getRewards({
|
||||
required String employeeId,
|
||||
}) async {
|
||||
final dtos = await remoteDataSource.getRewards(employeeId: employeeId);
|
||||
|
||||
return dtos
|
||||
.map(
|
||||
(dto) => ExtraPaymentModel(
|
||||
id: dto.id,
|
||||
employeeId: dto.employeeId,
|
||||
date: dto.date,
|
||||
amount: dto.amount,
|
||||
reason: dto.reason,
|
||||
note: dto.note,
|
||||
isPenalty: false,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ExtraPaymentModel>> getPunishments({
|
||||
required String employeeId,
|
||||
}) async {
|
||||
final dtos = await remoteDataSource.getPunishments(employeeId: employeeId);
|
||||
|
||||
return dtos
|
||||
.map(
|
||||
(dto) => ExtraPaymentModel(
|
||||
id: dto.id,
|
||||
employeeId: dto.employeeId,
|
||||
date: dto.date,
|
||||
amount: dto.amount,
|
||||
reason: dto.reason,
|
||||
note: dto.note,
|
||||
isPenalty: true,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user