Schedule send
This commit is contained in:
parent
ee20546276
commit
43a9df00e5
|
|
@ -1034,6 +1034,9 @@ abstract class InvoiceEntity extends Object
|
||||||
actions.add(EntityAction.bulkSendEmail);
|
actions.add(EntityAction.bulkSendEmail);
|
||||||
} else {
|
} else {
|
||||||
actions.add(EntityAction.sendEmail);
|
actions.add(EntityAction.sendEmail);
|
||||||
|
if (isUnpaid) {
|
||||||
|
actions.add(EntityAction.schedule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1278,7 +1281,9 @@ abstract class InvoiceEntity extends Object
|
||||||
bool get isApplied => isCredit && statusId == kCreditStatusApplied;
|
bool get isApplied => isCredit && statusId == kCreditStatusApplied;
|
||||||
|
|
||||||
bool get isUnpaid {
|
bool get isUnpaid {
|
||||||
if (isQuote) {
|
if (isPurchaseOrder) {
|
||||||
|
return !isApproved;
|
||||||
|
} else if (isQuote) {
|
||||||
return !isApproved;
|
return !isApproved;
|
||||||
} else if (isCredit) {
|
} else if (isCredit) {
|
||||||
return !isApplied;
|
return !isApplied;
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ class EntityAction extends EnumClass {
|
||||||
static const EntityAction merge = _$merge;
|
static const EntityAction merge = _$merge;
|
||||||
static const EntityAction bulkPrint = _$bulkPrint;
|
static const EntityAction bulkPrint = _$bulkPrint;
|
||||||
static const EntityAction autoBill = _$autoBill;
|
static const EntityAction autoBill = _$autoBill;
|
||||||
|
static const EntityAction schedule = _$schedule;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ const EntityAction _$convertToProject =
|
||||||
const EntityAction _$merge = const EntityAction._('merge');
|
const EntityAction _$merge = const EntityAction._('merge');
|
||||||
const EntityAction _$bulkPrint = const EntityAction._('bulkPrint');
|
const EntityAction _$bulkPrint = const EntityAction._('bulkPrint');
|
||||||
const EntityAction _$autoBill = const EntityAction._('autoBill');
|
const EntityAction _$autoBill = const EntityAction._('autoBill');
|
||||||
|
const EntityAction _$schedule = const EntityAction._('schedule');
|
||||||
|
|
||||||
EntityAction _$valueOf(String name) {
|
EntityAction _$valueOf(String name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|
@ -248,6 +249,8 @@ EntityAction _$valueOf(String name) {
|
||||||
return _$bulkPrint;
|
return _$bulkPrint;
|
||||||
case 'autoBill':
|
case 'autoBill':
|
||||||
return _$autoBill;
|
return _$autoBill;
|
||||||
|
case 'schedule':
|
||||||
|
return _$schedule;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentError(name);
|
throw new ArgumentError(name);
|
||||||
}
|
}
|
||||||
|
|
@ -331,6 +334,7 @@ final BuiltSet<EntityAction> _$values =
|
||||||
_$merge,
|
_$merge,
|
||||||
_$bulkPrint,
|
_$bulkPrint,
|
||||||
_$autoBill,
|
_$autoBill,
|
||||||
|
_$schedule,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Serializer<EntityAction> _$entityActionSerializer =
|
Serializer<EntityAction> _$entityActionSerializer =
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import 'package:built_collection/built_collection.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
// Project imports:
|
// Project imports:
|
||||||
|
|
@ -488,6 +489,7 @@ Future handleCreditAction(
|
||||||
break;
|
break;
|
||||||
case EntityAction.sendEmail:
|
case EntityAction.sendEmail:
|
||||||
case EntityAction.bulkSendEmail:
|
case EntityAction.bulkSendEmail:
|
||||||
|
case EntityAction.schedule:
|
||||||
bool emailValid = true;
|
bool emailValid = true;
|
||||||
credits.forEach((credit) {
|
credits.forEach((credit) {
|
||||||
final client = state.clientState.get(
|
final client = state.clientState.get(
|
||||||
|
|
@ -517,6 +519,29 @@ Future handleCreditAction(
|
||||||
snackBarCompleter<Null>(context, localization.emailedCredit),
|
snackBarCompleter<Null>(context, localization.emailedCredit),
|
||||||
credit: credit,
|
credit: credit,
|
||||||
context: context));
|
context: context));
|
||||||
|
} else if (action == EntityAction.schedule) {
|
||||||
|
if (!state.isProPlan) {
|
||||||
|
showMessageDialog(
|
||||||
|
context: context,
|
||||||
|
message: localization.upgradeToPaidPlanToSchedule,
|
||||||
|
secondaryActions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
store.dispatch(
|
||||||
|
ViewSettings(section: kSettingsAccountManagement));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(localization.upgrade.toUpperCase())),
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createEntity(
|
||||||
|
context: context,
|
||||||
|
entity: ScheduleEntity().rebuild((b) => b
|
||||||
|
..template = ScheduleEntity.TEMPLATE_SCHEDULE_ENTITY
|
||||||
|
..parameters.entityType = EntityType.credit.apiValue
|
||||||
|
..parameters.entityId = credit.id));
|
||||||
} else {
|
} else {
|
||||||
confirmCallback(
|
confirmCallback(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ import 'package:flutter/material.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:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
import 'package:invoiceninja_flutter/constants.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
// Project imports:
|
// Project imports:
|
||||||
|
|
@ -607,6 +609,7 @@ void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
|
||||||
break;
|
break;
|
||||||
case EntityAction.sendEmail:
|
case EntityAction.sendEmail:
|
||||||
case EntityAction.bulkSendEmail:
|
case EntityAction.bulkSendEmail:
|
||||||
|
case EntityAction.schedule:
|
||||||
bool emailValid = true;
|
bool emailValid = true;
|
||||||
invoices.forEach((invoice) {
|
invoices.forEach((invoice) {
|
||||||
final client = state.clientState.get(
|
final client = state.clientState.get(
|
||||||
|
|
@ -636,6 +639,29 @@ void handleInvoiceAction(BuildContext context, List<BaseEntity> invoices,
|
||||||
snackBarCompleter<Null>(context, localization.emailedInvoice),
|
snackBarCompleter<Null>(context, localization.emailedInvoice),
|
||||||
invoice: invoice,
|
invoice: invoice,
|
||||||
context: context));
|
context: context));
|
||||||
|
} else if (action == EntityAction.schedule) {
|
||||||
|
if (!state.isProPlan) {
|
||||||
|
showMessageDialog(
|
||||||
|
context: context,
|
||||||
|
message: localization.upgradeToPaidPlanToSchedule,
|
||||||
|
secondaryActions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
store.dispatch(
|
||||||
|
ViewSettings(section: kSettingsAccountManagement));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(localization.upgrade.toUpperCase())),
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createEntity(
|
||||||
|
context: context,
|
||||||
|
entity: ScheduleEntity().rebuild((b) => b
|
||||||
|
..template = ScheduleEntity.TEMPLATE_SCHEDULE_ENTITY
|
||||||
|
..parameters.entityType = EntityType.invoice.apiValue
|
||||||
|
..parameters.entityId = invoice.id));
|
||||||
} else {
|
} else {
|
||||||
confirmCallback(
|
confirmCallback(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:invoiceninja_flutter/constants.dart';
|
||||||
import 'package:invoiceninja_flutter/data/models/models.dart';
|
import 'package:invoiceninja_flutter/data/models/models.dart';
|
||||||
import 'package:invoiceninja_flutter/data/web_client.dart';
|
import 'package:invoiceninja_flutter/data/web_client.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/design/design_selectors.dart';
|
import 'package:invoiceninja_flutter/redux/design/design_selectors.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/settings/settings_actions.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/localization.dart';
|
import 'package:invoiceninja_flutter/utils/localization.dart';
|
||||||
|
|
@ -699,6 +701,7 @@ void handlePurchaseOrderAction(BuildContext context,
|
||||||
break;
|
break;
|
||||||
case EntityAction.sendEmail:
|
case EntityAction.sendEmail:
|
||||||
case EntityAction.bulkSendEmail:
|
case EntityAction.bulkSendEmail:
|
||||||
|
case EntityAction.schedule:
|
||||||
bool emailValid = true;
|
bool emailValid = true;
|
||||||
purchaseOrders.forEach((purchaseOrder) {
|
purchaseOrders.forEach((purchaseOrder) {
|
||||||
final vendor = state.vendorState.get(
|
final vendor = state.vendorState.get(
|
||||||
|
|
@ -729,6 +732,29 @@ void handlePurchaseOrderAction(BuildContext context,
|
||||||
context, localization.emailedPurchaseOrder),
|
context, localization.emailedPurchaseOrder),
|
||||||
purchaseOrder: purchaseOrder,
|
purchaseOrder: purchaseOrder,
|
||||||
context: context));
|
context: context));
|
||||||
|
} else if (action == EntityAction.schedule) {
|
||||||
|
if (!state.isProPlan) {
|
||||||
|
showMessageDialog(
|
||||||
|
context: context,
|
||||||
|
message: localization.upgradeToPaidPlanToSchedule,
|
||||||
|
secondaryActions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
store.dispatch(
|
||||||
|
ViewSettings(section: kSettingsAccountManagement));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(localization.upgrade.toUpperCase())),
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createEntity(
|
||||||
|
context: context,
|
||||||
|
entity: ScheduleEntity().rebuild((b) => b
|
||||||
|
..template = ScheduleEntity.TEMPLATE_SCHEDULE_ENTITY
|
||||||
|
..parameters.entityType = EntityType.purchaseOrder.apiValue
|
||||||
|
..parameters.entityId = purchaseOrder.id));
|
||||||
} else {
|
} else {
|
||||||
confirmCallback(
|
confirmCallback(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ import 'package:flutter/material.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:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
|
import 'package:invoiceninja_flutter/constants.dart';
|
||||||
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
import 'package:invoiceninja_flutter/redux/document/document_actions.dart';
|
||||||
|
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
// Project imports:
|
// Project imports:
|
||||||
|
|
@ -551,6 +553,7 @@ Future handleQuoteAction(
|
||||||
break;
|
break;
|
||||||
case EntityAction.sendEmail:
|
case EntityAction.sendEmail:
|
||||||
case EntityAction.bulkSendEmail:
|
case EntityAction.bulkSendEmail:
|
||||||
|
case EntityAction.schedule:
|
||||||
bool emailValid = true;
|
bool emailValid = true;
|
||||||
quotes.forEach((quote) {
|
quotes.forEach((quote) {
|
||||||
final client = state.clientState.get(
|
final client = state.clientState.get(
|
||||||
|
|
@ -580,6 +583,29 @@ Future handleQuoteAction(
|
||||||
snackBarCompleter<Null>(context, localization.emailedQuote),
|
snackBarCompleter<Null>(context, localization.emailedQuote),
|
||||||
quote: quote,
|
quote: quote,
|
||||||
context: context));
|
context: context));
|
||||||
|
} else if (action == EntityAction.schedule) {
|
||||||
|
if (!state.isProPlan) {
|
||||||
|
showMessageDialog(
|
||||||
|
context: context,
|
||||||
|
message: localization.upgradeToPaidPlanToSchedule,
|
||||||
|
secondaryActions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
store.dispatch(
|
||||||
|
ViewSettings(section: kSettingsAccountManagement));
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text(localization.upgrade.toUpperCase())),
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createEntity(
|
||||||
|
context: context,
|
||||||
|
entity: ScheduleEntity().rebuild((b) => b
|
||||||
|
..template = ScheduleEntity.TEMPLATE_SCHEDULE_ENTITY
|
||||||
|
..parameters.entityType = EntityType.quote.apiValue
|
||||||
|
..parameters.entityId = quote.id));
|
||||||
} else {
|
} else {
|
||||||
confirmCallback(
|
confirmCallback(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,8 @@ class _ScheduleEditState extends State<ScheduleEdit> {
|
||||||
value: schedule.template,
|
value: schedule.template,
|
||||||
onChanged: (dynamic value) {
|
onChanged: (dynamic value) {
|
||||||
viewModel.onChanged(
|
viewModel.onChanged(
|
||||||
schedule.rebuild((b) => b..template = value));
|
schedule.rebuild((b) => b..template = value),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
items: ScheduleEntity.TEMPLATES
|
items: ScheduleEntity.TEMPLATES
|
||||||
.map((entry) => DropdownMenuItem(
|
.map((entry) => DropdownMenuItem(
|
||||||
|
|
@ -351,15 +352,13 @@ class _ScheduleEditState extends State<ScheduleEdit> {
|
||||||
EntityType.purchaseOrder
|
EntityType.purchaseOrder
|
||||||
]
|
]
|
||||||
.map((entityType) => DropdownMenuItem<String>(
|
.map((entityType) => DropdownMenuItem<String>(
|
||||||
value: entityType.toString(),
|
value: entityType.apiValue,
|
||||||
child: Text(
|
child: Text(
|
||||||
localization
|
localization.lookup(entityType.apiValue),
|
||||||
.lookup(entityType.toString()),
|
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
.toList()),
|
.toList()),
|
||||||
if (parameters.entityType ==
|
if (parameters.entityType == EntityType.invoice.apiValue)
|
||||||
EntityType.invoice.toString())
|
|
||||||
EntityDropdown(
|
EntityDropdown(
|
||||||
labelText: localization.invoice,
|
labelText: localization.invoice,
|
||||||
entityType: EntityType.invoice,
|
entityType: EntityType.invoice,
|
||||||
|
|
@ -371,7 +370,7 @@ class _ScheduleEditState extends State<ScheduleEdit> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else if (parameters.entityType ==
|
else if (parameters.entityType ==
|
||||||
EntityType.quote.toString())
|
EntityType.quote.apiValue)
|
||||||
EntityDropdown(
|
EntityDropdown(
|
||||||
labelText: localization.quote,
|
labelText: localization.quote,
|
||||||
entityType: EntityType.quote,
|
entityType: EntityType.quote,
|
||||||
|
|
@ -383,7 +382,7 @@ class _ScheduleEditState extends State<ScheduleEdit> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else if (parameters.entityType ==
|
else if (parameters.entityType ==
|
||||||
EntityType.credit.toString())
|
EntityType.credit.apiValue)
|
||||||
EntityDropdown(
|
EntityDropdown(
|
||||||
labelText: localization.credit,
|
labelText: localization.credit,
|
||||||
entityType: EntityType.credit,
|
entityType: EntityType.credit,
|
||||||
|
|
@ -395,7 +394,7 @@ class _ScheduleEditState extends State<ScheduleEdit> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else if (parameters.entityType ==
|
else if (parameters.entityType ==
|
||||||
EntityType.purchaseOrder.toString())
|
EntityType.purchaseOrder.apiValue)
|
||||||
EntityDropdown(
|
EntityDropdown(
|
||||||
labelText: localization.purchaseOrder,
|
labelText: localization.purchaseOrder,
|
||||||
entityType: EntityType.purchaseOrder,
|
entityType: EntityType.purchaseOrder,
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,13 @@ class ScheduleListItem extends StatelessWidget {
|
||||||
|
|
||||||
final filterMatch = filter != null && filter.isNotEmpty
|
final filterMatch = filter != null && filter.isNotEmpty
|
||||||
? schedule.matchesFilterValue(filter)
|
? schedule.matchesFilterValue(filter)
|
||||||
: localization.lookup(schedule.template) +
|
: (schedule.template == ScheduleEntity.TEMPLATE_SCHEDULE_ENTITY
|
||||||
' • ' +
|
? localization.emailRecord
|
||||||
localization.lookup(kFrequencies[schedule.frequencyId]);
|
: localization.lookup(schedule.template)) +
|
||||||
|
(schedule.frequencyId.isEmpty
|
||||||
|
? ''
|
||||||
|
: ' • ' +
|
||||||
|
localization.lookup(kFrequencies[schedule.frequencyId]));
|
||||||
final subtitle = filterMatch;
|
final subtitle = filterMatch;
|
||||||
|
|
||||||
return DismissibleEntity(
|
return DismissibleEntity(
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ IconData getEntityActionIcon(EntityAction entityAction) {
|
||||||
case EntityAction.resendInvite:
|
case EntityAction.resendInvite:
|
||||||
case EntityAction.sendNow:
|
case EntityAction.sendNow:
|
||||||
return Icons.send;
|
return Icons.send;
|
||||||
|
case EntityAction.schedule:
|
||||||
|
return Icons.schedule;
|
||||||
case EntityAction.archive:
|
case EntityAction.archive:
|
||||||
return Icons.archive;
|
return Icons.archive;
|
||||||
case EntityAction.delete:
|
case EntityAction.delete:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue