Purchase orders

This commit is contained in:
Hillel Coren 2022-06-16 10:33:25 +03:00
parent 35af9889bc
commit d06e06c413
6 changed files with 237 additions and 0 deletions

View File

@ -579,9 +579,11 @@ abstract class CompanyEntity extends Object
);
bool isModuleEnabled(EntityType entityType) {
/*
if (entityType == EntityType.purchaseOrder) {
return false;
}
*/
if ((entityType == EntityType.invoice ||
entityType == EntityType.payment) &&

View File

@ -194,6 +194,33 @@ class RestorePurchaseOrdersFailure implements StopSaving {
final List<InvoiceEntity> purchaseOrders;
}
class EmailPurchaseOrderRequest implements StartSaving {
EmailPurchaseOrderRequest(
{this.completer,
this.purchaseOrderId,
this.template,
this.subject,
this.body});
final Completer completer;
final String purchaseOrderId;
final EmailTemplate template;
final String subject;
final String body;
}
class EmailPurchaseOrderSuccess implements StopSaving, PersistData {
EmailPurchaseOrderSuccess(this.quote);
final InvoiceEntity quote;
}
class EmailPurchaseOrderFailure implements StopSaving {
EmailPurchaseOrderFailure(this.error);
final dynamic error;
}
class FilterPurchaseOrders implements PersistUI {
FilterPurchaseOrders(this.filter);

View File

@ -4,6 +4,12 @@ import 'package:flutter/material.dart';
// Package imports:
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/ui/app/app_title_bar.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/edit/purchase_order_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_email_vm.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_pdf_vm.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_screen.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/purchase_order_screen_vm.dart';
import 'package:invoiceninja_flutter/ui/purchase_order/view/purchase_order_view_vm.dart';
import 'package:invoiceninja_flutter/ui/settings/payment_settings_vm.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:redux/redux.dart';
@ -169,6 +175,12 @@ class MainScreen extends StatelessWidget {
editingFilterEntity: editingFilterEntity,
);
break;
case PurchaseOrderScreen.route:
screen = EntityScreens(
entityType: EntityType.purchaseOrder,
editingFilterEntity: editingFilterEntity,
);
break;
case ProjectScreen.route:
screen = EntityScreens(
entityType: EntityType.project,
@ -392,6 +404,13 @@ class EntityScreens extends StatelessWidget {
? CreditEmailScreen()
: CreditEditScreen();
break;
case PurchaseOrderScreen.route:
child = isPdf
? PurchaseOrderPdfScreen()
: isEmail
? PurchaseOrderEmailScreen()
: PurchaseOrderEditScreen();
break;
case RecurringInvoiceScreen.route:
child = isPdf
? RecurringInvoicePdfScreen()
@ -447,6 +466,9 @@ class EntityScreens extends StatelessWidget {
case EntityType.credit:
child = CreditEditScreen();
break;
case EntityType.purchaseOrder:
child = PurchaseOrderEditScreen();
break;
case EntityType.project:
child = ProjectEditScreen();
break;
@ -497,6 +519,9 @@ class EntityScreens extends StatelessWidget {
case EntityType.credit:
child = CreditViewScreen();
break;
case EntityType.purchaseOrder:
child = PurchaseOrderViewScreen();
break;
case EntityType.project:
child = ProjectViewScreen();
break;
@ -562,6 +587,11 @@ class EntityScreens extends StatelessWidget {
? CreditViewScreen()
: CreditViewScreen(isFilter: true);
break;
case EntityType.purchaseOrder:
leftFilterChild = editingFilterEntity && !uiState.isEditing
? PurchaseOrderViewScreen()
: PurchaseOrderViewScreen(isFilter: true);
break;
case EntityType.payment:
leftFilterChild = editingFilterEntity && !uiState.isEditing
? PaymentEditScreen()
@ -650,6 +680,9 @@ class EntityScreens extends StatelessWidget {
case EntityType.credit:
listWidget = CreditScreenBuilder();
break;
case EntityType.purchaseOrder:
listWidget = PurchaseOrderScreenBuilder();
break;
case EntityType.project:
listWidget = ProjectScreenBuilder();
break;

View File

@ -0,0 +1,102 @@
// Flutter imports:
import 'package:flutter/material.dart';
// Package imports:
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.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/client/client_actions.dart';
import 'package:invoiceninja_flutter/redux/purchase_order/purchase_order_actions.dart';
import 'package:invoiceninja_flutter/ui/app/invoice/invoice_email_view.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_email_vm.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
class PurchaseOrderEmailScreen extends StatelessWidget {
const PurchaseOrderEmailScreen({Key key}) : super(key: key);
static const String route = '/purchase_order/email';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, EmailPurchaseOrderVM>(
onInit: (Store<AppState> store) {
final state = store.state;
final purchaseOrderId = state.uiState.purchaseOrderUIState.selectedId;
final purchaseOrder = state.purchaseOrderState.map[purchaseOrderId];
final client = state.clientState.map[purchaseOrder.clientId];
if (client.isStale) {
store.dispatch(LoadClient(clientId: client.id));
}
},
converter: (Store<AppState> store) {
final state = store.state;
final purchaseOrderId = state.uiState.purchaseOrderUIState.selectedId;
final purchaseOrder = state.purchaseOrderState.map[purchaseOrderId];
return EmailPurchaseOrderVM.fromStore(store, purchaseOrder);
},
builder: (context, viewModel) {
return InvoiceEmailView(
viewModel: viewModel,
);
},
);
}
}
class EmailPurchaseOrderVM extends EmailEntityVM {
EmailPurchaseOrderVM({
@required AppState state,
@required bool isLoading,
@required bool isSaving,
@required CompanyEntity company,
@required InvoiceEntity invoice,
@required ClientEntity client,
@required
Function(BuildContext, EmailTemplate, String, String) onSendPressed,
}) : super(
state: state,
isLoading: isLoading,
isSaving: isSaving,
company: company,
invoice: invoice,
client: client,
onSendPressed: onSendPressed,
);
factory EmailPurchaseOrderVM.fromStore(
Store<AppState> store, InvoiceEntity purchaseOrder) {
final state = store.state;
return EmailPurchaseOrderVM(
state: state,
isLoading: state.isLoading,
isSaving: state.isSaving,
company: state.company,
invoice: purchaseOrder,
client: state.clientState.map[purchaseOrder.clientId],
onSendPressed: (context, template, subject, body) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).emailedPurchaseOrder,
shouldPop: isMobile(context));
if (!isMobile(context)) {
completer.future.then((value) {
viewEntity(entity: purchaseOrder);
});
}
store.dispatch(EmailPurchaseOrderRequest(
completer: completer,
purchaseOrderId: purchaseOrder.id,
template: template,
subject: subject,
body: body,
));
},
);
}
}

View File

@ -0,0 +1,62 @@
// Flutter imports:
import 'package:flutter/material.dart';
// Package imports:
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
// Project imports:
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf.dart';
import 'package:invoiceninja_flutter/ui/invoice/invoice_pdf_vm.dart';
class PurchaseOrderPdfScreen extends StatelessWidget {
const PurchaseOrderPdfScreen({Key key, this.showAppBar = true})
: super(key: key);
final bool showAppBar;
static const String route = '/purchase_order/pdf';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, PurchaseOrderPdfVM>(
converter: (Store<AppState> store) {
return PurchaseOrderPdfVM.fromStore(store);
},
builder: (context, vm) {
return InvoicePdfView(
key: ValueKey('__purchase_order_pdf_${vm.invoice.id}__'),
viewModel: vm,
showAppBar: showAppBar,
);
},
);
}
}
class PurchaseOrderPdfVM extends EntityPdfVM {
PurchaseOrderPdfVM({
AppState state,
InvoiceEntity invoice,
String activityId,
}) : super(
state: state,
invoice: invoice,
activityId: activityId,
);
factory PurchaseOrderPdfVM.fromStore(Store<AppState> store) {
final state = store.state;
final purchaseOrderUIState = state.uiState.purchaseOrderUIState;
final invoiceId = purchaseOrderUIState.selectedId;
final invoice = state.purchaseOrderState.get(invoiceId);
return PurchaseOrderPdfVM(
state: state,
invoice: invoice,
//activityId: purchaseOrderUIState.historyActivityId,
);
}
}

View File

@ -16,6 +16,9 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
'emailed_purchase_order': 'Successfully queued purchase order to be sent',
'emailed_purchase_orders':
'Successfully queued purchase orders to be sent',
'enable_react_app': 'Change to the React web app',
'purchase_order_design': 'Purchase Order Design',
'purchase_order_terms': 'Purchase Order Terms',
@ -70688,6 +70691,14 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]['enable_react_app'] ??
_localizedValues['en']['enable_react_app'];
String get emailedPurchaseOrder =>
_localizedValues[localeCode]['emailed_purchase_orderk'] ??
_localizedValues['en']['emailed_purchase_order'];
String get emailedPurchaseOrders =>
_localizedValues[localeCode]['emailed_purchase_orders'] ??
_localizedValues['en']['emailed_purchase_orders'];
// STARTER: lang field - do not remove comment
String lookup(String key) {