Merge branch 'develop'

This commit is contained in:
Hillel Coren 2024-01-23 15:21:43 +02:00
commit 2528564f8c
17 changed files with 290 additions and 106 deletions

View File

@ -1,3 +1,5 @@
import 'package:invoiceninja_flutter/data/models/import_model.dart';
class Constants { class Constants {
//static String get hostedApiUrl => kReleaseMode ? kAppProductionUrl : kAppStagingUrl; //static String get hostedApiUrl => kReleaseMode ? kAppProductionUrl : kAppStagingUrl;
static String get hostedApiUrl => kAppProductionUrl; static String get hostedApiUrl => kAppProductionUrl;
@ -410,6 +412,10 @@ const String kGatewayTypeInstantBankPay = '21';
const String kGatewayTypeFPX = '22'; const String kGatewayTypeFPX = '22';
const String kGatewayTypeKlarna = '23'; const String kGatewayTypeKlarna = '23';
const String kGatewayTypeBacs = '24'; const String kGatewayTypeBacs = '24';
const String kGatewayTypeVenmo = '25';
const String kGatewayTypeMercadoPago = '26';
const String kGatewayTypeMyBank = '27';
const String kGatewayTypePayLater = '28';
const kGatewayTypes = { const kGatewayTypes = {
kGatewayTypeCreditCard: 'credit_card', kGatewayTypeCreditCard: 'credit_card',
@ -436,6 +442,10 @@ const kGatewayTypes = {
kGatewayTypeFPX: 'fpx', kGatewayTypeFPX: 'fpx',
kGatewayTypeKlarna: 'klarna', kGatewayTypeKlarna: 'klarna',
kGatewayTypeBacs: 'bacs', kGatewayTypeBacs: 'bacs',
kGatewayTypeVenmo: 'venmo',
kGatewayTypeMercadoPago: 'mercado_pago',
kGatewayTypeMyBank: 'my_bank',
kGatewayTypePayLater: 'pay_later',
}; };
const String kNotificationChannelEmail = 'email'; const String kNotificationChannelEmail = 'email';
@ -674,6 +684,32 @@ const String kReportPurchaseOrderItem = 'purchase_order_item';
const String kReportVendor = 'vendor'; const String kReportVendor = 'vendor';
const String kReportTransaction = 'transaction'; const String kReportTransaction = 'transaction';
final kReportMap = {
kReportClient: ExportType.clients,
kReportClientContact: ExportType.client_contacts,
kReportCredit: ExportType.credits,
kReportCreditItem: null,
kReportDocument: ExportType.documents,
kReportExpense: ExportType.expenses,
kReportInvoice: ExportType.invoices,
kReportPayment: ExportType.payments,
kReportProduct: ExportType.products,
kReportProfitAndLoss: ExportType.profitloss,
kReportTask: ExportType.tasks,
kReportTaskItem: null,
kReportInvoiceTax: ExportType.tax_summary,
kReportPaymentTax: null,
kReportQuote: ExportType.quotes,
kReportInvoiceItem: ExportType.invoice_items,
kReportQuoteItem: ExportType.quote_items,
kReportRecurringExpense: null,
kReportRecurringInvoice: ExportType.recurring_invoices,
kReportPurchaseOrder: null,
kReportPurchaseOrderItem: null,
kReportVendor: null,
kReportTransaction: null,
};
const String kPdfFieldsClientDetails = 'client_details'; const String kPdfFieldsClientDetails = 'client_details';
const String kPdfFieldsCompanyDetails = 'company_details'; const String kPdfFieldsCompanyDetails = 'company_details';
const String kPdfFieldsCompanyAddress = 'company_address'; const String kPdfFieldsCompanyAddress = 'company_address';

View File

@ -202,14 +202,12 @@ class ExportType extends EnumClass {
static const ExportType products = _$products; static const ExportType products = _$products;
static const ExportType tasks = _$tasks; static const ExportType tasks = _$tasks;
static const ExportType profitloss = _$profitloss; static const ExportType profitloss = _$profitloss;
static const ExportType aged_receivable_detailed_report = static const ExportType ar_detailed = _$ar_detailed;
_$aged_receivable_detailed_report; static const ExportType ar_summary = _$ar_summary;
static const ExportType aged_receivable_summary_report = static const ExportType client_balance = _$client_balance;
_$aged_receivable_summary_report; static const ExportType client_sales = _$client_sales;
static const ExportType client_balance_report = _$client_balance_report; static const ExportType tax_summary = _$tax_summary;
static const ExportType client_sales_report = _$client_sales_report; static const ExportType user_sales = _$user_sales;
static const ExportType tax_summary_report = _$tax_summary_report;
static const ExportType user_sales_report = _$user_sales_report;
static BuiltSet<ExportType> get values => _$exportValues; static BuiltSet<ExportType> get values => _$exportValues;

View File

@ -62,17 +62,12 @@ const ExportType _$payments = const ExportType._('payments');
const ExportType _$products = const ExportType._('products'); const ExportType _$products = const ExportType._('products');
const ExportType _$tasks = const ExportType._('tasks'); const ExportType _$tasks = const ExportType._('tasks');
const ExportType _$profitloss = const ExportType._('profitloss'); const ExportType _$profitloss = const ExportType._('profitloss');
const ExportType _$aged_receivable_detailed_report = const ExportType _$ar_detailed = const ExportType._('ar_detailed');
const ExportType._('aged_receivable_detailed_report'); const ExportType _$ar_summary = const ExportType._('ar_summary');
const ExportType _$aged_receivable_summary_report = const ExportType _$client_balance = const ExportType._('client_balance');
const ExportType._('aged_receivable_summary_report'); const ExportType _$client_sales = const ExportType._('client_sales');
const ExportType _$client_balance_report = const ExportType _$tax_summary = const ExportType._('tax_summary');
const ExportType._('client_balance_report'); const ExportType _$user_sales = const ExportType._('user_sales');
const ExportType _$client_sales_report =
const ExportType._('client_sales_report');
const ExportType _$tax_summary_report =
const ExportType._('tax_summary_report');
const ExportType _$user_sales_report = const ExportType._('user_sales_report');
ExportType _$exportValueOf(String name) { ExportType _$exportValueOf(String name) {
switch (name) { switch (name) {
@ -106,18 +101,18 @@ ExportType _$exportValueOf(String name) {
return _$tasks; return _$tasks;
case 'profitloss': case 'profitloss':
return _$profitloss; return _$profitloss;
case 'aged_receivable_detailed_report': case 'ar_detailed':
return _$aged_receivable_detailed_report; return _$ar_detailed;
case 'aged_receivable_summary_report': case 'ar_summary':
return _$aged_receivable_summary_report; return _$ar_summary;
case 'client_balance_report': case 'client_balance':
return _$client_balance_report; return _$client_balance;
case 'client_sales_report': case 'client_sales':
return _$client_sales_report; return _$client_sales;
case 'tax_summary_report': case 'tax_summary':
return _$tax_summary_report; return _$tax_summary;
case 'user_sales_report': case 'user_sales':
return _$user_sales_report; return _$user_sales;
default: default:
throw new ArgumentError(name); throw new ArgumentError(name);
} }
@ -140,12 +135,12 @@ final BuiltSet<ExportType> _$exportValues =
_$products, _$products,
_$tasks, _$tasks,
_$profitloss, _$profitloss,
_$aged_receivable_detailed_report, _$ar_detailed,
_$aged_receivable_summary_report, _$ar_summary,
_$client_balance_report, _$client_balance,
_$client_sales_report, _$client_sales,
_$tax_summary_report, _$tax_summary,
_$user_sales_report, _$user_sales,
]); ]);
Serializer<PreImportResponse> _$preImportResponseSerializer = Serializer<PreImportResponse> _$preImportResponseSerializer =

View File

@ -3,6 +3,7 @@ import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart'; import 'package:built_value/serializer.dart';
import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/dashboard_model.dart'; import 'package:invoiceninja_flutter/data/models/dashboard_model.dart';
import 'package:invoiceninja_flutter/data/models/import_model.dart';
import 'package:invoiceninja_flutter/main_app.dart'; import 'package:invoiceninja_flutter/main_app.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/data/models/models.dart';
@ -80,9 +81,11 @@ abstract class ScheduleEntity extends Object
static const TEMPLATE_EMAIL_STATEMENT = 'email_statement'; static const TEMPLATE_EMAIL_STATEMENT = 'email_statement';
static const TEMPLATE_EMAIL_RECORD = 'email_record'; static const TEMPLATE_EMAIL_RECORD = 'email_record';
static const TEMPLATE_EMAIL_REPORT = 'email_report';
static const TEMPLATES = [ static const TEMPLATES = [
TEMPLATE_EMAIL_STATEMENT, TEMPLATE_EMAIL_STATEMENT,
TEMPLATE_EMAIL_REPORT,
TEMPLATE_EMAIL_RECORD, TEMPLATE_EMAIL_RECORD,
]; ];
@ -216,6 +219,9 @@ abstract class ScheduleParameters
? EntityType.invoice.toString() ? EntityType.invoice.toString()
: null, : null,
entityId: action == ScheduleEntity.TEMPLATE_EMAIL_RECORD ? '' : null, entityId: action == ScheduleEntity.TEMPLATE_EMAIL_RECORD ? '' : null,
reportName: action == ScheduleEntity.TEMPLATE_EMAIL_REPORT
? ExportType.invoices.name
: null,
); );
} }
@ -250,6 +256,9 @@ abstract class ScheduleParameters
@BuiltValueField(wireName: 'entity_id') @BuiltValueField(wireName: 'entity_id')
String? get entityId; String? get entityId;
@BuiltValueField(wireName: 'report_name')
String? get reportName;
static Serializer<ScheduleParameters> get serializer => static Serializer<ScheduleParameters> get serializer =>
_$scheduleParametersSerializer; _$scheduleParametersSerializer;
} }

View File

@ -337,6 +337,13 @@ class _$ScheduleParametersSerializer
..add(serializers.serialize(value, ..add(serializers.serialize(value,
specifiedType: const FullType(String))); specifiedType: const FullType(String)));
} }
value = object.reportName;
if (value != null) {
result
..add('report_name')
..add(serializers.serialize(value,
specifiedType: const FullType(String)));
}
return result; return result;
} }
@ -390,6 +397,10 @@ class _$ScheduleParametersSerializer
result.entityId = serializers.deserialize(value, result.entityId = serializers.deserialize(value,
specifiedType: const FullType(String)) as String?; specifiedType: const FullType(String)) as String?;
break; break;
case 'report_name':
result.reportName = serializers.deserialize(value,
specifiedType: const FullType(String)) as String?;
break;
} }
} }
@ -904,6 +915,8 @@ class _$ScheduleParameters extends ScheduleParameters {
final String? entityType; final String? entityType;
@override @override
final String? entityId; final String? entityId;
@override
final String? reportName;
factory _$ScheduleParameters( factory _$ScheduleParameters(
[void Function(ScheduleParametersBuilder)? updates]) => [void Function(ScheduleParametersBuilder)? updates]) =>
@ -918,7 +931,8 @@ class _$ScheduleParameters extends ScheduleParameters {
this.status, this.status,
this.clients, this.clients,
this.entityType, this.entityType,
this.entityId}) this.entityId,
this.reportName})
: super._(); : super._();
@override @override
@ -942,7 +956,8 @@ class _$ScheduleParameters extends ScheduleParameters {
status == other.status && status == other.status &&
clients == other.clients && clients == other.clients &&
entityType == other.entityType && entityType == other.entityType &&
entityId == other.entityId; entityId == other.entityId &&
reportName == other.reportName;
} }
int? __hashCode; int? __hashCode;
@ -959,6 +974,7 @@ class _$ScheduleParameters extends ScheduleParameters {
_$hash = $jc(_$hash, clients.hashCode); _$hash = $jc(_$hash, clients.hashCode);
_$hash = $jc(_$hash, entityType.hashCode); _$hash = $jc(_$hash, entityType.hashCode);
_$hash = $jc(_$hash, entityId.hashCode); _$hash = $jc(_$hash, entityId.hashCode);
_$hash = $jc(_$hash, reportName.hashCode);
_$hash = $jf(_$hash); _$hash = $jf(_$hash);
return __hashCode ??= _$hash; return __hashCode ??= _$hash;
} }
@ -974,7 +990,8 @@ class _$ScheduleParameters extends ScheduleParameters {
..add('status', status) ..add('status', status)
..add('clients', clients) ..add('clients', clients)
..add('entityType', entityType) ..add('entityType', entityType)
..add('entityId', entityId)) ..add('entityId', entityId)
..add('reportName', reportName))
.toString(); .toString();
} }
} }
@ -1024,6 +1041,10 @@ class ScheduleParametersBuilder
String? get entityId => _$this._entityId; String? get entityId => _$this._entityId;
set entityId(String? entityId) => _$this._entityId = entityId; set entityId(String? entityId) => _$this._entityId = entityId;
String? _reportName;
String? get reportName => _$this._reportName;
set reportName(String? reportName) => _$this._reportName = reportName;
ScheduleParametersBuilder(); ScheduleParametersBuilder();
ScheduleParametersBuilder get _$this { ScheduleParametersBuilder get _$this {
@ -1038,6 +1059,7 @@ class ScheduleParametersBuilder
_clients = $v.clients?.toBuilder(); _clients = $v.clients?.toBuilder();
_entityType = $v.entityType; _entityType = $v.entityType;
_entityId = $v.entityId; _entityId = $v.entityId;
_reportName = $v.reportName;
_$v = null; _$v = null;
} }
return this; return this;
@ -1070,7 +1092,8 @@ class ScheduleParametersBuilder
status: status, status: status,
clients: _clients?.build(), clients: _clients?.build(),
entityType: entityType, entityType: entityType,
entityId: entityId); entityId: entityId,
reportName: reportName);
} catch (_) { } catch (_) {
late String _$failedField; late String _$failedField;
try { try {

View File

@ -49,7 +49,7 @@ class EntityPresenter {
isNarrow) { isNarrow) {
return name; return name;
} else { } else {
return '$type $name'; return '$type: $name';
} }
} }

View File

@ -90,13 +90,18 @@ class _SystemLogViewerState extends State<SystemLogViewer> {
}, },
isExpanded: _isExpanded[systemLog.id] == true, isExpanded: _isExpanded[systemLog.id] == true,
body: _isExpanded[systemLog.id] == true body: _isExpanded[systemLog.id] == true
? Container( ? logs == null
color: Colors.white, ? Padding(
child: Padding( child: Text(systemLog.log),
padding: const EdgeInsets.symmetric(vertical: 8), padding: EdgeInsets.symmetric(
child: JsonViewer(logs ?? <String, dynamic>{}), horizontal: 16, vertical: 10))
), : Container(
) color: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: JsonViewer(logs),
),
)
: SizedBox(), : SizedBox(),
); );
}).toList(), }).toList(),

View File

@ -57,6 +57,7 @@ enum ExpenseReportFields {
converted_amount, converted_amount,
status, status,
record_state, record_state,
is_invoiced,
} }
var memoizedExpenseReport = memo10(( var memoizedExpenseReport = memo10((
@ -284,6 +285,9 @@ ReportResult expenseReport(
value = AppLocalization.of(navigatorKey.currentContext!)! value = AppLocalization.of(navigatorKey.currentContext!)!
.lookup(expense.entityState); .lookup(expense.entityState);
break; break;
case ExpenseReportFields.is_invoiced:
value = expense.isInvoiced;
break;
} }
if (!ReportResult.matchField( if (!ReportResult.matchField(

View File

@ -385,6 +385,13 @@ class ReportsScreen extends StatelessWidget {
viewModel.onExportPressed(context); viewModel.onExportPressed(context);
}, },
), ),
AppTextButton(
label: localization.schedule,
isInHeader: true,
onPressed: () {
viewModel.onSchedulePressed(context);
},
),
], ],
Padding( Padding(
padding: const EdgeInsets.only(right: 8), padding: const EdgeInsets.only(right: 8),
@ -538,6 +545,15 @@ class ReportsScreen extends StatelessWidget {
}, },
), ),
), ),
SizedBox(width: kGutterWidth),
Expanded(
child: AppButton(
label: localization.schedule,
onPressed: () {
viewModel.onSchedulePressed(context);
},
),
),
], ],
), ),
), ),

View File

@ -11,6 +11,9 @@ import 'package:flutter/widgets.dart';
import 'package:built_collection/built_collection.dart'; import 'package:built_collection/built_collection.dart';
import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:invoiceninja_flutter/data/models/import_model.dart';
import 'package:invoiceninja_flutter/data/models/schedule_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/ui/reports/credit_item_report.dart'; import 'package:invoiceninja_flutter/ui/reports/credit_item_report.dart';
import 'package:invoiceninja_flutter/ui/reports/purchase_order_item_report.dart'; import 'package:invoiceninja_flutter/ui/reports/purchase_order_item_report.dart';
import 'package:invoiceninja_flutter/ui/reports/purchase_order_report.dart'; import 'package:invoiceninja_flutter/ui/reports/purchase_order_report.dart';
@ -81,6 +84,7 @@ class ReportsScreenVM {
required this.onReportColumnsChanged, required this.onReportColumnsChanged,
required this.onReportFiltersChanged, required this.onReportFiltersChanged,
required this.onExportPressed, required this.onExportPressed,
required this.onSchedulePressed,
required this.onReportSorted, required this.onReportSorted,
required this.groupTotals, required this.groupTotals,
required this.reportResult, required this.reportResult,
@ -94,6 +98,7 @@ class ReportsScreenVM {
final GroupTotals groupTotals; final GroupTotals groupTotals;
final Function(BuildContext, List<String>) onReportColumnsChanged; final Function(BuildContext, List<String>) onReportColumnsChanged;
final Function(BuildContext) onExportPressed; final Function(BuildContext) onExportPressed;
final Function(BuildContext) onSchedulePressed;
final Function(BuildContext, BuiltMap<String?, String?>) final Function(BuildContext, BuiltMap<String?, String?>)
onReportFiltersChanged; onReportFiltersChanged;
final Function(String?, bool) onReportSorted; final Function(String?, bool) onReportSorted;
@ -457,6 +462,13 @@ class ReportsScreenVM {
)); ));
}); });
}, },
onSchedulePressed: (context) async {
createEntity(
entity: ScheduleEntity(ScheduleEntity.TEMPLATE_EMAIL_REPORT)
.rebuild((b) => b
..parameters.reportName =
kReportMap[report]?.name ?? ExportType.invoices.name));
},
onExportPressed: (context) async { onExportPressed: (context) async {
final localization = AppLocalization.of(context); final localization = AppLocalization.of(context);
final reportState = state.uiState.reportsUIState; final reportState = state.uiState.reportsUIState;

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/constants.dart'; import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/dashboard_model.dart'; import 'package:invoiceninja_flutter/data/models/dashboard_model.dart';
import 'package:invoiceninja_flutter/data/models/import_model.dart';
import 'package:invoiceninja_flutter/data/models/models.dart'; import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/credit/credit_selectors.dart'; import 'package:invoiceninja_flutter/redux/credit/credit_selectors.dart';
import 'package:invoiceninja_flutter/redux/invoice/invoice_selectors.dart'; import 'package:invoiceninja_flutter/redux/invoice/invoice_selectors.dart';
@ -231,6 +232,49 @@ class _ScheduleEditState extends State<ScheduleEdit> {
], ],
), ),
if (schedule.template == if (schedule.template ==
ScheduleEntity.TEMPLATE_EMAIL_REPORT) ...[
FormCard(
isLast: true,
children: [
AppDropdownButton<String>(
value: schedule.parameters.reportName,
labelText: localization.report,
onChanged: (dynamic value) {
setState(() {
viewModel.onChanged(schedule.rebuild(
(b) => b..parameters.reportName = value));
});
},
items: ExportType.values
.map((importType) => DropdownMenuItem<String>(
value: importType.name,
child:
Text(localization.lookup('$importType'))))
.toList()),
AppDropdownButton<DateRange>(
labelText: localization.dateRange,
blankValue: null,
value: parameters.dateRange!.isNotEmpty
? DateRange.valueOf(
toCamelCase(parameters.dateRange!))
: null,
onChanged: (dynamic value) {
viewModel.onChanged(schedule.rebuild((b) => b
..parameters.dateRange =
(value as DateRange).snakeCase));
},
items: DateRange.values
.where((value) => value != DateRange.custom)
.map((dateRange) => DropdownMenuItem<DateRange>(
child: Text(localization
.lookup(dateRange.toString())),
value: dateRange,
))
.toList(),
),
],
),
] else if (schedule.template ==
ScheduleEntity.TEMPLATE_EMAIL_STATEMENT) ...[ ScheduleEntity.TEMPLATE_EMAIL_STATEMENT) ...[
FormCard(children: [ FormCard(children: [
AppDropdownButton<DateRange>( AppDropdownButton<DateRange>(
@ -300,8 +344,8 @@ class _ScheduleEditState extends State<ScheduleEdit> {
isLast: true, isLast: true,
children: [ children: [
ClientPicker( ClientPicker(
key: key: ValueKey(
ValueKey('__client_picker_${_clientClearedAt}__'), '__statement_client_picker_${_clientClearedAt}__'),
isRequired: false, isRequired: false,
clientId: null, clientId: null,
clientState: state.clientState, clientState: state.clientState,
@ -339,6 +383,7 @@ class _ScheduleEditState extends State<ScheduleEdit> {
] else if (schedule.template == ] else if (schedule.template ==
ScheduleEntity.TEMPLATE_EMAIL_RECORD) ...[ ScheduleEntity.TEMPLATE_EMAIL_RECORD) ...[
FormCard( FormCard(
isLast: true,
children: [ children: [
AppDropdownButton<String>( AppDropdownButton<String>(
labelText: localization.type, labelText: localization.type,

View File

@ -75,6 +75,8 @@ class ScheduleListItem extends StatelessWidget {
} }
subtitle += subtitle +=
'' + localization.lookup(kFrequencies[schedule.frequencyId]); '' + localization.lookup(kFrequencies[schedule.frequencyId]);
} else if (schedule.template == ScheduleEntity.TEMPLATE_EMAIL_REPORT) {
title += ': ' + localization.lookup(schedule.parameters.reportName);
} }
return DismissibleEntity( return DismissibleEntity(

View File

@ -63,16 +63,13 @@ class _ScheduleViewState extends State<ScheduleView> {
localization.lookup(schedule.parameters.entityType): localization.lookup(schedule.parameters.entityType):
entity!.listDisplayName entity!.listDisplayName
}) })
else else if (schedule.template == ScheduleEntity.TEMPLATE_EMAIL_STATEMENT)
FieldGrid({ FieldGrid({
localization.frequency: localization.frequency:
localization.lookup(kFrequencies[schedule.frequencyId]), localization.lookup(kFrequencies[schedule.frequencyId]),
localization.remainingCycles: schedule.remainingCycles == -1 localization.remainingCycles: schedule.remainingCycles == -1
? localization.endless ? localization.endless
: '${schedule.remainingCycles}', : '${schedule.remainingCycles}',
}),
if (schedule.template == ScheduleEntity.TEMPLATE_EMAIL_STATEMENT)
FieldGrid({
localization.clients: parameters.clients!.isEmpty localization.clients: parameters.clients!.isEmpty
? localization.allClients ? localization.allClients
: parameters.clients!.length == 1 : parameters.clients!.length == 1
@ -94,6 +91,17 @@ class _ScheduleViewState extends State<ScheduleView> {
: localization.no, : localization.no,
localization.status: localization.lookup(parameters.status), localization.status: localization.lookup(parameters.status),
}) })
else if (schedule.template == ScheduleEntity.TEMPLATE_EMAIL_REPORT)
FieldGrid({
localization.frequency:
localization.lookup(kFrequencies[schedule.frequencyId]),
localization.remainingCycles: schedule.remainingCycles == -1
? localization.endless
: '${schedule.remainingCycles}',
localization.report:
localization.lookup(schedule.parameters.reportName),
localization.dateRange: localization.lookup(parameters.dateRange),
})
], ],
), ),
); );

View File

@ -235,6 +235,9 @@ class _EmailSettingsState extends State<EmailSettings> {
DropdownMenuItem( DropdownMenuItem(
child: Text(localization.defaultWord), child: Text(localization.defaultWord),
value: SettingsEntity.EMAIL_SENDING_METHOD_DEFAULT), value: SettingsEntity.EMAIL_SENDING_METHOD_DEFAULT),
DropdownMenuItem(
child: Text('SMTP'),
value: SettingsEntity.EMAIL_SENDING_METHOD_SMTP),
if (viewModel.state.isHosted) ...[ if (viewModel.state.isHosted) ...[
DropdownMenuItem( DropdownMenuItem(
child: Text('Gmail'), child: Text('Gmail'),
@ -243,9 +246,6 @@ class _EmailSettingsState extends State<EmailSettings> {
child: Text('Microsoft'), child: Text('Microsoft'),
value: SettingsEntity.EMAIL_SENDING_METHOD_MICROSOFT), value: SettingsEntity.EMAIL_SENDING_METHOD_MICROSOFT),
], ],
DropdownMenuItem(
child: Text('SMTP'),
value: SettingsEntity.EMAIL_SENDING_METHOD_SMTP),
DropdownMenuItem( DropdownMenuItem(
child: Text('Postmark'), child: Text('Postmark'),
value: SettingsEntity.EMAIL_SENDING_METHOD_POSTMARK), value: SettingsEntity.EMAIL_SENDING_METHOD_POSTMARK),

View File

@ -12,6 +12,8 @@ import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:invoiceninja_flutter/data/models/bank_account_model.dart'; import 'package:invoiceninja_flutter/data/models/bank_account_model.dart';
import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/data/models/entities.dart';
import 'package:invoiceninja_flutter/data/models/schedule_model.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/bank_account/bank_account_actions.dart'; import 'package:invoiceninja_flutter/redux/bank_account/bank_account_actions.dart';
import 'package:invoiceninja_flutter/redux/bank_account/bank_account_selectors.dart'; import 'package:invoiceninja_flutter/redux/bank_account/bank_account_selectors.dart';
import 'package:invoiceninja_flutter/ui/app/entity_dropdown.dart'; import 'package:invoiceninja_flutter/ui/app/entity_dropdown.dart';
@ -304,48 +306,71 @@ class _ImportExportState extends State<ImportExport> {
] ]
], ],
], ],
AppButton( Row(
iconData: MdiIcons.export, children: [
label: localization.export.toUpperCase(), Expanded(
onPressed: () { child: AppButton(
final webClient = WebClient(); iconData: MdiIcons.export,
final state = StoreProvider.of<AppState>(context).state; label: localization.export.toUpperCase(),
final credentials = state.credentials; onPressed: () {
String? url = credentials.url; final webClient = WebClient();
final state =
StoreProvider.of<AppState>(context).state;
final credentials = state.credentials;
String? url = credentials.url;
if (_exportFormat == ImportType.json) { if (_exportFormat == ImportType.json) {
url = '$url/export'; url = '$url/export';
} else { } else {
url = '$url/reports/$_exportType'; url = '$url/reports/$_exportType';
} }
setState(() => _isExporting = true); setState(() => _isExporting = true);
final data = { final data = {
'send_email': true, 'send_email': true,
'report_keys': <String>[], 'report_keys': <String>[],
'date_key': _exportDate, 'date_key': _exportDate,
'date_range': _exportDateRange, 'date_range': _exportDateRange,
'start_date': _exportStartDate, 'start_date': _exportStartDate,
'end_date': _exportEndDate, 'end_date': _exportEndDate,
}; };
if (_exportType == ExportType.profitloss) { if (_exportType == ExportType.profitloss) {
data['is_income_billed'] = true; data['is_income_billed'] = true;
data['is_expense_billed'] = true; data['is_expense_billed'] = true;
data['include_tax'] = true; data['include_tax'] = true;
} }
webClient webClient
.post(url, credentials.token, data: json.encode(data)) .post(url, credentials.token,
.then((dynamic result) { data: json.encode(data))
setState(() => _isExporting = false); .then((dynamic result) {
showMessageDialog(message: localization.exportedData); setState(() => _isExporting = false);
}).catchError((dynamic error) { showMessageDialog(
setState(() => _isExporting = false); message: localization.exportedData);
showErrorDialog(message: '$error'); }).catchError((dynamic error) {
}); setState(() => _isExporting = false);
}, showErrorDialog(message: '$error');
});
},
),
),
SizedBox(width: kGutterWidth),
Expanded(
child: AppButton(
label: localization.schedule,
iconData: Icons.schedule,
onPressed: () {
createEntity(
entity: ScheduleEntity(
ScheduleEntity.TEMPLATE_EMAIL_REPORT)
.rebuild((b) => b
..parameters.reportName =
_exportType.name));
},
))
],
) )
], ],
], ],

View File

@ -18,6 +18,11 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = { static final Map<String, Map<String, String>> _localizedValues = {
'en': { 'en': {
// STARTER: lang key - do not remove comment // STARTER: lang key - do not remove comment
'venmo': 'Venmo',
'mercado_pago': 'Mercado Pago',
'my_bank': 'MyBank',
'pay_later': 'Pay Later',
'email_report': 'Email Report',
'host': 'Host', 'host': 'Host',
'port': 'Port', 'port': 'Port',
'encryption': 'Encryption', 'encryption': 'Encryption',
@ -36,12 +41,11 @@ mixin LocalizationsProvider on LocaleCodeAware {
'primary_contact': 'Primary Contact', 'primary_contact': 'Primary Contact',
'all_contacts': 'All Contacts', 'all_contacts': 'All Contacts',
'insert_below': 'Insert Below', 'insert_below': 'Insert Below',
'aged_receivable_detailed_report': 'Aged Receivable Detailed Report', 'ar_detailed': 'Accounts Receivable Detailed',
'aged_receivable_summary_report': 'Aged Receivable Summary Report', 'ar_summary': 'Accounts Receivable Summary',
'client_balance_report': 'Client Balance Report', 'client_sales': 'Client Sales',
'client_sales_report': 'Client Sales Report', 'tax_summary': 'Tax Summary',
'tax_summary_report': 'Tax Summary Report', 'user_sales': 'User Sales',
'user_sales_report': 'User Sales Report',
'run_template': 'Run Template', 'run_template': 'Run Template',
'task_extension_banner': 'task_extension_banner':
'Install the Chrome extension to manage tasks in your browser', 'Install the Chrome extension to manage tasks in your browser',
@ -114239,12 +114243,10 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues['en']!['nordigen_help']!; _localizedValues['en']!['nordigen_help']!;
String get host => String get host =>
_localizedValues[localeCode]!['host'] ?? _localizedValues[localeCode]!['host'] ?? _localizedValues['en']!['host']!;
_localizedValues['en']!['host']!;
String get port => String get port =>
_localizedValues[localeCode]!['port'] ?? _localizedValues[localeCode]!['port'] ?? _localizedValues['en']!['port']!;
_localizedValues['en']!['port']!;
String get encryption => String get encryption =>
_localizedValues[localeCode]!['encryption'] ?? _localizedValues[localeCode]!['encryption'] ??
@ -114262,6 +114264,10 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]!['username'] ?? _localizedValues[localeCode]!['username'] ??
_localizedValues['en']!['username']!; _localizedValues['en']!['username']!;
String get emailReport =>
_localizedValues[localeCode]!['email_report'] ??
_localizedValues['en']!['email_report']!;
// STARTER: lang field - do not remove comment // STARTER: lang field - do not remove comment
String lookup(String? key) { String lookup(String? key) {

View File

@ -136,4 +136,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 8d40c19d3cbdb380d870685c3a564c989f1efa52 PODFILE CHECKSUM: 8d40c19d3cbdb380d870685c3a564c989f1efa52
COCOAPODS: 1.14.3 COCOAPODS: 1.11.3