maestrano-connector-rails 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +7 -20
  3. data/VERSION +1 -1
  4. data/app/controllers/maestrano/synchronizations_controller.rb +3 -3
  5. data/app/models/maestrano/connector/rails/concerns/complex_entity.rb +50 -22
  6. data/app/models/maestrano/connector/rails/concerns/connec_helper.rb +157 -19
  7. data/app/models/maestrano/connector/rails/concerns/entity.rb +63 -42
  8. data/app/models/maestrano/connector/rails/concerns/external.rb +4 -0
  9. data/app/models/maestrano/connector/rails/concerns/sub_entity_base.rb +18 -5
  10. data/app/models/maestrano/connector/rails/organization.rb +1 -1
  11. data/lib/generators/connector/templates/complex_entity_example/contact_and_lead.rb +5 -5
  12. data/lib/generators/connector/templates/entity.rb +4 -5
  13. data/lib/generators/connector/templates/external.rb +6 -0
  14. data/lib/generators/connector/templates/home_index.haml +7 -4
  15. data/maestrano-connector-rails.gemspec +7 -4
  16. data/release_notes.md +5 -0
  17. data/spec/factories.rb +2 -2
  18. data/spec/integration/complex_id_references_spec.rb +248 -0
  19. data/spec/integration/complex_naming_spec.rb +191 -0
  20. data/spec/integration/{integration_complex_spec.rb → complex_spec.rb} +9 -9
  21. data/spec/integration/connec_to_external_spec.rb +7 -3
  22. data/spec/integration/id_references_spec.rb +581 -0
  23. data/spec/integration/singleton_spec.rb +3 -3
  24. data/spec/models/complex_entity_spec.rb +42 -27
  25. data/spec/models/connec_helper_spec.rb +399 -31
  26. data/spec/models/entity_spec.rb +76 -21
  27. data/spec/models/external_spec.rb +4 -0
  28. data/spec/models/sub_entity_base_spec.rb +11 -4
  29. metadata +6 -3
@@ -0,0 +1,248 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'complex id references' do
4
+
5
+ class Entities::IdPayment < Maestrano::Connector::Rails::ComplexEntity
6
+ def self.connec_entities_names
7
+ %w(IdPayment)
8
+ end
9
+ def self.external_entities_names
10
+ %w(IdBill)
11
+ end
12
+ def connec_model_to_external_model(connec_hash_of_entities)
13
+ {'IdPayment' => {'IdBill' => connec_hash_of_entities['IdPayment']}}
14
+ end
15
+ def external_model_to_connec_model(external_hash_of_entities)
16
+ {'IdBill' => {'IdPayment' => external_hash_of_entities['IdBill']}}
17
+ end
18
+ end
19
+
20
+ module Entities::SubEntities
21
+ end
22
+ class Entities::SubEntities::IdPayment < Maestrano::Connector::Rails::SubEntityBase
23
+ def self.external?
24
+ false
25
+ end
26
+ def self.entity_name
27
+ 'IdPayment'
28
+ end
29
+ def self.mapper_classes
30
+ {
31
+ 'IdBill' => ::IdPaymentMapper
32
+ }
33
+ end
34
+ def self.object_name_from_connec_entity_hash(entity)
35
+ entity['title']
36
+ end
37
+ def self.references
38
+ {'IdBill' => {record_references: %w(organization_id), id_references: %w(lines/id)}}
39
+ end
40
+ def self.id_from_external_entity_hash(entity)
41
+ entity['ID']
42
+ end
43
+ end
44
+
45
+ class Entities::SubEntities::IdBill < Maestrano::Connector::Rails::SubEntityBase
46
+ def self.external?
47
+ true
48
+ end
49
+ def self.entity_name
50
+ 'IdBill'
51
+ end
52
+ def self.mapper_classes
53
+ {'IdPayment' => ::IdPaymentMapper}
54
+ end
55
+ def self.id_from_external_entity_hash(entity)
56
+ entity['ID']
57
+ end
58
+ def self.references
59
+ {'IdPayment' => {record_references: %w(organization_id), id_references: %w(lines/id)}}
60
+ end
61
+ end
62
+
63
+ class IdLineMapper
64
+ extend HashMapper
65
+ map from('id'), to('ID')
66
+ map from('amount'), to('Price')
67
+ end
68
+
69
+ class IdPaymentMapper
70
+ extend HashMapper
71
+ map from('title'), to('Title')
72
+ map from('organization_id'), to('AccountId')
73
+ map from('lines'), to('Line'), using: IdLineMapper
74
+ end
75
+
76
+ let(:provider) { 'provider' }
77
+ let(:oauth_uid) { 'oauth uid' }
78
+ let!(:organization) { create(:organization, oauth_provider: provider, oauth_uid: oauth_uid) }
79
+ let(:connec_client) { Maestrano::Connector::Rails::ConnecHelper.get_client(organization) }
80
+ let(:external_client) { Object.new }
81
+ let(:connec_payment_id) { '1205c5e0-e18e-0133-890f-07d4de9f9781' }
82
+ let(:connec_line_id1) { '3405c5e0-e18e-0133-890f-07d4de9f9781' }
83
+ let(:connec_line_id2) { '4505c5e0-e18e-0133-890f-07d4de9f9781' }
84
+ let(:ext_payment_id) { 'ext payment id' }
85
+ let(:ext_org_id) { 'ext org id' }
86
+ let(:ext_line_id1) { 'ext line id1' }
87
+ let(:ext_line_id2) { 'ext line id2' }
88
+
89
+ let(:payment_title) { 'This is a payment' }
90
+
91
+ before {
92
+ allow(Maestrano::Connector::Rails::External).to receive(:entities_list).and_return(%w(id_payment))
93
+
94
+ allow(connec_client).to receive(:get).and_return(ActionDispatch::Response.new(200, {}, {idpayments: [connec_payment]}.to_json, {}))
95
+ allow(connec_client).to receive(:batch).and_return(ActionDispatch::Response.new(200, {}, {results: [{status: 200, body: {payments: {}}}]}.to_json, {}))
96
+
97
+ allow_any_instance_of(Entities::SubEntities::IdBill).to receive(:get_external_entities).and_return([])
98
+ }
99
+
100
+ subject { Maestrano::Connector::Rails::SynchronizationJob.new.sync_entity('id_payment', organization, connec_client, external_client, organization.last_synchronization_date, {}) }
101
+
102
+ describe 'a creation from connec' do
103
+ before {
104
+ allow_any_instance_of(Entities::SubEntities::IdPayment).to receive(:create_external_entity).and_return(entity_received_after_creation)
105
+ }
106
+
107
+ let(:connec_payment) {
108
+ {
109
+ 'id' => [
110
+ {
111
+ 'realm' => 'org-fg4a',
112
+ 'provider' => 'connec',
113
+ 'id' => connec_payment_id
114
+ }
115
+ ],
116
+ 'title' => payment_title,
117
+ 'organization_id' => [
118
+ {
119
+ 'realm' => 'org-fg4a',
120
+ 'provider' => 'connec',
121
+ 'id' => '2305c5e0-e18e-0133-890f-07d4de9f9781'
122
+ },
123
+ {
124
+ 'realm' => oauth_uid,
125
+ 'provider' => provider,
126
+ 'id' => ext_org_id
127
+ }
128
+ ],
129
+ 'lines' => lines
130
+ }
131
+ }
132
+
133
+ let(:lines) {
134
+ [
135
+ {
136
+ 'id' => [
137
+ {
138
+ 'realm' => 'org-fg4a',
139
+ 'provider' => 'connec',
140
+ 'id' => connec_line_id1
141
+ }
142
+ ],
143
+ 'amount' => 123
144
+ },
145
+ {
146
+ 'id' => [
147
+ {
148
+ 'realm' => 'org-fg4a',
149
+ 'provider' => 'connec',
150
+ 'id' => connec_line_id2
151
+ }
152
+ ],
153
+ 'amount' => 456
154
+ }
155
+ ]
156
+ }
157
+
158
+ let(:entity_received_after_creation) {
159
+ {
160
+ 'ID' => ext_payment_id,
161
+ 'Title' => payment_title,
162
+ 'AccountId' => ext_org_id,
163
+ 'Line' => [
164
+ {
165
+ 'ID' => ext_line_id1,
166
+ 'Price' => 123
167
+ },
168
+ {
169
+ 'ID' => ext_line_id2,
170
+ 'Price' => 456
171
+ }
172
+ ]
173
+ }
174
+ }
175
+
176
+ let(:batch_params) {
177
+ {
178
+ :sequential=>true,
179
+ :ops=> [
180
+ {
181
+ :method=>"put",
182
+ :url=>"/api/v2/#{organization.uid}/idpayments/#{connec_payment_id}",
183
+ :params=>
184
+ {
185
+ :idpayments=>{
186
+ 'id' => [
187
+ {
188
+ 'id' => ext_payment_id,
189
+ 'provider' =>provider,
190
+ 'realm' =>oauth_uid
191
+ }
192
+ ],
193
+ 'lines' => [
194
+ {
195
+ 'id' => [
196
+ {
197
+ 'realm' => 'org-fg4a',
198
+ 'provider' => 'connec',
199
+ 'id' => connec_line_id1
200
+ },
201
+ {
202
+ 'realm' => oauth_uid,
203
+ 'provider' => provider,
204
+ 'id' => ext_line_id1
205
+ }
206
+ ]
207
+ },
208
+ {
209
+ 'id' => [
210
+ {
211
+ 'realm' => 'org-fg4a',
212
+ 'provider' => 'connec',
213
+ 'id' => connec_line_id2
214
+ },
215
+ {
216
+ 'realm' => oauth_uid,
217
+ 'provider' => provider,
218
+ 'id' => ext_line_id2
219
+ }
220
+ ]
221
+ }
222
+ ]
223
+ }
224
+ }
225
+ }
226
+ ]
227
+ }
228
+ }
229
+
230
+ it 'handles the idmap correctly' do
231
+ expect{
232
+ subject
233
+ }.to change{ Maestrano::Connector::Rails::IdMap.count }.by(1)
234
+ idmap = Maestrano::Connector::Rails::IdMap.last
235
+ expect(idmap.name).to eql(payment_title)
236
+ expect(idmap.connec_entity).to eql('idpayment')
237
+ expect(idmap.external_entity).to eql('idbill')
238
+ expect(idmap.message).to be_nil
239
+ expect(idmap.external_id).to eql(ext_payment_id)
240
+ expect(idmap.connec_id).to eql(connec_payment_id)
241
+ end
242
+
243
+ it 'send the external id to connec' do
244
+ expect(connec_client).to receive(:batch).with(batch_params)
245
+ subject
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'complex entity subentities naming conflict' do
4
+
5
+ class Entities::NamePayment < Maestrano::Connector::Rails::ComplexEntity
6
+ def self.connec_entities_names
7
+ {Payment: 'NamePayment'}
8
+ end
9
+ def self.external_entities_names
10
+ {Payment: 'ExtPayment'}
11
+ end
12
+ def connec_model_to_external_model(connec_hash_of_entities)
13
+ {'Payment' => {'Payment' => connec_hash_of_entities['Payment']}}
14
+ end
15
+ def external_model_to_connec_model(external_hash_of_entities)
16
+ {'Payment' => {'Payment' => external_hash_of_entities['Payment']}}
17
+ end
18
+ end
19
+
20
+ module Entities::SubEntities
21
+ end
22
+ class Entities::SubEntities::NamePayment < Maestrano::Connector::Rails::SubEntityBase
23
+ def self.external?
24
+ false
25
+ end
26
+ def self.entity_name
27
+ 'Payment'
28
+ end
29
+ def self.mapper_classes
30
+ {
31
+ 'Payment' => ::PaymentMapper
32
+ }
33
+ end
34
+ def self.object_name_from_connec_entity_hash(entity)
35
+ entity['title']
36
+ end
37
+ def self.references
38
+ {'Payment' => {record_references: %w(organization_id), id_references: %w(lines/id)}}
39
+ end
40
+ def self.id_from_external_entity_hash(entity)
41
+ entity['ID']
42
+ end
43
+ end
44
+
45
+ class Entities::SubEntities::ExtPayment < Maestrano::Connector::Rails::SubEntityBase
46
+ def self.external?
47
+ true
48
+ end
49
+ def self.entity_name
50
+ 'Payment'
51
+ end
52
+ def self.mapper_classes
53
+ {'Payment' => ::PaymentMapper}
54
+ end
55
+ def self.id_from_external_entity_hash(entity)
56
+ entity['ID']
57
+ end
58
+ def self.references
59
+ {'Payment' => {record_references: %w(organization_id), id_references: %w(lines/id)}}
60
+ end
61
+ end
62
+
63
+ class LineMapper
64
+ extend HashMapper
65
+ map from('id'), to('ID')
66
+ map from('amount'), to('Price')
67
+ end
68
+
69
+ class PaymentMapper
70
+ extend HashMapper
71
+ map from('title'), to('Title')
72
+ map from('organization_id'), to('AccountId')
73
+ map from('lines'), to('Line'), using: LineMapper
74
+ end
75
+
76
+ let(:provider) { 'provider' }
77
+ let(:oauth_uid) { 'oauth uid' }
78
+ let!(:organization) { create(:organization, oauth_provider: provider, oauth_uid: oauth_uid) }
79
+ let(:connec_client) { Maestrano::Connector::Rails::ConnecHelper.get_client(organization) }
80
+ let(:external_client) { Object.new }
81
+ let(:connec_payment_id) { '1205c5e0-e18e-0133-890f-07d4de9f9781' }
82
+ let(:connec_line_id1) { '3405c5e0-e18e-0133-890f-07d4de9f9781' }
83
+ let(:ext_payment_id) { 'ext payment id' }
84
+ let(:ext_org_id) { 'ext org id' }
85
+ let(:ext_line_id1) { 'ext line id1' }
86
+ let(:payment_title) { 'This is a payment' }
87
+
88
+ before {
89
+ allow(Maestrano::Connector::Rails::External).to receive(:entities_list).and_return(%w(name_payment))
90
+ }
91
+
92
+ subject { Maestrano::Connector::Rails::SynchronizationJob.new.sync_entity('name_payment', organization, connec_client, external_client, organization.last_synchronization_date, {}) }
93
+
94
+ describe 'fetching entities from external' do
95
+ before {
96
+ allow_any_instance_of(Entities::SubEntities::NamePayment).to receive(:get_connec_entities).and_return([])
97
+ }
98
+
99
+ it 'does a fetch with the right name' do
100
+ expect_any_instance_of(Entities::SubEntities::ExtPayment).to receive(:get_external_entities).with('Payment', organization.last_synchronization_date).and_return([])
101
+ subject
102
+ end
103
+ end
104
+
105
+ describe 'sending entities to external' do
106
+ before {
107
+ allow(connec_client).to receive(:get).and_return(ActionDispatch::Response.new(200, {}, {payments: [connec_payment]}.to_json, {}))
108
+ allow(connec_client).to receive(:batch).and_return(ActionDispatch::Response.new(200, {}, {results: [{status: 200, body: {payments: {}}}]}.to_json, {}))
109
+
110
+ allow_any_instance_of(Entities::SubEntities::ExtPayment).to receive(:get_external_entities).and_return([])
111
+ }
112
+
113
+ let(:connec_payment) {
114
+ {
115
+ 'id' => [
116
+ {
117
+ 'realm' => 'org-fg4a',
118
+ 'provider' => 'connec',
119
+ 'id' => connec_payment_id
120
+ }
121
+ ],
122
+ 'title' => payment_title,
123
+ 'organization_id' => [
124
+ {
125
+ 'realm' => 'org-fg4a',
126
+ 'provider' => 'connec',
127
+ 'id' => '2305c5e0-e18e-0133-890f-07d4de9f9781'
128
+ },
129
+ {
130
+ 'realm' => oauth_uid,
131
+ 'provider' => provider,
132
+ 'id' => ext_org_id
133
+ }
134
+ ],
135
+ 'lines' => lines
136
+ }
137
+ }
138
+
139
+ let(:lines) {
140
+ [
141
+ {
142
+ 'id' => [
143
+ {
144
+ 'realm' => 'org-fg4a',
145
+ 'provider' => 'connec',
146
+ 'id' => connec_line_id1
147
+ }
148
+ ],
149
+ 'amount' => 123
150
+ }
151
+ ]
152
+ }
153
+
154
+ let(:mapped_payment) {
155
+ {
156
+ "Title"=>"This is a payment",
157
+ "AccountId"=>"ext org id",
158
+ "Line"=>[{"Price"=>123}]}
159
+ }
160
+
161
+ before {
162
+ allow_any_instance_of(Entities::SubEntities::NamePayment).to receive(:create_external_entity).and_return({'ID' => ext_payment_id})
163
+ }
164
+
165
+ it 'handles the idmap correctly' do
166
+ expect{
167
+ subject
168
+ }.to change{ Maestrano::Connector::Rails::IdMap.count }.by(1)
169
+ idmap = Maestrano::Connector::Rails::IdMap.last
170
+ expect(idmap.name).to eql(payment_title)
171
+ expect(idmap.connec_entity).to eql('payment')
172
+ expect(idmap.external_entity).to eql('payment')
173
+ expect(idmap.message).to be_nil
174
+ expect(idmap.external_id).to eql(ext_payment_id)
175
+ expect(idmap.connec_id).to eql(connec_payment_id)
176
+ end
177
+
178
+ it 'handles the mapping correctly' do
179
+ payment_idmap = Entities::SubEntities::NamePayment.create_idmap(organization_id: organization.id, external_id: ext_payment_id, connec_entity: 'payment')
180
+ allow(Maestrano::Connector::Rails::IdMap).to receive(:create).and_return(payment_idmap)
181
+ expect_any_instance_of(Entities::NamePayment).to receive(:push_entities_to_external).with({'Payment' => {'Payment' => [{entity: mapped_payment.with_indifferent_access, idmap: payment_idmap, id_refs_only_connec_entity: {'lines' => lines.map { |l| l.delete('amount'); l }}}]}})
182
+ subject
183
+ end
184
+
185
+ it 'handles the sending with the correct names' do
186
+ expect_any_instance_of(Entities::SubEntities::NamePayment).to receive(:create_external_entity).once.with(mapped_payment, 'Payment').and_return({})
187
+ expect(connec_client).to receive(:batch).once.and_return(ActionDispatch::Response.new(201, {}, {results: []}.to_json, {}))
188
+ subject
189
+ end
190
+ end
191
+ end
@@ -10,16 +10,16 @@ describe 'complex entities workflow' do
10
10
  end
11
11
  def connec_model_to_external_model(connec_hash_of_entities)
12
12
  organizations = connec_hash_of_entities['CompOrganization']
13
- modeled_connec_entities = {'CompOrganization' => { 'CompSupplier' => [], 'CompCustomer' => [] }}
13
+ modelled_connec_entities = {'CompOrganization' => { 'CompSupplier' => [], 'CompCustomer' => [] }}
14
14
 
15
15
  organizations.each do |organization|
16
16
  if organization['is_supplier']
17
- modeled_connec_entities['CompOrganization']['CompSupplier'] << organization
17
+ modelled_connec_entities['CompOrganization']['CompSupplier'] << organization
18
18
  else
19
- modeled_connec_entities['CompOrganization']['CompCustomer'] << organization
19
+ modelled_connec_entities['CompOrganization']['CompCustomer'] << organization
20
20
  end
21
21
  end
22
- return modeled_connec_entities
22
+ return modelled_connec_entities
23
23
  end
24
24
  def external_model_to_connec_model(external_hash_of_entities)
25
25
  return {'CompCustomer' => {'CompOrganization' => external_hash_of_entities['CompCustomer']}, 'CompSupplier' => {'CompOrganization' => external_hash_of_entities['CompSupplier']}}
@@ -228,7 +228,7 @@ describe 'complex entities workflow' do
228
228
 
229
229
  it 'handles the idmap correctly' do
230
230
  allow(connec_client).to receive(:batch).and_return(ActionDispatch::Response.new(201, {}, {results: []}.to_json, {}))
231
- allow_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:create_external_entity).and_return(connec_org1_ext_id)
231
+ allow_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:create_external_entity).and_return({'id' => connec_org1_ext_id})
232
232
  allow_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:update_external_entity).and_return(nil)
233
233
  expect{
234
234
  subject
@@ -267,14 +267,14 @@ describe 'complex entities workflow' do
267
267
  org1_idmap = Entities::SubEntities::CompOrganization.create_idmap(organization_id: organization.id, external_id: connec_org1_ext_id, external_entity: 'compsupplier')
268
268
  org2_idmap = Entities::SubEntities::CompOrganization.create_idmap(organization_id: organization.id, external_id: connec_org2_ext_id, external_entity: 'compcustomer')
269
269
  allow(Maestrano::Connector::Rails::IdMap).to receive(:create).and_return(org1_idmap, org2_idmap, cust_idmap)
270
- expect_any_instance_of(Entities::CustomerAndSupplier).to receive(:push_entities_to_external).with({'CompOrganization' => {'CompSupplier' => [{entity: mapped_connec_org1, idmap: org1_idmap}], 'CompCustomer' => [{entity: mapped_connec_org2, idmap: org2_idmap}]}})
271
- expect_any_instance_of(Entities::CustomerAndSupplier).to receive(:push_entities_to_connec).with({'CompCustomer' => {'CompOrganization' => [{entity: mapped_ext_customer, idmap: cust_idmap}]}, 'CompSupplier' => {'CompOrganization' => [{entity: mapped_ext_supplier, idmap: supplier_idmap}]}})
270
+ expect_any_instance_of(Entities::CustomerAndSupplier).to receive(:push_entities_to_external).with({'CompOrganization' => {'CompSupplier' => [{entity: mapped_connec_org1.with_indifferent_access, idmap: org1_idmap, id_refs_only_connec_entity: {}}], 'CompCustomer' => [{entity: mapped_connec_org2.with_indifferent_access, idmap: org2_idmap, id_refs_only_connec_entity: {}}]}})
271
+ expect_any_instance_of(Entities::CustomerAndSupplier).to receive(:push_entities_to_connec).with({'CompCustomer' => {'CompOrganization' => [{entity: mapped_ext_customer.with_indifferent_access, idmap: cust_idmap}]}, 'CompSupplier' => {'CompOrganization' => [{entity: mapped_ext_supplier.with_indifferent_access, idmap: supplier_idmap}]}})
272
272
  subject
273
273
  end
274
274
 
275
275
  it 'sends two objects to connec, two objects to external and send back one id to connec' do
276
- expect_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:create_external_entity).once
277
- expect_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:update_external_entity).once
276
+ expect_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:create_external_entity).once.with(mapped_connec_org1, 'CompSupplier').and_return({})
277
+ expect_any_instance_of(Entities::SubEntities::CompOrganization).to receive(:update_external_entity).once.with(mapped_connec_org2, connec_org2_ext_id, 'CompCustomer')
278
278
  expect(connec_client).to receive(:batch).exactly(3).times.and_return(ActionDispatch::Response.new(201, {}, {results: []}.to_json, {}), ActionDispatch::Response.new(200, {}, {results: []}.to_json, {}))
279
279
  subject
280
280
  end