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