virtuous 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yml +26 -0
  3. data/.gitignore +5 -0
  4. data/.reek.yml +36 -0
  5. data/.rubocop.yml +87 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/CHANGELOG.md +18 -0
  9. data/Gemfile +17 -0
  10. data/LICENSE +21 -0
  11. data/README.md +54 -0
  12. data/Rakefile +24 -0
  13. data/lib/virtuous/client/contact.rb +220 -0
  14. data/lib/virtuous/client/contact_address.rb +78 -0
  15. data/lib/virtuous/client/gift.rb +394 -0
  16. data/lib/virtuous/client/gift_designation.rb +59 -0
  17. data/lib/virtuous/client/individual.rb +125 -0
  18. data/lib/virtuous/client/recurring_gift.rb +86 -0
  19. data/lib/virtuous/client.rb +272 -0
  20. data/lib/virtuous/error.rb +54 -0
  21. data/lib/virtuous/helpers/hash_helper.rb +28 -0
  22. data/lib/virtuous/helpers/string_helper.rb +31 -0
  23. data/lib/virtuous/parse_oj.rb +24 -0
  24. data/lib/virtuous/version.rb +5 -0
  25. data/lib/virtuous.rb +12 -0
  26. data/logo/virtuous.svg +1 -0
  27. data/spec/spec_helper.rb +25 -0
  28. data/spec/support/client_factory.rb +10 -0
  29. data/spec/support/fixtures/contact.json +112 -0
  30. data/spec/support/fixtures/contact_address.json +20 -0
  31. data/spec/support/fixtures/contact_addresses.json +42 -0
  32. data/spec/support/fixtures/contact_gifts.json +80 -0
  33. data/spec/support/fixtures/gift.json +55 -0
  34. data/spec/support/fixtures/gift_designation_query_options.json +2701 -0
  35. data/spec/support/fixtures/gift_designations.json +175 -0
  36. data/spec/support/fixtures/gifts.json +112 -0
  37. data/spec/support/fixtures/import.json +0 -0
  38. data/spec/support/fixtures/individual.json +46 -0
  39. data/spec/support/fixtures/recurring_gift.json +26 -0
  40. data/spec/support/fixtures_helper.rb +5 -0
  41. data/spec/support/virtuous_mock.rb +101 -0
  42. data/spec/virtuous/client_spec.rb +270 -0
  43. data/spec/virtuous/error_spec.rb +74 -0
  44. data/spec/virtuous/resources/contact_address_spec.rb +75 -0
  45. data/spec/virtuous/resources/contact_spec.rb +137 -0
  46. data/spec/virtuous/resources/gift_designation_spec.rb +70 -0
  47. data/spec/virtuous/resources/gift_spec.rb +249 -0
  48. data/spec/virtuous/resources/individual_spec.rb +95 -0
  49. data/spec/virtuous/resources/recurring_gift_spec.rb +67 -0
  50. data/spec/virtuous_spec.rb +7 -0
  51. data/virtuous.gemspec +25 -0
  52. metadata +121 -0
@@ -0,0 +1,394 @@
1
+ module Virtuous
2
+ class Client
3
+ ##
4
+ # ### Gift data
5
+ #
6
+ # {
7
+ # contact_id: [Integer],
8
+ # gift_type: [String],
9
+ # gift_date: [Time],
10
+ # amount: [Float],
11
+ # transaction_source: [String],
12
+ # transaction_id: [String],
13
+ # batch: [String],
14
+ # segment_id: [Integer],
15
+ # receipt_segment_id: [Integer],
16
+ # media_outlet_id: [Integer],
17
+ # notes: [String],
18
+ # is_private: [Boolean],
19
+ # receipt_date: [Time],
20
+ # contact_individual_id: [Integer],
21
+ # contact_passthrough_id: [Integer],
22
+ # cash_accounting_code: [String],
23
+ # state: [String],
24
+ # is_tax_deductible: [Boolean],
25
+ # gift_ask_id: [Integer],
26
+ # passthrough_gift_ask_id: [Integer],
27
+ # grant_id: [Integer],
28
+ # contact_membership_id: [Integer],
29
+ # currency_code: [String],
30
+ # exchange_rate: [Float],
31
+ # check_number: [String],
32
+ # credit_card_type: [String],
33
+ # cryptocoin_type: [String],
34
+ # transaction_hash: [String],
35
+ # coin_sold_for_cash: [Boolean],
36
+ # coin_amount: [Float],
37
+ # date_coin_was_sold: [Time],
38
+ # coin_sale_amount: [Float],
39
+ # ticker_symbol: [String],
40
+ # number_of_shares: [Float],
41
+ # ira_custodian: [String],
42
+ # stock_sold_for_cash: [Boolean],
43
+ # date_stock_was_sold: [Time],
44
+ # stock_sale_amount: [Float],
45
+ # non_cash_gift_type_id: [Integer],
46
+ # non_cash_gift_type: [String],
47
+ # description: [String],
48
+ # non_cash_sold_for_cash: [Boolean],
49
+ # date_non_cash_was_sold: [Time],
50
+ # non_cash_original_amount: [Float],
51
+ # non_cash_sale_amount: [Float],
52
+ # gift_designations: [
53
+ # {
54
+ # project_id: [Integer],
55
+ # amount: [Float],
56
+ # state: [String]
57
+ # }
58
+ # ],
59
+ # gift_premiums: [
60
+ # {
61
+ # premium_id: [Integer],
62
+ # quantity: [Integer],
63
+ # state: [String]
64
+ # }
65
+ # ],
66
+ # pledge_payments: [
67
+ # {
68
+ # id: [Integer],
69
+ # amount: [Float],
70
+ # state: [String]
71
+ # }
72
+ # ],
73
+ # recurring_gift_payments: [
74
+ # {
75
+ # id: [Integer],
76
+ # amount: [Float],
77
+ # state: [String]
78
+ # }
79
+ # ],
80
+ # tribute_type: [String],
81
+ # tribute_id: [Integer],
82
+ # tribute_description: [String],
83
+ # acknowledgee_id: [Integer],
84
+ # reversed_gift_id: [Integer],
85
+ # custom_fields: [
86
+ # {
87
+ # name: [String],
88
+ # value: [String],
89
+ # display_name: [String]
90
+ # }
91
+ # ]
92
+ # }
93
+ #
94
+ module Gift
95
+ ##
96
+ # Gets the gifts made by a contact.
97
+ #
98
+ # @example
99
+ # client.get_contact_gifts(1, take: 10)
100
+ #
101
+ # @param contact_id [Integer] The id of the Contact.
102
+ # @option options [String] :sort_by The field to be sorted. Supported: `Id`, `GiftDate`,
103
+ # `Amount`, `Batch`, `CreatedDateTime`.
104
+ # @option options [Boolean] :descending The direction to be sorted.
105
+ # @option options [Integer] :skip The number of records to skip. Default = 0.
106
+ # @option options [Integer] :take The number of records to take. Default = 10.
107
+ #
108
+ # @return [Hash] A hash with a list of gifts and the total amount of gifts belonging to the
109
+ # contact
110
+ # @example Output
111
+ # { list: [...], total: n }
112
+ #
113
+ def get_contact_gifts(contact_id, **options)
114
+ options = options.slice(:sort_by, :descending, :skip, :take)
115
+
116
+ parse(get(
117
+ "api/Gift/ByContact/#{contact_id}",
118
+ format(options)
119
+ ))
120
+ end
121
+
122
+ ##
123
+ # Fetches a gift record by id.
124
+ #
125
+ # @example
126
+ # client.get_gift(1)
127
+ #
128
+ # @param id [Integer] The id of the gift.
129
+ #
130
+ # @return [Hash] The gift information in a hash.
131
+ def get_gift(id)
132
+ parse(get("api/Gift/#{id}"))
133
+ end
134
+
135
+ ##
136
+ # Fetches a gift record by transaction id.
137
+ #
138
+ # @example
139
+ # client.find_gift_by_transaction_id('source', 1)
140
+ #
141
+ # @param transaction_source [String] The source of the transaction.
142
+ # @param transaction_id [Integer, String] The id of the transaction.
143
+ #
144
+ # @return [Hash] The gift information in a hash.
145
+ def find_gift_by_transaction_id(transaction_source, transaction_id)
146
+ encoded_id = transaction_id.is_a?(String) ? encode(transaction_id) : transaction_id
147
+ parse(get("api/Gift/#{encode(transaction_source)}/#{encoded_id}"))
148
+ end
149
+
150
+ ##
151
+ # Creates a gift.
152
+ #
153
+ # @example
154
+ # client.create_gift(
155
+ # contact_id: 1, gift_type: 'Cash', amount: 10.5, currency_code: 'USD',
156
+ # gift_date: Date.today
157
+ # )
158
+ #
159
+ # @param data [Hash] A hash containing the gift details.
160
+ # Refer to the [Gift data](#label-Gift+data) section
161
+ # above to see the available attributes.
162
+ #
163
+ # @return [Hash] The gift that has been created.
164
+ def create_gift(data)
165
+ parse(post('api/Gift', format(data)))
166
+ end
167
+
168
+ ##
169
+ # Creates gifts in bulks of up to 100 at a time.
170
+ #
171
+ # @example
172
+ # client.create_gifts([
173
+ # {
174
+ # contact_id: 1, gift_type: 'Cash', amount: 10.5, currency_code: 'USD',
175
+ # gift_date: Date.today
176
+ # },
177
+ # {
178
+ # contact_id: 2, gift_type: 'Cash', amount: 5.0, currency_code: 'USD',
179
+ # gift_date: Date.today
180
+ # }
181
+ # ])
182
+ #
183
+ # @param gifts [Array] An array of gifts.
184
+ # Refer to the [Gift data](#label-Gift+data) section
185
+ # above to see the available attributes.
186
+ #
187
+ # @return [Array] An array of gifts.
188
+ def create_gifts(gifts)
189
+ request_body = gifts.map { |gift| format(gift) }
190
+ response = post('api/Gift/Bulk', request_body)
191
+ response.map { |gift| parse(gift) }
192
+ end
193
+
194
+ ##
195
+ # Updates a gift.
196
+ #
197
+ # @example
198
+ # client.update_gift(
199
+ # 1, gift_type: 'Cash', amount: 5.0, currency_code: 'USD',
200
+ # gift_date: Date.today
201
+ # )
202
+ #
203
+ # @note Excluding a property will remove it's value from the object.
204
+ # If you're only updating a single property, the entire model is still required.
205
+ #
206
+ # @param id [Integer] The id of the gift to update.
207
+ # @param data [Hash] A hash containing the gift details.
208
+ # Refer to the [Gift data](#label-Gift+data) section
209
+ # above to see the available attributes.
210
+ #
211
+ # @return [Hash] The gift that has been updated.
212
+ def update_gift(id, data)
213
+ parse(put("api/Gift/#{id}", format(data)))
214
+ end
215
+
216
+ ##
217
+ # Delete a gift.
218
+ #
219
+ # @example
220
+ # client.delete_gift(1)
221
+ #
222
+ # @param id [Integer] The id of the gift to delete.
223
+ def delete_gift(id)
224
+ delete("api/Gift/#{id}")
225
+ end
226
+
227
+ ##
228
+ # Creates a gift. This ensures the gift is matched using the Virtuous matching algorithms
229
+ # for Contacts, Recurring gifts, Designations, etc.
230
+ #
231
+ # Transactions are posted to the API and are set to a holding state.
232
+ # At midnight, transactions are bundled into imports based on the source they were posted
233
+ # with.
234
+ # The organization reviews the imported transactions, and then clicks run.
235
+ #
236
+ # @example
237
+ # client.import_gift(
238
+ # gift_type: 'Cash', amount: 10.5, currency_code: 'USD', gift_date: Date.today,
239
+ # contact: {
240
+ # contact_type: 'Organization', name: 'Org name', first_name: 'John',
241
+ # last_name: 'Doe', email: 'john_doe@email.com'
242
+ # }
243
+ # )
244
+ #
245
+ # @param data [Hash] A hash containing the gift details.
246
+ #
247
+ # #### Full list of accepted fields
248
+ #
249
+ # {
250
+ # transaction_source: [String],
251
+ # transaction_id: [String],
252
+ # contact: [Contact],
253
+ # gift_date: [String],
254
+ # cancel_date: [String],
255
+ # gift_type: [String],
256
+ # amount: [String],
257
+ # currency_code: [String],
258
+ # exchange_rate: [Float],
259
+ # frequency: [String],
260
+ # recurring_gift_transaction_id: [String],
261
+ # recurring_gift_transaction_update: [Boolean],
262
+ # pledge_frequency: [String],
263
+ # pledge_transaction_id: [String],
264
+ # pledge_expected_fullfillment_date: [String],
265
+ # batch: [String],
266
+ # notes: [String],
267
+ # segment: [String],
268
+ # media_outlet: [String],
269
+ # receipt_date: [String],
270
+ # receipt_segment: [String],
271
+ # cash_accounting_code: [String],
272
+ # tribute: [String],
273
+ # tribute_dedication: {
274
+ # tribute_id: [Integer],
275
+ # tribute_type: [String],
276
+ # tribute_first_name: [String],
277
+ # tribute_last_name: [String],
278
+ # tribute_city: [String],
279
+ # tribute_state: [String],
280
+ # acknowledgee_individual_id: [Integer],
281
+ # acknowledgee_first_name: [String],
282
+ # acknowledgee_last_name: [String],
283
+ # acknowledgee_address: [String],
284
+ # acknowledgee_city: [String],
285
+ # acknowledgee_state: [String],
286
+ # acknowledgee_postal: [String],
287
+ # acknowledgee_email: [String],
288
+ # acknowledgee_phone: [String]
289
+ # },
290
+ # is_private: [Boolean],
291
+ # is_tax_deductible: [Boolean],
292
+ # check_number: [String],
293
+ # credit_card_type: [String],
294
+ # non_cash_gift_type_id: [Integer],
295
+ # non_cash_gift_type: [String],
296
+ # non_cash_gift_description: [String],
297
+ # stock_ticker_symbol: [String],
298
+ # stock_number_of_shares: [Integer],
299
+ # ira_custodian: [String],
300
+ # submission_url: [String],
301
+ # designations: [
302
+ # {
303
+ # id: [Integer],
304
+ # name: [String],
305
+ # code: [String],
306
+ # amount_designated: [String]
307
+ # }
308
+ # ],
309
+ # premiums: [
310
+ # {
311
+ # id: [Integer],
312
+ # name: [String],
313
+ # code: [String],
314
+ # quantity: [String]
315
+ # }
316
+ # ],
317
+ # custom_fields: [Hash],
318
+ # custom_objects: [
319
+ # {
320
+ # name: [String],
321
+ # fields: [
322
+ # {
323
+ # name: [String],
324
+ # value: [String]
325
+ # }
326
+ # ]
327
+ # }
328
+ # ],
329
+ # contact_individual_id: [Integer],
330
+ # passthrough_contact: [Contact],
331
+ # event_attendee: {
332
+ # event_id: [Integer],
333
+ # event_name: [String],
334
+ # invited: [Boolean],
335
+ # rsvp: [Boolean],
336
+ # rsvp_response: [Boolean],
337
+ # attended: [Boolean]
338
+ # }
339
+ # }
340
+ #
341
+ def import_gift(data)
342
+ post('api/v2/Gift/Transaction', format(data))
343
+ end
344
+
345
+ ##
346
+ # Creates a batch of gift transactions. This ensures the gift is matched using the Virtuous
347
+ # matching algorithms for Contacts, Recurring gifts, Designations, etc.
348
+ #
349
+ # Transactions are posted to the API and are set to a holding state.
350
+ # At midnight, transactions are bundled into imports based on the source they were posted
351
+ # with.
352
+ # The organization reviews the imported transactions, and then clicks run.
353
+ #
354
+ # @example
355
+ # client.import_gifts(
356
+ # transaction_source: 'Source', transactions: [
357
+ # {
358
+ # gift_type: 'Cash', amount: 10.5, currency_code: 'USD', gift_date: Date.today,
359
+ # contact: {
360
+ # contact_type: 'Organization', name: 'Org name', first_name: 'John',
361
+ # last_name: 'Doe', email: 'john_doe@email.com'
362
+ # }
363
+ # },
364
+ # {
365
+ # gift_type: 'Cash', amount: 5.0, currency_code: 'USD', gift_date: Date.today,
366
+ # contact: {
367
+ # contact_type: 'Organization', name: 'Org name', first_name: 'John',
368
+ # last_name: 'Doe', email: 'john_doe@email.com'
369
+ # }
370
+ # }
371
+ # ]
372
+ # )
373
+ #
374
+ # @param transactions [Array] An array of gifts. Refer to {#import_gift}
375
+ # to see a full list of accepted fields.
376
+ # @param shared_fields [Hash] Shared fields for the transactions.
377
+ # @option shared_fields [String] :transaction_source
378
+ # @option shared_fields [Boolean] :create_import
379
+ # @option shared_fields [String] :import_name
380
+ # @option shared_fields [String] :batch
381
+ # @option shared_fields [Float] :batch_total
382
+ # @option shared_fields [String] :default_gift_date
383
+ # @option shared_fields [String] :default_gift_type
384
+ def import_gifts(transactions:, **shared_fields)
385
+ shared_fields = shared_fields.slice(
386
+ :transaction_source, :create_import, :import_name, :batch, :batch_total,
387
+ :default_gift_date, :default_gift_type
388
+ )
389
+
390
+ post('api/v2/Gift/Transactions', format(shared_fields.merge(transactions: transactions)))
391
+ end
392
+ end
393
+ end
394
+ end
@@ -0,0 +1,59 @@
1
+ module Virtuous
2
+ class Client
3
+ module GiftDesignation
4
+ ##
5
+ # Queries a list of available gift designation query options.
6
+ # @return [Hash] A list of available gift designation query options.
7
+ def gift_designation_query_options
8
+ parse(get('api/GiftDesignation/QueryOptions'))
9
+ end
10
+
11
+ ##
12
+ # Queries gift designations.
13
+ #
14
+ # @example
15
+ # client.query_gift_designations(
16
+ # take: 5, skip: 0, sort_by: 'Id',
17
+ # conditions: [{ parameter: 'Gift Id', operator: 'Is', value: 102 }]
18
+ # )
19
+ #
20
+ # @option options [Integer] :take The maximum amount of designations to query. Default: 10.
21
+ # Max is 1000.
22
+ # @option options [Integer] :skip The number of designations to skip. Default: 0.
23
+ # @option options [String] :sort_by The value to sort records by.
24
+ # You can sort by Id, Amount, GiftDate, ReceiptDate and Batch.
25
+ # @option options [Boolean] :descending If true the records will be sorted in descending
26
+ # order.
27
+ # @option options [Array] :conditions An array of conditions to filter the gift designation.
28
+ # Use {gift_designation_query_options} to see
29
+ # a full list of available conditions.
30
+ #
31
+ # @return [Hash] A hash with a list and the total amount of gift designations that satisfy
32
+ # the conditions.
33
+ # @example Output
34
+ # { list: [...], total: n }
35
+ #
36
+ def query_gift_designations(**options)
37
+ uri = URI('api/GiftDesignation/Query')
38
+ query_params = options.slice(:take, :skip)
39
+ uri.query = URI.encode_www_form(query_params) unless query_params.empty?
40
+
41
+ parse(post(uri, format(query_gift_designations_body(options))))
42
+ end
43
+
44
+ private
45
+
46
+ def query_gift_designations_body(options)
47
+ conditions = options[:conditions]
48
+ body = options.slice(:sort_by, :descending)
49
+ return body if conditions.nil?
50
+
51
+ body.merge({
52
+ groups: [{
53
+ conditions: conditions
54
+ }]
55
+ })
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,125 @@
1
+ module Virtuous
2
+ class Client
3
+ ##
4
+ # ### Individual data
5
+ #
6
+ # {
7
+ # contact_id: [Integer],
8
+ # first_name: [String],
9
+ # last_name: [String],
10
+ # contact_methods: [
11
+ # {
12
+ # type: [String],
13
+ # value: [String],
14
+ # is_opted_in: [Boolean],
15
+ # is_primary: [Boolean]
16
+ # }
17
+ # ],
18
+ # prefix: [String],
19
+ # middle_name: [String],
20
+ # suffix: [String],
21
+ # gender: [String],
22
+ # set_as_primary: [Boolean],
23
+ # set_as_secondary: [Boolean],
24
+ # birth_month: [Integer],
25
+ # birth_day: [Integer],
26
+ # birth_year: [Integer],
27
+ # approximate_age: [Integer],
28
+ # is_deceased: [Boolean],
29
+ # deceased_date: [Date],
30
+ # passion: [String],
31
+ # avatar_url: [String],
32
+ # custom_fields: [
33
+ # {
34
+ # name: [String],
35
+ # value: [String],
36
+ # display_name: [String]
37
+ # }
38
+ # ],
39
+ # custom_collections: [
40
+ # {
41
+ # name: [String],
42
+ # fields: [
43
+ # {
44
+ # name: [String],
45
+ # value: [String]
46
+ # }
47
+ # ]
48
+ # }
49
+ # ]
50
+ # }
51
+ #
52
+ module Individual
53
+ ##
54
+ # Fetches an individual record by email.
55
+ #
56
+ # @example
57
+ # client.find_individual_by_email('individual@email.com')
58
+ #
59
+ # @param email [String] The email of the individual.
60
+ #
61
+ # @return [Hash] The individual information in a hash.
62
+ def find_individual_by_email(email)
63
+ parse(get('api/ContactIndividual/Find', { email: email }))
64
+ end
65
+
66
+ ##
67
+ # Fetches an individual record by id.
68
+ #
69
+ # @example
70
+ # client.get_individual(1)
71
+ #
72
+ # @param id [Integer] The id of the individual.
73
+ #
74
+ # @return [Hash] The individual information in a hash.
75
+ def get_individual(id)
76
+ parse(get("api/ContactIndividual/#{id}"))
77
+ end
78
+
79
+ ##
80
+ # Creates an individual.
81
+ #
82
+ # @example
83
+ # client.create_individual(first_name: 'John', last_name: 'Doe', contact_id: 1)
84
+ #
85
+ # @param data [Hash] A hash containing the individual details.
86
+ # Refer to the [Individual data](#label-Individual+data)
87
+ # section above to see the available attributes.
88
+ #
89
+ # @return [Hash] The individual that has been created.
90
+ def create_individual(data)
91
+ parse(post('api/ContactIndividual', format(data)))
92
+ end
93
+
94
+ ##
95
+ # Updates an individual.
96
+ #
97
+ # @example
98
+ # client.update_individual(1, first_name: 'New', last_name: 'Name')
99
+ #
100
+ # @note Excluding a property will remove it's value from the object.
101
+ # If you're only updating a single property, the entire model is still required.
102
+ #
103
+ # @param id [Integer] The id of the individual to update.
104
+ # @param data [Hash] A hash containing the individual details.
105
+ # Refer to the [Individual data](#label-Individual+data)
106
+ # section above to see the available attributes.
107
+ #
108
+ # @return [Hash] The individual that has been updated.
109
+ def update_individual(id, data)
110
+ parse(put("api/ContactIndividual/#{id}", format(data)))
111
+ end
112
+
113
+ ##
114
+ # Delete an individual.
115
+ #
116
+ # @example
117
+ # client.delete_individual(1)
118
+ #
119
+ # @param id [Integer] The id of the individual to delete.
120
+ def delete_individual(id)
121
+ delete("api/ContactIndividual/#{id}")
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,86 @@
1
+ module Virtuous
2
+ class Client
3
+ ##
4
+ # ### Recurring Gift data
5
+ #
6
+ # {
7
+ # contactId: [Integer],
8
+ # startDate: [Time],
9
+ # frequency: [String],
10
+ # amount: [Float],
11
+ # nextExpectedPaymentDate: [Time],
12
+ # anticipatedEndDate: [Time],
13
+ # thankYouDate: [Time],
14
+ # segmentId: [Integer],
15
+ # automatedPayments: [Boolean],
16
+ # trackPayments: [Boolean],
17
+ # isPrivate: [Boolean],
18
+ # designations: [
19
+ # {
20
+ # projectId: [Integer],
21
+ # amountDesignated: [Float]
22
+ # }
23
+ # ],
24
+ # customFields: [
25
+ # {
26
+ # name: [String],
27
+ # value: [String],
28
+ # displayName: [String]
29
+ # }
30
+ # ]
31
+ # }
32
+ #
33
+ module RecurringGift
34
+ ##
35
+ # Fetches a recurring gift record by id.
36
+ #
37
+ # @example
38
+ # client.get_recurring_gift(1)
39
+ #
40
+ # @param id [Integer] The id of the recurring gift.
41
+ #
42
+ # @return [Hash] The recurring gift information in a hash.
43
+ def get_recurring_gift(id)
44
+ parse(get("api/RecurringGift/#{id}"))
45
+ end
46
+
47
+ ##
48
+ # Creates a recurring gift.
49
+ #
50
+ # @example
51
+ # client.create_recurring_gift(
52
+ # contact_id: 1, start_date: Date.today, frequency: 'Monthly', amount: 1000
53
+ # )
54
+ #
55
+ # @param data [Hash] A hash containing the recurring gift details.
56
+ # Refer to the [Recurring Gift data](#label-Recurring+Gift+data)
57
+ # section above to see the available attributes.
58
+ #
59
+ # @return [Hash] The recurring gift that has been created.
60
+ def create_recurring_gift(data)
61
+ parse(post('api/RecurringGift', format(data)))
62
+ end
63
+
64
+ ##
65
+ # Updates a recurring gift.
66
+ #
67
+ # @example
68
+ # client.update_recurring_gift(
69
+ # 1, start_date: Date.today, frequency: 'Daily', amount: 500
70
+ # )
71
+ #
72
+ # @note Excluding a property will remove it's value from the object.
73
+ # If you're only updating a single property, the entire model is still required.
74
+ #
75
+ # @param id [Integer] The id of the recurring gift to update.
76
+ # @param data [Hash] A hash containing the recurring gift details.
77
+ # Refer to the [Gift data](#label-Recurring+Gift+data) section
78
+ # above to see the available attributes.
79
+ #
80
+ # @return [Hash] The recurring gift that has been updated.
81
+ def update_recurring_gift(id, data)
82
+ parse(put("api/RecurringGift/#{id}", format(data)))
83
+ end
84
+ end
85
+ end
86
+ end