585 lines
14 KiB
Dart
585 lines
14 KiB
Dart
import 'dart:async';
|
|
import 'package:built_collection/built_collection.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_redux/flutter_redux.dart';
|
|
import 'package:invoiceninja_flutter/data/models/models.dart';
|
|
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
|
import 'package:invoiceninja_flutter/utils/completers.dart';
|
|
import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
|
import 'package:invoiceninja_flutter/utils/pdf.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
class ViewInvoiceList extends AbstractNavigatorAction
|
|
implements PersistUI, StopLoading {
|
|
ViewInvoiceList({@required NavigatorState navigator, this.force = false})
|
|
: super(navigator: navigator);
|
|
|
|
final bool force;
|
|
}
|
|
|
|
class ViewInvoice extends AbstractNavigatorAction
|
|
implements PersistUI, PersistPrefs {
|
|
ViewInvoice(
|
|
{this.invoiceId, @required NavigatorState navigator, this.force = false})
|
|
: super(navigator: navigator);
|
|
|
|
final String invoiceId;
|
|
final bool force;
|
|
}
|
|
|
|
class EditInvoice extends AbstractNavigatorAction
|
|
implements PersistUI, PersistPrefs {
|
|
EditInvoice({
|
|
this.invoice,
|
|
@required NavigatorState navigator,
|
|
this.completer,
|
|
this.invoiceItemIndex,
|
|
this.force = false,
|
|
}) : super(navigator: navigator);
|
|
|
|
final InvoiceEntity invoice;
|
|
final int invoiceItemIndex;
|
|
final Completer completer;
|
|
final bool force;
|
|
}
|
|
|
|
class ShowEmailInvoice {
|
|
ShowEmailInvoice({this.invoice, this.context, this.completer});
|
|
|
|
final InvoiceEntity invoice;
|
|
final BuildContext context;
|
|
final Completer completer;
|
|
}
|
|
|
|
class EditInvoiceItem implements PersistUI {
|
|
EditInvoiceItem([this.invoiceItemIndex]);
|
|
|
|
final int invoiceItemIndex;
|
|
}
|
|
|
|
class UpdateInvoice implements PersistUI {
|
|
UpdateInvoice(this.invoice);
|
|
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class UpdateInvoiceClient implements PersistUI {
|
|
UpdateInvoiceClient({this.client});
|
|
|
|
final ClientEntity client;
|
|
}
|
|
|
|
class LoadInvoice {
|
|
LoadInvoice({this.completer, this.invoiceId});
|
|
|
|
final Completer completer;
|
|
final String invoiceId;
|
|
}
|
|
|
|
class LoadInvoices {
|
|
LoadInvoices({this.completer, this.force = false});
|
|
|
|
final Completer completer;
|
|
final bool force;
|
|
}
|
|
|
|
class LoadInvoiceRequest implements StartLoading {}
|
|
|
|
class LoadInvoiceFailure implements StopLoading {
|
|
LoadInvoiceFailure(this.error);
|
|
|
|
final dynamic error;
|
|
|
|
@override
|
|
String toString() {
|
|
return 'LoadInvoiceFailure{error: $error}';
|
|
}
|
|
}
|
|
|
|
class LoadInvoiceSuccess implements StopLoading, PersistData {
|
|
LoadInvoiceSuccess(this.invoice);
|
|
|
|
final InvoiceEntity invoice;
|
|
|
|
@override
|
|
String toString() {
|
|
return 'LoadInvoiceSuccess{invoice: $invoice}';
|
|
}
|
|
}
|
|
|
|
class LoadInvoicesRequest implements StartLoading {}
|
|
|
|
class LoadInvoicesFailure implements StopLoading {
|
|
LoadInvoicesFailure(this.error);
|
|
|
|
final dynamic error;
|
|
|
|
@override
|
|
String toString() {
|
|
return 'LoadInvoicesFailure{error: $error}';
|
|
}
|
|
}
|
|
|
|
class LoadInvoicesSuccess implements StopLoading, PersistData {
|
|
LoadInvoicesSuccess(this.invoices);
|
|
|
|
final BuiltList<InvoiceEntity> invoices;
|
|
|
|
@override
|
|
String toString() {
|
|
return 'LoadInvoicesSuccess{invoices: $invoices}';
|
|
}
|
|
}
|
|
|
|
class AddInvoiceContact implements PersistUI {
|
|
AddInvoiceContact({this.contact, this.invitation});
|
|
|
|
final ContactEntity contact;
|
|
final InvitationEntity invitation;
|
|
}
|
|
|
|
class RemoveInvoiceContact implements PersistUI {
|
|
RemoveInvoiceContact({this.invitation});
|
|
|
|
final InvitationEntity invitation;
|
|
}
|
|
|
|
class AddInvoiceItem implements PersistUI {
|
|
AddInvoiceItem({this.invoiceItem});
|
|
|
|
final InvoiceItemEntity invoiceItem;
|
|
}
|
|
|
|
class AddInvoiceItems implements PersistUI {
|
|
AddInvoiceItems(this.lineItems);
|
|
|
|
final List<InvoiceItemEntity> lineItems;
|
|
}
|
|
|
|
class UpdateInvoiceItem implements PersistUI {
|
|
UpdateInvoiceItem({this.index, this.invoiceItem});
|
|
|
|
final int index;
|
|
final InvoiceItemEntity invoiceItem;
|
|
}
|
|
|
|
class DeleteInvoiceItem implements PersistUI {
|
|
DeleteInvoiceItem(this.index);
|
|
|
|
final int index;
|
|
}
|
|
|
|
class SaveInvoiceRequest implements StartSaving {
|
|
SaveInvoiceRequest({this.completer, this.invoice});
|
|
|
|
final Completer completer;
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class SaveInvoiceSuccess implements StopSaving, PersistData, PersistUI {
|
|
SaveInvoiceSuccess(this.invoice);
|
|
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class AddInvoiceSuccess implements StopSaving, PersistData, PersistUI {
|
|
AddInvoiceSuccess(this.invoice);
|
|
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class SaveInvoiceFailure implements StopSaving {
|
|
SaveInvoiceFailure(this.error);
|
|
|
|
final Object error;
|
|
}
|
|
|
|
class EmailInvoiceRequest implements StartSaving {
|
|
EmailInvoiceRequest(
|
|
{this.completer, this.invoiceId, this.template, this.subject, this.body});
|
|
|
|
final Completer completer;
|
|
final String invoiceId;
|
|
final EmailTemplate template;
|
|
final String subject;
|
|
final String body;
|
|
}
|
|
|
|
class EmailInvoiceSuccess implements StopSaving, PersistData {
|
|
EmailInvoiceSuccess({@required this.invoice});
|
|
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class EmailInvoiceFailure implements StopSaving {
|
|
EmailInvoiceFailure(this.error);
|
|
|
|
final dynamic error;
|
|
}
|
|
|
|
class MarkInvoicesSentRequest implements StartSaving {
|
|
MarkInvoicesSentRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class MarkInvoicesSentSuccess implements StopSaving, PersistData {
|
|
MarkInvoicesSentSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class MarkInvoicesSentFailure implements StopSaving {
|
|
MarkInvoicesSentFailure(this.error);
|
|
|
|
final dynamic error;
|
|
}
|
|
|
|
class MarkInvoicesPaidRequest implements StartSaving {
|
|
MarkInvoicesPaidRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class MarkInvoicesPaidSuccess implements StopSaving, PersistData {
|
|
MarkInvoicesPaidSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class MarkInvoicesPaidFailure implements StopSaving {
|
|
MarkInvoicesPaidFailure(this.error);
|
|
|
|
final dynamic error;
|
|
}
|
|
|
|
class ReverseInvoicesRequest implements StartSaving {
|
|
ReverseInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class ReverseInvoicesSuccess implements StopSaving, PersistData {
|
|
ReverseInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class ReverseInvoicesFailure implements StopSaving {
|
|
ReverseInvoicesFailure(this.error);
|
|
|
|
final Object error;
|
|
}
|
|
|
|
class CancelInvoicesRequest implements StartSaving {
|
|
CancelInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class CancelInvoicesSuccess implements StopSaving, PersistData {
|
|
CancelInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class CancelInvoicesFailure implements StopSaving {
|
|
CancelInvoicesFailure(this.error);
|
|
|
|
final Object error;
|
|
}
|
|
|
|
class ArchiveInvoicesRequest implements StartSaving {
|
|
ArchiveInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class ArchiveInvoicesSuccess implements StopSaving, PersistData {
|
|
ArchiveInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class ArchiveInvoicesFailure implements StopSaving {
|
|
ArchiveInvoicesFailure(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class DeleteInvoicesRequest implements StartSaving {
|
|
DeleteInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class DeleteInvoicesSuccess implements StopSaving, PersistData {
|
|
DeleteInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class DeleteInvoicesFailure implements StopSaving {
|
|
DeleteInvoicesFailure(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class RestoreInvoicesRequest implements StartSaving {
|
|
RestoreInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class RestoreInvoicesSuccess implements StopSaving, PersistData {
|
|
RestoreInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class RestoreInvoicesFailure implements StopSaving {
|
|
RestoreInvoicesFailure(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class FilterInvoices implements PersistUI {
|
|
FilterInvoices(this.filter);
|
|
|
|
final String filter;
|
|
}
|
|
|
|
class SortInvoices implements PersistUI {
|
|
SortInvoices(this.field);
|
|
|
|
final String field;
|
|
}
|
|
|
|
class FilterInvoicesByState implements PersistUI {
|
|
FilterInvoicesByState(this.state);
|
|
|
|
final EntityState state;
|
|
}
|
|
|
|
class FilterInvoicesByStatus implements PersistUI {
|
|
FilterInvoicesByStatus(this.status);
|
|
|
|
final EntityStatus status;
|
|
}
|
|
|
|
class FilterInvoiceDropdown {
|
|
FilterInvoiceDropdown(this.filter);
|
|
|
|
final String filter;
|
|
}
|
|
|
|
class FilterInvoicesByCustom1 implements PersistUI {
|
|
FilterInvoicesByCustom1(this.value);
|
|
|
|
final String value;
|
|
}
|
|
|
|
class FilterInvoicesByCustom2 implements PersistUI {
|
|
FilterInvoicesByCustom2(this.value);
|
|
|
|
final String value;
|
|
}
|
|
|
|
class FilterInvoicesByCustom3 implements PersistUI {
|
|
FilterInvoicesByCustom3(this.value);
|
|
|
|
final String value;
|
|
}
|
|
|
|
class FilterInvoicesByCustom4 implements PersistUI {
|
|
FilterInvoicesByCustom4(this.value);
|
|
|
|
final String value;
|
|
}
|
|
|
|
class StartInvoiceMultiselect {}
|
|
|
|
class AddToInvoiceMultiselect {
|
|
AddToInvoiceMultiselect({@required this.entity});
|
|
|
|
final BaseEntity entity;
|
|
}
|
|
|
|
class RemoveFromInvoiceMultiselect {
|
|
RemoveFromInvoiceMultiselect({@required this.entity});
|
|
|
|
final BaseEntity entity;
|
|
}
|
|
|
|
class ClearInvoiceMultiselect {}
|
|
|
|
class SaveInvoiceDocumentRequest implements StartSaving {
|
|
SaveInvoiceDocumentRequest({
|
|
@required this.completer,
|
|
@required this.filePath,
|
|
@required this.invoice,
|
|
});
|
|
|
|
final Completer completer;
|
|
final String filePath;
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class SaveInvoiceDocumentSuccess implements StopSaving, PersistData, PersistUI {
|
|
SaveInvoiceDocumentSuccess(this.document);
|
|
|
|
final DocumentEntity document;
|
|
}
|
|
|
|
class SaveInvoiceDocumentFailure implements StopSaving {
|
|
SaveInvoiceDocumentFailure(this.error);
|
|
|
|
final Object error;
|
|
}
|
|
|
|
void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
|
|
EntityAction action) async {
|
|
if (invoices.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
final store = StoreProvider.of<AppState>(context);
|
|
final state = store.state;
|
|
final localization = AppLocalization.of(context);
|
|
final invoice = invoices.first as InvoiceEntity;
|
|
final invoiceIds = invoices.map((invoice) => invoice.id).toList();
|
|
|
|
switch (action) {
|
|
case EntityAction.edit:
|
|
editEntity(context: context, entity: invoice);
|
|
break;
|
|
case EntityAction.viewPdf:
|
|
viewPdf(invoice, context);
|
|
break;
|
|
case EntityAction.clientPortal:
|
|
if (await canLaunch(invoice.invitationSilentLink)) {
|
|
await launch(invoice.invitationSilentLink,
|
|
forceSafariVC: false, forceWebView: false);
|
|
}
|
|
break;
|
|
case EntityAction.markSent:
|
|
store.dispatch(MarkInvoicesSentRequest(
|
|
snackBarCompleter<Null>(
|
|
context,
|
|
invoiceIds.length == 1
|
|
? localization.markedInvoiceAsSent
|
|
: localization.markedInvoicesAsSent),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.reverse:
|
|
store.dispatch(ReverseInvoicesRequest(
|
|
snackBarCompleter<Null>(
|
|
context,
|
|
invoiceIds.length == 1
|
|
? localization.reversedInvoice
|
|
: localization.reversedInvoices),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.cancel:
|
|
store.dispatch(CancelInvoicesRequest(
|
|
snackBarCompleter<Null>(
|
|
context,
|
|
invoiceIds.length == 1
|
|
? localization.cancelledInvoice
|
|
: localization.cancelledInvoices),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.markPaid:
|
|
store.dispatch(MarkInvoicesPaidRequest(
|
|
snackBarCompleter<Null>(
|
|
context,
|
|
invoiceIds.length == 1
|
|
? localization.markedInvoiceAsPaid
|
|
: localization.markedInvoicesAsPaid),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.emailInvoice:
|
|
final client = state.clientState.get(invoice.clientId);
|
|
if (!client.hasEmailAddress) {
|
|
showMessageDialog(
|
|
context: context, message: localization.clientEmailNotSet);
|
|
return;
|
|
}
|
|
store.dispatch(ShowEmailInvoice(
|
|
completer:
|
|
snackBarCompleter<Null>(context, localization.emailedInvoice),
|
|
invoice: invoice,
|
|
context: context));
|
|
break;
|
|
case EntityAction.cloneToInvoice:
|
|
createEntity(context: context, entity: invoice.clone);
|
|
break;
|
|
case EntityAction.cloneToQuote:
|
|
createEntity(
|
|
context: context,
|
|
entity:
|
|
invoice.clone.rebuild((b) => b..entityType = EntityType.quote));
|
|
break;
|
|
case EntityAction.cloneToCredit:
|
|
createEntity(
|
|
context: context,
|
|
entity:
|
|
invoice.clone.rebuild((b) => b..entityType = EntityType.credit));
|
|
break;
|
|
case EntityAction.newPayment:
|
|
createEntity(
|
|
context: context,
|
|
entity: PaymentEntity(state: state).rebuild((b) => b
|
|
..isForInvoice = true
|
|
..clientId = invoice.clientId
|
|
..invoices.addAll(invoices
|
|
.map((invoice) => PaymentableEntity.fromInvoice(invoice))
|
|
.toList())),
|
|
filterEntity: state.clientState.map[invoice.clientId],
|
|
);
|
|
break;
|
|
case EntityAction.restore:
|
|
store.dispatch(RestoreInvoicesRequest(
|
|
snackBarCompleter<Null>(context, localization.restoredInvoice),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.archive:
|
|
store.dispatch(ArchiveInvoicesRequest(
|
|
snackBarCompleter<Null>(context, localization.archivedInvoice),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.delete:
|
|
store.dispatch(DeleteInvoicesRequest(
|
|
snackBarCompleter<Null>(context, localization.deletedInvoice),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.toggleMultiselect:
|
|
if (!store.state.invoiceListState.isInMultiselect()) {
|
|
store.dispatch(StartInvoiceMultiselect());
|
|
}
|
|
|
|
if (invoices.isEmpty) {
|
|
break;
|
|
}
|
|
|
|
for (final invoice in invoices) {
|
|
if (!store.state.invoiceListState.isSelected(invoice.id)) {
|
|
store.dispatch(AddToInvoiceMultiselect(entity: invoice));
|
|
} else {
|
|
store.dispatch(RemoveFromInvoiceMultiselect(entity: invoice));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|