feat: refactor payments repository and use cases to integrate payment summary and transaction entities

This commit is contained in:
Achintha Isuru
2026-01-29 11:09:10 -05:00
parent 8c8951ff51
commit 3308fec70b
10 changed files with 114 additions and 88 deletions

View File

@@ -1,5 +1,3 @@
// ignore: unused_import
// import 'package:data_connect/data_connect.dart';
import '../../domain/entities/payment_summary.dart'; import '../../domain/entities/payment_summary.dart';
import '../../domain/entities/payment_transaction.dart'; import '../../domain/entities/payment_transaction.dart';
import '../../domain/repositories/payments_repository.dart'; import '../../domain/repositories/payments_repository.dart';

View File

@@ -1,22 +1,21 @@
import 'package:krow_data_connect/krow_data_connect.dart'; import '../../domain/entities/payment_summary.dart';
import 'package:krow_domain/krow_domain.dart'; import '../../domain/entities/payment_transaction.dart';
import '../../domain/repositories/payments_repository.dart'; import '../../domain/repositories/payments_repository.dart';
import '../datasources/payments_remote_datasource.dart';
/// Implementation of [PaymentsRepository]. /// Implementation of [PaymentsRepository].
///
/// This class handles the retrieval of payment data by delegating to the
/// [FinancialRepositoryMock] from the data connect package.
///
/// It resides in the data layer and depends on the domain layer for the repository interface.
class PaymentsRepositoryImpl implements PaymentsRepository { class PaymentsRepositoryImpl implements PaymentsRepository {
final FinancialRepositoryMock financialRepository; final PaymentsRemoteDataSource remoteDataSource;
/// Creates a [PaymentsRepositoryImpl] with the given [financialRepository]. PaymentsRepositoryImpl({required this.remoteDataSource});
PaymentsRepositoryImpl({required this.financialRepository});
@override @override
Future<List<StaffPayment>> getPayments() async { Future<PaymentSummary> getPaymentSummary() async {
// TODO: Get actual logged in staff ID return await remoteDataSource.fetchPaymentSummary();
return await financialRepository.getStaffPayments('staff_1'); }
@override
Future<List<PaymentTransaction>> getPaymentHistory(String period) async {
return await remoteDataSource.fetchPaymentHistory(period);
} }
} }

View File

@@ -0,0 +1,23 @@
import 'package:equatable/equatable.dart';
class PaymentSummary extends Equatable {
final double weeklyEarnings;
final double monthlyEarnings;
final double pendingEarnings;
final double totalEarnings;
const PaymentSummary({
required this.weeklyEarnings,
required this.monthlyEarnings,
required this.pendingEarnings,
required this.totalEarnings,
});
@override
List<Object?> get props => [
weeklyEarnings,
monthlyEarnings,
pendingEarnings,
totalEarnings,
];
}

View File

@@ -0,0 +1,41 @@
import 'package:equatable/equatable.dart';
class PaymentTransaction extends Equatable {
final String id;
final String title;
final String location;
final String address;
final String workedTime;
final double amount;
final String status;
final int hours;
final double rate;
final DateTime date;
const PaymentTransaction({
required this.id,
required this.title,
required this.location,
required this.address,
required this.workedTime,
required this.amount,
required this.status,
required this.hours,
required this.rate,
required this.date,
});
@override
List<Object?> get props => [
id,
title,
location,
address,
workedTime,
amount,
status,
hours,
rate,
date,
];
}

View File

@@ -1,10 +1,14 @@
import 'package:krow_domain/krow_domain.dart'; import '../entities/payment_summary.dart';
import '../entities/payment_transaction.dart';
/// Repository interface for Payments feature. /// Repository interface for Payments feature.
/// ///
/// Defines the contract for data access related to staff payments. /// Defines the contract for data access related to staff payments.
/// Implementations of this interface should reside in the data layer. /// Implementations of this interface should reside in the data layer.
abstract class PaymentsRepository { abstract class PaymentsRepository {
/// Fetches the list of payments for the current staff member. /// Fetches the payment summary (earnings).
Future<List<StaffPayment>> getPayments(); Future<PaymentSummary> getPaymentSummary();
/// Fetches the payment history for a specific period.
Future<List<PaymentTransaction>> getPaymentHistory(String period);
} }

View File

@@ -1,20 +1,19 @@
import 'package:krow_core/core.dart'; import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../arguments/get_payment_history_arguments.dart'; import '../arguments/get_payment_history_arguments.dart';
import '../entities/payment_transaction.dart';
import '../repositories/payments_repository.dart'; import '../repositories/payments_repository.dart';
/// Use case to retrieve payment history filtered by a period. /// Use case to retrieve payment history filtered by a period.
/// ///
/// This use case delegates the data retrieval to [PaymentsRepository]. /// This use case delegates the data retrieval to [PaymentsRepository].
class GetPaymentHistoryUseCase extends UseCase<GetPaymentHistoryArguments, List<StaffPayment>> { class GetPaymentHistoryUseCase extends UseCase<GetPaymentHistoryArguments, List<PaymentTransaction>> {
final PaymentsRepository repository; final PaymentsRepository repository;
/// Creates a [GetPaymentHistoryUseCase]. /// Creates a [GetPaymentHistoryUseCase].
GetPaymentHistoryUseCase(this.repository); GetPaymentHistoryUseCase(this.repository);
@override @override
Future<List<StaffPayment>> call(GetPaymentHistoryArguments arguments) async { Future<List<PaymentTransaction>> call(GetPaymentHistoryArguments arguments) async {
// TODO: Implement filtering by period return await repository.getPaymentHistory(arguments.period);
return await repository.getPayments();
} }
} }

View File

@@ -1,19 +1,16 @@
import 'package:krow_core/core.dart'; import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart'; import '../entities/payment_summary.dart';
import '../repositories/payments_repository.dart'; import '../repositories/payments_repository.dart';
/// Use case to retrieve payment summary information. /// Use case to retrieve payment summary information.
/// class GetPaymentSummaryUseCase extends NoInputUseCase<PaymentSummary> {
/// It fetches the full list of payments, which ideally should be aggregated
/// by the presentation layer or a specific data source method.
class GetPaymentSummaryUseCase extends NoInputUseCase<List<StaffPayment>> {
final PaymentsRepository repository; final PaymentsRepository repository;
/// Creates a [GetPaymentSummaryUseCase]. /// Creates a [GetPaymentSummaryUseCase].
GetPaymentSummaryUseCase(this.repository); GetPaymentSummaryUseCase(this.repository);
@override @override
Future<List<StaffPayment>> call() async { Future<PaymentSummary> call() async {
return await repository.getPayments(); return await repository.getPaymentSummary();
} }
} }

View File

@@ -1,9 +1,9 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../../domain/arguments/get_payment_history_arguments.dart'; import '../../../domain/arguments/get_payment_history_arguments.dart';
import '../../../domain/usecases/get_payment_summary_usecase.dart'; import '../../../domain/entities/payment_summary.dart';
import '../../../domain/entities/payment_transaction.dart';
import '../../../domain/usecases/get_payment_history_usecase.dart'; import '../../../domain/usecases/get_payment_history_usecase.dart';
import '../../models/payment_stats.dart'; import '../../../domain/usecases/get_payment_summary_usecase.dart';
import 'payments_event.dart'; import 'payments_event.dart';
import 'payments_state.dart'; import 'payments_state.dart';
@@ -25,14 +25,13 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
) async { ) async {
emit(PaymentsLoading()); emit(PaymentsLoading());
try { try {
final List<StaffPayment> allPayments = await getPaymentSummary(); final PaymentSummary currentSummary = await getPaymentSummary();
final PaymentStats stats = _calculateStats(allPayments);
final List<StaffPayment> history = await getPaymentHistory( final List<PaymentTransaction> history = await getPaymentHistory(
const GetPaymentHistoryArguments('week'), const GetPaymentHistoryArguments('week'),
); );
emit(PaymentsLoaded( emit(PaymentsLoaded(
summary: stats, summary: currentSummary,
history: history, history: history,
activePeriod: 'week', activePeriod: 'week',
)); ));
@@ -48,7 +47,7 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
final PaymentsState currentState = state; final PaymentsState currentState = state;
if (currentState is PaymentsLoaded) { if (currentState is PaymentsLoaded) {
try { try {
final List<StaffPayment> newHistory = await getPaymentHistory( final List<PaymentTransaction> newHistory = await getPaymentHistory(
GetPaymentHistoryArguments(event.period), GetPaymentHistoryArguments(event.period),
); );
emit(currentState.copyWith( emit(currentState.copyWith(
@@ -60,38 +59,4 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
} }
} }
} }
PaymentStats _calculateStats(List<StaffPayment> payments) {
double total = 0;
double pending = 0;
double weekly = 0;
double monthly = 0;
final DateTime now = DateTime.now();
for (final StaffPayment p in payments) {
// Assuming all payments count towards total history
total += p.amount;
if (p.status == PaymentStatus.pending) {
pending += p.amount;
}
if (p.paidAt != null) {
if (now.difference(p.paidAt!).inDays < 7) {
weekly += p.amount;
}
if (now.month == p.paidAt!.month && now.year == p.paidAt!.year) {
monthly += p.amount;
}
}
}
return PaymentStats(
totalEarnings: total,
pendingEarnings: pending,
weeklyEarnings: weekly,
monthlyEarnings: monthly,
);
}
} }

View File

@@ -1,6 +1,6 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:krow_domain/krow_domain.dart'; import '../../../domain/entities/payment_summary.dart';
import '../../models/payment_stats.dart'; import '../../../domain/entities/payment_transaction.dart';
abstract class PaymentsState extends Equatable { abstract class PaymentsState extends Equatable {
const PaymentsState(); const PaymentsState();
@@ -14,8 +14,8 @@ class PaymentsInitial extends PaymentsState {}
class PaymentsLoading extends PaymentsState {} class PaymentsLoading extends PaymentsState {}
class PaymentsLoaded extends PaymentsState { class PaymentsLoaded extends PaymentsState {
final PaymentStats summary; final PaymentSummary summary;
final List<StaffPayment> history; final List<PaymentTransaction> history;
final String activePeriod; final String activePeriod;
const PaymentsLoaded({ const PaymentsLoaded({
@@ -25,8 +25,8 @@ class PaymentsLoaded extends PaymentsState {
}); });
PaymentsLoaded copyWith({ PaymentsLoaded copyWith({
PaymentStats? summary, PaymentSummary? summary,
List<StaffPayment>? history, List<PaymentTransaction>? history,
String? activePeriod, String? activePeriod,
}) { }) {
return PaymentsLoaded( return PaymentsLoaded(

View File

@@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:lucide_icons/lucide_icons.dart'; import 'package:lucide_icons/lucide_icons.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:krow_domain/krow_domain.dart'; import '../../domain/entities/payment_transaction.dart';
import '../blocs/payments/payments_bloc.dart'; import '../blocs/payments/payments_bloc.dart';
import '../blocs/payments/payments_event.dart'; import '../blocs/payments/payments_event.dart';
import '../blocs/payments/payments_state.dart'; import '../blocs/payments/payments_state.dart';
@@ -177,19 +177,19 @@ class _PaymentsPageState extends State<PaymentsPage> {
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
Column( Column(
children: state.history.map((StaffPayment payment) { children: state.history.map((PaymentTransaction payment) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.only(bottom: 8),
child: PaymentHistoryItem( child: PaymentHistoryItem(
amount: payment.amount, amount: payment.amount,
title: 'Assignment ${payment.assignmentId}', title: payment.title,
location: 'Location', // TODO: Fetch from assignment location: payment.location,
address: '', address: payment.address,
date: payment.paidAt != null ? DateFormat('E, MMM d').format(payment.paidAt!) : 'Pending', date: DateFormat('E, MMM d').format(payment.date),
workedTime: '00:00 - 00:00', // TODO: Fetch from assignment workedTime: payment.workedTime,
hours: 0, hours: payment.hours,
rate: 0, rate: payment.rate,
status: payment.status.toString().split('.').last, status: payment.status,
), ),
); );
}).toList(), }).toList(),