Payment terms

This commit is contained in:
Hillel Coren 2020-05-26 10:30:14 +03:00
parent ba4554998b
commit a8265d110d
8 changed files with 169 additions and 3 deletions

View File

@ -279,6 +279,7 @@ const String kReminderScheduleAfterDueDate = 'after_due_date';
const String kSettingsCompanyDetails = 'company_details';
const String kSettingsPaymentTerms = 'payment_terms';
const String kSettingsPaymentTermView = 'payment_term_view';
const String kSettingsPaymentTermEdit = 'payment_term_edit';
const String kSettingsUserDetails = 'user_details';
const String kSettingsLocalization = 'localization';

View File

@ -262,7 +262,7 @@ abstract class BaseEntity implements SelectableEntity {
bool get isActive => archivedAt == null || archivedAt == 0;
bool get isArchived => archivedAt != null && archivedAt > 0 && !isDeleted;
bool get isArchived => archivedAt != null && archivedAt > 0 && !(isDeleted ?? false);
bool userCanAccess(String userId) =>
createdUserId == userId || assignedUserId == userId;

View File

@ -30,6 +30,7 @@ import 'package:invoiceninja_flutter/ui/payment/refund/payment_refund_vm.dart';
import 'package:invoiceninja_flutter/ui/payment_term/edit/payment_term_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/payment_term/payment_term_screen.dart';
import 'package:invoiceninja_flutter/ui/payment_term/payment_term_screen_vm.dart';
import 'package:invoiceninja_flutter/ui/payment_term/view/payment_term_view_vm.dart';
import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
import 'package:invoiceninja_flutter/ui/reports/reports_screen_vm.dart';
import 'package:invoiceninja_flutter/ui/settings/account_management_vm.dart';
@ -228,6 +229,8 @@ class InvoiceNinjaAppState extends State<InvoiceNinjaApp> {
PaymentTermScreenBuilder(),
PaymentTermEditScreen.route: (context) =>
PaymentTermEditScreen(),
PaymentTermViewScreen.route: (context) =>
PaymentTermViewScreen(),
DesignScreen.route: (context) => DesignScreenBuilder(),
DesignViewScreen.route: (context) => DesignViewScreen(),
DesignEditScreen.route: (context) => DesignEditScreen(),

View File

@ -470,8 +470,11 @@ void viewEntityById({
break;
// STARTER: view - do not remove comment
case EntityType.paymentTerm:
editEntityById(
context: context, entityId: entityId, entityType: entityType);
store.dispatch(ViewPaymentTerm(
paymentTermId: entityId,
navigator: navigator,
force: force,
));
break;
case EntityType.design:
store.dispatch(ViewDesign(

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:invoiceninja_flutter/data/models/payment_term_model.dart';
import 'package:invoiceninja_flutter/ui/payment_term/view/payment_term_view_vm.dart';
import 'package:redux/redux.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';
import 'package:invoiceninja_flutter/redux/app/app_middleware.dart';
@ -16,6 +17,7 @@ List<Middleware<AppState>> createStorePaymentTermsMiddleware([
PaymentTermRepository repository = const PaymentTermRepository(),
]) {
final viewPaymentTermList = _viewPaymentTermList();
final viewPaymentTerm = _viewPaymentTerm();
final editPaymentTerm = _editPaymentTerm();
final loadPaymentTerms = _loadPaymentTerms(repository);
final loadPaymentTerm = _loadPaymentTerm(repository);
@ -26,6 +28,7 @@ List<Middleware<AppState>> createStorePaymentTermsMiddleware([
return [
TypedMiddleware<AppState, ViewPaymentTermList>(viewPaymentTermList),
TypedMiddleware<AppState, ViewPaymentTerm>(viewPaymentTerm),
TypedMiddleware<AppState, EditPaymentTerm>(editPaymentTerm),
TypedMiddleware<AppState, LoadPaymentTerms>(loadPaymentTerms),
TypedMiddleware<AppState, LoadPaymentTerm>(loadPaymentTerm),
@ -55,6 +58,26 @@ Middleware<AppState> _editPaymentTerm() {
};
}
Middleware<AppState> _viewPaymentTerm() {
return (Store<AppState> store, dynamic dynamicAction,
NextDispatcher next) async {
final action = dynamicAction as ViewPaymentTerm;
if (!action.force &&
hasChanges(store: store, context: action.context, action: action)) {
return;
}
next(action);
store.dispatch(UpdateCurrentRoute(PaymentTermViewScreen.route));
if (isMobile(action.context)) {
action.navigator.pushNamed(PaymentTermViewScreen.route);
}
};
}
Middleware<AppState> _viewPaymentTermList() {
return (Store<AppState> store, dynamic dynamicAction, NextDispatcher next) {
final action = dynamicAction as ViewPaymentTermList;

View File

@ -24,6 +24,7 @@ import 'package:invoiceninja_flutter/ui/design/edit/design_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/design/view/design_view_vm.dart';
import 'package:invoiceninja_flutter/ui/payment_term/edit/payment_term_edit_vm.dart';
import 'package:invoiceninja_flutter/ui/payment_term/payment_term_screen_vm.dart';
import 'package:invoiceninja_flutter/ui/payment_term/view/payment_term_view_vm.dart';
import 'package:invoiceninja_flutter/ui/reports/reports_screen.dart';
import 'package:invoiceninja_flutter/ui/reports/reports_screen_vm.dart';
import 'package:invoiceninja_flutter/ui/settings/account_management_vm.dart';
@ -302,6 +303,9 @@ class SettingsScreens extends StatelessWidget {
case kSettingsPaymentTermEdit:
screen = PaymentTermEditScreen();
break;
case kSettingsPaymentTermView:
screen = PaymentTermViewScreen();
break;
case kSettingsUserDetails:
screen = UserDetailsScreen();
break;

View File

@ -0,0 +1,39 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/ui/app/entity_header.dart';
import 'package:invoiceninja_flutter/ui/app/view_scaffold.dart';
import 'package:invoiceninja_flutter/ui/payment_term/view/payment_term_view_vm.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
class PaymentTermView extends StatefulWidget {
const PaymentTermView({
Key key,
@required this.viewModel,
}) : super(key: key);
final PaymentTermViewVM viewModel;
@override
_PaymentTermViewState createState() => new _PaymentTermViewState();
}
class _PaymentTermViewState extends State<PaymentTermView> {
@override
Widget build(BuildContext context) {
final viewModel = widget.viewModel;
final paymentTerm = viewModel.paymentTerm;
final localization = AppLocalization.of(context);
return ViewScaffold(
entity: paymentTerm,
onBackPressed: () => viewModel.onBackPressed(),
body: ListView(children: [
EntityHeader(
entity: paymentTerm,
label: localization.name,
value: paymentTerm.name,
),
]),
);
}
}

View File

@ -0,0 +1,93 @@
import 'dart:async';
import 'package:invoiceninja_flutter/constants.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:invoiceninja_flutter/data/models/payment_term_model.dart';
import 'package:invoiceninja_flutter/redux/payment_term/payment_term_actions.dart';
import 'package:invoiceninja_flutter/redux/ui/ui_actions.dart';
import 'package:invoiceninja_flutter/ui/app/screen_imports.dart';
import 'package:invoiceninja_flutter/ui/payment_term/payment_term_screen.dart';
import 'package:invoiceninja_flutter/ui/payment_term/view/payment_term_view.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
class PaymentTermViewScreen extends StatelessWidget {
const PaymentTermViewScreen({
Key key,
this.isFilter = false,
}) : super(key: key);
final bool isFilter;
static const String route = '/$kSettings/$kSettingsPaymentTermView';
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, PaymentTermViewVM>(
converter: (Store<AppState> store) {
return PaymentTermViewVM.fromStore(store);
},
builder: (context, vm) {
return PaymentTermView(
viewModel: vm,
);
},
);
}
}
class PaymentTermViewVM {
PaymentTermViewVM({
@required this.state,
@required this.paymentTerm,
@required this.company,
@required this.onEntityAction,
@required this.onBackPressed,
@required this.onRefreshed,
@required this.isSaving,
@required this.isLoading,
@required this.isDirty,
});
factory PaymentTermViewVM.fromStore(Store<AppState> store) {
final state = store.state;
final paymentTerm =
state.paymentTermState.map[state.paymentTermUIState.selectedId] ??
PaymentTermEntity(id: state.paymentTermUIState.selectedId);
Future<Null> _handleRefresh(BuildContext context) {
final completer = snackBarCompleter<Null>(
context, AppLocalization.of(context).refreshComplete);
store.dispatch(
LoadPaymentTerm(completer: completer, paymentTermId: paymentTerm.id));
return completer.future;
}
return PaymentTermViewVM(
state: state,
company: state.company,
isSaving: state.isSaving,
isLoading: state.isLoading,
isDirty: paymentTerm.isNew,
paymentTerm: paymentTerm,
onRefreshed: (context) => _handleRefresh(context),
onBackPressed: () {
store.dispatch(UpdateCurrentRoute(PaymentTermScreen.route));
},
onEntityAction: (BuildContext context, EntityAction action) =>
handlePaymentTermAction(context, [paymentTerm], action),
);
}
final AppState state;
final PaymentTermEntity paymentTerm;
final CompanyEntity company;
final Function(BuildContext, EntityAction) onEntityAction;
final Function onBackPressed;
final Function(BuildContext) onRefreshed;
final bool isSaving;
final bool isLoading;
final bool isDirty;
}