From 41c3d543391058ccb529198e21bdec25f53700e5 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 30 Jan 2024 13:57:33 +0200 Subject: [PATCH 1/4] Improve client portal buttons with empty client --- lib/ui/app/portal_links.dart | 24 +------------------ lib/ui/client/view/client_view_fullwidth.dart | 2 +- lib/ui/vendor/view/vendor_view_fullwidth.dart | 2 +- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/lib/ui/app/portal_links.dart b/lib/ui/app/portal_links.dart index 524ec357a7f..340c86c189c 100644 --- a/lib/ui/app/portal_links.dart +++ b/lib/ui/app/portal_links.dart @@ -1,15 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_redux/flutter_redux.dart'; import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'package:invoiceninja_flutter/data/models/client_model.dart'; -import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/ui/app/icon_text.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:url_launcher/url_launcher.dart'; enum PortalLinkStyle { - icons, buttons, dropdown, } @@ -30,9 +27,6 @@ class PortalLinks extends StatelessWidget { @override Widget build(BuildContext context) { - final store = StoreProvider.of(context); - final state = store.state; - final prefState = state.prefState; final localization = AppLocalization.of(context); var viewLinkWithHash = viewLink; @@ -49,23 +43,7 @@ class PortalLinks extends StatelessWidget { showToast(localization!.copiedToClipboard.replaceFirst(':value ', '')); }; - if (style == PortalLinkStyle.icons) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - IconButton( - onPressed: viewLinkPressed, - icon: Icon(Icons.open_in_new), - tooltip: prefState.enableTooltips ? localization!.viewPortal : '', - ), - IconButton( - onPressed: copyLinkPressed, - icon: Icon(Icons.copy), - tooltip: prefState.enableTooltips ? localization!.copyLink : '', - ), - ], - ); - } else if (style == PortalLinkStyle.dropdown) { + if (style == PortalLinkStyle.dropdown) { return PopupMenuButton( itemBuilder: (BuildContext context) => [ PopupMenuItem( diff --git a/lib/ui/client/view/client_view_fullwidth.dart b/lib/ui/client/view/client_view_fullwidth.dart index e09a1a89149..c9f9e5f1e9b 100644 --- a/lib/ui/client/view/client_view_fullwidth.dart +++ b/lib/ui/client/view/client_view_fullwidth.dart @@ -393,7 +393,7 @@ class _ClientViewFullwidthState extends State viewLink: contact.silentLink, copyLink: contact.link, client: client, - style: PortalLinkStyle.icons, + style: PortalLinkStyle.buttons, ), SizedBox(height: 16), ] else diff --git a/lib/ui/vendor/view/vendor_view_fullwidth.dart b/lib/ui/vendor/view/vendor_view_fullwidth.dart index 7faaf4c87a0..f233fdfbe9d 100644 --- a/lib/ui/vendor/view/vendor_view_fullwidth.dart +++ b/lib/ui/vendor/view/vendor_view_fullwidth.dart @@ -299,7 +299,7 @@ class _VendorViewFullwidthState extends State viewLink: contact.silentLink, copyLink: contact.link, client: null, - style: PortalLinkStyle.icons, + style: PortalLinkStyle.buttons, ), SizedBox(height: 16), ] else From 6a6b0fb665292191e77cb0582fed29fb5eb89728 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 30 Jan 2024 15:47:53 +0200 Subject: [PATCH 2/4] =?UTF-8?q?Don=E2=80=99t=20allow=20creating=20an=20emp?= =?UTF-8?q?ty=20payment=20if=20client=20initiated=20payments=20is=20disabl?= =?UTF-8?q?ed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ui/payment/edit/payment_edit_vm.dart | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/ui/payment/edit/payment_edit_vm.dart b/lib/ui/payment/edit/payment_edit_vm.dart index d81488a2b18..37d2c5a44f3 100644 --- a/lib/ui/payment/edit/payment_edit_vm.dart +++ b/lib/ui/payment/edit/payment_edit_vm.dart @@ -80,7 +80,7 @@ class PaymentEditVM { onSavePressed: (BuildContext context) { Debouncer.runOnComplete(() { final payment = store.state.paymentUIState.editing!; - final localization = navigatorKey.localization; + final localization = navigatorKey.localization!; final navigator = navigatorKey.currentState; double amount = 0; payment.invoices.forEach((invoice) => amount += invoice.amount); @@ -89,17 +89,27 @@ class PaymentEditVM { showDialog( context: navigatorKey.currentContext!, builder: (BuildContext context) { - return ErrorDialog(localization!.creditPaymentError); + return ErrorDialog(localization.creditPaymentError); + }); + return null; + } else if (!state.company.enableApplyingPayments && + payment.invoices.isEmpty && + payment.credits.isEmpty) { + showDialog( + context: navigatorKey.currentContext!, + builder: (BuildContext context) { + return ErrorDialog(localization.pleaseSelectAnInvoice); }); return null; } + final Completer completer = Completer(); store.dispatch( SavePaymentRequest(completer: completer, payment: payment)); return completer.future.then((savedPayment) { showToast(payment.isNew - ? localization!.createdPayment - : localization!.updatedPayment); + ? localization.createdPayment + : localization.updatedPayment); if (state.prefState.isMobile) { store.dispatch(UpdateCurrentRoute(PaymentViewScreen.route)); if (payment.isNew) { From ce862942ea808cbe7c29ea8fb226e0c8fdf87917 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 30 Jan 2024 15:49:57 +0200 Subject: [PATCH 3/4] =?UTF-8?q?Don=E2=80=99t=20allow=20creating=20an=20emp?= =?UTF-8?q?ty=20payment=20if=20client=20initiated=20payments=20is=20disabl?= =?UTF-8?q?ed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ui/payment/edit/payment_edit_vm.dart | 3 ++- lib/utils/i18n.dart | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ui/payment/edit/payment_edit_vm.dart b/lib/ui/payment/edit/payment_edit_vm.dart index 37d2c5a44f3..f25f7034e50 100644 --- a/lib/ui/payment/edit/payment_edit_vm.dart +++ b/lib/ui/payment/edit/payment_edit_vm.dart @@ -98,7 +98,8 @@ class PaymentEditVM { showDialog( context: navigatorKey.currentContext!, builder: (BuildContext context) { - return ErrorDialog(localization.pleaseSelectAnInvoice); + return ErrorDialog( + localization.pleaseSelectAnInvoiceOrCredit); }); return null; } diff --git a/lib/utils/i18n.dart b/lib/utils/i18n.dart index b5a58126554..1364615caf1 100644 --- a/lib/utils/i18n.dart +++ b/lib/utils/i18n.dart @@ -18,6 +18,8 @@ mixin LocalizationsProvider on LocaleCodeAware { static final Map> _localizedValues = { 'en': { // STARTER: lang key - do not remove comment + 'please_select_an_invoice_or_credit': + 'Please select an invoice or credit', 'mobile_version': 'Mobile Version', 'venmo': 'Venmo', 'mercado_pago': 'Mercado Pago', @@ -114273,6 +114275,10 @@ mixin LocalizationsProvider on LocaleCodeAware { _localizedValues[localeCode]!['mobile_version'] ?? _localizedValues['en']!['mobile_version']!; + String get pleaseSelectAnInvoiceOrCredit => + _localizedValues[localeCode]!['please_select_an_invoice_or_credit'] ?? + _localizedValues['en']!['please_select_an_invoice_or_credit']!; + // STARTER: lang field - do not remove comment String lookup(String? key) { From 900ddf5c4fe4ec6d7897bbcd86991c253d5ee692 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 30 Jan 2024 18:15:00 +0200 Subject: [PATCH 4/4] Profit loss report is doesn't reflect converted currencies #620 --- lib/data/models/payment_model.dart | 4 ++++ lib/ui/reports/profit_loss_report.dart | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/data/models/payment_model.dart b/lib/data/models/payment_model.dart index 678d5c8c48c..fe786bb5db0 100644 --- a/lib/data/models/payment_model.dart +++ b/lib/data/models/payment_model.dart @@ -501,6 +501,10 @@ abstract class PaymentEntity extends Object bool get isOnline => companyGatewayId.isNotEmpty; + double get convertedExchangeRate => exchangeRate == 0 ? 1 : exchangeRate; + + double get convertedAmount => completedAmount * convertedExchangeRate; + bool get isCompletedOrPartiallyRefunded => [ kPaymentStatusCompleted, kPaymentStatusPartiallyRefunded diff --git a/lib/ui/reports/profit_loss_report.dart b/lib/ui/reports/profit_loss_report.dart index 2a4f6bbd99a..a0d70811480 100644 --- a/lib/ui/reports/profit_loss_report.dart +++ b/lib/ui/reports/profit_loss_report.dart @@ -36,6 +36,7 @@ enum ProfitAndLossReportFields { currency, transaction_reference, record_state, + converted_amount, } var memoizedProfitAndLossReport = memo9(( @@ -179,6 +180,9 @@ ReportResult profitAndLossReport( value = AppLocalization.of(navigatorKey.currentContext!)! .lookup(payment.entityState); break; + case ProfitAndLossReportFields.converted_amount: + value = payment.convertedAmount; + break; } if (!ReportResult.matchField( @@ -194,6 +198,9 @@ ReportResult profitAndLossReport( row.add(payment.getReportEntityType()); } else if (value.runtimeType == bool) { row.add(payment.getReportBool(value: value)); + } else if (column == ProfitAndLossReportFields.converted_amount) { + row.add(payment.getReportDouble( + value: value, currencyId: userCompany.company.currencyId)); } else if (value.runtimeType == double || value.runtimeType == int) { row.add(payment.getReportDouble( value: value, currencyId: client.currencyId)); @@ -286,6 +293,9 @@ ReportResult profitAndLossReport( value = AppLocalization.of(navigatorKey.currentContext!)! .lookup(expense.entityState); break; + case ProfitAndLossReportFields.converted_amount: + value = expense.convertedAmount; + break; } if (!ReportResult.matchField( @@ -301,6 +311,9 @@ ReportResult profitAndLossReport( row.add(expense.getReportEntityType()); } else if (value.runtimeType == bool) { row.add(expense.getReportBool(value: value)); + } else if (column == ProfitAndLossReportFields.converted_amount) { + row.add(expense.getReportDouble( + value: value, currencyId: userCompany.company.currencyId)); } else if (value.runtimeType == double || value.runtimeType == int) { row.add(expense.getReportDouble( value: value, currencyId: expense.currencyId));