This repository has been archived on 2025-08-25. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
Seshat/lib/data/repositories/bal_repository.dart

197 lines
5.5 KiB
Dart

import 'package:seshat/data/services/api_client.dart';
import 'package:seshat/domain/models/accounting.dart';
import 'package:seshat/domain/models/bal.dart';
import 'package:seshat/domain/models/bal_stats.dart';
import 'package:seshat/domain/models/enums.dart';
import 'package:seshat/utils/result.dart';
/// Repository to manage [Bal]
class BalRepository {
BalRepository({required ApiClient apiClient}) : _apiClient = apiClient;
final ApiClient _apiClient;
/// [List<Bal>] of all the user's [Bal]
List<Bal>? _bals;
/// [Accounting] of [Bal], mapped by [Bal] id
final Map<int, Accounting?> _accountingMap = {};
/// Gets a list of all [Bal] from cache or remote
Future<Result<List<Bal>>> getBals() async {
if (_bals != null) {
return Result.ok(_bals!);
}
final result = await _apiClient.getBals();
switch (result) {
case Ok():
_bals = result.value;
return Result.ok(result.value);
case Error():
return result;
}
}
/// Gets a list of all [Bal] from remote only
Future<Result<List<Bal>>> _getBalsNoCache() async {
final result = await _apiClient.getBals();
switch (result) {
case Ok():
_bals = result.value;
return Result.ok(result.value);
case Error():
return result;
}
}
/// Gets a [Bal] by [balId], either from cache or remote
Future<Result<Bal>> balById(int balId) async {
if (_bals == null) {
await getBals();
}
Bal? bal = _bals!.where((bal) => bal.id == balId).firstOrNull;
if (bal != null) {
return Result.ok(bal);
}
final result = await _apiClient.getBalById(balId);
switch (result) {
case Ok():
return Result.ok(result.value);
case Error():
return result;
}
}
/// Return wether or not a [Bal] is currently [BalState.ongoing]
bool isABalOngoing() {
return _bals?.where((bal) => bal.state == BalState.ongoing).isNotEmpty ??
false;
}
/// Gets the [Bal] that is [BalState.ongoing]
Future<Bal?> ongoingBal() async {
if (_bals == null) {
await _getBalsNoCache();
}
return _bals!.where((bal) => bal.state == BalState.ongoing).firstOrNull;
}
/// Stops a [Bal] and refresh cache
Future<Result<Bal>> stopBal(int id) async {
final result = await _apiClient.stopBal(id);
_getBalsNoCache();
return result;
}
/// Starts a [Bal] and refresh cache
Future<Result<Bal>> startBal(int id) async {
if (isABalOngoing()) {
return Result.error(
Exception("Cannot have multiple BAL ongoing at the same time !"),
);
}
final result = await _apiClient.startBal(id);
_getBalsNoCache();
return result;
}
/// Changes a [Bal]'s [name], [startTime] or [endTime]
Future<Result<Bal>> editBal(
int id,
String name,
DateTime startTime,
DateTime endTime,
) async {
final result = await _apiClient.editBal(id, name, startTime, endTime);
await _getBalsNoCache();
return result;
}
/// Creates a [Bal] from its [name], [startTime] and [endTime]
Future<Result<void>> addBal(
String name,
DateTime startTime,
DateTime endTime,
) async {
final result = await _apiClient.addBal(name, startTime, endTime);
await _getBalsNoCache();
return result;
}
/// Gets a [BalStats] from its [balId]
Future<Result<BalStats>> getBalStats(int balId) async {
return _apiClient.getBalStats(balId);
}
/// Get [Accounting] of a [Bal] from remote only
Future<Result<Accounting>> getAccountingNoCache(int balId) async {
final result = await _apiClient.getAccounting(balId);
switch (result) {
case Ok():
_accountingMap[balId] = result.value;
break;
default:
}
return result;
}
/// Get [Accounting] of a [Bal] from cache or remote
Future<Result<Accounting>> getAccounting(int balId) async {
if (_accountingMap[balId] != null) {
return Result.ok(_accountingMap[balId]!);
}
final result = await _apiClient.getAccounting(balId);
switch (result) {
case Ok():
_accountingMap[balId] = result.value;
break;
default:
}
return result;
}
/// Manages what returning (of type [ReturnType]) does to cache and notifies remote
Future<Result<void>> returnToId(
int balId,
int ownerId,
ReturnType type,
) async {
final result = await _apiClient.returnToId(balId, ownerId, type.name);
switch (result) {
case Ok():
switch (type) {
case ReturnType.books:
final owner = _accountingMap[balId]?.owners
.where((el) => el.ownerId == ownerId)
.firstOrNull;
if (owner?.owedMoney == 0) {
_accountingMap[balId]?.owners.removeWhere(
(el) => el.ownerId == ownerId,
);
}
owner?.owed = [];
owner?.owedInstances = [];
break;
case ReturnType.money:
final owner = _accountingMap[balId]?.owners
.where((el) => el.ownerId == ownerId)
.firstOrNull;
if (owner?.owed == null || owner!.owed.isEmpty) {
_accountingMap[balId]?.owners.removeWhere(
(el) => el.ownerId == ownerId,
);
}
owner?.owedMoney = 0;
break;
case ReturnType.all:
_accountingMap[balId]?.owners.removeWhere(
(el) => el.ownerId == ownerId,
);
break;
}
break;
default:
}
return result;
}
}