902 lines
25 KiB
Dart
902 lines
25 KiB
Dart
// Dart imports:
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
// Flutter imports:
|
|
import 'package:flutter/material.dart';
|
|
|
|
// Package imports:
|
|
import 'package:built_collection/built_collection.dart';
|
|
import 'package:flutter_redux/flutter_redux.dart';
|
|
import 'package:http/http.dart';
|
|
import 'package:invoiceninja_flutter/constants.dart';
|
|
import 'package:invoiceninja_flutter/main_app.dart';
|
|
import 'package:invoiceninja_flutter/redux/client/client_selectors.dart';
|
|
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
|
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
|
import 'package:invoiceninja_flutter/utils/files.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
// Project imports:
|
|
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/redux/design/design_selectors.dart';
|
|
import 'package:invoiceninja_flutter/ui/app/entities/entity_actions_dialog.dart';
|
|
import 'package:invoiceninja_flutter/utils/completers.dart';
|
|
import 'package:invoiceninja_flutter/utils/dialogs.dart';
|
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:invoiceninja_flutter/data/web_client.dart';
|
|
import 'package:printing/printing.dart';
|
|
|
|
class ViewInvoiceList implements PersistUI {
|
|
ViewInvoiceList({
|
|
this.force = false,
|
|
this.page = 0,
|
|
});
|
|
|
|
final bool force;
|
|
final int? page;
|
|
}
|
|
|
|
class ViewInvoice implements PersistUI, PersistPrefs {
|
|
ViewInvoice({this.invoiceId, this.force = false});
|
|
|
|
final String? invoiceId;
|
|
final bool force;
|
|
}
|
|
|
|
class EditInvoice implements PersistUI, PersistPrefs {
|
|
EditInvoice({
|
|
this.invoice,
|
|
this.completer,
|
|
this.invoiceItemIndex,
|
|
this.force = false,
|
|
});
|
|
|
|
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 ShowPdfInvoice {
|
|
ShowPdfInvoice({this.invoice, this.context, this.activityId});
|
|
|
|
final InvoiceEntity? invoice;
|
|
final BuildContext? context;
|
|
final String? activityId;
|
|
}
|
|
|
|
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.page = 1});
|
|
|
|
final Completer? completer;
|
|
final int page;
|
|
}
|
|
|
|
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 {
|
|
LoadInvoicesSuccess(this.invoices);
|
|
|
|
final BuiltList<InvoiceEntity> invoices;
|
|
|
|
@override
|
|
String toString() {
|
|
return 'LoadInvoicesSuccess{invoices: $invoices}';
|
|
}
|
|
}
|
|
|
|
class AddInvoiceContact implements PersistUI {
|
|
AddInvoiceContact({this.contact, this.invitation});
|
|
|
|
final ClientContactEntity? 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 MoveInvoiceItem implements PersistUI {
|
|
MoveInvoiceItem({
|
|
this.oldIndex,
|
|
this.newIndex,
|
|
});
|
|
|
|
final int? oldIndex;
|
|
final int? newIndex;
|
|
}
|
|
|
|
class AddInvoiceItems implements PersistUI {
|
|
AddInvoiceItems(this.lineItems);
|
|
|
|
final List<InvoiceItemEntity> lineItems;
|
|
}
|
|
|
|
class UpdateInvoiceItem implements PersistUI {
|
|
UpdateInvoiceItem({
|
|
required this.index,
|
|
required this.invoiceItem,
|
|
});
|
|
|
|
final int index;
|
|
final InvoiceItemEntity invoiceItem;
|
|
}
|
|
|
|
class DeleteInvoiceItem implements PersistUI {
|
|
DeleteInvoiceItem(this.index);
|
|
|
|
final int index;
|
|
}
|
|
|
|
class SaveInvoiceRequest implements StartSaving {
|
|
SaveInvoiceRequest({
|
|
required this.completer,
|
|
required this.invoice,
|
|
required this.entityAction,
|
|
});
|
|
|
|
final Completer completer;
|
|
final InvoiceEntity invoice;
|
|
final EntityAction? entityAction;
|
|
}
|
|
|
|
class SaveInvoiceSuccess implements StopSaving, PersistUI {
|
|
SaveInvoiceSuccess(this.invoice);
|
|
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class AddInvoiceSuccess implements StopSaving, PersistUI {
|
|
AddInvoiceSuccess(this.invoice);
|
|
|
|
final InvoiceEntity invoice;
|
|
}
|
|
|
|
class SaveInvoiceFailure implements StopSaving {
|
|
SaveInvoiceFailure(this.error);
|
|
|
|
final Object error;
|
|
}
|
|
|
|
class EmailInvoiceRequest implements StartSaving {
|
|
EmailInvoiceRequest({
|
|
required this.completer,
|
|
required this.invoiceId,
|
|
required this.template,
|
|
required this.subject,
|
|
required this.body,
|
|
required this.ccEmail,
|
|
});
|
|
|
|
final Completer completer;
|
|
final String invoiceId;
|
|
final EmailTemplate template;
|
|
final String subject;
|
|
final String body;
|
|
final String ccEmail;
|
|
}
|
|
|
|
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 BulkEmailInvoicesRequest implements StartSaving {
|
|
BulkEmailInvoicesRequest({this.completer, this.invoiceIds, this.template});
|
|
|
|
final Completer? completer;
|
|
final List<String>? invoiceIds;
|
|
final EmailTemplate? template;
|
|
}
|
|
|
|
class BulkEmailInvoicesSuccess implements StopSaving, PersistData {
|
|
BulkEmailInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class BulkEmailInvoicesFailure implements StopSaving {
|
|
BulkEmailInvoicesFailure(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 {
|
|
MarkInvoicesPaidSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class MarkInvoicesPaidFailure implements StopSaving {
|
|
MarkInvoicesPaidFailure(this.error);
|
|
|
|
final dynamic error;
|
|
}
|
|
|
|
class AutoBillInvoicesRequest implements StartSaving {
|
|
AutoBillInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class AutoBillInvoicesSuccess implements StopSaving {
|
|
AutoBillInvoicesSuccess(this.invoices);
|
|
|
|
final List<InvoiceEntity> invoices;
|
|
}
|
|
|
|
class AutoBillInvoicesFailure implements StopSaving {
|
|
AutoBillInvoicesFailure(this.error);
|
|
|
|
final dynamic error;
|
|
}
|
|
|
|
class CancelInvoicesRequest implements StartSaving {
|
|
CancelInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class CancelInvoicesSuccess implements StopSaving {
|
|
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 DownloadInvoicesRequest implements StartSaving {
|
|
DownloadInvoicesRequest(this.completer, this.invoiceIds);
|
|
|
|
final Completer completer;
|
|
final List<String> invoiceIds;
|
|
}
|
|
|
|
class DownloadInvoicesSuccess implements StopSaving {}
|
|
|
|
class DownloadInvoicesFailure implements StopSaving {
|
|
DownloadInvoicesFailure(this.error);
|
|
|
|
final Object error;
|
|
}
|
|
|
|
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, PersistPrefs {
|
|
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.isPrivate,
|
|
required this.completer,
|
|
required this.multipartFiles,
|
|
required this.invoice,
|
|
});
|
|
|
|
final bool? isPrivate;
|
|
final Completer completer;
|
|
final List<MultipartFile> multipartFiles;
|
|
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;
|
|
}
|
|
|
|
class UpdateInvoiceTab implements PersistUI {
|
|
UpdateInvoiceTab({this.tabIndex});
|
|
|
|
final int? tabIndex;
|
|
}
|
|
|
|
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();
|
|
final client = state.clientState.get(invoice.clientId);
|
|
|
|
switch (action) {
|
|
case EntityAction.edit:
|
|
editEntity(entity: invoice);
|
|
break;
|
|
case EntityAction.viewPdf:
|
|
store.dispatch(ShowPdfInvoice(invoice: invoice, context: context));
|
|
break;
|
|
case EntityAction.clientPortal:
|
|
var link = invoice.invitationSilentLink;
|
|
if (link.isNotEmpty) {
|
|
if (!link.contains('?')) {
|
|
link += '?';
|
|
}
|
|
link += '&client_hash=${client.clientHash}';
|
|
launchUrl(Uri.parse(link));
|
|
}
|
|
break;
|
|
case EntityAction.markSent:
|
|
store.dispatch(MarkInvoicesSentRequest(
|
|
snackBarCompleter<Null>(invoiceIds.length == 1
|
|
? localization!.markedInvoiceAsSent
|
|
: localization!.markedInvoicesAsSent),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.reverse:
|
|
final designId = getDesignIdForClientByEntity(
|
|
state: state,
|
|
clientId: invoice.clientId,
|
|
entityType: EntityType.credit);
|
|
createEntity(
|
|
entity: invoice.clone.rebuild((b) => b
|
|
..invoiceId = invoice.id
|
|
..entityType = EntityType.credit
|
|
..designId = designId));
|
|
break;
|
|
case EntityAction.cancelInvoice:
|
|
confirmCallback(
|
|
context: context,
|
|
message: localization!.cancelInvoice,
|
|
callback: (_) {
|
|
store.dispatch(CancelInvoicesRequest(
|
|
snackBarCompleter<Null>(invoiceIds.length == 1
|
|
? localization.cancelledInvoice
|
|
: localization.cancelledInvoices),
|
|
invoiceIds));
|
|
});
|
|
break;
|
|
case EntityAction.markPaid:
|
|
store.dispatch(MarkInvoicesPaidRequest(
|
|
snackBarCompleter<Null>(invoiceIds.length == 1
|
|
? localization!.markedInvoiceAsPaid
|
|
: localization!.markedInvoicesAsPaid),
|
|
invoiceIds));
|
|
break;
|
|
case EntityAction.autoBill:
|
|
confirmCallback(
|
|
context: context,
|
|
message: localization!.autoBill,
|
|
callback: (_) {
|
|
store.dispatch(AutoBillInvoicesRequest(
|
|
snackBarCompleter<Null>(invoiceIds.length == 1
|
|
? localization.autoBilledInvoice
|
|
: localization.autoBilledInvoices),
|
|
invoiceIds));
|
|
});
|
|
break;
|
|
case EntityAction.sendEmail:
|
|
case EntityAction.bulkSendEmail:
|
|
case EntityAction.schedule:
|
|
bool emailValid = true;
|
|
invoices.forEach((invoice) {
|
|
final client = state.clientState.get(
|
|
(invoice as InvoiceEntity).clientId,
|
|
);
|
|
if (!client.hasEmailAddress) {
|
|
emailValid = false;
|
|
}
|
|
});
|
|
if (!emailValid) {
|
|
showMessageDialog(
|
|
message: localization!.clientEmailNotSet,
|
|
secondaryActions: [
|
|
TextButton(
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
editEntity(entity: client);
|
|
},
|
|
child: Text(localization.editClient.toUpperCase()))
|
|
]);
|
|
return;
|
|
}
|
|
if (action == EntityAction.sendEmail) {
|
|
store.dispatch(ShowEmailInvoice(
|
|
completer: snackBarCompleter<Null>(localization!.emailedInvoice),
|
|
invoice: invoice,
|
|
context: context));
|
|
} else if (action == EntityAction.schedule) {
|
|
if (!state.isProPlan) {
|
|
showMessageDialog(
|
|
message: localization!.upgradeToPaidPlanToSchedule,
|
|
secondaryActions: [
|
|
TextButton(
|
|
onPressed: () {
|
|
store.dispatch(
|
|
ViewSettings(section: kSettingsAccountManagement));
|
|
Navigator.of(context).pop();
|
|
},
|
|
child: Text(localization.upgrade.toUpperCase())),
|
|
]);
|
|
return;
|
|
}
|
|
|
|
createEntity(
|
|
entity: ScheduleEntity(ScheduleEntity.TEMPLATE_EMAIL_RECORD)
|
|
.rebuild((b) => b
|
|
..parameters.entityType = EntityType.invoice.apiValue
|
|
..parameters.entityId = invoice.id));
|
|
} else {
|
|
final template = await showDialog<EmailTemplate>(
|
|
context: context,
|
|
builder: (context) {
|
|
final settings = getClientSettings(state, client);
|
|
final templates = {
|
|
EmailTemplate.invoice: localization!.initialEmail,
|
|
EmailTemplate.reminder1: localization.firstReminder,
|
|
EmailTemplate.reminder2: localization.secondReminder,
|
|
EmailTemplate.reminder3: localization.thirdReminder,
|
|
EmailTemplate.reminder_endless: localization.endlessReminder,
|
|
if ((settings.emailSubjectCustom1 ?? '').isNotEmpty)
|
|
EmailTemplate.custom1: localization.firstCustom,
|
|
if ((settings.emailSubjectCustom2 ?? '').isNotEmpty)
|
|
EmailTemplate.custom2: localization.secondCustom,
|
|
if ((settings.emailSubjectCustom3 ?? '').isNotEmpty)
|
|
EmailTemplate.custom3: localization.thirdCustom,
|
|
};
|
|
return SimpleDialog(
|
|
title: Text(
|
|
invoiceIds.length == 1
|
|
? localization.emailInvoice
|
|
: localization.emailCountInvoices
|
|
.replaceFirst(':count', '${invoiceIds.length}'),
|
|
),
|
|
children: templates.keys
|
|
.map((template) => SimpleDialogOption(
|
|
child: Text(templates[template]!),
|
|
onPressed: () {
|
|
Navigator.of(context).pop(template);
|
|
},
|
|
))
|
|
.toList(),
|
|
);
|
|
},
|
|
);
|
|
|
|
if (template != null) {
|
|
store.dispatch(BulkEmailInvoicesRequest(
|
|
completer: snackBarCompleter<Null>(invoiceIds.length == 1
|
|
? localization!.emailedInvoice
|
|
: localization!.emailedInvoices),
|
|
invoiceIds: invoiceIds,
|
|
template: template,
|
|
));
|
|
}
|
|
}
|
|
break;
|
|
case EntityAction.cloneToOther:
|
|
cloneToDialog(invoice: invoice);
|
|
break;
|
|
case EntityAction.clone:
|
|
case EntityAction.cloneToInvoice:
|
|
createEntity(entity: invoice.clone);
|
|
break;
|
|
case EntityAction.cloneToQuote:
|
|
final designId = getDesignIdForClientByEntity(
|
|
state: state,
|
|
clientId: invoice.clientId,
|
|
entityType: EntityType.quote);
|
|
createEntity(
|
|
entity: invoice.clone.rebuild((b) => b
|
|
..entityType = EntityType.quote
|
|
..designId = designId));
|
|
break;
|
|
case EntityAction.cloneToCredit:
|
|
final designId = getDesignIdForClientByEntity(
|
|
state: state,
|
|
clientId: invoice.clientId,
|
|
entityType: EntityType.credit);
|
|
createEntity(
|
|
entity: invoice.clone.rebuild((b) => b
|
|
..entityType = EntityType.credit
|
|
..designId = designId));
|
|
break;
|
|
case EntityAction.cloneToPurchaseOrder:
|
|
final designId = getDesignIdForVendorByEntity(
|
|
state: state,
|
|
vendorId: invoice.vendorId,
|
|
entityType: EntityType.purchaseOrder);
|
|
createEntity(
|
|
entity: invoice.clone
|
|
.rebuild((b) => b
|
|
..entityType = EntityType.purchaseOrder
|
|
..designId = designId)
|
|
.recreateInvitations(state));
|
|
break;
|
|
case EntityAction.cloneToRecurring:
|
|
createEntity(
|
|
entity: invoice.clone
|
|
.rebuild((b) => b..entityType = EntityType.recurringInvoice));
|
|
break;
|
|
case EntityAction.newPayment:
|
|
createEntity(
|
|
entity: PaymentEntity(state: state, client: client).rebuild((b) => b
|
|
..invoices.addAll(invoices
|
|
.where((invoice) => !(invoice as InvoiceEntity).isPaid)
|
|
.map((invoice) =>
|
|
PaymentableEntity.fromInvoice(invoice as InvoiceEntity))
|
|
.toList())),
|
|
filterEntity: client,
|
|
);
|
|
break;
|
|
case EntityAction.download:
|
|
store.dispatch(StartLoading());
|
|
await WebClient()
|
|
.get(invoice.invitationDownloadLink, state.token, rawResponse: true)
|
|
.then((response) {
|
|
store.dispatch(StopLoading());
|
|
saveDownloadedFile(response.bodyBytes,
|
|
localization!.invoice + '_' + invoice.number + '.pdf');
|
|
}).catchError((_) {
|
|
store.dispatch(StopLoading());
|
|
});
|
|
break;
|
|
case EntityAction.eInvoice:
|
|
store.dispatch(StartLoading());
|
|
await WebClient()
|
|
.get(invoice.invitationEInvoiceDownloadLink, state.token,
|
|
rawResponse: true)
|
|
.then((response) {
|
|
store.dispatch(StopLoading());
|
|
saveDownloadedFile(response.bodyBytes,
|
|
localization!.invoice + '_' + invoice.number + '.xml');
|
|
}).catchError((_) {
|
|
store.dispatch(StopLoading());
|
|
});
|
|
break;
|
|
case EntityAction.bulkDownload:
|
|
store.dispatch(DownloadInvoicesRequest(
|
|
snackBarCompleter<Null>(localization!.exportedData), invoiceIds));
|
|
break;
|
|
case EntityAction.restore:
|
|
final message = invoiceIds.length > 1
|
|
? localization!.restoredInvoices
|
|
.replaceFirst(':value', ':count')
|
|
.replaceFirst(':count', invoiceIds.length.toString())
|
|
: localization!.restoredInvoice;
|
|
store.dispatch(
|
|
RestoreInvoicesRequest(snackBarCompleter<Null>(message), invoiceIds));
|
|
break;
|
|
case EntityAction.archive:
|
|
final message = invoiceIds.length > 1
|
|
? localization!.archivedInvoices
|
|
.replaceFirst(':value', ':count')
|
|
.replaceFirst(':count', invoiceIds.length.toString())
|
|
: localization!.archivedInvoice;
|
|
store.dispatch(
|
|
ArchiveInvoicesRequest(snackBarCompleter<Null>(message), invoiceIds));
|
|
break;
|
|
case EntityAction.delete:
|
|
final message = invoiceIds.length > 1
|
|
? localization!.deletedInvoices
|
|
.replaceFirst(':value', ':count')
|
|
.replaceFirst(':count', invoiceIds.length.toString())
|
|
: localization!.deletedInvoice;
|
|
store.dispatch(
|
|
DeleteInvoicesRequest(snackBarCompleter<Null>(message), invoiceIds));
|
|
break;
|
|
case EntityAction.toggleMultiselect:
|
|
if (!store.state.invoiceListState.isInMultiselect()) {
|
|
store.dispatch(StartInvoiceMultiselect());
|
|
}
|
|
for (final invoice in invoices) {
|
|
if (!store.state.invoiceListState.isSelected(invoice.id)) {
|
|
store.dispatch(AddToInvoiceMultiselect(entity: invoice));
|
|
} else {
|
|
store.dispatch(RemoveFromInvoiceMultiselect(entity: invoice));
|
|
}
|
|
}
|
|
break;
|
|
case EntityAction.printPdf:
|
|
final invitation = invoice.invitations.first;
|
|
final url = invitation.downloadLink;
|
|
store.dispatch(StartSaving());
|
|
final http.Response? response =
|
|
await WebClient().get(url, state.token, rawResponse: true);
|
|
store.dispatch(StopSaving());
|
|
await Printing.layoutPdf(onLayout: (_) => response!.bodyBytes);
|
|
break;
|
|
case EntityAction.bulkPrint:
|
|
store.dispatch(StartSaving());
|
|
final url = state.credentials.url + '/invoices/bulk';
|
|
final data = json.encode(
|
|
{'ids': invoiceIds, 'action': EntityAction.bulkPrint.toApiParam()});
|
|
final http.Response? response = await WebClient()
|
|
.post(url, state.credentials.token, data: data, rawResponse: true);
|
|
store.dispatch(StopSaving());
|
|
await Printing.layoutPdf(onLayout: (_) => response!.bodyBytes);
|
|
break;
|
|
case EntityAction.runTemplate:
|
|
showDialog<void>(
|
|
context: navigatorKey.currentContext!,
|
|
barrierDismissible: false,
|
|
builder: (context) => RunTemplateDialog(
|
|
entityType: EntityType.invoice,
|
|
entities: invoices,
|
|
),
|
|
);
|
|
break;
|
|
case EntityAction.more:
|
|
showEntityActionsDialog(
|
|
entities: [invoice],
|
|
);
|
|
break;
|
|
case EntityAction.documents:
|
|
final documentIds = <String>[];
|
|
for (var invoice in invoices) {
|
|
for (var document in (invoice as InvoiceEntity).documents) {
|
|
documentIds.add(document.id);
|
|
}
|
|
}
|
|
if (documentIds.isEmpty) {
|
|
showMessageDialog(message: localization!.noDocumentsToDownload);
|
|
} else {
|
|
store.dispatch(
|
|
DownloadDocumentsRequest(
|
|
documentIds: documentIds,
|
|
completer: snackBarCompleter<Null>(
|
|
localization!.exportedData,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
print('## ERROR: unhandled action $action in invoice_actions');
|
|
break;
|
|
}
|
|
}
|