Line data Source code
1 : // Copyright 2023 The terCAD team. All rights reserved.
2 : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
3 :
4 : import 'dart:collection';
5 :
6 : import 'package:app_finance/_classes/storage/app_data.dart';
7 : import 'package:app_finance/_classes/math/abstract_recalculation.dart';
8 : import 'package:app_finance/_classes/structure/currency/exchange.dart';
9 : import 'package:app_finance/_classes/structure/summary_app_data.dart';
10 :
11 : class TotalRecalculation extends AbstractRecalculation {
12 : @override
13 : // ignore: overridden_fields
14 : Exchange exchange;
15 : bool isBudgetPositive;
16 :
17 2 : TotalRecalculation({
18 : required this.exchange,
19 : this.isBudgetPositive = false,
20 : });
21 :
22 0 : @override
23 : double getDelta() {
24 0 : throw UnimplementedError();
25 : }
26 :
27 2 : double updateTotalMap(AppDataType type, String uuid, HashMap<String, dynamic> hashTable) {
28 2 : final item = hashTable[uuid];
29 4 : if (item == null || item.hidden || item.skip) {
30 : return 0.0;
31 : }
32 8 : double total = exchange.reform(item.details, item.currency, Exchange.defaultCurrency);
33 6 : if (type == AppDataType.budgets && total < 0 && isBudgetPositive) {
34 : total = 0.0;
35 : }
36 2 : if (type == AppDataType.goals) {
37 0 : total *= (1 - item.progress);
38 : }
39 : return total;
40 : }
41 :
42 2 : List<String> getSummaryList(AppDataType type, SummaryAppData? summary) {
43 : if (summary == null) {
44 0 : return [];
45 : }
46 8 : return [AppDataType.bills, AppDataType.invoice].contains(type) ? summary.listActual : summary.list;
47 : }
48 :
49 2 : Future<void> updateTotal(AppDataType type, SummaryAppData? summary, HashMap<String, dynamic> hashTable) async {
50 2 : final list = getSummaryList(type, summary);
51 4 : summary?.total = list.isEmpty
52 : ? 0.0
53 : : list
54 6 : .map<double>((String uuid) => updateTotalMap(type, uuid, hashTable))
55 2 : .reduce((value, details) => value + details);
56 : }
57 :
58 2 : void updateGoals(dynamic goalList, double initTotal, double total) {
59 2 : double delta = total - initTotal;
60 2 : if (goalList.isNotEmpty) {
61 : int index = 0;
62 0 : delta /= goalList.length;
63 0 : goalList.forEach((dynamic goal) {
64 0 : index++;
65 : double convDelta = 0;
66 0 : if (delta > 0 && total <= goal.initial) {
67 0 : convDelta = exchange.reform(total, Exchange.defaultCurrency, goal.currency) - goal.initial;
68 : } else {
69 0 : convDelta = exchange.reform(delta, Exchange.defaultCurrency, goal.currency);
70 : }
71 0 : double progress = getProgress(goal.details, goal.progress, convDelta);
72 0 : if (progress > 1.0) {
73 0 : if (index < goalList.length) {
74 0 : delta += exchange.reform(goal.details * (progress - 1.0), goal.currency, Exchange.defaultCurrency) /
75 0 : (goalList.length - index);
76 : }
77 : progress = 1.0;
78 : }
79 0 : if (progress < 1.0 && goal.progress == 1.0 && goal.initial + goal.details < total) {
80 : progress = 1.0;
81 0 : delta += delta / (goalList.length - index);
82 : }
83 0 : if (progress < 0.0) {
84 : progress = 0.0;
85 : }
86 0 : goal.progress = progress;
87 : });
88 : }
89 : }
90 : }
|