infuser 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ced6e7246187597ea92df1ff1d847afe130377dc
4
+ data.tar.gz: 64dfee1e7ebfbc4707cb3a0b249a54d548a8299d
5
+ SHA512:
6
+ metadata.gz: ac008b42df54932f0a6a21327e2f492bf397bd09d44db310febfc4617107d96253d0f5bc7fc178bb306b8149e99473e02d9181211fcce6ce2a53aad3c5756ca4
7
+ data.tar.gz: 336aced5a96227541377156f7b6b8de36a63c8d675cccc148c793b762a7aed04a4f9b3d3f3e9f6639204f7e37b2988aa6b9ed372275a165c8f721d35d283581f
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ log/*.log
3
+ tmp/**/*
4
+ .DS_Store
5
+ rdoc/
6
+ .ruby-version
data/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # Infuser
2
+
3
+ A cleaner Ruby wrapper for the InfusionSoft API.
4
+
5
+ This gem is for use with the Infusionsoft OAuth2 API. If you are using the token-based API, see [Nathan Levitt's gem](https://github.com/nateleavitt/infusionsoft), which this gem is based on.
6
+
7
+ ## Philosophy
8
+
9
+ Infusionsoft has quite the annoying API. One example: field names are not standardized. Another: some API calls require specific arguments in a specific order, others take a hash.
10
+
11
+ I've gone out of my way to standardize these things behind the scenes in order to provide a cleaner, Ruby-esque way of dealing with the API.
12
+
13
+ ## Caveats
14
+
15
+ I developed this gem as part of a project for a client. It covers companies, contacts, and invoices, but not much else, as that was all the client required. Pull requests are always welcome.
16
+
17
+ ## Installation
18
+ 1. Add the gem to your gemfile.
19
+
20
+ ```
21
+ gem install infuser
22
+ ```
23
+
24
+ 2. Create an initializer file in your Rails app, with your Infusionsoft API settings:
25
+
26
+ ```ruby
27
+ Infuser::Configuration.configure do |config|
28
+ config.api_key = 'Your-App-API-Key'
29
+ config.api_secret = 'Your-App-API-Secret'
30
+ end
31
+ ```
32
+
33
+ Within the configuration block above, you can also set the `logger` as well as `retry_count` for how many times a call should be attempted before giving up.
34
+
35
+ ## Usage
36
+
37
+ This gem is for use with Infusionsoft's *OAuth2* API, not the token-based API.
38
+
39
+ Use the [omniauth-infusionsoft](https://github.com/l1h3r/omniauth-infusionsoft) gem to allow your users to connect and authorize their accounts, just like you would connect [any other OAuth gem](http://railscasts.com/episodes/360-facebook-authentication).
40
+
41
+ Once a user authorizes their account, Infusionsoft returns an `access_token`. You use this `access_token` to begin using this Infuser gem.
42
+
43
+ #### General Structure
44
+
45
+ All models work the same way, and are as close to ActiveRecord as possible. Here is an example with Contacts.
46
+
47
+ ```ruby
48
+ client = Infuser::Client.new(access-token)
49
+
50
+ # retrieve contacts
51
+ client.contacts.all
52
+
53
+ # find a contact
54
+ client.contacts.find(1)
55
+
56
+ # search for a contact
57
+ client.contacts.find_by(first_name: 'David', last_name: 'Lesches')
58
+
59
+ # initialize a contact without saving it
60
+ client.contacts.build(first_name: 'David', last_name: 'Lesches')
61
+
62
+ # create a new contact
63
+ client.contacts.create(first_name: 'David', last_name: 'Lesches')
64
+
65
+ # update a contact
66
+ contact = client.contacts.find(1)
67
+ contact.first_name = 'John'
68
+ contact.save
69
+
70
+ # get a contact's attributes as a hash
71
+ contact = client.contacts.find(1)
72
+ contact.attributes
73
+
74
+ # delete a contact
75
+ contact = client.contacts.find(1)
76
+ contact.destroy
77
+ ```
78
+
79
+ #### Contacts
80
+
81
+ Complete field list: `:first_name, :middle_name, :nickname, :last_name, :suffix, :title, :company_id, :job_title, :assistant_name, :assistant_phone, :contact_notes, :contact_type, :referral_code, :spouse_name, :username, :website, :date_created, :last_updated`
82
+
83
+ A contact can also have many phones, faxes, emails, and addresses. A contact can belong to a company.
84
+
85
+ #### Companies
86
+
87
+ Complete field list: `:company, :website, :date_created, :last_updated`. Note that the "name" field for a company is called 'company'. Infusionsoft :)
88
+
89
+ A contact can also have many phones, faxes, emails, and addresses.
90
+
91
+ You can also assign a contact to a company:
92
+
93
+ ```ruby
94
+ client = Infuser::Client.new(access-token)
95
+ company = client.companies.find(1)
96
+ contact = client.contacts.find(1)
97
+ contact.company = company # => assigns and saves company 1 to contact
98
+ contact.company # => retrieves company 1
99
+
100
+ company.contacts # => get all contacts for this company
101
+ ```
102
+
103
+ #### Addresses
104
+
105
+ Both Companies and Contacts have many addresses.
106
+
107
+ ```ruby
108
+ # See all addresses for this contact
109
+ contact.addresses
110
+
111
+ # Add an address to this contact
112
+ contact.addresses << Infuser::Address.new(street_address: '123 Broadway')
113
+ contact.save
114
+
115
+ # Remove an address from this contact
116
+ address = contact.addresses.find(1)
117
+ contact.addresses.remove(address)
118
+ contact.save
119
+ ```
120
+
121
+ Complete field list: `:street_address, :street_address2, :address_type, :city, :state, :country, :postal_code, :zip`
122
+
123
+ #### Phones
124
+
125
+ Both Companies and Contacts have many phones.
126
+
127
+ ```ruby
128
+ # See all phones for this contact
129
+ contact.phones
130
+
131
+ # Add a phone to this contact
132
+ contact.phones << Infuser::Phone.new(number: '1-222-333-4444')
133
+ contact.save
134
+
135
+ # Remove a phone from this contact
136
+ phone = contact.phones.find(1)
137
+ contact.phones.remove(phone)
138
+ contact.save
139
+ ```
140
+
141
+ Complete field list: `:number, :extension, :type`
142
+
143
+ #### Faxes
144
+
145
+ Both Companies and Contacts have many faxes.
146
+
147
+ ```ruby
148
+ # See all faxes for this contact
149
+ contact.faxes
150
+
151
+ # Add a fax to this contact
152
+ contact.faxes << Infuser::Fax.new(number: '1-222-333-4444')
153
+ contact.save
154
+
155
+ # Remove a fax from this contact
156
+ fax = contact.faxes.find(1)
157
+ contact.faxes.remove(fax)
158
+ contact.save
159
+ ```
160
+
161
+ Complete field list: `:number, :extension, :type`
162
+
163
+ #### Emails
164
+
165
+ Both Companies and Contacts have many emails.
166
+
167
+ ```ruby
168
+ # See all emails for this contact
169
+ contact.emails
170
+
171
+ # Add an email to this contact
172
+ contact.emails << Infuser::Email.new(email: 'info@google.com')
173
+ contact.save
174
+
175
+ # Remove an email from this contact
176
+ email = contact.emails.find(1)
177
+ contact.emails.remove(email)
178
+ contact.save
179
+ ```
180
+
181
+ Complete field list: `:email`
182
+
183
+ #### Invoices
184
+
185
+ Because Infusionsoft is awesome, creating invoices requires specific parameters in exact order.
186
+
187
+ ```ruby
188
+ # 1: contact_id
189
+ # 2: description
190
+ # 3: date
191
+ # 4: lead_affiliate_id (0 should be used if none)
192
+ # 5: sale_affiliate_id (0 should be used if none)
193
+
194
+ client.invoices.create(1, "A test invoice", Time.zone.now.to_date, 0, 0)
195
+ ```
196
+
197
+ Once an invoice is created, you can add items to it. These too require specific parameters in exact order.
198
+ ```ruby
199
+ # 1: product_id
200
+ # 2: type (UNKNOWN = 0, SHIPPING = 1, TAX = 2, SERVICE = 3, PRODUCT = 4, UPSELL = 5, FINANCECHARGE = 6, SPECIAL = 7)
201
+ # 3: price
202
+ # 4: quantity
203
+ # 5: description
204
+ # 6: notes
205
+
206
+ invoice.add_item(0, 4, 10.00, 3, 'Lollipop Consulting', '')
207
+ ```
208
+
209
+ Complete field list when reading fields from an invoice: `:affiliate_id, :contact_id, :credit_status, :date_created, :description, :invoice_total, :invoice_type, :job_id, :lead_affiliate_id, :pay_plan_status, :pay_status, :product_sold,
210
+ :promo_code, :refund_status, :synced, :total_due, :total_paid`
211
+
212
+ #### InvoiceItems
213
+
214
+ An invoice item is a line item on an invoice. Usage: `invoice.invoice_items`
215
+
216
+ To add an invoice item, see the Invoices section above. Complete field list when reading: `:commission_status, :date_created, :description, :discount, :invoice_amt, :invoice_id, :order_item_id`
217
+
218
+ Every invoice item belongs to an order item. These are created automatically by Infusionsoft when adding an invoice item. Order item contains quantity and price per unit information. Usage: `invoice.invoice_items.first.order_item`
219
+
220
+ Complete field list of order items: `:item_description, :item_name, :item_type, :notes, :order_id, :product_id, :cpu, :ppu, :qty`
221
+
222
+ ## Refreshing Tokens
223
+
224
+ Infusionsoft access tokens expire after a few hours. You can get a new one using Infuser if you have stored the **refresh\_token**. Every time you sign in to Infusionsoft, you get both an access\_token and a refresh\_token. The access\_token is what you use to retrieve data. Once it expires, you use the refresh\_token to get a new access\_token and refresh\_token.
225
+
226
+ ```ruby
227
+ r = Infuser::TokenRefresher.new(refresh-token)
228
+ r.refresh
229
+ ```
230
+
231
+ ## Issues
232
+ Submit the issue on Github. I handle gems in my spare time, so if something is time sensitive, be prepared to fork. Pull requests appreciated.
233
+
234
+ ## Copyright
235
+ Copyright (c) 2014 David Lesches.
236
+
237
+ Original based on code from [Nathan Levitt's gem](https://github.com/nateleavitt/infusionsoft).
238
+
239
+ ## License
240
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software.
241
+
242
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+ require 'bundler/gem_tasks'
3
+
4
+ Rake::TestTask.new
5
+
6
+ task :console do
7
+ exec "irb -r infuser -I ./lib"
8
+ end
data/infuser.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ require File.expand_path('../lib/infuser/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'infuser'
6
+ spec.summary = %q{Ruby wrapper for the Infusionsoft API}
7
+ spec.description = 'A Ruby wrapper for the Infusionsoft API'
8
+ spec.authors = ["David Lesches"]
9
+ spec.email = ['david@lesches.com']
10
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
11
+ spec.files = `git ls-files`.split("\n")
12
+ spec.homepage = 'https://github.com/davidlesches/infuser'
13
+ spec.require_paths = ['lib']
14
+ spec.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
15
+
16
+ spec.add_dependency 'activesupport'
17
+ spec.add_dependency 'rest-client'
18
+ spec.add_development_dependency 'rake'
19
+
20
+ spec.version = Infuser::VERSION
21
+ end
22
+
data/lib/infuser.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'active_support/core_ext/string/inflections'
3
+ require 'infuser/helpers/hashie'
4
+ require 'infuser/version'
5
+
6
+ require 'infuser/logger'
7
+ require 'infuser/exceptions'
8
+ require 'infuser/configuration'
9
+
10
+ require 'infuser/collections/base'
11
+ require 'infuser/collections/proxy'
12
+ require 'infuser/collections/child_proxy'
13
+ require 'infuser/address'
14
+ require 'infuser/phone'
15
+ require 'infuser/fax'
16
+ require 'infuser/email'
17
+
18
+ require 'infuser/tables/base'
19
+ require 'infuser/tables/contact'
20
+ require 'infuser/tables/company'
21
+ require 'infuser/tables/invoice'
22
+ require 'infuser/tables/invoice_item'
23
+ require 'infuser/tables/order_item'
24
+
25
+ require 'infuser/models/base'
26
+ require 'infuser/contact'
27
+ require 'infuser/company'
28
+ require 'infuser/invoice'
29
+ require 'infuser/invoice_item'
30
+ require 'infuser/order_item'
31
+
32
+ require 'infuser/requester'
33
+ require 'infuser/client'
34
+ require 'infuser/token_refresher'
35
+
36
+
37
+ module Infuser
38
+
39
+ def self.logger
40
+ Infuser::Configuration.logger
41
+ end
42
+
43
+ end
44
+
45
+ # delete this
46
+ Infuser::Configuration.configure do |c|
47
+ c.api_key = 'zyh7cwtt24exdxnmhd82ukta'
48
+ c.api_secret = 'zHnUXTZMn6'
49
+ end
@@ -0,0 +1,38 @@
1
+ module Infuser
2
+ class Address < Infuser::Collections::Base
3
+
4
+ define_mappings({
5
+ 1 => {
6
+ :street_address1 => :street_address,
7
+ :street_address2 => :street_address2,
8
+ :address1_type => :address_type,
9
+ :city => :city,
10
+ :state => :state,
11
+ :country => :country,
12
+ :postal_code => :postal_code,
13
+ :zip_four1 => :zip
14
+ },
15
+ 2 => {
16
+ :address2_street1 => :street_address,
17
+ :address2_street2 => :street_address2,
18
+ :address2_type => :address_type,
19
+ :city2 => :city,
20
+ :state2 => :state,
21
+ :country2 => :country,
22
+ :postal_code2 => :postal_code,
23
+ :zip_four2 => :zip
24
+ },
25
+ 3 => {
26
+ :address3_street1 => :street_address,
27
+ :address3_street2 => :street_address2,
28
+ :address3_type => :address_type,
29
+ :city3 => :city,
30
+ :state3 => :state,
31
+ :country3 => :country,
32
+ :postal_code3 => :postal_code,
33
+ :zip_four3 => :zip
34
+ }
35
+ })
36
+
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ module Infuser
2
+ class Client
3
+
4
+ TABLES = %w( contact company invoices invoice_items order_items )
5
+ attr_reader *TABLES.map(&:pluralize)
6
+ attr_reader :access_token
7
+
8
+ def initialize access_token
9
+ @access_token = access_token || raise(Infuser::ArgumentError, 'You must specify an access token.')
10
+ setup_associations
11
+ self
12
+ end
13
+
14
+ def inspect
15
+ "#<#{self.class.name} access_token: #{access_token}>"
16
+ end
17
+
18
+
19
+ private
20
+
21
+ def setup_associations
22
+ TABLES.each do |assoc|
23
+ instance_variable_set "@#{assoc.pluralize}".to_sym, Infuser::Tables.const_get(assoc.classify).new(__client__)
24
+ end
25
+ end
26
+
27
+ def __client__
28
+ @__client__ ||= Infuser::Requester.new(access_token)
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ module Infuser
2
+ module Collections
3
+ class Base
4
+
5
+ def self.define_mappings map
6
+ @mappings = map
7
+ @standardized_fields = map.values.map(&:values).flatten.uniq
8
+ attr_accessor *standardized_fields
9
+ attr_accessor :id
10
+ end
11
+
12
+ def self.inverted_mappings
13
+ @inverted_mappings ||= mappings.each_with_object({}) do |(key, value), hash|
14
+ value.keys.each do |field|
15
+ hash[field] = key
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.schema
21
+ inverted_mappings.keys
22
+ end
23
+
24
+ def self.mappings
25
+ @mappings
26
+ end
27
+
28
+ def self.standardized_fields
29
+ @standardized_fields
30
+ end
31
+
32
+ def initialize data = {}
33
+ initial_id = data.fetch(:id) { 0 }
34
+
35
+ if initial_id > 0
36
+ self.class.mappings[initial_id].each do |key, value|
37
+ next if key == value
38
+
39
+ define_singleton_method key do
40
+ send value
41
+ end
42
+
43
+ define_singleton_method "#{key}=" do |*args|
44
+ send "#{value}=", *args
45
+ end
46
+ end
47
+ end
48
+
49
+ data.each do |key, value|
50
+ send "#{key}=", value
51
+ end
52
+ end
53
+
54
+ def data
55
+ raise(Infuser::ArgumentError, 'Cannot be called if item has no ID') if id.nil?
56
+ self.class.mappings[id].each_with_object({}) do |(key, value), hash|
57
+ hash[key] = send(value)
58
+ end
59
+ end
60
+
61
+ def attributes
62
+ raise(Infuser::ArgumentError, 'Cannot be called if item has no ID') if id.nil?
63
+ self.class.mappings[id].each_with_object({}) do |(key, value), hash|
64
+ hash[value] = send(value)
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end