Payment terms

This commit is contained in:
Hillel Coren 2020-05-25 21:35:47 +03:00
parent 3e66f7ea24
commit 7a7c17be5a
22 changed files with 69 additions and 27 deletions

View File

@ -96,6 +96,7 @@ abstract class CompanyEntity extends Object
projects: BuiltList<ProjectEntity>(),
vendors: BuiltList<VendorEntity>(),
designs: BuiltList<DesignEntity>(),
paymentTerms: BuiltList<PaymentTermEntity>(),
);
}
@ -215,6 +216,8 @@ abstract class CompanyEntity extends Object
BuiltList<DesignEntity> get designs;
BuiltList<PaymentTermEntity> get paymentTerms;
BuiltMap<String, UserEntity> get userMap;
@BuiltValueField(wireName: 'custom_fields')

View File

@ -173,6 +173,10 @@ class _$CompanyEntitySerializer implements StructuredSerializer<CompanyEntity> {
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<CompanyEntity> {
BuiltList, const [const FullType(DesignEntity)]))
as BuiltList<Object>);
break;
case 'paymentTerms':
result.paymentTerms.replace(serializers.deserialize(value,
specifiedType: const FullType(
BuiltList, const [const FullType(PaymentTermEntity)]))
as BuiltList<Object>);
break;
case 'userMap':
result.userMap.replace(serializers.deserialize(value,
specifiedType: const FullType(BuiltMap,
@ -2726,6 +2736,8 @@ class _$CompanyEntity extends CompanyEntity {
@override
final BuiltList<DesignEntity> designs;
@override
final BuiltList<PaymentTermEntity> paymentTerms;
@override
final BuiltMap<String, UserEntity> userMap;
@override
final BuiltMap<String, String> 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<DesignEntity>();
set designs(ListBuilder<DesignEntity> designs) => _$this._designs = designs;
ListBuilder<PaymentTermEntity> _paymentTerms;
ListBuilder<PaymentTermEntity> get paymentTerms =>
_$this._paymentTerms ??= new ListBuilder<PaymentTermEntity>();
set paymentTerms(ListBuilder<PaymentTermEntity> paymentTerms) =>
_$this._paymentTerms = paymentTerms;
MapBuilder<String, UserEntity> _userMap;
MapBuilder<String, UserEntity> get userMap =>
_$this._userMap ??= new MapBuilder<String, UserEntity>();
@ -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';

View File

@ -64,6 +64,7 @@ class EntityType extends EnumClass {
EntityType.companyGateway,
EntityType.user,
EntityType.group,
EntityType.design,
].contains(this);
List<EntityType> get relatedTypes {

View File

@ -292,8 +292,10 @@ Serializers _$serializers = (new Serializers().toBuilder()
BuiltList, const [const FullType(ExpenseCategoryEntity)]),
() => new ListBuilder<ExpenseCategoryEntity>())
..addBuilderFactory(
const FullType(BuiltMap,
const [const FullType(String), const FullType(ExpenseCategoryEntity)]),
const FullType(BuiltMap, const [
const FullType(String),
const FullType(ExpenseCategoryEntity)
]),
() => new MapBuilder<String, ExpenseCategoryEntity>())
..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<DesignEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(PaymentTermEntity)]),
() => new ListBuilder<PaymentTermEntity>())
..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<InvoiceItemEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(InvitationEntity)]),
() => new ListBuilder<InvitationEntity>())
..addBuilderFactory(
const FullType(BuiltList, const [const FullType(LanguageEntity)]), () => new ListBuilder<LanguageEntity>())
const FullType(BuiltList, const [const FullType(InvitationEntity)]), () => new ListBuilder<InvitationEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(LanguageEntity)]), () => new ListBuilder<LanguageEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentEntity)]), () => new ListBuilder<PaymentEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentTermEntity)]), () => new ListBuilder<PaymentTermEntity>())
..addBuilderFactory(const FullType(BuiltList, const [const FullType(PaymentTypeEntity)]), () => new ListBuilder<PaymentTypeEntity>())

View File

@ -411,7 +411,7 @@ Middleware<AppState> _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));

View File

@ -561,6 +561,7 @@ abstract class AppState implements Built<AppState, AppStateBuilder> {
//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}';
}

View File

@ -160,6 +160,7 @@ final paymentTermsReducer = combineReducers<PaymentTermState>([
TypedReducer<PaymentTermState, LoadPaymentTermsSuccess>(
_setLoadedPaymentTerms),
TypedReducer<PaymentTermState, LoadPaymentTermSuccess>(_setLoadedPaymentTerm),
TypedReducer<PaymentTermState, LoadCompanySuccess>(_setLoadedCompany),
TypedReducer<PaymentTermState, ArchivePaymentTermsRequest>(
_archivePaymentTermRequest),
TypedReducer<PaymentTermState, ArchivePaymentTermsSuccess>(
@ -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));
}

View File

@ -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<Widget> 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<AppState>(context);
final state = store.state;
final localization = AppLocalization.of(context);
final isSettings = entityType.isSetting;
Widget leading = SizedBox();
if (showCheckbox && state.prefState.isModuleList) {

View File

@ -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<AppState>(context);
final state = store.state;
final userCompany = state.userCompany;
final isSettings = entity.entityType.isSetting;
Widget leading;
if (!isMobile(context)) {

View File

@ -53,7 +53,6 @@ class CompanyGatewayScreen extends StatelessWidget {
handleCompanyGatewayAction(
context, companyGateways, EntityAction.toggleMultiselect);
},
isSettings: true,
appBarTitle: Text(localization.companyGateways),
appBarActions: [
if (viewModel.isInMultiselect)

View File

@ -54,7 +54,6 @@ class _CompanyGatewayViewState extends State<CompanyGatewayView> {
isFilter: widget.isFilter,
entity: companyGateway,
onBackPressed: () => viewModel.onBackPressed(),
isSettings: true,
body: ListView(
children: <Widget>[
/*

View File

@ -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,

View File

@ -26,7 +26,6 @@ class _DesignViewState extends State<DesignView> {
return ViewScaffold(
isFilter: widget.isFilter,
entity: design,
isSettings: true,
onBackPressed: () => viewModel.onBackPressed(),
body: Placeholder(),
);

View File

@ -51,7 +51,6 @@ class GroupSettingsScreen extends StatelessWidget {
handleGroupAction(context, groups, EntityAction.toggleMultiselect);
},
isSettings: true,
appBarTitle: ListFilter(
placeholder: localization.searchGroups,
filter: state.groupListState.filter,

View File

@ -40,7 +40,6 @@ class _GroupViewState extends State<GroupView> {
return ViewScaffold(
isFilter: widget.isFilter,
entity: group,
isSettings: true,
onBackPressed: () => viewModel.onBackPressed(),
body: ListView(
children: <Widget>[

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -30,7 +30,6 @@ class _TaxRateViewState extends State<TaxRateView> {
return ViewScaffold(
isFilter: widget.isFilter,
entity: taxRate,
isSettings: true,
onBackPressed: () => viewModel.onBackPressed(),
body: ListView(children: [
EntityHeader(

View File

@ -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,

View File

@ -31,7 +31,6 @@ class UserView extends StatelessWidget {
return ViewScaffold(
isFilter: isFilter,
entity: user,
isSettings: true,
onBackPressed: () => viewModel.onBackPressed(),
body: ListView(
children: <Widget>[

View File

@ -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,