LCOV - code coverage report
Current view: top level - lib/_classes/structure - budget_app_data.dart Coverage Total Hit
Test: lcov.info Lines: 57.0 % 93 53
Test Date: 2026-11-14 15:08:11 Functions: - 0 0

            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 'package:app_finance/_classes/herald/app_locale.dart';
       5              : import 'package:app_finance/_classes/herald/app_start_of_month.dart';
       6              : import 'package:app_finance/_classes/herald/app_start_of_week.dart';
       7              : import 'package:app_finance/_classes/storage/app_preferences.dart';
       8              : import 'package:app_finance/_classes/structure/abstract_app_data.dart';
       9              : import 'package:app_finance/_classes/storage/app_data.dart';
      10              : import 'package:app_finance/_classes/structure/currency/exchange.dart';
      11              : import 'package:app_finance/_classes/structure/invoice_app_data.dart';
      12              : import 'package:app_finance/_configs/budget_type.dart';
      13              : import 'package:app_finance/_ext/date_time_ext.dart';
      14              : import 'package:app_finance/_ext/int_ext.dart';
      15              : import 'package:app_finance/_ext/string_ext.dart';
      16              : import 'package:app_finance/_mixins/storage_mixin.dart';
      17              : import 'package:material_ui/material_ui.dart';
      18              : import 'package:flutter_currency_picker/flutter_currency_picker.dart';
      19              : 
      20              : class BudgetAppData extends AbstractAppData with StorageMixin {
      21              :   double amount;
      22              :   Map<int, double> amountSet;
      23              :   String type;
      24              :   final int _month = DateTime.now().month;
      25              : 
      26            1 :   BudgetAppData({
      27              :     required super.title,
      28              :     super.uuid,
      29              :     super.progress = 0.0,
      30              :     super.color,
      31              :     super.icon,
      32              :     super.currency,
      33              :     super.updatedAt,
      34              :     super.createdAt,
      35              :     super.createdAtFormatted,
      36              :     amountLimit = 0.0,
      37              :     this.amountSet = const {},
      38              :     this.amount = 0.0,
      39              :     this.type = '',
      40              :     super.hidden,
      41              :     super.skip,
      42            1 :   }) : super(
      43              :           details: amountLimit,
      44              :         );
      45              : 
      46            1 :   @override
      47              :   String getClassName() => 'BudgetAppData';
      48              : 
      49            1 :   @override
      50              :   AppDataType getType() => AppDataType.budgets;
      51              : 
      52            1 :   @override
      53              :   BudgetAppData clone() {
      54            1 :     return BudgetAppData(
      55            1 :       title: super.title,
      56            1 :       type: type,
      57            1 :       uuid: super.uuid,
      58            1 :       progress: super.progress,
      59            1 :       color: super.color,
      60            1 :       icon: super.icon,
      61            1 :       currency: super.currency,
      62            1 :       createdAt: super.createdAt,
      63            1 :       amountLimit: super.details,
      64            1 :       amountSet: amountSet,
      65            1 :       amount: amount,
      66            1 :       hidden: super.hidden,
      67            1 :       skip: super.skip,
      68              :     );
      69              :   }
      70              : 
      71            0 :   factory BudgetAppData.fromJson(Map<String, dynamic> json) {
      72            0 :     return BudgetAppData(
      73            0 :       title: json['title'],
      74            0 :       type: json['type'] ?? AppBudgetType.month.name,
      75            0 :       uuid: json['uuid'],
      76            0 :       progress: 0.0 + json['progress'],
      77            0 :       color: json['color'] != null ? MaterialColor(json['color'], const <int, Color>{}) : null,
      78            0 :       icon: (json['icon'] as int?)?.toIcon(),
      79            0 :       currency: CurrencyProvider.find(json['currency']),
      80            0 :       updatedAt: DateTime.parse(json['updatedAt']),
      81            0 :       createdAt: DateTime.parse(json['createdAt']),
      82            0 :       amountLimit: 0.0 + json['amountLimit'],
      83            0 :       amountSet: json['amountSet'] != null ? json['amountSet'].toString().toMap<int, double>() : {},
      84            0 :       hidden: json['hidden'],
      85            0 :       skip: json['skip'] ?? false,
      86              :     );
      87              :   }
      88              : 
      89            1 :   @override
      90            1 :   Map<String, dynamic> toJson() => {
      91            2 :         ...super.toJson()..remove('description'),
      92            2 :         'amountLimit': amountLimit,
      93            3 :         'amountSet': amountSet.toString(),
      94            2 :         'type': type,
      95              :       };
      96              : 
      97            1 :   @override
      98              :   double get details {
      99            4 :     if (super.details > 0 && super.details < 1) {
     100            0 :       return _relativeAmountLimit() - amount;
     101            2 :     } else if (amountLimit == 0) {
     102            2 :       return -amount;
     103            2 :     } else if (super.details > 0) {
     104            4 :       return amountLimit * (1 - progress);
     105              :     } else {
     106              :       return 0.0;
     107              :     }
     108              :   }
     109              : 
     110            1 :   String get detailsFormatted {
     111            4 :     if (super.details > 0 && super.details < 1) {
     112            0 :       final curr = (_relativeAmountLimit() - amount).toCurrency(currency: currency, withPattern: false);
     113            0 :       return '$curr ${AppLocale.labels.left}';
     114            2 :     } else if (super.details > 0) {
     115            6 :       return '${details.toCurrency(currency: currency, withPattern: false)} ${AppLocale.labels.left}';
     116              :     } else {
     117            6 :       return '${amount.toCurrency(currency: currency, withPattern: false)} ${AppLocale.labels.spent}';
     118              :     }
     119              :   }
     120              : 
     121            1 :   String _description() {
     122              :     String description = '';
     123            4 :     if (super.details > 0 && super.details < 1) {
     124            0 :       final percents = (amountLimit * 100).toStringAsFixed(2);
     125            0 :       description = '${(amount).toCurrency(currency: currency, withPattern: false)} /'
     126            0 :           ' ${_relativeAmountLimit().toCurrency(currency: currency, withPattern: false)} ($percents%)';
     127            2 :     } else if (super.details > 0) {
     128            6 :       description = '${(amountLimit * progress).toCurrency(currency: currency, withPattern: false)} /'
     129            3 :           ' ${(amountLimit).toCurrency(currency: currency, withPattern: false)}'
     130            2 :           '${multiplication > 1 ? ' (${multiplication.toStringAsFixed(2)} ${AppLocale.labels.coef})' : ''}';
     131              :     }
     132            6 :     if (type == AppBudgetType.year.name || type == AppBudgetType.week.name) {
     133            0 :       description += ', ${BudgetType.getLabel(type)}';
     134              :     }
     135              :     return description;
     136              :   }
     137              : 
     138            5 :   double get progressLeft => progress < 1 ? 1 - progress : 0.0;
     139              : 
     140            4 :   double get multiplication => amountSet[_month] ?? 1.0;
     141              : 
     142            4 :   double get amountLimit => super.details * multiplication;
     143            0 :   set amountLimit(double value) => super.details = value;
     144              : 
     145            1 :   DateTime getDateBoundary() {
     146            1 :     DateTime boundary = DateTime.now();
     147            3 :     if (type == AppBudgetType.year.name) {
     148            0 :       boundary = DateTime(boundary.year);
     149            3 :     } else if (type == AppBudgetType.week.name) {
     150            0 :       int boundaryDay = switch (AppPreferences.get(AppPreferences.prefWeekStartDay)) {
     151            0 :         AppStartOfWeek.MONDAY => DateTime.monday,
     152            0 :         AppStartOfWeek.SATURDAY => DateTime.saturday,
     153            0 :         AppStartOfWeek.SUNDAY => DateTime.sunday,
     154              :         _ => DateTime.monday,
     155              :       };
     156            0 :       boundary = boundary.getPreviousDay(boundaryDay);
     157              :     } else {
     158            2 :       boundary = boundary.getStartingDay(AppStartOfMonth.get());
     159              :     }
     160              :     return boundary;
     161              :   }
     162              : 
     163            0 :   double _relativeAmountLimit() {
     164            0 :     final ex = Exchange(store: getState());
     165            0 :     return amountLimit *
     166            0 :         getState()
     167            0 :             .getStream(AppDataType.invoice)
     168            0 :             .getTill(getDateBoundary().millisecondsSinceEpoch.toDouble())
     169            0 :             .cast<InvoiceAppData>()
     170            0 :             .where((e) => e.accountFrom == null)
     171            0 :             .fold(0.0, (v, e) => v + ex.reform(e.details, e.currency, currency));
     172              :   }
     173              : 
     174            1 :   @override
     175            1 :   String get description => _description();
     176              : 
     177            0 :   @override
     178            0 :   set description(String? value) => {};
     179              : }
        

Generated by: LCOV version 2.0-1