diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 9faf900..72d6be6 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -20,6 +20,8 @@ Metrics/AbcSize: # Configuration parameters: CountComments. Metrics/ClassLength: Max: 110 + Exclude: + - "app/models/maestrano/connector/rails/services/data_consolidator.rb" # Offense count: 9 Metrics/CyclomaticComplexity: @@ -154,3 +156,7 @@ Style/RescueStandardError: - 'app/models/maestrano/connector/rails/concerns/entity.rb' - 'app/models/maestrano/connector/rails/concerns/organization.rb' - 'app/resources/maestrano/api/base_resource.rb' + +Layout/IndentationWidth: + Exclude: + - 'app/models/maestrano/connector/rails/services/data_consolidator.rb' diff --git a/.travis.yml b/.travis.yml index 1703d4f..1a7f36e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,5 @@ rvm: services: - redis-server before_install: - - gem install bundler # Update bundler version + - rvm @global do gem uninstall bundler -a -x + - rvm @global do gem install bundler -v 1.17.3 diff --git a/app/models/maestrano/connector/rails/concerns/complex_entity.rb b/app/models/maestrano/connector/rails/concerns/complex_entity.rb index f9b1531..ef4cdba 100644 --- a/app/models/maestrano/connector/rails/concerns/complex_entity.rb +++ b/app/models/maestrano/connector/rails/concerns/complex_entity.rb @@ -48,6 +48,10 @@ def public_name(formatted_names) (names[0..-2].join(', ') + " and #{names.last}").humanize end + + def immutable? + false + end end # input : { diff --git a/app/models/maestrano/connector/rails/concerns/entity.rb b/app/models/maestrano/connector/rails/concerns/entity.rb index 421a138..dc26055 100644 --- a/app/models/maestrano/connector/rails/concerns/entity.rb +++ b/app/models/maestrano/connector/rails/concerns/entity.rb @@ -80,6 +80,10 @@ def singleton? false end + def immutable? + false + end + # Entity name in Connec! def connec_entity_name raise 'Not implemented' diff --git a/app/models/maestrano/connector/rails/services/data_consolidator.rb b/app/models/maestrano/connector/rails/services/data_consolidator.rb index f0cb336..cfe73c1 100644 --- a/app/models/maestrano/connector/rails/services/data_consolidator.rb +++ b/app/models/maestrano/connector/rails/services/data_consolidator.rb @@ -81,6 +81,9 @@ def consolidate_external_entities(external_entities, connec_entity_name) entity_id = @current_entity.class.id_from_external_entity_hash(entity) idmap = @current_entity.class.find_or_create_idmap(external_id: entity_id, organization_id: @organization.id, connec_entity: connec_entity_name.downcase) + # Don't push to connec, the immutable entities which have already been pushed + next if immutable_and_already_pushed_to_connec?(idmap) + # Not pushing entity to Connec! next unless idmap.to_connec @@ -158,5 +161,11 @@ def solve_conflict(connec_entity, external_entities, external_entity_name, idmap def connec_more_recent?(connec_entity, external_entity) connec_entity['updated_at'] > @current_entity.class.last_update_date_from_external_entity_hash(external_entity) end + + private + + def immutable_and_already_pushed_to_connec?(idmap) + @current_entity.class.immutable? && idmap.connec_id.present? + end end end diff --git a/lib/generators/connector/templates/entity.rb b/lib/generators/connector/templates/entity.rb index f4d91f3..5b4cf0d 100644 --- a/lib/generators/connector/templates/entity.rb +++ b/lib/generators/connector/templates/entity.rb @@ -53,4 +53,10 @@ def self.creation_date_from_external_entity_hash(entity) def self.inactive_from_external_entity_hash?(entity) # TODO end + + # This method return true if entity is immutable. + # An entity is immutable, if it is only ever created, but never updated. eg. BankTransaction + def self.immutable?(entity) + # TODO + end end diff --git a/spec/models/services/data_consolidator_spec.rb b/spec/models/services/data_consolidator_spec.rb new file mode 100644 index 0000000..d88de0f --- /dev/null +++ b/spec/models/services/data_consolidator_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +def process_entities_to_cmp(entities) + entities.flat_map do |e| + e[:entity]['id'] = e[:entity]['id'].first['id'] + e[:entity] + end +end + +describe Maestrano::Connector::Rails::Services::DataConsolidator do + let!(:organization) { create(:organization, uid: 'cld-123') } + let(:external_entities) do + [ + { + 'amount' => 8.93, + 'type' => 'RECEIVE', + 'public_note' => '', + 'transaction_date' => '2018-07-31 12:00:00 +0000', + 'name' => 'INTEREST PAYMENT', + 'id' => 'TX8934077941420180731', + 'account_id' => '4518736' + }, + { + 'amount' => -26.47, + 'type' => 'SPEND', + 'public_note' => 'DISBURSEMENT TO MORTGAGOR', + 'transaction_date' => '2018-01-16 12:00:00 +0000', + 'name' => 'DISBURSEMENT TO MORTGAGOR', + 'id' => '201801160', + 'account_id' => '4518738' + }, + { + 'amount' => 25.0, + 'type' => 'RECEIVE', + 'public_note' => 'LATE CHARGE PAID', + 'transaction_date' => '2018-01-12 12:00:00 +0000', + 'name' => 'LATE CHARGE PAID', + 'id' => '201801121', + 'account_id' => '4518738' + } + ] + end + + class BankTransactionMapper + extend HashMapper + map from('name'), to('name') + map from('transaction_date'), to('transaction_date') + map from('type'), to('type') + map from('public_note'), to('public_note') + map from('account_id'), to('account_id') + map from('id'), to('id') + map from('lines'), to('lines') + map from('status'), to('status') + map from('amount'), to('amount') + end + + class BankTransaction < Maestrano::Connector::Rails::Entity + def self.id_from_external_entity_hash(entity) + entity['id'] + end + + def self.connec_entity_name + 'Transaction' + end + + # Entity name in external system + def self.external_entity_name + 'Transaction' + end + + def self.object_name_from_external_entity_hash(entity) + id_from_external_entity_hash(entity) + end + + def self.mapper_class + BankTransactionMapper + end + end + + describe '#consolidate_external_entities' do + let(:transaction) { BankTransaction.new(organization, nil, nil) } + let(:data_consolidator) { described_class.new(organization, transaction, {}) } + let(:entities) { data_consolidator.consolidate_external_entities(external_entities, 'BankTransaction') } + let(:subject) { process_entities_to_cmp(entities) } + + context 'when entity is mutable' do + before do + allow(BankTransaction).to receive(:immutable?).and_return(false) + end + context 'when none of the entities have been pushed to connec!' do + it 'returns all external entities' do + expect(subject).to eq(external_entities) + end + end + end + + context 'when entity is immutable' do + before do + allow(BankTransaction).to receive(:immutable?).and_return(true) + end + + context 'when some entities have been pushed to connec!' do + before do + create(:idmap, external_id: 'TX8934077941420180731', external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 1) + end + + it 'only returns new entities' do + expect(subject.count).to eq(2) + expect(subject).to eq(external_entities[1..2]) + end + end + + context 'when all entities have been pushed to connec!' do + before do + create(:idmap, external_id: 'TX8934077941420180731', external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 1) + create(:idmap, external_id: '201801160', external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 2) + create(:idmap, external_id: '201801121', external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 3) + end + + it 'does not return any entity' do + expect(subject.count).to eq(0) + end + end + end + end +end