Charts
This commit is contained in:
parent
949f2b4985
commit
be449c1fc7
|
|
@ -1,45 +0,0 @@
|
||||||
import 'package:built_collection/built_collection.dart';
|
|
||||||
import 'package:invoiceninja_flutter/data/models/client_model.dart';
|
|
||||||
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
|
||||||
import 'package:invoiceninja_flutter/data/models/invoice_model.dart';
|
|
||||||
import 'package:invoiceninja_flutter/redux/reports/reports_state.dart';
|
|
||||||
import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
|
|
||||||
|
|
||||||
ReportResult invoiceReport({
|
|
||||||
CompanyEntity company,
|
|
||||||
ReportsUIState reportsUIState,
|
|
||||||
BuiltMap<String, ClientEntity> clientMap,
|
|
||||||
BuiltMap<String, InvoiceEntity> invoiceMap,
|
|
||||||
}) {
|
|
||||||
final List<List<ReportElement>> data = [];
|
|
||||||
final Map<String, double> totalAmounts = {};
|
|
||||||
final Map<String, double> totalPaid = {};
|
|
||||||
|
|
||||||
for (var invoiceId in invoiceMap.keys) {
|
|
||||||
final invoice = invoiceMap[invoiceId];
|
|
||||||
final client = clientMap[invoice.clientId];
|
|
||||||
|
|
||||||
if (invoice.isDeleted) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!totalAmounts.containsKey(client.id)) {
|
|
||||||
totalAmounts[client.id] = 0;
|
|
||||||
totalPaid[client.id] = 0;
|
|
||||||
}
|
|
||||||
totalAmounts[client.id] += invoice.amount;
|
|
||||||
totalPaid[client.id] += invoice.amount - invoice.balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var clientId in clientMap.keys) {
|
|
||||||
final client = clientMap[clientId];
|
|
||||||
if (client.isDeleted) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReportResult(
|
|
||||||
columns: [],
|
|
||||||
data: data,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -137,6 +137,7 @@ class ReportsScreen extends StatelessWidget {
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
|
if (reportsUIState.group.isNotEmpty)
|
||||||
AppDropdownButton<String>(
|
AppDropdownButton<String>(
|
||||||
labelText: localization.chart,
|
labelText: localization.chart,
|
||||||
value: reportsUIState.chart,
|
value: reportsUIState.chart,
|
||||||
|
|
@ -333,7 +334,7 @@ class _ReportDataTableState extends State<ReportDataTable> {
|
||||||
state.uiState.reportsUIState.filters
|
state.uiState.reportsUIState.filters
|
||||||
.rebuild((b) => b..addAll({column: value})));
|
.rebuild((b) => b..addAll({column: value})));
|
||||||
}),
|
}),
|
||||||
...reportResult.tableRows(context),
|
...reportResult.tableRows(context, widget.viewModel),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -364,9 +365,9 @@ ReportColumnType getReportColumnType(String column) {
|
||||||
|
|
||||||
class ReportResult {
|
class ReportResult {
|
||||||
ReportResult({
|
ReportResult({
|
||||||
this.columns,
|
@required this.columns,
|
||||||
this.allColumns,
|
@required this.allColumns,
|
||||||
this.data,
|
@required this.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<String> columns;
|
final List<String> columns;
|
||||||
|
|
@ -611,7 +612,7 @@ class ReportResult {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DataRow> tableRows(BuildContext context) {
|
List<DataRow> tableRows(BuildContext context, ReportsScreenVM viewModel) {
|
||||||
final rows = <DataRow>[];
|
final rows = <DataRow>[];
|
||||||
final store = StoreProvider.of<AppState>(context);
|
final store = StoreProvider.of<AppState>(context);
|
||||||
final reportState = store.state.uiState.reportsUIState;
|
final reportState = store.state.uiState.reportsUIState;
|
||||||
|
|
@ -629,43 +630,7 @@ class ReportResult {
|
||||||
rows.add(DataRow(cells: cells));
|
rows.add(DataRow(cells: cells));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final Map<String, Map<String, double>> totals = {};
|
viewModel.reportTotals.forEach((group, values) {
|
||||||
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
|
||||||
final row = data[i];
|
|
||||||
for (var j = 0; j < row.length; j++) {
|
|
||||||
final cell = row[j];
|
|
||||||
final column = columns[j];
|
|
||||||
final columnIndex = columns.indexOf(groupBy);
|
|
||||||
|
|
||||||
String value = row[columnIndex].renderText(context, column);
|
|
||||||
|
|
||||||
if (getReportColumnType(reportState.group) ==
|
|
||||||
ReportColumnType.dateTime) {
|
|
||||||
value = convertDateTimeToSqlDate(DateTime.tryParse(value));
|
|
||||||
if (reportState.subgroup == kReportGroupYear) {
|
|
||||||
value = value.substring(0, 4) + '-01-01';
|
|
||||||
} else if (reportState.subgroup == kReportGroupMonth) {
|
|
||||||
value = value.substring(0, 7) + '-01';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!totals.containsKey(value)) {
|
|
||||||
totals[value] = {'count': 0};
|
|
||||||
}
|
|
||||||
if (column == groupBy) {
|
|
||||||
totals[value]['count'] += 1;
|
|
||||||
}
|
|
||||||
if (cell is ReportNumberValue) {
|
|
||||||
if (!totals[value].containsKey(column)) {
|
|
||||||
totals[value][column] = 0;
|
|
||||||
}
|
|
||||||
totals[value][column] += cell.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totals.forEach((group, values) {
|
|
||||||
final cells = <DataCell>[];
|
final cells = <DataCell>[];
|
||||||
for (var column in columns) {
|
for (var column in columns) {
|
||||||
String value = '';
|
String value = '';
|
||||||
|
|
@ -800,7 +765,6 @@ class ReportResult {
|
||||||
rows.add(DataRow(cells: cells));
|
rows.add(DataRow(cells: cells));
|
||||||
});
|
});
|
||||||
|
|
||||||
print('## TOTALS: $totals');
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,19 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
|
import 'package:invoiceninja_flutter/constants.dart';
|
||||||
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
import 'package:invoiceninja_flutter/data/models/company_model.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/reports/reports_actions.dart';
|
import 'package:invoiceninja_flutter/redux/reports/reports_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/reports/reports_state.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/reports/client_report.dart';
|
import 'package:invoiceninja_flutter/ui/reports/client_report.dart';
|
||||||
import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
|
import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/completers.dart';
|
import 'package:invoiceninja_flutter/utils/completers.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
||||||
|
import 'package:invoiceninja_flutter/utils/formatting.dart';
|
||||||
import 'package:invoiceninja_flutter/utils/localization.dart';
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
import 'package:memoize/memoize.dart';
|
||||||
import 'package:redux/redux.dart';
|
import 'package:redux/redux.dart';
|
||||||
|
|
||||||
import 'reports_screen.dart';
|
import 'reports_screen.dart';
|
||||||
|
|
@ -39,11 +43,13 @@ class ReportsScreenVM {
|
||||||
@required this.onReportColumnsChanged,
|
@required this.onReportColumnsChanged,
|
||||||
@required this.onReportFiltersChanged,
|
@required this.onReportFiltersChanged,
|
||||||
@required this.onReportSorted,
|
@required this.onReportSorted,
|
||||||
|
@required this.reportTotals,
|
||||||
@required this.reportResult,
|
@required this.reportResult,
|
||||||
});
|
});
|
||||||
|
|
||||||
final AppState state;
|
final AppState state;
|
||||||
final ReportResult reportResult;
|
final ReportResult reportResult;
|
||||||
|
final Map<String, Map<String, double>> reportTotals;
|
||||||
final Function(BuildContext, List<String>) onReportColumnsChanged;
|
final Function(BuildContext, List<String>) onReportColumnsChanged;
|
||||||
final Function(BuildContext, BuiltMap<String, String>) onReportFiltersChanged;
|
final Function(BuildContext, BuiltMap<String, String>) onReportFiltersChanged;
|
||||||
final Function(int, bool) onReportSorted;
|
final Function(int, bool) onReportSorted;
|
||||||
|
|
@ -73,9 +79,13 @@ class ReportsScreenVM {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print('## TOTALS: ${memoizedReportTotals(reportResult, state.uiState.reportsUIState)}');
|
||||||
|
|
||||||
return ReportsScreenVM(
|
return ReportsScreenVM(
|
||||||
state: state,
|
state: state,
|
||||||
reportResult: reportResult,
|
reportResult: reportResult,
|
||||||
|
reportTotals:
|
||||||
|
memoizedReportTotals(reportResult, state.uiState.reportsUIState),
|
||||||
onReportSorted: (index, ascending) {
|
onReportSorted: (index, ascending) {
|
||||||
store.dispatch(UpdateReportSettings(
|
store.dispatch(UpdateReportSettings(
|
||||||
report: state.uiState.reportsUIState.report,
|
report: state.uiState.reportsUIState.report,
|
||||||
|
|
@ -156,3 +166,59 @@ class ReportsScreenVM {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var memoizedReportTotals = memo2((
|
||||||
|
ReportResult reportResult,
|
||||||
|
ReportsUIState reportUIState,
|
||||||
|
) =>
|
||||||
|
calculateReportTotals(
|
||||||
|
reportResult: reportResult, reportUIState: reportUIState));
|
||||||
|
|
||||||
|
Map<String, Map<String, double>> calculateReportTotals({
|
||||||
|
ReportResult reportResult,
|
||||||
|
ReportsUIState reportUIState,
|
||||||
|
}) {
|
||||||
|
if (reportUIState.group.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, Map<String, double>> totals = {};
|
||||||
|
final data = reportResult.data;
|
||||||
|
final columns = reportResult.columns;
|
||||||
|
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
final row = data[i];
|
||||||
|
for (var j = 0; j < row.length; j++) {
|
||||||
|
final cell = row[j];
|
||||||
|
final column = columns[j];
|
||||||
|
final columnIndex = columns.indexOf(reportUIState.group);
|
||||||
|
|
||||||
|
String group = row[columnIndex].value;
|
||||||
|
|
||||||
|
if (getReportColumnType(reportUIState.group) ==
|
||||||
|
ReportColumnType.dateTime) {
|
||||||
|
group = convertDateTimeToSqlDate(DateTime.tryParse(group));
|
||||||
|
if (reportUIState.subgroup == kReportGroupYear) {
|
||||||
|
group = group.substring(0, 4) + '-01-01';
|
||||||
|
} else if (reportUIState.subgroup == kReportGroupMonth) {
|
||||||
|
group = group.substring(0, 7) + '-01';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!totals.containsKey(group)) {
|
||||||
|
totals[group] = {'count': 0};
|
||||||
|
}
|
||||||
|
if (column == reportUIState.group) {
|
||||||
|
totals[group]['count'] += 1;
|
||||||
|
}
|
||||||
|
if (cell is ReportNumberValue) {
|
||||||
|
if (!totals[group].containsKey(column)) {
|
||||||
|
totals[group][column] = 0;
|
||||||
|
}
|
||||||
|
totals[group][column] += cell.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totals;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue