From 7a7c17be5a309087f059d6ad94baeeee2b0a4dd0 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Mon, 25 May 2020 21:35:47 +0300 Subject: [PATCH] Payment terms --- lib/data/models/company_model.dart | 3 ++ lib/data/models/company_model.g.dart | 38 ++++++++++++++++--- lib/data/models/entities.dart | 1 + lib/data/models/serializers.g.dart | 15 +++++--- lib/redux/app/app_middleware.dart | 2 +- lib/redux/app/app_state.dart | 1 + .../payment_term/payment_term_reducer.dart | 14 +++++++ lib/ui/app/list_scaffold.dart | 5 +-- lib/ui/app/view_scaffold.dart | 3 +- .../company_gateway_screen.dart | 1 - .../view/company_gateway_view.dart | 1 - lib/ui/design/design_screen.dart | 1 - lib/ui/design/view/design_view.dart | 1 - lib/ui/group/group_screen.dart | 1 - lib/ui/group/view/group_view.dart | 1 - lib/ui/payment_term/payment_term_screen.dart | 1 + lib/ui/settings/settings_screen.dart | 2 + lib/ui/tax_rate/tax_rate_screen.dart | 1 - lib/ui/tax_rate/view/tax_rate_view.dart | 1 - lib/ui/user/user_screen.dart | 1 - lib/ui/user/view/user_view.dart | 1 - stubs/ui/stub/stub_screen | 1 + 22 files changed, 69 insertions(+), 27 deletions(-) diff --git a/lib/data/models/company_model.dart b/lib/data/models/company_model.dart index c3af92ca4..8e4069c47 100644 --- a/lib/data/models/company_model.dart +++ b/lib/data/models/company_model.dart @@ -96,6 +96,7 @@ abstract class CompanyEntity extends Object projects: BuiltList(), vendors: BuiltList(), designs: BuiltList(), + paymentTerms: BuiltList(), ); } @@ -215,6 +216,8 @@ abstract class CompanyEntity extends Object BuiltList get designs; + BuiltList get paymentTerms; + BuiltMap get userMap; @BuiltValueField(wireName: 'custom_fields') diff --git a/lib/data/models/company_model.g.dart b/lib/data/models/company_model.g.dart index 439fbfc94..1ae23f30b 100644 --- a/lib/data/models/company_model.g.dart +++ b/lib/data/models/company_model.g.dart @@ -173,6 +173,10 @@ class _$CompanyEntitySerializer implements StructuredSerializer { serializers.serialize(object.designs, specifiedType: const FullType(BuiltList, const [const FullType(DesignEntity)])), + 'paymentTerms', + serializers.serialize(object.paymentTerms, + specifiedType: const FullType( + BuiltList, const [const FullType(PaymentTermEntity)])), 'userMap', serializers.serialize(object.userMap, specifiedType: const FullType(BuiltMap, @@ -484,6 +488,12 @@ class _$CompanyEntitySerializer implements StructuredSerializer { BuiltList, const [const FullType(DesignEntity)])) as BuiltList); break; + case 'paymentTerms': + result.paymentTerms.replace(serializers.deserialize(value, + specifiedType: const FullType( + BuiltList, const [const FullType(PaymentTermEntity)])) + as BuiltList); + break; case 'userMap': result.userMap.replace(serializers.deserialize(value, specifiedType: const FullType(BuiltMap, @@ -2726,6 +2736,8 @@ class _$CompanyEntity extends CompanyEntity { @override final BuiltList designs; @override + final BuiltList paymentTerms; + @override final BuiltMap userMap; @override final BuiltMap customFields; @@ -2801,6 +2813,7 @@ class _$CompanyEntity extends CompanyEntity { this.expenses, this.vendors, this.designs, + this.paymentTerms, this.userMap, this.customFields, this.slackWebhookUrl, @@ -2940,6 +2953,9 @@ class _$CompanyEntity extends CompanyEntity { if (designs == null) { throw new BuiltValueNullFieldError('CompanyEntity', 'designs'); } + if (paymentTerms == null) { + throw new BuiltValueNullFieldError('CompanyEntity', 'paymentTerms'); + } if (userMap == null) { throw new BuiltValueNullFieldError('CompanyEntity', 'userMap'); } @@ -3009,6 +3025,7 @@ class _$CompanyEntity extends CompanyEntity { expenses == other.expenses && vendors == other.vendors && designs == other.designs && + paymentTerms == other.paymentTerms && userMap == other.userMap && customFields == other.customFields && slackWebhookUrl == other.slackWebhookUrl && @@ -3047,11 +3064,11 @@ class _$CompanyEntity extends CompanyEntity { $jc( $jc( $jc( - $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, enableCustomSurchargeTaxes1.hashCode), enableCustomSurchargeTaxes2.hashCode), enableCustomSurchargeTaxes3.hashCode), enableCustomSurchargeTaxes4.hashCode), sizeId.hashCode), industryId.hashCode), subdomain.hashCode), portalMode.hashCode), portalDomain.hashCode), updateProducts.hashCode), convertProductExchangeRate.hashCode), fillProducts.hashCode), enableProductCost.hashCode), enableProductQuantity.hashCode), defaultQuantity.hashCode), showProductDetails.hashCode), plan.hashCode), companyKey.hashCode), appUrl.hashCode), firstDayOfWeek.hashCode), firstMonthOfYear.hashCode), groups.hashCode), activities.hashCode), taxRates.hashCode), taskStatuses.hashCode), taskStatusMap.hashCode), companyGateways.hashCode), expenseCategories.hashCode), expenseCategoryMap.hashCode), users.hashCode), clients.hashCode), products.hashCode), invoices.hashCode), payments.hashCode), quotes.hashCode), credits.hashCode), tasks.hashCode), - projects.hashCode), - expenses.hashCode), - vendors.hashCode), - designs.hashCode), + $jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc($jc(0, enableCustomSurchargeTaxes1.hashCode), enableCustomSurchargeTaxes2.hashCode), enableCustomSurchargeTaxes3.hashCode), enableCustomSurchargeTaxes4.hashCode), sizeId.hashCode), industryId.hashCode), subdomain.hashCode), portalMode.hashCode), portalDomain.hashCode), updateProducts.hashCode), convertProductExchangeRate.hashCode), fillProducts.hashCode), enableProductCost.hashCode), enableProductQuantity.hashCode), defaultQuantity.hashCode), showProductDetails.hashCode), plan.hashCode), companyKey.hashCode), appUrl.hashCode), firstDayOfWeek.hashCode), firstMonthOfYear.hashCode), groups.hashCode), activities.hashCode), taxRates.hashCode), taskStatuses.hashCode), taskStatusMap.hashCode), companyGateways.hashCode), expenseCategories.hashCode), expenseCategoryMap.hashCode), users.hashCode), clients.hashCode), products.hashCode), invoices.hashCode), payments.hashCode), quotes.hashCode), credits.hashCode), tasks.hashCode), projects.hashCode), + expenses.hashCode), + vendors.hashCode), + designs.hashCode), + paymentTerms.hashCode), userMap.hashCode), customFields.hashCode), slackWebhookUrl.hashCode), @@ -3113,6 +3130,7 @@ class _$CompanyEntity extends CompanyEntity { ..add('expenses', expenses) ..add('vendors', vendors) ..add('designs', designs) + ..add('paymentTerms', paymentTerms) ..add('userMap', userMap) ..add('customFields', customFields) ..add('slackWebhookUrl', slackWebhookUrl) @@ -3346,6 +3364,12 @@ class CompanyEntityBuilder _$this._designs ??= new ListBuilder(); set designs(ListBuilder designs) => _$this._designs = designs; + ListBuilder _paymentTerms; + ListBuilder get paymentTerms => + _$this._paymentTerms ??= new ListBuilder(); + set paymentTerms(ListBuilder paymentTerms) => + _$this._paymentTerms = paymentTerms; + MapBuilder _userMap; MapBuilder get userMap => _$this._userMap ??= new MapBuilder(); @@ -3462,6 +3486,7 @@ class CompanyEntityBuilder _expenses = _$v.expenses?.toBuilder(); _vendors = _$v.vendors?.toBuilder(); _designs = _$v.designs?.toBuilder(); + _paymentTerms = _$v.paymentTerms?.toBuilder(); _userMap = _$v.userMap?.toBuilder(); _customFields = _$v.customFields?.toBuilder(); _slackWebhookUrl = _$v.slackWebhookUrl; @@ -3542,6 +3567,7 @@ class CompanyEntityBuilder expenses: expenses.build(), vendors: vendors.build(), designs: designs.build(), + paymentTerms: paymentTerms.build(), userMap: userMap.build(), customFields: customFields.build(), slackWebhookUrl: slackWebhookUrl, @@ -3600,6 +3626,8 @@ class CompanyEntityBuilder vendors.build(); _$failedField = 'designs'; designs.build(); + _$failedField = 'paymentTerms'; + paymentTerms.build(); _$failedField = 'userMap'; userMap.build(); _$failedField = 'customFields'; diff --git a/lib/data/models/entities.dart b/lib/data/models/entities.dart index 90e0e0249..6e0611891 100644 --- a/lib/data/models/entities.dart +++ b/lib/data/models/entities.dart @@ -64,6 +64,7 @@ class EntityType extends EnumClass { EntityType.companyGateway, EntityType.user, EntityType.group, + EntityType.design, ].contains(this); List get relatedTypes { diff --git a/lib/data/models/serializers.g.dart b/lib/data/models/serializers.g.dart index 2427cd534..80e32b6fb 100644 --- a/lib/data/models/serializers.g.dart +++ b/lib/data/models/serializers.g.dart @@ -292,8 +292,10 @@ Serializers _$serializers = (new Serializers().toBuilder() BuiltList, const [const FullType(ExpenseCategoryEntity)]), () => new ListBuilder()) ..addBuilderFactory( - const FullType(BuiltMap, - const [const FullType(String), const FullType(ExpenseCategoryEntity)]), + const FullType(BuiltMap, const [ + const FullType(String), + const FullType(ExpenseCategoryEntity) + ]), () => new MapBuilder()) ..addBuilderFactory( const FullType(BuiltList, const [const FullType(UserEntity)]), @@ -331,6 +333,9 @@ Serializers _$serializers = (new Serializers().toBuilder() ..addBuilderFactory( const FullType(BuiltList, const [const FullType(DesignEntity)]), () => new ListBuilder()) + ..addBuilderFactory( + const FullType(BuiltList, const [const FullType(PaymentTermEntity)]), + () => new ListBuilder()) ..addBuilderFactory( const FullType(BuiltMap, const [const FullType(String), const FullType(UserEntity)]), @@ -355,10 +360,8 @@ Serializers _$serializers = (new Serializers().toBuilder() const FullType(BuiltList, const [const FullType(InvoiceItemEntity)]), () => new ListBuilder()) ..addBuilderFactory( - const FullType(BuiltList, const [const FullType(InvitationEntity)]), - () => new ListBuilder()) - ..addBuilderFactory( - const FullType(BuiltList, const [const FullType(LanguageEntity)]), () => new ListBuilder()) + const FullType(BuiltList, const [const FullType(InvitationEntity)]), () => new ListBuilder()) + ..addBuilderFactory(const FullType(BuiltList, const [const FullType(LanguageEntity)]), () => new ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentEntity)]), () => new ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentTermEntity)]), () => new ListBuilder()) ..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentTypeEntity)]), () => new ListBuilder()) diff --git a/lib/redux/app/app_middleware.dart b/lib/redux/app/app_middleware.dart index dbb84fbe2..534c1aa50 100644 --- a/lib/redux/app/app_middleware.dart +++ b/lib/redux/app/app_middleware.dart @@ -411,7 +411,7 @@ Middleware _createAccountLoaded() { store.dispatch(SelectCompany(i)); store.dispatch(LoadCompanySuccess(userCompany)); - // TODO remove this code + // TODO remove this code/use reducers instead final company = userCompany.company; if (company.clients.isNotEmpty) { store.dispatch(LoadClientsSuccess(company.clients)); diff --git a/lib/redux/app/app_state.dart b/lib/redux/app/app_state.dart index 034398ffd..966252edd 100644 --- a/lib/redux/app/app_state.dart +++ b/lib/redux/app/app_state.dart @@ -561,6 +561,7 @@ abstract class AppState implements Built { //return 'PLAN: ${account.plan}'; //return 'Invoice ${invoiceUIState.editing}'; //return 'Account: $account'; + return 'Payment Terms: ${paymentTermState.map}'; return 'Selected client: ${uiState.clientUIState.selectedId}, Filter: ${uiState.filterEntityType} ${uiState.filterEntityId}'; return 'Layout: ${prefState.appLayout}, Route: ${uiState.currentRoute} Prev: ${uiState.previousRoute}'; } diff --git a/lib/redux/payment_term/payment_term_reducer.dart b/lib/redux/payment_term/payment_term_reducer.dart index bd403b01c..7e652d73f 100644 --- a/lib/redux/payment_term/payment_term_reducer.dart +++ b/lib/redux/payment_term/payment_term_reducer.dart @@ -160,6 +160,7 @@ final paymentTermsReducer = combineReducers([ TypedReducer( _setLoadedPaymentTerms), TypedReducer(_setLoadedPaymentTerm), + TypedReducer(_setLoadedCompany), TypedReducer( _archivePaymentTermRequest), TypedReducer( @@ -306,3 +307,16 @@ PaymentTermState _setLoadedPaymentTerm( PaymentTermState _setLoadedPaymentTerms( PaymentTermState paymentTermState, LoadPaymentTermsSuccess action) => paymentTermState.loadPaymentTerms(action.paymentTerms); + +PaymentTermState _setLoadedCompany( + PaymentTermState paymentTermState, LoadCompanySuccess action) { + final state = paymentTermState.rebuild((b) => b + ..lastUpdated = DateTime.now().millisecondsSinceEpoch + ..map.addAll(Map.fromIterable( + action.userCompany.company.paymentTerms, + key: (dynamic item) => item.id, + value: (dynamic item) => item, + ))); + + return state.rebuild((b) => b..list.replace(state.map.keys)); +} diff --git a/lib/ui/app/list_scaffold.dart b/lib/ui/app/list_scaffold.dart index 3f06f7fde..f1a7aa365 100644 --- a/lib/ui/app/list_scaffold.dart +++ b/lib/ui/app/list_scaffold.dart @@ -16,7 +16,7 @@ class ListScaffold extends StatelessWidget { const ListScaffold({ @required this.appBarTitle, @required this.body, - this.entityType, + @required this.entityType, this.appBarActions, this.bottomNavigationBar, this.floatingActionButton, @@ -24,7 +24,6 @@ class ListScaffold extends StatelessWidget { this.onCheckboxChanged, this.onHamburgerLongPress, this.onBackPressed, - this.isSettings = false, this.showCheckbox = false, }); @@ -34,7 +33,6 @@ class ListScaffold extends StatelessWidget { final FloatingActionButton floatingActionButton; final Widget appBarTitle; final List appBarActions; - final bool isSettings; final bool showCheckbox; final Function(bool) onCheckboxChanged; final Function() onHamburgerLongPress; @@ -46,6 +44,7 @@ class ListScaffold extends StatelessWidget { final store = StoreProvider.of(context); final state = store.state; final localization = AppLocalization.of(context); + final isSettings = entityType.isSetting; Widget leading = SizedBox(); if (showCheckbox && state.prefState.isModuleList) { diff --git a/lib/ui/app/view_scaffold.dart b/lib/ui/app/view_scaffold.dart index b79ccb63f..5fe262896 100644 --- a/lib/ui/app/view_scaffold.dart +++ b/lib/ui/app/view_scaffold.dart @@ -17,12 +17,10 @@ class ViewScaffold extends StatelessWidget { this.title, this.floatingActionButton, this.appBarBottom, - this.isSettings = false, this.isFilter = false, this.onBackPressed, }); - final bool isSettings; final bool isFilter; final BaseEntity entity; final String title; @@ -36,6 +34,7 @@ class ViewScaffold extends StatelessWidget { final store = StoreProvider.of(context); final state = store.state; final userCompany = state.userCompany; + final isSettings = entity.entityType.isSetting; Widget leading; if (!isMobile(context)) { diff --git a/lib/ui/company_gateway/company_gateway_screen.dart b/lib/ui/company_gateway/company_gateway_screen.dart index 5659f9fdf..5b0a74200 100644 --- a/lib/ui/company_gateway/company_gateway_screen.dart +++ b/lib/ui/company_gateway/company_gateway_screen.dart @@ -53,7 +53,6 @@ class CompanyGatewayScreen extends StatelessWidget { handleCompanyGatewayAction( context, companyGateways, EntityAction.toggleMultiselect); }, - isSettings: true, appBarTitle: Text(localization.companyGateways), appBarActions: [ if (viewModel.isInMultiselect) diff --git a/lib/ui/company_gateway/view/company_gateway_view.dart b/lib/ui/company_gateway/view/company_gateway_view.dart index ef72631b1..730c591d8 100644 --- a/lib/ui/company_gateway/view/company_gateway_view.dart +++ b/lib/ui/company_gateway/view/company_gateway_view.dart @@ -54,7 +54,6 @@ class _CompanyGatewayViewState extends State { isFilter: widget.isFilter, entity: companyGateway, onBackPressed: () => viewModel.onBackPressed(), - isSettings: true, body: ListView( children: [ /* diff --git a/lib/ui/design/design_screen.dart b/lib/ui/design/design_screen.dart index 1d1ed2b5e..099a1e0a1 100644 --- a/lib/ui/design/design_screen.dart +++ b/lib/ui/design/design_screen.dart @@ -39,7 +39,6 @@ class DesignScreen extends StatelessWidget { return ListScaffold( entityType: EntityType.design, - isSettings: true, isChecked: isInMultiselect && listUIState.selectedIds.length == viewModel.designList.length, showCheckbox: isInMultiselect, diff --git a/lib/ui/design/view/design_view.dart b/lib/ui/design/view/design_view.dart index f022928e9..73201094f 100644 --- a/lib/ui/design/view/design_view.dart +++ b/lib/ui/design/view/design_view.dart @@ -26,7 +26,6 @@ class _DesignViewState extends State { return ViewScaffold( isFilter: widget.isFilter, entity: design, - isSettings: true, onBackPressed: () => viewModel.onBackPressed(), body: Placeholder(), ); diff --git a/lib/ui/group/group_screen.dart b/lib/ui/group/group_screen.dart index 1444043f1..bcd30fb33 100644 --- a/lib/ui/group/group_screen.dart +++ b/lib/ui/group/group_screen.dart @@ -51,7 +51,6 @@ class GroupSettingsScreen extends StatelessWidget { handleGroupAction(context, groups, EntityAction.toggleMultiselect); }, - isSettings: true, appBarTitle: ListFilter( placeholder: localization.searchGroups, filter: state.groupListState.filter, diff --git a/lib/ui/group/view/group_view.dart b/lib/ui/group/view/group_view.dart index 593e2df95..ad73babc2 100644 --- a/lib/ui/group/view/group_view.dart +++ b/lib/ui/group/view/group_view.dart @@ -40,7 +40,6 @@ class _GroupViewState extends State { return ViewScaffold( isFilter: widget.isFilter, entity: group, - isSettings: true, onBackPressed: () => viewModel.onBackPressed(), body: ListView( children: [ diff --git a/lib/ui/payment_term/payment_term_screen.dart b/lib/ui/payment_term/payment_term_screen.dart index 166194cb4..4d6d3de67 100644 --- a/lib/ui/payment_term/payment_term_screen.dart +++ b/lib/ui/payment_term/payment_term_screen.dart @@ -38,6 +38,7 @@ class PaymentTermScreen extends StatelessWidget { final isInMultiselect = listUIState.isInMultiselect(); return ListScaffold( + entityType: EntityType.paymentTerm, isChecked: isInMultiselect && listUIState.selectedIds.length == viewModel.paymentTermList.length, showCheckbox: isInMultiselect, diff --git a/lib/ui/settings/settings_screen.dart b/lib/ui/settings/settings_screen.dart index 151c2bc34..05a17df61 100644 --- a/lib/ui/settings/settings_screen.dart +++ b/lib/ui/settings/settings_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_redux/flutter_redux.dart'; +import 'package:invoiceninja_flutter/data/models/entities.dart'; import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart'; import 'package:invoiceninja_flutter/ui/app/list_scaffold.dart'; @@ -25,6 +26,7 @@ class SettingsScreen extends StatelessWidget { final state = store.state; return ListScaffold( + entityType: EntityType.settings, appBarTitle: ListFilter( placeholder: localization.searchSettings, filter: state.settingsUIState.filter, diff --git a/lib/ui/tax_rate/tax_rate_screen.dart b/lib/ui/tax_rate/tax_rate_screen.dart index 515e33938..2bb39c59b 100644 --- a/lib/ui/tax_rate/tax_rate_screen.dart +++ b/lib/ui/tax_rate/tax_rate_screen.dart @@ -37,7 +37,6 @@ class TaxRateSettingsScreen extends StatelessWidget { return ListScaffold( entityType: EntityType.taxRate, - isSettings: true, isChecked: isInMultiselect && listUIState.selectedIds.length == viewModel.taxRateList.length, showCheckbox: isInMultiselect, diff --git a/lib/ui/tax_rate/view/tax_rate_view.dart b/lib/ui/tax_rate/view/tax_rate_view.dart index e0be7d4d7..677ecb3b4 100644 --- a/lib/ui/tax_rate/view/tax_rate_view.dart +++ b/lib/ui/tax_rate/view/tax_rate_view.dart @@ -30,7 +30,6 @@ class _TaxRateViewState extends State { return ViewScaffold( isFilter: widget.isFilter, entity: taxRate, - isSettings: true, onBackPressed: () => viewModel.onBackPressed(), body: ListView(children: [ EntityHeader( diff --git a/lib/ui/user/user_screen.dart b/lib/ui/user/user_screen.dart index 923252b65..e6061af6b 100644 --- a/lib/ui/user/user_screen.dart +++ b/lib/ui/user/user_screen.dart @@ -39,7 +39,6 @@ class UserScreen extends StatelessWidget { return ListScaffold( entityType: EntityType.user, - isSettings: true, isChecked: isInMultiselect && listUIState.selectedIds.length == viewModel.userList.length, showCheckbox: isInMultiselect, diff --git a/lib/ui/user/view/user_view.dart b/lib/ui/user/view/user_view.dart index a51c01b85..3a4f300f4 100644 --- a/lib/ui/user/view/user_view.dart +++ b/lib/ui/user/view/user_view.dart @@ -31,7 +31,6 @@ class UserView extends StatelessWidget { return ViewScaffold( isFilter: isFilter, entity: user, - isSettings: true, onBackPressed: () => viewModel.onBackPressed(), body: ListView( children: [ diff --git a/stubs/ui/stub/stub_screen b/stubs/ui/stub/stub_screen index 3b5b1794f..0d1768ce2 100644 --- a/stubs/ui/stub/stub_screen +++ b/stubs/ui/stub/stub_screen @@ -38,6 +38,7 @@ class StubScreen extends StatelessWidget { final isInMultiselect = listUIState.isInMultiselect(); return ListScaffold( + entityType: EntityType.stub, isChecked: isInMultiselect && listUIState.selectedIds.length == viewModel.stubList.length, showCheckbox: isInMultiselect,