From dfcdcf15c95dfa62b3fee0e05d7d76593acbfde7 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 2 Dec 2020 11:29:26 +0200 Subject: [PATCH] Reports --- lib/data/models/entities.dart | 8 +++++ lib/data/models/task_model.dart | 36 +++++++++++++++++++++++ lib/ui/reports/reports_screen.dart | 47 +++++++++++++++++++++++------- lib/ui/reports/task_report.dart | 26 +++++++++-------- lib/utils/extensions.dart | 2 ++ 5 files changed, 97 insertions(+), 22 deletions(-) diff --git a/lib/data/models/entities.dart b/lib/data/models/entities.dart index 7b53dd7b2..1116e287f 100644 --- a/lib/data/models/entities.dart +++ b/lib/data/models/entities.dart @@ -338,6 +338,14 @@ abstract class BaseEntity implements SelectableEntity { currencyId: currencyId, ); + ReportTimestampValue getReportTimestamp({int value, String currencyId}) => + ReportTimestampValue( + entityType: entityType, + entityId: id, + value: value, + currencyId: currencyId, + ); + ReportNumberValue getReportDouble( {double value, String currencyId, diff --git a/lib/data/models/task_model.dart b/lib/data/models/task_model.dart index 9d185a586..34abd180b 100644 --- a/lib/data/models/task_model.dart +++ b/lib/data/models/task_model.dart @@ -259,6 +259,42 @@ abstract class TaskEntity extends Object DateTime.parse(endDate).compareTo(lastEndDate.toLocal()) == 1; } + int get startTimestamp { + if (timeLog.isEmpty) { + return null; + } + + final List log = jsonDecode(timeLog); + + if (log.isEmpty) { + return null; + } + + final first = log.first as List; + + return first[0]; + } + + int get endTimestamp { + if (timeLog.isEmpty) { + return null; + } + + final List log = jsonDecode(timeLog); + + if (log.isEmpty) { + return null; + } + + final last = log.last as List; + + if (last.length < 2) { + return null; + } + + return last[1]; + } + List get taskTimes { final List details = []; diff --git a/lib/ui/reports/reports_screen.dart b/lib/ui/reports/reports_screen.dart index 06ae55d3c..0d7313fe2 100644 --- a/lib/ui/reports/reports_screen.dart +++ b/lib/ui/reports/reports_screen.dart @@ -1167,22 +1167,27 @@ class ReportResult { for (var j = 0; j < row.length; j++) { final cell = row[j]; final column = columns[j]; + final canTotal = cell is ReportNumberValue || cell is ReportAgeValue || + cell is ReportDurationValue; - if (cell is ReportNumberValue || cell is ReportAgeValue) { - String currencyId; + String currencyId = ''; + if (canTotal) { if (cell is ReportNumberValue) { currencyId = cell.currencyId; } else if (cell is ReportAgeValue) { currencyId = cell.currencyId; + } else if (cell is ReportDurationValue) { + currencyId = cell.currencyId; } - - if (!totals.containsKey(currencyId)) { - totals[currencyId] = {'count': 0}; - } - if (!countedRow) { - totals[currencyId]['count']++; - countedRow = true; - } + } + if (!totals.containsKey(currencyId)) { + totals[currencyId] = {'count': 0}; + } + if (!countedRow) { + totals[currencyId]['count']++; + countedRow = true; + } + if (canTotal) { if (!totals[currencyId].containsKey(column)) { totals[currencyId][column] = 0; } @@ -1362,6 +1367,28 @@ class ReportDurationValue extends ReportElement { } } +class ReportTimestampValue extends ReportElement { + ReportTimestampValue({ + @required dynamic value, + @required EntityType entityType, + @required String entityId, + @required this.currencyId, + }) : super(value: value, entityType: entityType, entityId: entityId); + + final String currencyId; + + @override + Widget renderWidget(BuildContext context, String column) { + return Text(renderText(context, column)); + } + + @override + String renderText(BuildContext context, String column) { + return formatDate( + convertTimestampToDateString(value), context, showTime: true); + } +} + class ReportIntValue extends ReportElement { ReportIntValue({ dynamic value, diff --git a/lib/ui/reports/task_report.dart b/lib/ui/reports/task_report.dart index a381b0cb8..4c9e1cfd1 100644 --- a/lib/ui/reports/task_report.dart +++ b/lib/ui/reports/task_report.dart @@ -8,15 +8,13 @@ import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/redux/reports/reports_state.dart'; import 'package:invoiceninja_flutter/redux/static/static_state.dart'; import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart'; -import 'package:invoiceninja_flutter/utils/formatting.dart'; import 'package:memoize/memoize.dart'; -import 'package:invoiceninja_flutter/utils/extensions.dart'; enum TaskReportFields { rate, calculated_rate, - start_date, - end_date, + start_time, + end_time, duration, description, invoice, @@ -70,8 +68,9 @@ ReportResult taskReport( : ReportSettingsEntity(); final defaultColumns = [ - TaskReportFields.start_date, - TaskReportFields.end_date, + TaskReportFields.start_time, + TaskReportFields.end_time, + TaskReportFields.duration, TaskReportFields.description, TaskReportFields.client, TaskReportFields.invoice, @@ -80,6 +79,7 @@ ReportResult taskReport( if (taskReportSettings.columns.isNotEmpty) { columns = BuiltList(taskReportSettings.columns .map((e) => EnumUtils.fromString(TaskReportFields.values, e)) + .where((element) => element != null) .toList()); } else { columns = BuiltList(defaultColumns); @@ -113,12 +113,11 @@ ReportResult taskReport( task: task, ); break; - case TaskReportFields.start_date: - value = - convertDateTimeToSqlDate(task.taskTimes.firstOrNull?.startDate); + case TaskReportFields.start_time: + value = task.startTimestamp; break; - case TaskReportFields.end_date: - value = convertDateTimeToSqlDate(task.taskTimes.firstOrNull?.endDate); + case TaskReportFields.end_time: + value = task.endTimestamp; break; case TaskReportFields.description: value = task.description; @@ -179,7 +178,10 @@ ReportResult taskReport( skip = true; } - if (column == TaskReportFields.duration) { + if (column == TaskReportFields.start_time || + column == TaskReportFields.end_time) { + row.add(task.getReportTimestamp(value: value)); + } else if (column == TaskReportFields.duration) { row.add(task.getReportDuration(value: value)); } else if (value.runtimeType == bool) { row.add(task.getReportBool(value: value)); diff --git a/lib/utils/extensions.dart b/lib/utils/extensions.dart index a2a0d2021..6cb12a6ee 100644 --- a/lib/utils/extensions.dart +++ b/lib/utils/extensions.dart @@ -20,4 +20,6 @@ extension ContextHelper on BuildContext { extension ListHelper on List { T get firstOrNull => isEmpty ? null : first; + + T get lastOrNull => isEmpty ? null : last; }