diff --git a/lib/data/models/invoice_model.dart b/lib/data/models/invoice_model.dart index 4cd981d82..0f79663ac 100644 --- a/lib/data/models/invoice_model.dart +++ b/lib/data/models/invoice_model.dart @@ -209,7 +209,7 @@ abstract class InvoiceEntity extends Object invitations: client == null ? BuiltList() : BuiltList(client.emailContacts - .map((contact) => InvitationEntity(contactId: contact.id)) + .map((contact) => InvitationEntity(clientContactId: contact.id)) .toList()), updatedAt: 0, archivedAt: 0, @@ -275,7 +275,8 @@ abstract class InvoiceEntity extends Object (lineItem) => lineItem.typeId != InvoiceItemEntity.TYPE_UNPAID_FEE) .toList()) ..invitations.replace(invitations - .map((invitation) => InvitationEntity(contactId: invitation.contactId)) + .map((invitation) => + InvitationEntity(clientContactId: invitation.clientContactId)) .toList())); InvoiceEntity applyClient(AppState state, ClientEntity client) { @@ -1193,7 +1194,7 @@ abstract class InvoiceEntity extends Object InvitationEntity getInvitationForContact(ContactEntity contact) { return invitations.firstWhere( - (invitation) => invitation.contactId == contact.id, + (invitation) => invitation.clientContactId == contact.id, orElse: () => null); } @@ -1579,11 +1580,15 @@ abstract class InvoiceItemEntity abstract class InvitationEntity extends Object with BaseEntity, SelectableEntity implements Built { - factory InvitationEntity({String contactId}) { + factory InvitationEntity({ + String clientContactId, + String vendorContactId, + }) { return _$InvitationEntity._( id: BaseEntity.nextId, isChanged: false, - contactId: contactId ?? '', + clientContactId: clientContactId ?? '', + vendorContactId: vendorContactId ?? '', createdAt: 0, key: '', link: '', @@ -1611,7 +1616,10 @@ abstract class InvitationEntity extends Object String get link; @BuiltValueField(wireName: 'client_contact_id') - String get contactId; + String get clientContactId; + + @BuiltValueField(wireName: 'vendor_contact_id') + String get vendorContactId; @BuiltValueField(wireName: 'sent_date', compare: false) String get sentDate; @@ -1662,6 +1670,11 @@ abstract class InvitationEntity extends Object @override FormatNumberType get listDisplayAmountType => FormatNumberType.money; + // ignore: unused_element + static void _initializeBuilder(InvitationEntityBuilder builder) => builder + ..clientContactId = '' + ..vendorContactId = ''; + static Serializer get serializer => _$invitationEntitySerializer; } diff --git a/lib/data/models/invoice_model.g.dart b/lib/data/models/invoice_model.g.dart index 54835f563..45e1c4c43 100644 --- a/lib/data/models/invoice_model.g.dart +++ b/lib/data/models/invoice_model.g.dart @@ -935,7 +935,10 @@ class _$InvitationEntitySerializer 'link', serializers.serialize(object.link, specifiedType: const FullType(String)), 'client_contact_id', - serializers.serialize(object.contactId, + serializers.serialize(object.clientContactId, + specifiedType: const FullType(String)), + 'vendor_contact_id', + serializers.serialize(object.vendorContactId, specifiedType: const FullType(String)), 'sent_date', serializers.serialize(object.sentDate, @@ -1025,7 +1028,11 @@ class _$InvitationEntitySerializer specifiedType: const FullType(String)) as String; break; case 'client_contact_id': - result.contactId = serializers.deserialize(value, + result.clientContactId = serializers.deserialize(value, + specifiedType: const FullType(String)) as String; + break; + case 'vendor_contact_id': + result.vendorContactId = serializers.deserialize(value, specifiedType: const FullType(String)) as String; break; case 'sent_date': @@ -2806,7 +2813,9 @@ class _$InvitationEntity extends InvitationEntity { @override final String link; @override - final String contactId; + final String clientContactId; + @override + final String vendorContactId; @override final String sentDate; @override @@ -2841,7 +2850,8 @@ class _$InvitationEntity extends InvitationEntity { _$InvitationEntity._( {this.key, this.link, - this.contactId, + this.clientContactId, + this.vendorContactId, this.sentDate, this.viewedDate, this.openedDate, @@ -2859,7 +2869,9 @@ class _$InvitationEntity extends InvitationEntity { BuiltValueNullFieldError.checkNotNull(key, 'InvitationEntity', 'key'); BuiltValueNullFieldError.checkNotNull(link, 'InvitationEntity', 'link'); BuiltValueNullFieldError.checkNotNull( - contactId, 'InvitationEntity', 'contactId'); + clientContactId, 'InvitationEntity', 'clientContactId'); + BuiltValueNullFieldError.checkNotNull( + vendorContactId, 'InvitationEntity', 'vendorContactId'); BuiltValueNullFieldError.checkNotNull( sentDate, 'InvitationEntity', 'sentDate'); BuiltValueNullFieldError.checkNotNull( @@ -2889,7 +2901,8 @@ class _$InvitationEntity extends InvitationEntity { return other is InvitationEntity && key == other.key && link == other.link && - contactId == other.contactId && + clientContactId == other.clientContactId && + vendorContactId == other.vendorContactId && isChanged == other.isChanged && createdAt == other.createdAt && updatedAt == other.updatedAt && @@ -2914,9 +2927,11 @@ class _$InvitationEntity extends InvitationEntity { $jc( $jc( $jc( - $jc($jc(0, key.hashCode), - link.hashCode), - contactId.hashCode), + $jc( + $jc($jc(0, key.hashCode), + link.hashCode), + clientContactId.hashCode), + vendorContactId.hashCode), isChanged.hashCode), createdAt.hashCode), updatedAt.hashCode), @@ -2933,7 +2948,8 @@ class _$InvitationEntity extends InvitationEntity { return (newBuiltValueToStringHelper('InvitationEntity') ..add('key', key) ..add('link', link) - ..add('contactId', contactId) + ..add('clientContactId', clientContactId) + ..add('vendorContactId', vendorContactId) ..add('sentDate', sentDate) ..add('viewedDate', viewedDate) ..add('openedDate', openedDate) @@ -2963,9 +2979,15 @@ class InvitationEntityBuilder String get link => _$this._link; set link(String link) => _$this._link = link; - String _contactId; - String get contactId => _$this._contactId; - set contactId(String contactId) => _$this._contactId = contactId; + String _clientContactId; + String get clientContactId => _$this._clientContactId; + set clientContactId(String clientContactId) => + _$this._clientContactId = clientContactId; + + String _vendorContactId; + String get vendorContactId => _$this._vendorContactId; + set vendorContactId(String vendorContactId) => + _$this._vendorContactId = vendorContactId; String _sentDate; String get sentDate => _$this._sentDate; @@ -3021,14 +3043,17 @@ class InvitationEntityBuilder String get id => _$this._id; set id(String id) => _$this._id = id; - InvitationEntityBuilder(); + InvitationEntityBuilder() { + InvitationEntity._initializeBuilder(this); + } InvitationEntityBuilder get _$this { final $v = _$v; if ($v != null) { _key = $v.key; _link = $v.link; - _contactId = $v.contactId; + _clientContactId = $v.clientContactId; + _vendorContactId = $v.vendorContactId; _sentDate = $v.sentDate; _viewedDate = $v.viewedDate; _openedDate = $v.openedDate; @@ -3066,8 +3091,10 @@ class InvitationEntityBuilder key, 'InvitationEntity', 'key'), link: BuiltValueNullFieldError.checkNotNull( link, 'InvitationEntity', 'link'), - contactId: BuiltValueNullFieldError.checkNotNull( - contactId, 'InvitationEntity', 'contactId'), + clientContactId: BuiltValueNullFieldError.checkNotNull( + clientContactId, 'InvitationEntity', 'clientContactId'), + vendorContactId: BuiltValueNullFieldError.checkNotNull( + vendorContactId, 'InvitationEntity', 'vendorContactId'), sentDate: BuiltValueNullFieldError.checkNotNull( sentDate, 'InvitationEntity', 'sentDate'), viewedDate: BuiltValueNullFieldError.checkNotNull( @@ -3078,10 +3105,9 @@ class InvitationEntityBuilder isChanged: isChanged, createdAt: BuiltValueNullFieldError.checkNotNull( createdAt, 'InvitationEntity', 'createdAt'), - updatedAt: BuiltValueNullFieldError.checkNotNull( - updatedAt, 'InvitationEntity', 'updatedAt'), - archivedAt: BuiltValueNullFieldError.checkNotNull( - archivedAt, 'InvitationEntity', 'archivedAt'), + updatedAt: + BuiltValueNullFieldError.checkNotNull(updatedAt, 'InvitationEntity', 'updatedAt'), + archivedAt: BuiltValueNullFieldError.checkNotNull(archivedAt, 'InvitationEntity', 'archivedAt'), isDeleted: isDeleted, createdUserId: createdUserId, assignedUserId: assignedUserId, diff --git a/lib/data/models/vendor_model.dart b/lib/data/models/vendor_model.dart index 506a6a4e8..ec9b03e5a 100644 --- a/lib/data/models/vendor_model.dart +++ b/lib/data/models/vendor_model.dart @@ -438,6 +438,12 @@ abstract class VendorEntity extends Object } } + List get emailContacts { + //final list = contacts.where((contact) => contact.sendEmail).toList(); + final list = contacts.where((contact) => true).toList(); + return list.isEmpty ? [primaryContact] : list; + } + VendorContactEntity get primaryContact => contacts.firstWhere((contact) => contact.isPrimary, orElse: () => VendorContactEntity()); diff --git a/lib/redux/credit/credit_reducer.dart b/lib/redux/credit/credit_reducer.dart index 76723945a..e60552cfc 100644 --- a/lib/redux/credit/credit_reducer.dart +++ b/lib/redux/credit/credit_reducer.dart @@ -118,7 +118,7 @@ final editingReducer = combineReducers([ ..isChanged = true ..clientId = client?.id ?? '' ..invitations.replace((client?.emailContacts ?? []) - .map((contact) => InvitationEntity(contactId: contact.id)) + .map((contact) => InvitationEntity(clientContactId: contact.id)) .toList())); }), TypedReducer((credits, action) { @@ -137,8 +137,8 @@ final editingReducer = combineReducers([ TypedReducer(_clearEditing), TypedReducer((invoice, action) { return invoice.rebuild((b) => b - ..invitations.add( - action.invitation ?? InvitationEntity(contactId: action.contact.id))); + ..invitations.add(action.invitation ?? + InvitationEntity(clientContactId: action.contact.id))); }), TypedReducer((invoice, action) { return invoice.rebuild((b) => b..invitations.remove(action.invitation)); diff --git a/lib/redux/credit/credit_selectors.dart b/lib/redux/credit/credit_selectors.dart index c4bd8a98a..ee525c254 100644 --- a/lib/redux/credit/credit_selectors.dart +++ b/lib/redux/credit/credit_selectors.dart @@ -8,8 +8,9 @@ import 'package:invoiceninja_flutter/redux/app/app_state.dart'; import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart'; ContactEntity creditContactSelector(InvoiceEntity credit, ClientEntity client) { - var contactIds = - credit.invitations.map((invitation) => invitation.contactId).toList(); + var contactIds = credit.invitations + .map((invitation) => invitation.clientContactId) + .toList(); if (contactIds.contains(client.primaryContact.id)) { contactIds = [client.primaryContact.id]; } diff --git a/lib/redux/invoice/invoice_reducer.dart b/lib/redux/invoice/invoice_reducer.dart index e0f2248e7..68cf1b1bf 100644 --- a/lib/redux/invoice/invoice_reducer.dart +++ b/lib/redux/invoice/invoice_reducer.dart @@ -122,7 +122,7 @@ final editingReducer = combineReducers([ ..isChanged = true ..clientId = client?.id ?? '' ..invitations.replace((client?.emailContacts ?? []) - .map((contact) => InvitationEntity(contactId: contact.id)) + .map((contact) => InvitationEntity(clientContactId: contact.id)) .toList())); }), TypedReducer((invoices, action) { @@ -141,8 +141,8 @@ final editingReducer = combineReducers([ TypedReducer(_clearEditing), TypedReducer((invoice, action) { return invoice.rebuild((b) => b - ..invitations.add( - action.invitation ?? InvitationEntity(contactId: action.contact.id))); + ..invitations.add(action.invitation ?? + InvitationEntity(clientContactId: action.contact.id))); }), TypedReducer((invoice, action) { return invoice.rebuild((b) => b..invitations.remove(action.invitation)); diff --git a/lib/redux/invoice/invoice_selectors.dart b/lib/redux/invoice/invoice_selectors.dart index c77afb751..3fe779c6f 100644 --- a/lib/redux/invoice/invoice_selectors.dart +++ b/lib/redux/invoice/invoice_selectors.dart @@ -20,8 +20,9 @@ InvoiceEntity invoiceQuoteSelector( ContactEntity invoiceContactSelector( InvoiceEntity invoice, ClientEntity client) { - var contactIds = - invoice.invitations.map((invitation) => invitation.contactId).toList(); + var contactIds = invoice.invitations + .map((invitation) => invitation.clientContactId) + .toList(); if (contactIds.contains(client.primaryContact.id)) { contactIds = [client.primaryContact.id]; } diff --git a/lib/redux/purchase_order/purchase_order_actions.dart b/lib/redux/purchase_order/purchase_order_actions.dart index dc0a24238..7bf5d9d4d 100644 --- a/lib/redux/purchase_order/purchase_order_actions.dart +++ b/lib/redux/purchase_order/purchase_order_actions.dart @@ -29,11 +29,13 @@ class EditPurchaseOrder implements PersistUI, PersistPrefs { EditPurchaseOrder( {@required this.purchaseOrder, this.completer, + this.purchaseOrderItemIndex, this.cancelCompleter, this.force = false}); final InvoiceEntity purchaseOrder; final Completer completer; + final int purchaseOrderItemIndex; final Completer cancelCompleter; final bool force; } @@ -66,6 +68,12 @@ class UpdatePurchaseOrder implements PersistUI { final InvoiceEntity purchaseOrder; } +class UpdatePurchaseOrderVendor implements PersistUI { + UpdatePurchaseOrderVendor({this.vendor}); + + final VendorEntity vendor; +} + class LoadPurchaseOrder { LoadPurchaseOrder({this.completer, this.purchaseOrderId}); @@ -237,9 +245,9 @@ class EmailPurchaseOrderRequest implements StartSaving { } class EmailPurchaseOrderSuccess implements StopSaving, PersistData { - EmailPurchaseOrderSuccess(this.quote); + EmailPurchaseOrderSuccess(this.purchaseOrder); - final InvoiceEntity quote; + final InvoiceEntity purchaseOrder; } class EmailPurchaseOrderFailure implements StopSaving { @@ -248,6 +256,44 @@ class EmailPurchaseOrderFailure implements StopSaving { final dynamic error; } +class MarkSentPurchaseOrdersRequest implements StartSaving { + MarkSentPurchaseOrdersRequest(this.completer, this.purchaseOrderIds); + + final Completer completer; + final List purchaseOrderIds; +} + +class MarkSentPurchaseOrderSuccess implements StopSaving, PersistData { + MarkSentPurchaseOrderSuccess(this.purchaseOrders); + + final List purchaseOrders; +} + +class MarkSentPurchaseOrderFailure implements StopSaving { + MarkSentPurchaseOrderFailure(this.error); + + final Object error; +} + +class ApprovePurchaseOrders implements StartSaving { + ApprovePurchaseOrders(this.completer, this.purchaseOrderIds); + + final List purchaseOrderIds; + final Completer completer; +} + +class ApprovePurchaseOrderSuccess implements StopSaving { + ApprovePurchaseOrderSuccess({this.purchaseOrders}); + + final List purchaseOrders; +} + +class ApprovePurchaseOrderFailure implements StopSaving { + ApprovePurchaseOrderFailure(this.error); + + final dynamic error; +} + class AddPurchaseOrderContact implements PersistUI { AddPurchaseOrderContact({this.contact, this.invitation}); @@ -314,6 +360,18 @@ class FilterPurchaseOrdersByState implements PersistUI { final EntityState state; } +class FilterPurchaseOrdersByStatus implements PersistUI { + FilterPurchaseOrdersByStatus(this.status); + + final EntityStatus status; +} + +class FilterPurchaseOrderDropdown { + FilterPurchaseOrderDropdown(this.filter); + + final String filter; +} + class FilterPurchaseOrdersByCustom1 implements PersistUI { FilterPurchaseOrdersByCustom1(this.value); diff --git a/lib/redux/purchase_order/purchase_order_reducer.dart b/lib/redux/purchase_order/purchase_order_reducer.dart index 347ffdedc..027fac3ef 100644 --- a/lib/redux/purchase_order/purchase_order_reducer.dart +++ b/lib/redux/purchase_order/purchase_order_reducer.dart @@ -1,21 +1,28 @@ -import 'package:redux/redux.dart'; +// Package imports: import 'package:built_collection/built_collection.dart'; -import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/data/models/models.dart'; +import 'package:redux/redux.dart'; + +// Project imports: +import 'package:invoiceninja_flutter/redux/app/app_actions.dart'; import 'package:invoiceninja_flutter/redux/company/company_actions.dart'; -import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart'; import 'package:invoiceninja_flutter/redux/purchase_order/purchase_order_actions.dart'; -import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart'; import 'package:invoiceninja_flutter/redux/purchase_order/purchase_order_state.dart'; +import 'package:invoiceninja_flutter/redux/ui/entity_ui_state.dart'; +import 'package:invoiceninja_flutter/redux/ui/list_ui_state.dart'; EntityUIState purchaseOrderUIReducer( PurchaseOrderUIState state, dynamic action) { return state.rebuild((b) => b - ..listUIState.replace(purchaseOrderListReducer(state.listUIState, action)) - ..editing.replace(editingReducer(state.editing, action)) - ..selectedId = selectedIdReducer(state.selectedId, action) - ..forceSelected = forceSelectedReducer(state.forceSelected, action) - ..tabIndex = tabIndexReducer(state.tabIndex, action)); + ..listUIState + .replace(purchaseOrderListReducer(state.listUIState, action)) + ..editing.replace(editingReducer(state.editing, action)) + ..editingItemIndex = editingItemReducer(state.editingItemIndex, action) + ..selectedId = selectedIdReducer(state.selectedId, action) + ..forceSelected = forceSelectedReducer(state.forceSelected, action) + ..tabIndex = tabIndexReducer(state.tabIndex, action) + //..historyActivityId = historyActivityIdReducer(state.historyActivityId, action) + ); } final forceSelectedReducer = combineReducers([ @@ -42,6 +49,27 @@ final tabIndexReducer = combineReducers([ }), ]); +final historyActivityIdReducer = combineReducers([ + TypedReducer( + (index, action) => action.activityId), +]); + +final editingItemReducer = combineReducers([ + TypedReducer( + (index, action) => action.purchaseOrderItemIndex), + TypedReducer((index, action) => action.itemIndex), +]); + +Reducer dropdownFilterReducer = combineReducers([ + TypedReducer( + filterpurchaseOrderDropdownReducer), +]); + +String filterpurchaseOrderDropdownReducer( + String dropdownFilter, FilterPurchaseOrderDropdown action) { + return action.filter; +} + Reducer selectedIdReducer = combineReducers([ TypedReducer((completer, action) => ''), TypedReducer((completer, action) => ''), @@ -50,15 +78,21 @@ Reducer selectedIdReducer = combineReducers([ ? action.entityId : selectedId), TypedReducer( - (String selectedId, dynamic action) => action.purchaseOrderId), + (selectedId, action) => action.purchaseOrderId), TypedReducer( - (String selectedId, dynamic action) => action.purchaseOrder.id), + (selectedId, action) => action.purchaseOrder.id), + TypedReducer( + (selectedId, action) => action.purchaseOrder.id), + TypedReducer( + (selectedId, action) => action.purchaseOrder.id), TypedReducer( (selectedId, action) => action.clearSelection ? '' : selectedId), TypedReducer((selectedId, action) => ''), TypedReducer((selectedId, action) => ''), TypedReducer((selectedId, action) => ''), TypedReducer((selectedId, action) => ''), + TypedReducer( + (selectedId, action) => ''), TypedReducer( (selectedId, action) => ''), TypedReducer( @@ -67,6 +101,8 @@ Reducer selectedIdReducer = combineReducers([ (selectedId, action) => ''), TypedReducer( (selectedId, action) => ''), + TypedReducer((selectedId, action) => + action.entityType == EntityType.purchaseOrder ? '' : selectedId), TypedReducer( (selectedId, action) => action.clearSelection ? '' @@ -78,6 +114,32 @@ Reducer selectedIdReducer = combineReducers([ final editingReducer = combineReducers([ TypedReducer(_updateEditing), TypedReducer(_updateEditing), + TypedReducer(_updateEditing), + TypedReducer((purchaseOrder, action) { + return action.purchaseOrder.rebuild((b) => b..isChanged = true); + }), + TypedReducer((invoice, action) { + return invoice.rebuild((b) => b..isChanged = true); + }), + TypedReducer((invoice, action) { + return invoice.moveLineItem(action.oldIndex, action.newIndex); + }), + TypedReducer((invoice, action) { + return invoice.rebuild((b) => b..isChanged = true); + }), + TypedReducer((invoice, action) { + return invoice.rebuild((b) => b..isChanged = true); + }), + TypedReducer( + (purchaseOrder, action) { + final vendor = action.vendor; + return purchaseOrder.rebuild((b) => b + ..isChanged = true + ..vendorId = vendor?.id ?? '' + ..invitations.replace((vendor?.emailContacts ?? []) + .map((contact) => InvitationEntity(vendorContactId: contact.id)) + .toList())); + }), TypedReducer( (purchaseOrders, action) { return action.purchaseOrders[0]; @@ -90,11 +152,21 @@ final editingReducer = combineReducers([ (purchaseOrders, action) { return action.purchaseOrders[0]; }), - TypedReducer(_updateEditing), - TypedReducer((purchaseOrder, action) { - return action.purchaseOrder.rebuild((b) => b..isChanged = true); - }), + TypedReducer(_addPurchaseOrderItem), + TypedReducer(_addPurchaseOrderItems), + TypedReducer( + _removePurchaseOrderItem), + TypedReducer( + _updatePurchaseOrderItem), TypedReducer(_clearEditing), + TypedReducer((invoice, action) { + return invoice.rebuild((b) => b + ..invitations.add(action.invitation ?? + InvitationEntity(clientContactId: action.contact.id))); + }), + TypedReducer((invoice, action) { + return invoice.rebuild((b) => b..invitations.remove(action.invitation)); + }), ]); InvoiceEntity _clearEditing(InvoiceEntity purchaseOrder, dynamic action) { @@ -105,15 +177,49 @@ InvoiceEntity _updateEditing(InvoiceEntity purchaseOrder, dynamic action) { return action.purchaseOrder; } +InvoiceEntity _addPurchaseOrderItem( + InvoiceEntity purchaseOrder, AddPurchaseOrderItem action) { + return purchaseOrder.rebuild( + (b) => b..lineItems.add(action.purchaseOrderItem ?? InvoiceItemEntity())); +} + +InvoiceEntity _addPurchaseOrderItems( + InvoiceEntity purchaseOrder, AddPurchaseOrderItems action) { + return purchaseOrder.rebuild((b) => b..lineItems.addAll(action.lineItems)); +} + +InvoiceEntity _removePurchaseOrderItem( + InvoiceEntity purchaseOrder, DeletePurchaseOrderItem action) { + if (purchaseOrder.lineItems.length <= action.index) { + return purchaseOrder; + } + return purchaseOrder.rebuild((b) => b..lineItems.removeAt(action.index)); +} + +InvoiceEntity _updatePurchaseOrderItem( + InvoiceEntity purchaseOrder, UpdatePurchaseOrderItem action) { + if (purchaseOrder.lineItems.length <= action.index) { + return purchaseOrder; + } + return purchaseOrder + .rebuild((b) => b..lineItems[action.index] = action.purchaseOrderItem); +} + final purchaseOrderListReducer = combineReducers([ TypedReducer(_sortPurchaseOrders), TypedReducer( _filterPurchaseOrdersByState), + TypedReducer( + _filterPurchaseOrdersByStatus), TypedReducer(_filterPurchaseOrders), TypedReducer( _filterPurchaseOrdersByCustom1), TypedReducer( _filterPurchaseOrdersByCustom2), + TypedReducer( + _filterPurchaseOrdersByCustom3), + TypedReducer( + _filterPurchaseOrdersByCustom4), TypedReducer( _startListMultiselect), TypedReducer( @@ -155,6 +261,28 @@ ListUIState _filterPurchaseOrdersByCustom2( } } +ListUIState _filterPurchaseOrdersByCustom3( + ListUIState purchaseOrderListState, FilterPurchaseOrdersByCustom3 action) { + if (purchaseOrderListState.custom3Filters.contains(action.value)) { + return purchaseOrderListState + .rebuild((b) => b..custom3Filters.remove(action.value)); + } else { + return purchaseOrderListState + .rebuild((b) => b..custom3Filters.add(action.value)); + } +} + +ListUIState _filterPurchaseOrdersByCustom4( + ListUIState purchaseOrderListState, FilterPurchaseOrdersByCustom4 action) { + if (purchaseOrderListState.custom4Filters.contains(action.value)) { + return purchaseOrderListState + .rebuild((b) => b..custom4Filters.remove(action.value)); + } else { + return purchaseOrderListState + .rebuild((b) => b..custom4Filters.add(action.value)); + } +} + ListUIState _filterPurchaseOrdersByState( ListUIState purchaseOrderListState, FilterPurchaseOrdersByState action) { if (purchaseOrderListState.stateFilters.contains(action.state)) { @@ -166,6 +294,17 @@ ListUIState _filterPurchaseOrdersByState( } } +ListUIState _filterPurchaseOrdersByStatus( + ListUIState purchaseOrderListState, FilterPurchaseOrdersByStatus action) { + if (purchaseOrderListState.statusFilters.contains(action.status)) { + return purchaseOrderListState + .rebuild((b) => b..statusFilters.remove(action.status)); + } else { + return purchaseOrderListState + .rebuild((b) => b..statusFilters.add(action.status)); + } +} + ListUIState _filterPurchaseOrders( ListUIState purchaseOrderListState, FilterPurchaseOrders action) { return purchaseOrderListState.rebuild((b) => b @@ -183,24 +322,25 @@ ListUIState _sortPurchaseOrders( } ListUIState _startListMultiselect( - ListUIState productListState, StartPurchaseOrderMultiselect action) { - return productListState.rebuild((b) => b..selectedIds = ListBuilder()); + ListUIState purchaseOrderListState, StartPurchaseOrderMultiselect action) { + return purchaseOrderListState.rebuild((b) => b..selectedIds = ListBuilder()); } ListUIState _addToListMultiselect( - ListUIState productListState, AddToPurchaseOrderMultiselect action) { - return productListState.rebuild((b) => b..selectedIds.add(action.entity.id)); + ListUIState purchaseOrderListState, AddToPurchaseOrderMultiselect action) { + return purchaseOrderListState + .rebuild((b) => b..selectedIds.add(action.entity.id)); } -ListUIState _removeFromListMultiselect( - ListUIState productListState, RemoveFromPurchaseOrderMultiselect action) { - return productListState +ListUIState _removeFromListMultiselect(ListUIState purchaseOrderListState, + RemoveFromPurchaseOrderMultiselect action) { + return purchaseOrderListState .rebuild((b) => b..selectedIds.remove(action.entity.id)); } ListUIState _clearListMultiselect( - ListUIState productListState, ClearPurchaseOrderMultiselect action) { - return productListState.rebuild((b) => b..selectedIds = null); + ListUIState purchaseOrderListState, ClearPurchaseOrderMultiselect action) { + return purchaseOrderListState.rebuild((b) => b..selectedIds = null); } final purchaseOrdersReducer = combineReducers([ @@ -210,16 +350,33 @@ final purchaseOrdersReducer = combineReducers([ TypedReducer( _setLoadedPurchaseOrders), TypedReducer( - _setLoadedPurchaseOrder), + _updatePurchaseOrder), TypedReducer(_setLoadedCompany), + TypedReducer( + _markSentPurchaseOrderSuccess), + TypedReducer( + _emailPurchaseOrderSuccess), TypedReducer( _archivePurchaseOrderSuccess), TypedReducer( _deletePurchaseOrderSuccess), TypedReducer( _restorePurchaseOrderSuccess), + TypedReducer( + _approvePurchaseOrderSuccess), ]); +PurchaseOrderState _markSentPurchaseOrderSuccess( + PurchaseOrderState purchaseOrderState, + MarkSentPurchaseOrderSuccess action) { + final purchaseOrderMap = Map.fromIterable( + action.purchaseOrders, + key: (dynamic item) => item.id, + value: (dynamic item) => item, + ); + return purchaseOrderState.rebuild((b) => b..map.addAll(purchaseOrderMap)); +} + PurchaseOrderState _archivePurchaseOrderSuccess( PurchaseOrderState purchaseOrderState, ArchivePurchaseOrdersSuccess action) { @@ -249,23 +406,36 @@ PurchaseOrderState _restorePurchaseOrderSuccess( }); } +PurchaseOrderState _emailPurchaseOrderSuccess( + PurchaseOrderState purchaseOrderState, EmailPurchaseOrderSuccess action) { + return purchaseOrderState + .rebuild((b) => b..map[action.purchaseOrder.id] = action.purchaseOrder); +} + +PurchaseOrderState _approvePurchaseOrderSuccess( + PurchaseOrderState purchaseOrderState, ApprovePurchaseOrderSuccess action) { + final purchaseOrderMap = Map.fromIterable( + action.purchaseOrders, + key: (dynamic item) => item.id, + value: (dynamic item) => item, + ); + return purchaseOrderState.rebuild((b) => b..map.addAll(purchaseOrderMap)); +} + PurchaseOrderState _addPurchaseOrder( PurchaseOrderState purchaseOrderState, AddPurchaseOrderSuccess action) { return purchaseOrderState.rebuild((b) => b ..map[action.purchaseOrder.id] = action.purchaseOrder + .rebuild((b) => b..loadedAt = DateTime.now().millisecondsSinceEpoch) ..list.add(action.purchaseOrder.id)); } PurchaseOrderState _updatePurchaseOrder( - PurchaseOrderState purchaseOrderState, SavePurchaseOrderSuccess action) { - return purchaseOrderState - .rebuild((b) => b..map[action.purchaseOrder.id] = action.purchaseOrder); -} - -PurchaseOrderState _setLoadedPurchaseOrder( - PurchaseOrderState purchaseOrderState, LoadPurchaseOrderSuccess action) { - return purchaseOrderState - .rebuild((b) => b..map[action.purchaseOrder.id] = action.purchaseOrder); + PurchaseOrderState invoiceState, dynamic action) { + final InvoiceEntity purchaseOrder = action.purchaseOrder; + return invoiceState.rebuild((b) => b + ..map[purchaseOrder.id] = purchaseOrder + .rebuild((b) => b..loadedAt = DateTime.now().millisecondsSinceEpoch)); } PurchaseOrderState _setLoadedPurchaseOrders( diff --git a/lib/redux/quote/quote_reducer.dart b/lib/redux/quote/quote_reducer.dart index 3ade679d2..550f6bf38 100644 --- a/lib/redux/quote/quote_reducer.dart +++ b/lib/redux/quote/quote_reducer.dart @@ -119,7 +119,7 @@ final editingReducer = combineReducers([ ..isChanged = true ..clientId = client?.id ?? '' ..invitations.replace((client?.emailContacts ?? []) - .map((contact) => InvitationEntity(contactId: contact.id)) + .map((contact) => InvitationEntity(clientContactId: contact.id)) .toList())); }), TypedReducer((quotes, action) { @@ -138,8 +138,8 @@ final editingReducer = combineReducers([ TypedReducer(_clearEditing), TypedReducer((invoice, action) { return invoice.rebuild((b) => b - ..invitations.add( - action.invitation ?? InvitationEntity(contactId: action.contact.id))); + ..invitations.add(action.invitation ?? + InvitationEntity(clientContactId: action.contact.id))); }), TypedReducer((invoice, action) { return invoice.rebuild((b) => b..invitations.remove(action.invitation)); @@ -151,7 +151,7 @@ InvoiceEntity _clearEditing(InvoiceEntity quote, dynamic action) { } InvoiceEntity _updateEditing(InvoiceEntity quote, dynamic action) { - return action.quote; + return action.purchaseOrder; } InvoiceEntity _addQuoteItem(InvoiceEntity quote, AddQuoteItem action) { @@ -367,7 +367,7 @@ QuoteState _addQuote(QuoteState quoteState, AddQuoteSuccess action) { } QuoteState _updateQuote(QuoteState invoiceState, dynamic action) { - final InvoiceEntity quote = action.quote; + final InvoiceEntity quote = action.purchaseOrder; return invoiceState.rebuild((b) => b ..map[quote.id] = quote .rebuild((b) => b..loadedAt = DateTime.now().millisecondsSinceEpoch)); diff --git a/lib/redux/quote/quote_selectors.dart b/lib/redux/quote/quote_selectors.dart index aed73e74d..3a707ec36 100644 --- a/lib/redux/quote/quote_selectors.dart +++ b/lib/redux/quote/quote_selectors.dart @@ -13,8 +13,9 @@ ClientEntity quoteClientSelector( } ContactEntity quoteContactSelector(InvoiceEntity quote, ClientEntity client) { - var contactIds = - quote.invitations.map((invitation) => invitation.contactId).toList(); + var contactIds = quote.invitations + .map((invitation) => invitation.clientContactId) + .toList(); if (contactIds.contains(client.primaryContact.id)) { contactIds = [client.primaryContact.id]; } diff --git a/lib/redux/recurring_invoice/recurring_invoice_reducer.dart b/lib/redux/recurring_invoice/recurring_invoice_reducer.dart index b5457da7e..a8202c09e 100644 --- a/lib/redux/recurring_invoice/recurring_invoice_reducer.dart +++ b/lib/redux/recurring_invoice/recurring_invoice_reducer.dart @@ -145,7 +145,7 @@ final editingReducer = combineReducers([ ..isChanged = true ..clientId = client?.id ?? '' ..invitations.replace((client?.emailContacts ?? []) - .map((contact) => InvitationEntity(contactId: contact.id)) + .map((contact) => InvitationEntity(clientContactId: contact.id)) .toList())); }), TypedReducer( @@ -172,8 +172,8 @@ final editingReducer = combineReducers([ TypedReducer( (recurringInvoice, action) { return recurringInvoice.rebuild((b) => b - ..invitations.add( - action.invitation ?? InvitationEntity(contactId: action.contact.id))); + ..invitations.add(action.invitation ?? + InvitationEntity(clientContactId: action.contact.id))); }), TypedReducer( (recurringInvoice, action) { diff --git a/lib/ui/app/invoice/invoice_email_view.dart b/lib/ui/app/invoice/invoice_email_view.dart index 0098e23c4..467f3723b 100644 --- a/lib/ui/app/invoice/invoice_email_view.dart +++ b/lib/ui/app/invoice/invoice_email_view.dart @@ -177,7 +177,7 @@ class _InvoiceEmailViewState extends State final settings = getClientSettings(state, client); final contacts = invoice.invitations .map((invitation) => client.contacts.firstWhere( - (contact) => contact.id == invitation.contactId, + (contact) => contact.id == invitation.clientContactId, orElse: () => null)) .toList(); diff --git a/lib/ui/invoice/edit/invoice_edit_desktop.dart b/lib/ui/invoice/edit/invoice_edit_desktop.dart index 66382dc9e..c5834b149 100644 --- a/lib/ui/invoice/edit/invoice_edit_desktop.dart +++ b/lib/ui/invoice/edit/invoice_edit_desktop.dart @@ -43,6 +43,7 @@ import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_contacts_vm.da import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_details_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_items_vm.dart'; import 'package:invoiceninja_flutter/ui/invoice/edit/invoice_edit_vm.dart'; +import 'package:invoiceninja_flutter/ui/purchase_order/edit/purchase_order_edit_items_vm.dart'; import 'package:invoiceninja_flutter/ui/quote/edit/quote_edit_items_vm.dart'; import 'package:invoiceninja_flutter/ui/recurring_invoice/edit/recurring_invoice_edit_items_vm.dart'; import 'package:invoiceninja_flutter/utils/completers.dart'; @@ -568,6 +569,10 @@ class InvoiceEditDesktopState extends State viewModel: widget.entityViewModel, isTasks: _showTasksTable, ) + else if (entityType == EntityType.purchaseOrder) + PurchaseOrderEditItemsScreen( + viewModel: widget.entityViewModel, + ) else SizedBox(), Row( diff --git a/lib/ui/invoice/edit/invoice_edit_vm.dart b/lib/ui/invoice/edit/invoice_edit_vm.dart index 5105884dd..44c65b477 100644 --- a/lib/ui/invoice/edit/invoice_edit_vm.dart +++ b/lib/ui/invoice/edit/invoice_edit_vm.dart @@ -203,7 +203,7 @@ class InvoiceEditVM extends AbstractInvoiceEditVM { ..projectId = projectId ?? '' ..invitations.replace(BuiltList(client .emailContacts - .map((contact) => InvitationEntity(contactId: contact.id)) + .map((contact) => InvitationEntity(clientContactId: contact.id)) .toList()))))); } store.dispatch(AddInvoiceItems(items)); diff --git a/lib/ui/invoice/view/invoice_view_contacts.dart b/lib/ui/invoice/view/invoice_view_contacts.dart index 88ab6eeeb..83212c5c9 100644 --- a/lib/ui/invoice/view/invoice_view_contacts.dart +++ b/lib/ui/invoice/view/invoice_view_contacts.dart @@ -46,7 +46,7 @@ class _InvitationListTile extends StatelessWidget { final state = viewModel.state; final client = state.clientState.get(viewModel.invoice.clientId); final contact = client.contacts.firstWhere( - (contact) => contact.id == invitation.contactId, + (contact) => contact.id == invitation.clientContactId, orElse: () => ContactEntity()); if (contact.isNew) { diff --git a/lib/ui/reports/credit_report.dart b/lib/ui/reports/credit_report.dart index c66f8319b..4f0c8596d 100644 --- a/lib/ui/reports/credit_report.dart +++ b/lib/ui/reports/credit_report.dart @@ -132,7 +132,7 @@ ReportResult creditReport( continue; } - final contact = client.getContact(credit.invitations.first.contactId); + final contact = client.getContact(credit.invitations.first.clientContactId); if (credit.isDeleted || client.isDeleted) { continue; diff --git a/lib/ui/reports/invoice_report.dart b/lib/ui/reports/invoice_report.dart index 1d80a8df1..41189da57 100644 --- a/lib/ui/reports/invoice_report.dart +++ b/lib/ui/reports/invoice_report.dart @@ -160,7 +160,8 @@ ReportResult invoiceReport( continue; } - final contact = client.getContact(invoice.invitations.first.contactId); + final contact = + client.getContact(invoice.invitations.first.clientContactId); if (invoice.isDeleted || client.isDeleted) { continue; diff --git a/lib/ui/reports/quote_report.dart b/lib/ui/reports/quote_report.dart index eb517b6d5..cce2126b4 100644 --- a/lib/ui/reports/quote_report.dart +++ b/lib/ui/reports/quote_report.dart @@ -130,7 +130,7 @@ ReportResult quoteReport( continue; } - final contact = client.getContact(quote.invitations.first.contactId); + final contact = client.getContact(quote.invitations.first.clientContactId); //final vendor = vendorMap[quote.vendorId]; if (quote.isDeleted || client.isDeleted) { diff --git a/lib/ui/reports/recurring_invoice_report.dart b/lib/ui/reports/recurring_invoice_report.dart index 00c005c40..421a23423 100644 --- a/lib/ui/reports/recurring_invoice_report.dart +++ b/lib/ui/reports/recurring_invoice_report.dart @@ -152,7 +152,8 @@ ReportResult recurringInvoiceReport( continue; } - final contact = client.getContact(invoice.invitations.first.contactId); + final contact = + client.getContact(invoice.invitations.first.clientContactId); if (invoice.isDeleted || client.isDeleted) { continue;