maestrano-connector-rails 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -23,6 +23,10 @@ describe 'connec to the external application' do
23
23
  entity['first_name']
24
24
  end
25
25
 
26
+ def self.id_from_external_entity_hash(entity)
27
+ entity['ID']
28
+ end
29
+
26
30
  class PersonMapper
27
31
  extend HashMapper
28
32
  map from('organization_id'), to('AccountId')
@@ -83,7 +87,7 @@ describe 'connec to the external application' do
83
87
 
84
88
  describe 'a new record created in connec with all references known' do
85
89
  before {
86
- allow_any_instance_of(Entities::ConnecToExternal).to receive(:create_external_entity).and_return(ext_contact_id)
90
+ allow_any_instance_of(Entities::ConnecToExternal).to receive(:create_external_entity).and_return({'ID' => ext_contact_id})
87
91
  }
88
92
 
89
93
  let(:mapped_entity) {
@@ -133,7 +137,7 @@ describe 'connec to the external application' do
133
137
  it 'does the mapping correctly' do
134
138
  idmap = Entities::ConnecToExternal.create_idmap(organization_id: organization.id, external_id: ext_contact_id, connec_id: "23daf041-e18e-0133-7b6a-15461b913fab")
135
139
  allow(Entities::ConnecToExternal).to receive(:find_or_create_idmap).and_return(idmap)
136
- expect_any_instance_of(Entities::ConnecToExternal).to receive(:push_entities_to_external).with([{entity: mapped_entity, idmap: idmap}])
140
+ expect_any_instance_of(Entities::ConnecToExternal).to receive(:push_entities_to_external).with([{entity: mapped_entity.with_indifferent_access, idmap: idmap, id_refs_only_connec_entity: {}}])
137
141
  subject
138
142
  end
139
143
 
@@ -165,7 +169,7 @@ describe 'connec to the external application' do
165
169
  end
166
170
 
167
171
  it 'does the mapping correctly' do
168
- expect_any_instance_of(Entities::ConnecToExternal).to receive(:push_entities_to_external).with([{entity: mapped_entity, idmap: idmap}])
172
+ expect_any_instance_of(Entities::ConnecToExternal).to receive(:push_entities_to_external).with([{entity: mapped_entity.with_indifferent_access, idmap: idmap, id_refs_only_connec_entity: {}}])
169
173
  subject
170
174
  end
171
175
 
@@ -0,0 +1,581 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'id references' do
4
+
5
+ class Entities::IdReference < Maestrano::Connector::Rails::Entity
6
+ def self.external_entity_name
7
+ 'Payment'
8
+ end
9
+
10
+ def self.connec_entity_name
11
+ 'Payment'
12
+ end
13
+
14
+ def self.mapper_class
15
+ PaymentMapper
16
+ end
17
+
18
+ def self.references
19
+ {
20
+ record_references: %w(organization_id),
21
+ id_references: %w(lines/id)
22
+ }
23
+ end
24
+
25
+ def self.object_name_from_connec_entity_hash(entity)
26
+ entity['title']
27
+ end
28
+
29
+ def self.id_from_external_entity_hash(entity)
30
+ entity['ID']
31
+ end
32
+
33
+ class LineMapper
34
+ extend HashMapper
35
+ map from('id'), to('ID')
36
+ map from('amount'), to('Price')
37
+ end
38
+
39
+ class PaymentMapper
40
+ extend HashMapper
41
+ map from('title'), to('Title')
42
+ map from('organization_id'), to('AccountId')
43
+ map from('lines'), to('Line'), using: LineMapper
44
+ end
45
+ end
46
+
47
+ let(:provider) { 'provider' }
48
+ let(:oauth_uid) { 'oauth uid' }
49
+ let!(:organization) { create(:organization, oauth_provider: provider, oauth_uid: oauth_uid) }
50
+ let(:connec_client) { Maestrano::Connector::Rails::ConnecHelper.get_client(organization) }
51
+ let(:external_client) { Object.new }
52
+ let(:connec_payment_id) { '1205c5e0-e18e-0133-890f-07d4de9f9781' }
53
+ let(:connec_line_id1) { '3405c5e0-e18e-0133-890f-07d4de9f9781' }
54
+ let(:connec_line_id2) { '4505c5e0-e18e-0133-890f-07d4de9f9781' }
55
+ let(:ext_payment_id) { 'ext payment id' }
56
+ let(:ext_org_id) { 'ext org id' }
57
+ let(:ext_line_id1) { 'ext line id1' }
58
+ let(:ext_line_id2) { 'ext line id2' }
59
+
60
+ let(:payment_title) { 'This is a payment' }
61
+
62
+
63
+ before {
64
+ allow(connec_client).to receive(:get).and_return(ActionDispatch::Response.new(200, {}, {payments: [connec_payment]}.to_json, {}))
65
+ allow(connec_client).to receive(:batch).and_return(ActionDispatch::Response.new(200, {}, {results: [{status: 200, body: {payments: {}}}]}.to_json, {}))
66
+
67
+ allow_any_instance_of(Entities::IdReference).to receive(:get_external_entities).and_return([])
68
+ }
69
+
70
+ subject { Maestrano::Connector::Rails::SynchronizationJob.new.sync_entity('id_reference', organization, connec_client, external_client, organization.last_synchronization_date, {}) }
71
+
72
+ describe 'a creation from connec' do
73
+ before {
74
+ allow_any_instance_of(Entities::IdReference).to receive(:create_external_entity).and_return(entity_received_after_creation)
75
+ }
76
+
77
+ let(:connec_payment) {
78
+ {
79
+ 'id' => [
80
+ {
81
+ 'realm' => 'org-fg4a',
82
+ 'provider' => 'connec',
83
+ 'id' => connec_payment_id
84
+ }
85
+ ],
86
+ 'title' => payment_title,
87
+ 'organization_id' => [
88
+ {
89
+ 'realm' => 'org-fg4a',
90
+ 'provider' => 'connec',
91
+ 'id' => '2305c5e0-e18e-0133-890f-07d4de9f9781'
92
+ },
93
+ {
94
+ 'realm' => oauth_uid,
95
+ 'provider' => provider,
96
+ 'id' => ext_org_id
97
+ }
98
+ ],
99
+ 'lines' => lines
100
+ }
101
+ }
102
+
103
+ let(:lines) {
104
+ [
105
+ {
106
+ 'id' => [
107
+ {
108
+ 'realm' => 'org-fg4a',
109
+ 'provider' => 'connec',
110
+ 'id' => connec_line_id1
111
+ }
112
+ ],
113
+ 'amount' => 123
114
+ },
115
+ {
116
+ 'id' => [
117
+ {
118
+ 'realm' => 'org-fg4a',
119
+ 'provider' => 'connec',
120
+ 'id' => connec_line_id2
121
+ }
122
+ ],
123
+ 'amount' => 456
124
+ }
125
+ ]
126
+ }
127
+
128
+ let(:mapped_entity) {
129
+ {
130
+ Title: payment_title,
131
+ AccountId: ext_org_id,
132
+ Line: [
133
+ {
134
+ Price: 123
135
+ },
136
+ {
137
+ Price: 456
138
+ }
139
+ ]
140
+ }.with_indifferent_access
141
+ }
142
+
143
+ let(:entity_received_after_creation) {
144
+ {
145
+ 'ID' => ext_payment_id,
146
+ 'Title' => payment_title,
147
+ 'AccountId' => ext_org_id,
148
+ 'Line' => [
149
+ {
150
+ 'ID' => ext_line_id1,
151
+ 'Price' => 123
152
+ },
153
+ {
154
+ 'ID' => ext_line_id2,
155
+ 'Price' => 456
156
+ }
157
+ ]
158
+ }
159
+ }
160
+
161
+ let(:batch_params) {
162
+ {
163
+ :sequential=>true,
164
+ :ops=> [
165
+ {
166
+ :method=>"put",
167
+ :url=>"/api/v2/#{organization.uid}/payments/#{connec_payment_id}",
168
+ :params=>
169
+ {
170
+ :payments=>{
171
+ 'id' => [
172
+ {
173
+ 'id' => ext_payment_id,
174
+ 'provider' =>provider,
175
+ 'realm' =>oauth_uid
176
+ }
177
+ ],
178
+ 'lines' => [
179
+ {
180
+ 'id' => [
181
+ {
182
+ 'realm' => 'org-fg4a',
183
+ 'provider' => 'connec',
184
+ 'id' => connec_line_id1
185
+ },
186
+ {
187
+ 'realm' => oauth_uid,
188
+ 'provider' => provider,
189
+ 'id' => ext_line_id1
190
+ }
191
+ ]
192
+ },
193
+ {
194
+ 'id' => [
195
+ {
196
+ 'realm' => 'org-fg4a',
197
+ 'provider' => 'connec',
198
+ 'id' => connec_line_id2
199
+ },
200
+ {
201
+ 'realm' => oauth_uid,
202
+ 'provider' => provider,
203
+ 'id' => ext_line_id2
204
+ }
205
+ ]
206
+ }
207
+ ]
208
+ }
209
+ }
210
+ }
211
+ ]
212
+ }
213
+ }
214
+
215
+ it 'handles the idmap correctly' do
216
+ expect{
217
+ subject
218
+ }.to change{ Maestrano::Connector::Rails::IdMap.count }.by(1)
219
+ idmap = Maestrano::Connector::Rails::IdMap.last
220
+ expect(idmap.name).to eql(payment_title)
221
+ expect(idmap.connec_entity).to eql('payment')
222
+ expect(idmap.external_entity).to eql('payment')
223
+ expect(idmap.message).to be_nil
224
+ expect(idmap.external_id).to eql(ext_payment_id)
225
+ expect(idmap.connec_id).to eql(connec_payment_id)
226
+ end
227
+
228
+ it 'does the mapping correctly' do
229
+ idmap = Entities::IdReference.create_idmap(organization_id: organization.id, external_id: ext_payment_id, connec_id: connec_payment_id)
230
+ allow(Entities::IdReference).to receive(:find_or_create_idmap).and_return(idmap)
231
+ expect_any_instance_of(Entities::IdReference).to receive(:push_entities_to_external).with([{entity: mapped_entity, idmap: idmap, id_refs_only_connec_entity: {'lines' => lines.map { |line| line.delete('amount'); line }}}])
232
+ subject
233
+ end
234
+
235
+ it 'send the external ids to connec' do
236
+ expect(connec_client).to receive(:batch).with(batch_params)
237
+ subject
238
+ end
239
+ end
240
+
241
+ describe 'an update from connec with no new lines' do
242
+ before {
243
+ allow_any_instance_of(Entities::IdReference).to receive(:update_external_entity).and_return(entity_received_after_update)
244
+ }
245
+
246
+ let!(:idmap) { Entities::IdReference.create_idmap(organization_id: organization.id, external_id: ext_payment_id, connec_id: connec_payment_id) }
247
+
248
+ let(:connec_payment) {
249
+ {
250
+ 'id' => [
251
+ {
252
+ 'realm' => 'org-fg4a',
253
+ 'provider' => 'connec',
254
+ 'id' => connec_payment_id
255
+ },
256
+ {
257
+ 'realm' => oauth_uid,
258
+ 'provider' => provider,
259
+ 'id' => ext_payment_id
260
+ }
261
+ ],
262
+ 'title' => payment_title,
263
+ 'organization_id' => [
264
+ {
265
+ 'realm' => 'org-fg4a',
266
+ 'provider' => 'connec',
267
+ 'id' => '2305c5e0-e18e-0133-890f-07d4de9f9781'
268
+ },
269
+ {
270
+ 'realm' => oauth_uid,
271
+ 'provider' => provider,
272
+ 'id' => ext_org_id
273
+ }
274
+ ],
275
+ 'lines' => lines
276
+ }
277
+ }
278
+
279
+ let(:lines) {
280
+ [
281
+ {
282
+ 'id' => [
283
+ {
284
+ 'realm' => 'org-fg4a',
285
+ 'provider' => 'connec',
286
+ 'id' => connec_line_id1
287
+ },
288
+ {
289
+ 'realm' => oauth_uid,
290
+ 'provider' => provider,
291
+ 'id' => ext_line_id1
292
+ }
293
+ ],
294
+ 'amount' => 345,
295
+ },
296
+ {
297
+ 'id' => [
298
+ {
299
+ 'realm' => 'org-fg4a',
300
+ 'provider' => 'connec',
301
+ 'id' => connec_line_id2
302
+ },
303
+ {
304
+ 'realm' => oauth_uid,
305
+ 'provider' => provider,
306
+ 'id' => ext_line_id2
307
+ }
308
+ ],
309
+ 'amount' => 678
310
+ }
311
+ ]
312
+ }
313
+
314
+ let(:mapped_entity) {
315
+ {
316
+ Title: payment_title,
317
+ AccountId: ext_org_id,
318
+ Line: [
319
+ {
320
+ ID: ext_line_id1,
321
+ Price: 345
322
+ },
323
+ {
324
+ ID: ext_line_id2,
325
+ Price: 678
326
+ }
327
+ ]
328
+ }.with_indifferent_access
329
+ }
330
+
331
+ let(:entity_received_after_update) {
332
+ {
333
+ 'ID' => ext_payment_id,
334
+ 'Title' => payment_title,
335
+ 'AccountId' => ext_org_id,
336
+ 'Line' => [
337
+ {
338
+ 'ID' => ext_line_id1,
339
+ 'Price' => 123
340
+ },
341
+ {
342
+ 'ID' => ext_line_id2,
343
+ 'Price' => 456
344
+ }
345
+ ]
346
+ }
347
+ }
348
+
349
+ it 'update the idmap' do
350
+ subject
351
+ expect(idmap.reload.message).to be_nil
352
+ expect(idmap.reload.name).to eql(payment_title)
353
+ expect(idmap.reload.last_push_to_external > 1.minute.ago).to be true
354
+ end
355
+
356
+ it 'does the mapping correctly' do
357
+ expect_any_instance_of(Entities::IdReference).to receive(:push_entities_to_external).with([{entity: mapped_entity, idmap: idmap, id_refs_only_connec_entity: {'lines' => lines.map { |line| line.delete('amount'); line }}}])
358
+ subject
359
+ end
360
+
361
+ it 'does not send anything back to connec' do
362
+ expect(connec_client).to receive(:batch)
363
+ # TODO change when performance improvment in connec helper is done
364
+ # expect(connec_client).to_not receive(:batch)
365
+ subject
366
+ end
367
+ end
368
+
369
+ describe 'an update from connec with a new lines' do
370
+ before {
371
+ allow_any_instance_of(Entities::IdReference).to receive(:update_external_entity).and_return(entity_received_after_update)
372
+ }
373
+
374
+ let!(:idmap) { Entities::IdReference.create_idmap(organization_id: organization.id, external_id: ext_payment_id, connec_id: connec_payment_id) }
375
+ let(:connec_line_id3) { '8905c5e0-e18e-0133-890f-07d4de9f9781' }
376
+ let(:ext_line_id3) { 'ext line id3' }
377
+
378
+ let(:connec_payment) {
379
+ {
380
+ 'id' => [
381
+ {
382
+ 'realm' => 'org-fg4a',
383
+ 'provider' => 'connec',
384
+ 'id' => connec_payment_id
385
+ },
386
+ {
387
+ 'realm' => oauth_uid,
388
+ 'provider' => provider,
389
+ 'id' => ext_payment_id
390
+ }
391
+ ],
392
+ 'title' => payment_title,
393
+ 'organization_id' => [
394
+ {
395
+ 'realm' => 'org-fg4a',
396
+ 'provider' => 'connec',
397
+ 'id' => '2305c5e0-e18e-0133-890f-07d4de9f9781'
398
+ },
399
+ {
400
+ 'realm' => oauth_uid,
401
+ 'provider' => provider,
402
+ 'id' => ext_org_id
403
+ }
404
+ ],
405
+ 'lines' => lines
406
+ }
407
+ }
408
+
409
+ let(:lines) {
410
+ [
411
+ {
412
+ 'id' => [
413
+ {
414
+ 'realm' => 'org-fg4a',
415
+ 'provider' => 'connec',
416
+ 'id' => connec_line_id1
417
+ },
418
+ {
419
+ 'realm' => oauth_uid,
420
+ 'provider' => provider,
421
+ 'id' => ext_line_id1
422
+ }
423
+ ],
424
+ 'amount' => 345,
425
+ },
426
+ {
427
+ 'id' => [
428
+ {
429
+ 'realm' => 'org-fg4a',
430
+ 'provider' => 'connec',
431
+ 'id' => connec_line_id2
432
+ },
433
+ {
434
+ 'realm' => oauth_uid,
435
+ 'provider' => provider,
436
+ 'id' => ext_line_id2
437
+ }
438
+ ],
439
+ 'amount' => 678
440
+ },
441
+ {
442
+ 'id' => [
443
+ {
444
+ 'realm' => 'org-fg4a',
445
+ 'provider' => 'connec',
446
+ 'id' => connec_line_id3
447
+ }
448
+ ],
449
+ 'amount' => 999
450
+ }
451
+ ]
452
+ }
453
+
454
+ let(:mapped_entity) {
455
+ {
456
+ Title: payment_title,
457
+ AccountId: ext_org_id,
458
+ Line: [
459
+ {
460
+ ID: ext_line_id1,
461
+ Price: 345
462
+ },
463
+ {
464
+ ID: ext_line_id2,
465
+ Price: 678
466
+ },
467
+ {
468
+ Price: 999
469
+ }
470
+ ]
471
+ }.with_indifferent_access
472
+ }
473
+
474
+ let(:entity_received_after_update) {
475
+ {
476
+ 'ID' => ext_payment_id,
477
+ 'Title' => payment_title,
478
+ 'AccountId' => ext_org_id,
479
+ 'Line' => [
480
+ {
481
+ 'ID' => ext_line_id1,
482
+ 'Price' => 123
483
+ },
484
+ {
485
+ 'ID' => ext_line_id2,
486
+ 'Price' => 456
487
+ },
488
+ {
489
+ 'ID' => ext_line_id3,
490
+ 'Price' => 999
491
+ }
492
+ ]
493
+ }
494
+ }
495
+
496
+ let(:batch_params) {
497
+ {
498
+ :sequential=>true,
499
+ :ops=> [
500
+ {
501
+ :method=>"put",
502
+ :url=>"/api/v2/#{organization.uid}/payments/#{connec_payment_id}",
503
+ :params=>
504
+ {
505
+ :payments=>{
506
+ 'id' => [
507
+ {
508
+ 'id' => ext_payment_id,
509
+ 'provider' =>provider,
510
+ 'realm' =>oauth_uid
511
+ }
512
+ ],
513
+ 'lines' => [
514
+ {
515
+ 'id' => [
516
+ {
517
+ 'realm' => 'org-fg4a',
518
+ 'provider' => 'connec',
519
+ 'id' => connec_line_id1
520
+ },
521
+ {
522
+ 'realm' => oauth_uid,
523
+ 'provider' => provider,
524
+ 'id' => ext_line_id1
525
+ }
526
+ ]
527
+ },
528
+ {
529
+ 'id' => [
530
+ {
531
+ 'realm' => 'org-fg4a',
532
+ 'provider' => 'connec',
533
+ 'id' => connec_line_id2
534
+ },
535
+ {
536
+ 'realm' => oauth_uid,
537
+ 'provider' => provider,
538
+ 'id' => ext_line_id2
539
+ }
540
+ ]
541
+ },
542
+ {
543
+ 'id' => [
544
+ {
545
+ 'realm' => 'org-fg4a',
546
+ 'provider' => 'connec',
547
+ 'id' => connec_line_id3
548
+ },
549
+ {
550
+ 'realm' => oauth_uid,
551
+ 'provider' => provider,
552
+ 'id' => ext_line_id3
553
+ }
554
+ ]
555
+ }
556
+ ]
557
+ }
558
+ }
559
+ }
560
+ ]
561
+ }
562
+ }
563
+
564
+ it 'update the idmap' do
565
+ subject
566
+ expect(idmap.reload.message).to be_nil
567
+ expect(idmap.reload.name).to eql(payment_title)
568
+ expect(idmap.reload.last_push_to_external > 1.minute.ago).to be true
569
+ end
570
+
571
+ it 'does the mapping correctly' do
572
+ expect_any_instance_of(Entities::IdReference).to receive(:push_entities_to_external).with([{entity: mapped_entity, idmap: idmap, id_refs_only_connec_entity: {'lines' => lines.map { |line| line.delete('amount'); line }}}])
573
+ subject
574
+ end
575
+
576
+ it 'send the external ids to connec' do
577
+ expect(connec_client).to receive(:batch).with(batch_params)
578
+ subject
579
+ end
580
+ end
581
+ end