nfg-client 1.0.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.
- checksums.yaml +15 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.md +21 -0
- data/README.md +360 -0
- data/Rakefile +8 -0
- data/lib/nfg-client.rb +3 -0
- data/lib/nfg-client/client.rb +321 -0
- data/lib/nfg-client/utils.rb +91 -0
- data/lib/nfg-client/version.rb +3 -0
- data/nfg-client.gemspec +25 -0
- data/spec/nfg_client_spec.rb +0 -0
- data/spec/spec_helper.rb +20 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZDhhZGYxODA1OTNjMTcwNWJiMDVjMzUwOTE5NTgzNzEwOGQ3NDY5Mg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZmVjOTFiMWM5ZTA2NGQwMzc5NjNmYWZjNTBlYjllYjlkNDllNmNlMw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OTU5ZjhlZTQ1NGNlNDNiNDY0MDI1OTI2ODA1N2JhZDk5NGJlNzgxYWQ0Njgy
|
10
|
+
YzRlZGRlOWY0MjA0MmMyYTY4MGE1NDg4ZTk3NmJmNjQ5ODA5MTg3M2U4OThl
|
11
|
+
ODYyODRlNGNjNjQ1ZGI3MjJkZTc0ZGEwNmExZjhiMzBhMzA4YmE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODc3MTViZmU1YzBmNzI2NjMwMGVhNWQ5OGRkNzg0MTliNzcyYjc2N2M1NzM2
|
14
|
+
ZTczOTMzYWE1YzQyNTgyNzA0MGE4ODMyMGFiNzc1ZjMxNGNhYmJmZTE1OGVm
|
15
|
+
NTM3NWY3MzAxMTFmZjNjOTA2ZDY2NGJjMDQ0Yjg4ZTk4ZWU2Mzc=
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Antonio Ruano Cuesta
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,360 @@
|
|
1
|
+
# NFG Client
|
2
|
+
|
3
|
+
A client to interact with the NFG (Network for Good) API via SOAP requests.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem:
|
8
|
+
|
9
|
+
gem install nfg-client
|
10
|
+
|
11
|
+
Or add it to your Gemfile:
|
12
|
+
|
13
|
+
gem "nfg-client"
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Create a NFG Client instance using your NFG credentials:
|
18
|
+
|
19
|
+
nfg_client = NFGClient.new(partner_id, partner_password, partner_source, partner_campaign, use_sandbox)
|
20
|
+
|
21
|
+
The fifth parameter is optional (defaults to false), and indicates the Client which API URLs to use (sandbox or production).
|
22
|
+
|
23
|
+
Use the Client to make calls to the NFG API, each call will take a hash with the parameters you want to send along with it (apart from the NFG credentials).
|
24
|
+
|
25
|
+
Example:
|
26
|
+
|
27
|
+
nfg_client.get_donor_cofs({"DonorToken" => donor_token})
|
28
|
+
|
29
|
+
All required parameters for the different calls should have the name specified by the NFG documentation.
|
30
|
+
|
31
|
+
For more information, refer to the official NFG documentation:
|
32
|
+
|
33
|
+
http://www.thenetworkforgood.org/t5/Developer-Resource-Center/ct-p/Developer
|
34
|
+
|
35
|
+
## Supported Calls
|
36
|
+
|
37
|
+
Below, the list of supported calls and examples of usage. All functions return a hash with the response from NFG.
|
38
|
+
|
39
|
+
### CreateCOF
|
40
|
+
|
41
|
+
Creates a Card on File without a transaction.
|
42
|
+
|
43
|
+
**_Call_**
|
44
|
+
|
45
|
+
response = nfg_client.create_cof({
|
46
|
+
"DonorToken" => "",
|
47
|
+
"DonorFirstName" => "",
|
48
|
+
"DonorLastName" => "",
|
49
|
+
"DonorEmail" => "",
|
50
|
+
"DonorAddress1" => "",
|
51
|
+
"DonorAddress2" => "",
|
52
|
+
"DonorCity" => "",
|
53
|
+
"DonorState" => "",
|
54
|
+
"DonorZip" => "",
|
55
|
+
"DonorCountry" => "",
|
56
|
+
"DonorPhone" => "",
|
57
|
+
"CardType" => "", # Unk, Visa, Mastercard, Amex or Discover
|
58
|
+
"NameOnCard" => "",
|
59
|
+
"CardNumber" => "",
|
60
|
+
"ExpMonth" => "",
|
61
|
+
"ExpYear" => "",
|
62
|
+
"CSC" => ""
|
63
|
+
})
|
64
|
+
|
65
|
+
**_Response on Success_**
|
66
|
+
|
67
|
+
{
|
68
|
+
"StatusCode" => "Success",
|
69
|
+
"Message" => "", # Empty
|
70
|
+
"ErrorDetails" => "", # Empty
|
71
|
+
"CallDuration" => "x.x",
|
72
|
+
"DonorToken" => "x",
|
73
|
+
"COFId" => "x" # Integer
|
74
|
+
}
|
75
|
+
|
76
|
+
### GetDonorCOFs
|
77
|
+
|
78
|
+
Gets a list of donor Cards on File.
|
79
|
+
|
80
|
+
**_Call_**
|
81
|
+
|
82
|
+
response = nfg_client.get_donor_cofs({
|
83
|
+
"DonorToken" => ""
|
84
|
+
})
|
85
|
+
|
86
|
+
**_Response on Success_**
|
87
|
+
|
88
|
+
{
|
89
|
+
"StatusCode" => "Success",
|
90
|
+
"Message" => "", # Empty
|
91
|
+
"ErrorDetails" => "", # Empty
|
92
|
+
"CallDuration" => "x.x",
|
93
|
+
"DonorToken" => "x",
|
94
|
+
"Cards" => [
|
95
|
+
{
|
96
|
+
"COFId" => "x", # Integer
|
97
|
+
"CardType" => "x", # e.g. Mastercard
|
98
|
+
"CCSuffix" => "xxxx", # Last four digits
|
99
|
+
"CCExpMonth" => "", # 1 or 2 digits
|
100
|
+
"CCExpYear" => "", # 4 digits
|
101
|
+
"bInUseByLiveRD" => "", # true or false
|
102
|
+
"COFEmailAddress" => ""
|
103
|
+
},
|
104
|
+
...
|
105
|
+
]
|
106
|
+
}
|
107
|
+
|
108
|
+
### DeleteDonorCOF
|
109
|
+
|
110
|
+
Removes an existing Card on File.
|
111
|
+
|
112
|
+
**_Call_**
|
113
|
+
|
114
|
+
response = nfg_client.delete_donor_cof({
|
115
|
+
"DonorToken" => "",
|
116
|
+
"COFId" => ""
|
117
|
+
})
|
118
|
+
|
119
|
+
**_Response on Success_**
|
120
|
+
|
121
|
+
{
|
122
|
+
"StatusCode" => "Success",
|
123
|
+
"Message" => "", # Empty
|
124
|
+
"ErrorDetails" => "", # Empty
|
125
|
+
"CallDuration" => "x.xx"
|
126
|
+
}
|
127
|
+
|
128
|
+
### MakeCOFDonation
|
129
|
+
|
130
|
+
Triggers a one-time or recurring donation to one or more charities with an existing Card on File.
|
131
|
+
|
132
|
+
**_Call_**
|
133
|
+
|
134
|
+
response = nfg_client.make_cof_donation({
|
135
|
+
"DonationLineItems" => {
|
136
|
+
"DonationItem1" => {
|
137
|
+
"NpoEin" => "",
|
138
|
+
"donorVis" => "", # ProvideAll, ProvideNameAndEmailOnly or Anonymous
|
139
|
+
"ItemAmount" => "",
|
140
|
+
"RecurType" => "", # NotRecurring, Monthly, Quarterly or Annually
|
141
|
+
"Designation" => ""
|
142
|
+
"Dedication" => ""
|
143
|
+
},
|
144
|
+
"DonationItem2" => {
|
145
|
+
...
|
146
|
+
},
|
147
|
+
...
|
148
|
+
},
|
149
|
+
"TotalAmount" => "",
|
150
|
+
"TipAmount" => "",
|
151
|
+
"DonorIpAddress" => "",
|
152
|
+
"DonorToken" => "",
|
153
|
+
"COFId" => ""
|
154
|
+
})
|
155
|
+
|
156
|
+
**_Response on Success_**
|
157
|
+
|
158
|
+
{
|
159
|
+
"StatusCode" => "Success",
|
160
|
+
"Message" => "", # Empty
|
161
|
+
"ErrorDetails" => "", # Empty
|
162
|
+
"CallDuration" => "x.x",
|
163
|
+
"ChargeId" => "x", # Integer
|
164
|
+
"COFId" => "0"
|
165
|
+
}
|
166
|
+
|
167
|
+
### MakeDonationAddCOF
|
168
|
+
|
169
|
+
Triggers a one-time or recurring donation to one or more charities with a new Card on File.
|
170
|
+
|
171
|
+
**_Call_**
|
172
|
+
|
173
|
+
response = nfg_client.make_donation_add_cof({
|
174
|
+
"DonationLineItems" => {
|
175
|
+
"DonationItem1" => {
|
176
|
+
"NpoEin" => "",
|
177
|
+
"donorVis" => "", # ProvideAll, ProvideNameAndEmailOnly or Anonymous
|
178
|
+
"ItemAmount" => "",
|
179
|
+
"RecurType" => "", # NotRecurring, Monthly, Quarterly or Annually
|
180
|
+
"Designation" => ""
|
181
|
+
"Dedication" => ""
|
182
|
+
},
|
183
|
+
"DonationItem2" => {
|
184
|
+
...
|
185
|
+
},
|
186
|
+
...
|
187
|
+
},
|
188
|
+
"TotalAmount" => "",
|
189
|
+
"TipAmount" => "",
|
190
|
+
"DonorIpAddress" => "",
|
191
|
+
"DonorToken" => "",
|
192
|
+
"COFId" => "",
|
193
|
+
"DonorFirstName" => "",
|
194
|
+
"DonorLastName" => "",
|
195
|
+
"DonorEmail" => "",
|
196
|
+
"DonorAddress1" => "",
|
197
|
+
"DonorAddress2" => "",
|
198
|
+
"DonorCity" => "",
|
199
|
+
"DonorState" => "",
|
200
|
+
"DonorZip" => "",
|
201
|
+
"DonorCountry" => "",
|
202
|
+
"DonorPhone" => "",
|
203
|
+
"CardType" => "", # Unk, Visa, Mastercard, Amex or Discover
|
204
|
+
"NameOnCard" => "",
|
205
|
+
"CardNumber" => "",
|
206
|
+
"ExpMonth" => "",
|
207
|
+
"ExpYear" => "",
|
208
|
+
"CSC" => ""
|
209
|
+
})
|
210
|
+
|
211
|
+
**_Response on Success_**
|
212
|
+
|
213
|
+
{
|
214
|
+
"StatusCode" => "Success",
|
215
|
+
"Message" => "", # Empty
|
216
|
+
"ErrorDetails" => "", # Empty
|
217
|
+
"CallDuration" => "x.x",
|
218
|
+
"ChargeId" => "x", # Integer
|
219
|
+
"COFId" => "0"
|
220
|
+
}
|
221
|
+
|
222
|
+
### GetFee
|
223
|
+
|
224
|
+
Calculates the fee for a transaction that would ultimately be used with payment functions.
|
225
|
+
|
226
|
+
**_Call_**
|
227
|
+
|
228
|
+
response = nfg_client.get_fee({
|
229
|
+
"DonationLineItems" => {
|
230
|
+
"DonationItem1" => {
|
231
|
+
"NpoEin" => "",
|
232
|
+
"donorVis" => "", # ProvideAll, ProvideNameAndEmailOnly or Anonymous
|
233
|
+
"ItemAmount" => "",
|
234
|
+
"RecurType" => "", # NotRecurring, Monthly, Quarterly or Annually
|
235
|
+
"Designation" => ""
|
236
|
+
"Dedication" => ""
|
237
|
+
},
|
238
|
+
"DonationItem2" => {
|
239
|
+
...
|
240
|
+
},
|
241
|
+
...
|
242
|
+
},
|
243
|
+
"TipAmount" => "",
|
244
|
+
"CardType" => ""
|
245
|
+
})
|
246
|
+
|
247
|
+
**_Response on Success_**
|
248
|
+
|
249
|
+
{
|
250
|
+
"Message" => "", # Empty
|
251
|
+
"ErrorDetails" => "", # Empty
|
252
|
+
"CallDuration" => "x.x",
|
253
|
+
"TotalChargeAmount" => "x.x",
|
254
|
+
"TotalAddFee" => "x.x",
|
255
|
+
"TotalDeductFee" => "x.x",
|
256
|
+
"TipAmount" => "x.x"
|
257
|
+
}
|
258
|
+
|
259
|
+
### GetDonorDonationHistory
|
260
|
+
|
261
|
+
Gets donor transactions.
|
262
|
+
|
263
|
+
**_Call_**
|
264
|
+
|
265
|
+
response = nfg_client.get_donor_donation_history({
|
266
|
+
"DonorToken" => ""
|
267
|
+
})
|
268
|
+
|
269
|
+
**_Response on Success_**
|
270
|
+
|
271
|
+
{
|
272
|
+
"StatusCode" => "Success",
|
273
|
+
"Message" => "", # Empty
|
274
|
+
"ErrorDetails" => "", # Empty
|
275
|
+
"CallDuration" => "x.x",
|
276
|
+
"DonorToken" => "x",
|
277
|
+
"Donations"=>[
|
278
|
+
{
|
279
|
+
"DonationDate" => "xxxx-xx-xxTxx:xx:xx.xx",
|
280
|
+
"RecurType" => "x", # e.g. NotRecurring
|
281
|
+
"IsTpcAddOnFee" => "", # true or false
|
282
|
+
"NpoName" => "", # e.g. Smithsonian Institution
|
283
|
+
"Designation" => "",
|
284
|
+
"Dedication" => "",
|
285
|
+
"Amount" => "x.x",
|
286
|
+
"ChargeId" => "x" # Integer
|
287
|
+
},
|
288
|
+
...
|
289
|
+
]
|
290
|
+
}
|
291
|
+
|
292
|
+
### GetDonationReport
|
293
|
+
|
294
|
+
Returns a report of partner transactions during a specific period of time.
|
295
|
+
|
296
|
+
**_Call_**
|
297
|
+
|
298
|
+
response = nfg_client.get_donation_report({
|
299
|
+
"StartDate" => "",
|
300
|
+
"EndDate" => "",
|
301
|
+
"DonationReportType" => "" # All, OneTime or Recurring
|
302
|
+
})
|
303
|
+
|
304
|
+
**_Response on Success_**
|
305
|
+
|
306
|
+
{
|
307
|
+
"StatusCode" => "Success",
|
308
|
+
"Message" => "", # Empty
|
309
|
+
"ErrorDetails" => "", # Empty
|
310
|
+
"CallDuration" => "x.x",
|
311
|
+
"ReturnCount" => "x",
|
312
|
+
"ReportResults"=>[
|
313
|
+
{
|
314
|
+
"Source" => "x",
|
315
|
+
"Campaign" => "x",
|
316
|
+
"ChargeId" => "x", # Integer
|
317
|
+
"ShareWithCharity" => "x", # e.g. No Donor Info - Anonymous
|
318
|
+
"DonorEmail" => "x",
|
319
|
+
"DonorFirstName" => "x",
|
320
|
+
"DonorLastName" => "x",
|
321
|
+
"DonorAddress1" => "x",
|
322
|
+
"DonorAddress2" => "x",
|
323
|
+
"DonorCity" => "x",
|
324
|
+
"DonorState" => "x",
|
325
|
+
"DonorZip" => "x",
|
326
|
+
"DonorCountry" => "x",
|
327
|
+
"DonorPhone" => "x",
|
328
|
+
"Designation" => "",
|
329
|
+
"DonateInName" => "",
|
330
|
+
"RecurringPeriod" => "",
|
331
|
+
"EventDate" => "xxxx-xx-xxTxx:xx:xx.xxxZ",
|
332
|
+
"NpoEIN" => "x",
|
333
|
+
"NpoName" => "x",
|
334
|
+
"ChargeStatus" => "", # e.g. CS_SUCCESS
|
335
|
+
"ChargeAmount" => "x.x",
|
336
|
+
"NpoTPC" => "x.x",
|
337
|
+
"DonationItemAmount" => "x.x",
|
338
|
+
"TotalDonationAmount" => "x.x",
|
339
|
+
"HistoryRecordId" => "x"
|
340
|
+
},
|
341
|
+
...
|
342
|
+
]
|
343
|
+
}
|
344
|
+
|
345
|
+
## Failed calls
|
346
|
+
|
347
|
+
When a call fails (i.e. the "StatusCode" is different than "Success"), it's usually possible to find out more about the error looking at the "Message" and "ErrorDetails" fields. "Message" is a string, while "ErrorDetails" is a hash with the following format:
|
348
|
+
|
349
|
+
{
|
350
|
+
"StatusCode" => "Other",
|
351
|
+
"Message" => "x",
|
352
|
+
"ErrorDetails" => {
|
353
|
+
"ErrorInfo"=>{
|
354
|
+
"ErrCode" => "x",
|
355
|
+
"ErrData" => "x"
|
356
|
+
}
|
357
|
+
}
|
358
|
+
"CallDuration" => "x.x",
|
359
|
+
...
|
360
|
+
}
|
data/Rakefile
ADDED
data/lib/nfg-client.rb
ADDED
@@ -0,0 +1,321 @@
|
|
1
|
+
module NFGClient
|
2
|
+
|
3
|
+
def self.new(partner_id, partner_password, partner_source, partner_campaign, use_sandbox = false)
|
4
|
+
NFGClient::Client.new(partner_id, partner_password, partner_source, partner_campaign, use_sandbox)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Client
|
8
|
+
include NFGClient::Utils
|
9
|
+
|
10
|
+
def initialize(partner_id, partner_password, partner_source, partner_campaign, use_sandbox)
|
11
|
+
@partner_id = partner_id
|
12
|
+
@partner_password = partner_password
|
13
|
+
@partner_source = partner_source
|
14
|
+
@partner_campaign = partner_campaign
|
15
|
+
@use_sandbox = use_sandbox
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a card on file for the given donor token
|
19
|
+
#
|
20
|
+
# Arguments:
|
21
|
+
# params: (Hash)
|
22
|
+
def create_cof(params)
|
23
|
+
call_params = add_credentials_to_params(params)
|
24
|
+
response = nfg_soap_request('CreateCOF', call_params, @use_sandbox)
|
25
|
+
if response.is_a? REXML::Element
|
26
|
+
{
|
27
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
28
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
29
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
30
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
31
|
+
'DonorToken' => response.elements['DonorToken'].get_text.to_s,
|
32
|
+
'COFId' => response.elements['CofId'].get_text.to_s
|
33
|
+
}
|
34
|
+
else
|
35
|
+
response
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Deletes a card on file for the given donor token
|
40
|
+
#
|
41
|
+
# Arguments:
|
42
|
+
# params: (Hash)
|
43
|
+
def delete_donor_cof(params)
|
44
|
+
call_params = add_credentials_to_params(params)
|
45
|
+
response = nfg_soap_request('DeleteDonorCOF', call_params, @use_sandbox)
|
46
|
+
if response.is_a? REXML::Element
|
47
|
+
if response.elements['StatusCode'].get_text.to_s == 'Success'
|
48
|
+
{
|
49
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
50
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
51
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
52
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s
|
53
|
+
}
|
54
|
+
else
|
55
|
+
{
|
56
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
57
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
58
|
+
'ErrorDetails' => {
|
59
|
+
'ErrorInfo' => {
|
60
|
+
'ErrCode' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrCode'].andand.get_text.andand.to_s,
|
61
|
+
'ErrData' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrData'].andand.get_text.andand.to_s
|
62
|
+
}
|
63
|
+
},
|
64
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s
|
65
|
+
}
|
66
|
+
end
|
67
|
+
else
|
68
|
+
response
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Gets a list of the given donor token's cards on file
|
73
|
+
#
|
74
|
+
# Arguments:
|
75
|
+
# params: (Hash)
|
76
|
+
def get_donor_cofs(params)
|
77
|
+
call_params = add_credentials_to_params(params)
|
78
|
+
response = nfg_soap_request('GetDonorCOFs', call_params, @use_sandbox)
|
79
|
+
if response.is_a? REXML::Element
|
80
|
+
response_hash = {
|
81
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
82
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
83
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
84
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
85
|
+
'DonorToken' => response.elements['DonorToken'].get_text.to_s
|
86
|
+
}
|
87
|
+
response_hash['Cards'] = Array.new
|
88
|
+
response.elements.each('Cards/COFRecord') do |card|
|
89
|
+
response_hash['Cards'] << {
|
90
|
+
'COFId' => card.elements['COFId'].get_text.to_s,
|
91
|
+
'CardType' => card.elements['CardType'].get_text.to_s,
|
92
|
+
'CCSuffix' => card.elements['CCSuffix'].get_text.to_s,
|
93
|
+
'CCExpMonth' => card.elements['CCExpMonth'].get_text.to_s,
|
94
|
+
'CCExpYear' => card.elements['CCExpYear'].get_text.to_s,
|
95
|
+
'bInUseByLiveRD' => card.elements['bInUseByLiveRD'].get_text.to_s,
|
96
|
+
'COFEmailAddress' => card.elements['COFEmailAddress'].get_text.to_s
|
97
|
+
}
|
98
|
+
end
|
99
|
+
response_hash
|
100
|
+
else
|
101
|
+
response
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Calculates fee tied to transaction
|
106
|
+
#
|
107
|
+
# Arguments:
|
108
|
+
# params: (Hash)
|
109
|
+
def get_fee(params)
|
110
|
+
call_params = add_credentials_to_params(params)
|
111
|
+
response = nfg_soap_request('GetFee', call_params, @use_sandbox)
|
112
|
+
if response.is_a? REXML::Element
|
113
|
+
if response.elements['ErrorDetails'].elements['ErrorInfo'].nil?
|
114
|
+
{
|
115
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
116
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
117
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
118
|
+
'TotalChargeAmount' => response.elements['TotalChargeAmount'].get_text.to_s,
|
119
|
+
'TotalAddFee' => response.elements['TotalAddFee'].get_text.to_s,
|
120
|
+
'TotalDeductFee' => response.elements['TotalChargeAmount'].get_text.to_s,
|
121
|
+
'TipAmount' => response.elements['TotalAddFee'].get_text.to_s
|
122
|
+
}
|
123
|
+
else
|
124
|
+
{
|
125
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
126
|
+
'ErrorDetails' => {
|
127
|
+
'ErrorInfo' => {
|
128
|
+
'ErrCode' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrCode'].andand.get_text.andand.to_s,
|
129
|
+
'ErrData' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrData'].andand.get_text.andand.to_s
|
130
|
+
}
|
131
|
+
},
|
132
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
133
|
+
'TotalChargeAmount' => response.elements['TotalChargeAmount'].get_text.to_s,
|
134
|
+
'TotalAddFee' => response.elements['TotalAddFee'].get_text.to_s,
|
135
|
+
'TotalDeductFee' => response.elements['TotalChargeAmount'].get_text.to_s,
|
136
|
+
'TipAmount' => response.elements['TotalAddFee'].get_text.to_s
|
137
|
+
}
|
138
|
+
end
|
139
|
+
else
|
140
|
+
response
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Makes a donation using the given COF
|
145
|
+
#
|
146
|
+
# Arguments:
|
147
|
+
# params: (Hash)
|
148
|
+
def make_cof_donation(params)
|
149
|
+
call_params = add_credentials_to_params(params)
|
150
|
+
response = nfg_soap_request('MakeCOFDonation', call_params, @use_sandbox)
|
151
|
+
if response.is_a? REXML::Element
|
152
|
+
if response.elements['StatusCode'].get_text.to_s == 'Success'
|
153
|
+
{
|
154
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
155
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
156
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
157
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
158
|
+
'ChargeId' => response.elements['ChargeId'].get_text.to_s,
|
159
|
+
'COFId' => response.elements['CofId'].get_text.to_s
|
160
|
+
}
|
161
|
+
else
|
162
|
+
{
|
163
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
164
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
165
|
+
'ErrorDetails' => {
|
166
|
+
'ErrorInfo' => {
|
167
|
+
'ErrCode' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrCode'].andand.get_text.andand.to_s,
|
168
|
+
'ErrData' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrData'].andand.get_text.andand.to_s
|
169
|
+
}
|
170
|
+
},
|
171
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
172
|
+
'ChargeId' => response.elements['ChargeId'].get_text.to_s,
|
173
|
+
'COFId' => response.elements['CofId'].get_text.to_s
|
174
|
+
}
|
175
|
+
end
|
176
|
+
else
|
177
|
+
response
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Makes a donation and stores a COF for the given donor token
|
182
|
+
#
|
183
|
+
# Arguments:
|
184
|
+
# params: (Hash)
|
185
|
+
def make_donation_add_cof(params)
|
186
|
+
call_params = add_credentials_to_params(params)
|
187
|
+
response = nfg_soap_request('MakeDonationAddCOF', call_params, @use_sandbox)
|
188
|
+
if response.is_a? REXML::Element
|
189
|
+
if (response.elements['StatusCode'].get_text.to_s == 'Success') || ((response.elements['StatusCode'].get_text.to_s != 'Success') && response.elements['ErrorDetails'].elements['ErrorInfo'].nil?)
|
190
|
+
{
|
191
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
192
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
193
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
194
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
195
|
+
'ChargeId' => response.elements['ChargeId'].get_text.to_s,
|
196
|
+
'COFId' => response.elements['CofId'].get_text.to_s
|
197
|
+
}
|
198
|
+
else
|
199
|
+
{
|
200
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
201
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
202
|
+
'ErrorDetails' => {
|
203
|
+
'ErrorInfo' => {
|
204
|
+
'ErrCode' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrCode'].andand.get_text.andand.to_s,
|
205
|
+
'ErrData' => response.elements['ErrorDetails'].andand.elements.andand['ErrorInfo'].andand.elements.andand['ErrData'].andand.get_text.andand.to_s
|
206
|
+
}
|
207
|
+
},
|
208
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
209
|
+
'ChargeId' => response.elements['ChargeId'].get_text.to_s,
|
210
|
+
'COFId' => response.elements['CofId'].get_text.to_s
|
211
|
+
}
|
212
|
+
end
|
213
|
+
else
|
214
|
+
response
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Retrieves the donation history for a specified donor token
|
219
|
+
#
|
220
|
+
# Arguments:
|
221
|
+
# params: (Hash)
|
222
|
+
def get_donor_donation_history(params)
|
223
|
+
call_params = add_credentials_to_params(params)
|
224
|
+
response = nfg_soap_request('GetDonorDonationHistory', call_params, @use_sandbox)
|
225
|
+
if response.is_a? REXML::Element
|
226
|
+
response_hash = {
|
227
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
228
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
229
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
230
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
231
|
+
'DonorToken' => response.elements['DonorToken'].get_text.to_s
|
232
|
+
}
|
233
|
+
response_hash['Donations'] = Array.new
|
234
|
+
response.elements.each('Donations/DonationItemData') do |donation|
|
235
|
+
response_hash['Donations'] << {
|
236
|
+
'DonationDate' => donation.elements['DonationDate'].get_text.to_s,
|
237
|
+
'RecurType' => donation.elements['RecurType'].get_text.to_s,
|
238
|
+
'IsTpcAddOnFee' => donation.elements['IsTpcAddOnFee'].get_text.to_s,
|
239
|
+
'NpoName' => donation.elements['NpoName'].get_text.to_s,
|
240
|
+
'Designation' => donation.elements['Designation'].get_text.to_s,
|
241
|
+
'Dedication' => donation.elements['Dedication'].get_text.to_s,
|
242
|
+
'Amount' => donation.elements['Amount'].get_text.to_s,
|
243
|
+
'ChargeId' => donation.elements['ChargeId'].get_text.to_s,
|
244
|
+
}
|
245
|
+
end
|
246
|
+
response_hash
|
247
|
+
else
|
248
|
+
response
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# Retrieves the donation history by date
|
253
|
+
#
|
254
|
+
# Arguments:
|
255
|
+
# params: (Hash)
|
256
|
+
def get_donation_report(params)
|
257
|
+
call_params = add_credentials_to_params(params)
|
258
|
+
response = nfg_soap_request('GetDonationReport', call_params, @use_sandbox)
|
259
|
+
if response.is_a? REXML::Element
|
260
|
+
response_hash = {
|
261
|
+
'StatusCode' => response.elements['StatusCode'].get_text.to_s,
|
262
|
+
'Message' => response.elements['Message'].get_text.to_s,
|
263
|
+
'ErrorDetails' => response.elements['ErrorDetails'].get_text.to_s,
|
264
|
+
'CallDuration' => response.elements['CallDuration'].get_text.to_s,
|
265
|
+
'ReturnCount' => response.elements['ReturnCount'].get_text.to_s
|
266
|
+
}
|
267
|
+
response_hash['ReportResults'] = Array.new
|
268
|
+
response.elements.each('ReportResults/DonationReportResult') do |donation|
|
269
|
+
response_hash['ReportResults'] << {
|
270
|
+
'Source' => donation.elements['Source'].get_text.to_s,
|
271
|
+
'Campaign' => donation.elements['Campaign'].get_text.to_s,
|
272
|
+
'ChargeId' => donation.elements['ChargeId'].get_text.to_s,
|
273
|
+
'ShareWithCharity' => donation.elements['ShareWithCharity'].get_text.to_s,
|
274
|
+
'DonorEmail' => donation.elements['DonorEmail'].get_text.to_s,
|
275
|
+
'DonorFirstName' => donation.elements['DonorFirstName'].get_text.to_s,
|
276
|
+
'DonorLastName' => donation.elements['DonorLastName'].get_text.to_s,
|
277
|
+
'DonorAddress1' => donation.elements['DonorAddress1'].get_text.to_s,
|
278
|
+
'DonorAddress2' => donation.elements['DonorAddress2'].get_text.to_s,
|
279
|
+
'DonorCity' => donation.elements['DonorCity'].get_text.to_s,
|
280
|
+
'DonorState' => donation.elements['DonorState'].get_text.to_s,
|
281
|
+
'DonorZip' => donation.elements['DonorZip'].get_text.to_s,
|
282
|
+
'DonorCountry' => donation.elements['DonorCountry'].get_text.to_s,
|
283
|
+
'DonorPhone' => donation.elements['DonorPhone'].get_text.to_s,
|
284
|
+
'Designation' => donation.elements['Designation'].get_text.to_s,
|
285
|
+
'DonateInName' => donation.elements['DonateInName'].get_text.to_s,
|
286
|
+
'RecurringPeriod' => donation.elements['RecurringPeriod'].get_text.to_s,
|
287
|
+
'EventDate' => donation.elements['EventDate'].get_text.to_s,
|
288
|
+
'NpoEIN' => donation.elements['NpoEIN'].get_text.to_s,
|
289
|
+
'NpoName' => donation.elements['NpoName'].get_text.to_s,
|
290
|
+
'ChargeStatus' => donation.elements['ChargeStatus'].get_text.to_s,
|
291
|
+
'ChargeAmount' => donation.elements['ChargeAmount'].get_text.to_s,
|
292
|
+
'NpoTPC' => donation.elements['NpoTPC'].get_text.to_s,
|
293
|
+
'DonationItemAmount' => donation.elements['DonationItemAmount'].get_text.to_s,
|
294
|
+
'TotalDonationAmount' => donation.elements['TotalDonationAmount'].get_text.to_s,
|
295
|
+
'HistoryRecordId' => donation.elements['HistoryRecordId'].get_text.to_s
|
296
|
+
}
|
297
|
+
end
|
298
|
+
response_hash
|
299
|
+
else
|
300
|
+
response
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
private
|
305
|
+
|
306
|
+
# Adds client credentials to hash of parameters
|
307
|
+
#
|
308
|
+
# Arguments:
|
309
|
+
# params: (Hash)
|
310
|
+
def add_credentials_to_params(params)
|
311
|
+
return params unless params.is_a? Hash
|
312
|
+
credentials = {
|
313
|
+
'PartnerID' => @partner_id,
|
314
|
+
'PartnerPW' => @partner_password,
|
315
|
+
'PartnerSource' => @partner_source,
|
316
|
+
'PartnerCampaign' => @partner_campaign
|
317
|
+
}
|
318
|
+
credentials.merge(params)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
module NFGClient
|
5
|
+
module Utils
|
6
|
+
@@nfg_urls = {
|
7
|
+
'sandbox' => {
|
8
|
+
'host' => 'api-sandbox.networkforgood.org',
|
9
|
+
'url' => 'https://api-sandbox.networkforgood.org/PartnerDonationService/DonationServices.asmx',
|
10
|
+
'wsdl' => 'https://api-sandbox.networkforgood.org/PartnerDonationService/DonationServices.asmx?wsdl'
|
11
|
+
},
|
12
|
+
'production' => {
|
13
|
+
'host' => 'api.networkforgood.org',
|
14
|
+
'url' => 'https://api.networkforgood.org/PartnerDonationService/DonationServices.asmx',
|
15
|
+
'wsdl' => 'https://api.networkforgood.org/PartnerDonationService/DonationServices.asmx?wsdl'
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
# Makes HTTP POST request to NFG server (sandbox or production) and returns parsed XML response.
|
20
|
+
#
|
21
|
+
# Arguments:
|
22
|
+
# nfg_method: (String)
|
23
|
+
# params: (Hash)
|
24
|
+
def nfg_soap_request(nfg_method, params, use_sandbox = false)
|
25
|
+
if (nfg_method.is_a? String) && (params.is_a? Hash)
|
26
|
+
# Build SOAP 1.2 request
|
27
|
+
soap_request = build_nfg_soap_request(nfg_method,params)
|
28
|
+
|
29
|
+
# Build request URL & header
|
30
|
+
host = use_sandbox ? @@nfg_urls['sandbox']['host'] : @@nfg_urls['production']['host']
|
31
|
+
url = use_sandbox ? @@nfg_urls['sandbox']['url'] : @@nfg_urls['production']['url']
|
32
|
+
headers = {
|
33
|
+
'Host' => host,
|
34
|
+
'Content-Type' => 'application/soap+xml; charset=utf-8',
|
35
|
+
'Content-Length' => soap_request.length.to_s,
|
36
|
+
'SOAPAction' => "#{url}/#{nfg_method}".gsub('.asmx','')
|
37
|
+
}
|
38
|
+
|
39
|
+
return_value = Hash.new
|
40
|
+
|
41
|
+
# Being HTTP Post
|
42
|
+
begin
|
43
|
+
uri = URI.parse(url)
|
44
|
+
https_conn = Net::HTTP.new(uri.host, uri.port)
|
45
|
+
https_conn.use_ssl = true
|
46
|
+
response = https_conn.post(uri.path, soap_request, headers)
|
47
|
+
if response.code == '200'
|
48
|
+
parsed = REXML::Document.new(response.body)
|
49
|
+
#return response.body
|
50
|
+
# Build return hash parsing XML response
|
51
|
+
if parsed.root.nil?
|
52
|
+
return_value['StatusCode'] = 'MissingParameter'
|
53
|
+
return_value['Message'] = response.body
|
54
|
+
return_value['ErrorDetails'] = nil
|
55
|
+
else
|
56
|
+
return_value = parsed.root.elements['soap:Body'].elements["#{nfg_method}Response"].elements["#{nfg_method}Result"]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
return_value['StatusCode'] = 'UnexpectedError'
|
60
|
+
return_value['Message'] = response.message
|
61
|
+
return_value['ErrorDetails'] = response.body
|
62
|
+
end
|
63
|
+
rescue StandardError => e
|
64
|
+
return_value['StatusCode'] = 'UnexpectedError'
|
65
|
+
return_value['Message'] = e
|
66
|
+
return_value['ErrorDetails'] = e.backtrace.join(' ')
|
67
|
+
end
|
68
|
+
|
69
|
+
return_value
|
70
|
+
else
|
71
|
+
raise ArgumentError.new('http_post requires a nfg_method and a hash of params')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_nfg_soap_request(nfg_method, params)
|
76
|
+
get_nfg_soap_request_template.gsub('|body|',"<#{nfg_method} xmlns=\"http://api.networkforgood.org/partnerdonationservice\">#{hash_to_xml(params)}</#{nfg_method}>")
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_nfg_soap_request_template
|
80
|
+
"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body>|body|</soap12:Body></soap12:Envelope>"
|
81
|
+
end
|
82
|
+
|
83
|
+
def hash_to_xml(hash)
|
84
|
+
hash.map do |k, v|
|
85
|
+
text = (v.is_a? Hash) ? hash_to_xml(v) : v
|
86
|
+
xml_elem = (v.is_a? Hash) ? k.gsub(/(\d)/, "") : k
|
87
|
+
"<%s>%s</%s>" % [xml_elem, text, xml_elem]
|
88
|
+
end.join
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/nfg-client.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'nfg-client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "nfg-client"
|
8
|
+
gem.version = NFGClient::VERSION
|
9
|
+
gem.authors = ["Antonio Ruano Cuesta"]
|
10
|
+
gem.email = ["ruanest@gmail.com"]
|
11
|
+
gem.description = %q{Client for the Network for Good SOAP API.}
|
12
|
+
gem.summary = gem.description
|
13
|
+
gem.licenses = %w(MIT)
|
14
|
+
gem.homepage = "https://github.com/aruanoc/nfg-client"
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ["lib"]
|
20
|
+
|
21
|
+
gem.add_runtime_dependency 'andand', "~> 1.3.3"
|
22
|
+
|
23
|
+
gem.add_development_dependency 'rspec', '~> 2.13.0'
|
24
|
+
gem.add_development_dependency 'simplecov'
|
25
|
+
end
|
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
5
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
6
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
7
|
+
# loaded once.
|
8
|
+
#
|
9
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nfg-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Antonio Ruano Cuesta
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: andand
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.3.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.3.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.13.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.13.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: simplecov
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Client for the Network for Good SOAP API.
|
56
|
+
email:
|
57
|
+
- ruanest@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.md
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/nfg-client.rb
|
69
|
+
- lib/nfg-client/client.rb
|
70
|
+
- lib/nfg-client/utils.rb
|
71
|
+
- lib/nfg-client/version.rb
|
72
|
+
- nfg-client.gemspec
|
73
|
+
- spec/nfg_client_spec.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
homepage: https://github.com/aruanoc/nfg-client
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.2.2
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Client for the Network for Good SOAP API.
|
99
|
+
test_files:
|
100
|
+
- spec/nfg_client_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
has_rdoc:
|