zoho_invoice 0.0.1
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.
- data/.gitignore +18 -0
- data/.travis.yml +6 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/lib/zoho_invoice.rb +31 -0
- data/lib/zoho_invoice/api/customers.rb +7 -0
- data/lib/zoho_invoice/auth_token.rb +28 -0
- data/lib/zoho_invoice/base.rb +151 -0
- data/lib/zoho_invoice/client.rb +39 -0
- data/lib/zoho_invoice/configurable.rb +49 -0
- data/lib/zoho_invoice/contact.rb +22 -0
- data/lib/zoho_invoice/customer.rb +29 -0
- data/lib/zoho_invoice/defaults.rb +9 -0
- data/lib/zoho_invoice/error.rb +7 -0
- data/lib/zoho_invoice/invoice.rb +25 -0
- data/lib/zoho_invoice/invoice_item.rb +7 -0
- data/lib/zoho_invoice/item.rb +9 -0
- data/lib/zoho_invoice/version.rb +3 -0
- data/spec/fixtures/500_internal_server_error +1 -0
- data/spec/fixtures/incorrect_verb_used +1 -0
- data/spec/fixtures/invalid_customer_id +1 -0
- data/spec/fixtures/invalid_password +4 -0
- data/spec/fixtures/invalid_url_passed +1 -0
- data/spec/fixtures/invalid_user +4 -0
- data/spec/fixtures/please_select_an_item +1 -0
- data/spec/fixtures/successful_authtoken +4 -0
- data/spec/spec_helper.rb +55 -0
- data/spec/zoho_invoice/auth_token_spec.rb +73 -0
- data/spec/zoho_invoice/base_spec.rb +182 -0
- data/spec/zoho_invoice/client_spec.rb +62 -0
- data/spec/zoho_invoice/contact_spec.rb +18 -0
- data/spec/zoho_invoice_spec.rb +24 -0
- data/zoho_invoice.gemspec +29 -0
- metadata +175 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'rake'
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'pry'
|
7
|
+
end
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem 'pry'
|
11
|
+
gem 'coveralls', :require => false
|
12
|
+
gem 'rspec', '>= 2.11'
|
13
|
+
gem 'simplecov', :require => false
|
14
|
+
gem 'webmock'
|
15
|
+
end
|
16
|
+
|
17
|
+
gemspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Rimas Silkaitis
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# ZohoInvoice
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'zoho_invoice'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install zoho_invoice
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/zoho_invoice.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'multi_xml'
|
5
|
+
|
6
|
+
require 'zoho_invoice/configurable'
|
7
|
+
require 'zoho_invoice/auth_token'
|
8
|
+
require 'zoho_invoice/defaults'
|
9
|
+
|
10
|
+
require 'zoho_invoice/client'
|
11
|
+
require 'zoho_invoice/version'
|
12
|
+
require 'zoho_invoice/base'
|
13
|
+
require 'zoho_invoice/customer'
|
14
|
+
require 'zoho_invoice/item'
|
15
|
+
require 'zoho_invoice/invoice_item'
|
16
|
+
require 'zoho_invoice/invoice'
|
17
|
+
|
18
|
+
module ZohoInvoice
|
19
|
+
class << self
|
20
|
+
include ZohoInvoice::Configurable
|
21
|
+
end
|
22
|
+
|
23
|
+
# Default for connecting to Zoho Invoice API
|
24
|
+
#
|
25
|
+
@client_options = {
|
26
|
+
:url => ZohoInvoice::Defaults::URL
|
27
|
+
}
|
28
|
+
|
29
|
+
@scope = ZohoInvoice::Defaults::SCOPE
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ZohoInvoice
|
2
|
+
module AuthToken
|
3
|
+
class AuthTokenResult < Struct.new(:authtoken, :cause)
|
4
|
+
def success?
|
5
|
+
return true if !authtoken.nil?
|
6
|
+
false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.generate_authtoken(email_id, password)
|
11
|
+
client = ZohoInvoice::Client.new(:client_options => {:url => 'https://accounts.zoho.com'})
|
12
|
+
response = client.request(
|
13
|
+
:get,
|
14
|
+
'/apiauthtoken/nb/create',
|
15
|
+
{
|
16
|
+
:SCOPE => 'invoiceapi',
|
17
|
+
:EMAIL_ID => email_id,
|
18
|
+
:PASSWORD => password
|
19
|
+
}
|
20
|
+
)
|
21
|
+
|
22
|
+
result = ZohoInvoice::AuthToken::AuthTokenResult.new(nil, nil)
|
23
|
+
result.cause = response.body.match(/\nCAUSE=(.+)\n/)[1] if response.body =~ /RESULT=FALSE/
|
24
|
+
result.authtoken = response.body.match(/AUTHTOKEN=(.+)\n/)[1] if response.body =~ /RESULT=TRUE/
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module ZohoInvoice
|
2
|
+
class Error < Struct.new(:message, :code, :status, :http_status)
|
3
|
+
end
|
4
|
+
|
5
|
+
# Used for instances when some of the representations in zoho
|
6
|
+
# dont have their own end points in the API
|
7
|
+
#
|
8
|
+
class ActionNotSupportedError < StandardError; end
|
9
|
+
|
10
|
+
class Base
|
11
|
+
|
12
|
+
attr_reader :client
|
13
|
+
|
14
|
+
def self.define_object_attrs(*attrs)
|
15
|
+
@attributes = attrs
|
16
|
+
create_attributes(attrs)
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO Create an Association class to manage the relationship
|
20
|
+
#
|
21
|
+
def self.has_many(*attrs)
|
22
|
+
@reflections = attrs
|
23
|
+
create_attributes(attrs)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create(client, options = {})
|
27
|
+
self.new(client, options).save
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(client, options = {})
|
31
|
+
@client = client
|
32
|
+
|
33
|
+
# Assign all of the single attribtues
|
34
|
+
#
|
35
|
+
if !self.attributes.empty?
|
36
|
+
(self.attributes & options.keys).each do |attribute|
|
37
|
+
self.send("#{attribute}=", options[attribute])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Assign all of the associations. Not the most advanced
|
42
|
+
#
|
43
|
+
if self.reflections.is_a?(Array)
|
44
|
+
self.reflections.each { |r| self.send("#{r}=", []) }
|
45
|
+
(self.reflections & options.keys).each do |reflection|
|
46
|
+
options[reflection].each do |reflection_obj|
|
47
|
+
klass = Kernel.const_get(camel_case(reflection.to_s[0..-2]))
|
48
|
+
if reflection_obj.is_a?(Hash)
|
49
|
+
self.send("#{reflection}") << klass.new(@client, reflection_obj)
|
50
|
+
elsif reflection_obj.is_a?(klass)
|
51
|
+
self.send("#{reflection}") << reflection_obj
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def reflections
|
59
|
+
self.class.instance_variable_get(:'@reflections') || []
|
60
|
+
end
|
61
|
+
|
62
|
+
def attributes
|
63
|
+
self.class.instance_variable_get(:'@attributes') || []
|
64
|
+
end
|
65
|
+
|
66
|
+
def errors
|
67
|
+
@errors ||= []
|
68
|
+
end
|
69
|
+
|
70
|
+
# TODO Determining the resource to use will need to change
|
71
|
+
#
|
72
|
+
def save
|
73
|
+
@errors = []
|
74
|
+
|
75
|
+
action = 'create'
|
76
|
+
action = 'update' if !send("#{self.class.to_s.downcase}_id").nil?
|
77
|
+
|
78
|
+
result = client.post("/api/#{self.class.to_s.downcase + 's'}/#{action}", :XMLString => self.to_xml)
|
79
|
+
|
80
|
+
if action == 'create' && !result.body.nil? && !result.body[self.class.to_s].nil?
|
81
|
+
self.send("#{self.class.to_s.downcase}_id=", result.body[self.class.to_s]["#{self.class}ID"])
|
82
|
+
end
|
83
|
+
|
84
|
+
self
|
85
|
+
rescue Faraday::Error::ClientError => e
|
86
|
+
if e.response[:body]
|
87
|
+
self.errors << process_error(e.response)
|
88
|
+
end
|
89
|
+
return self
|
90
|
+
end
|
91
|
+
|
92
|
+
# This needs to be a Nokogiri::XML::Builder
|
93
|
+
#
|
94
|
+
def to_xml(*args)
|
95
|
+
build_attributes.to_xml(*args)
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def process_error(request_result)
|
101
|
+
self.class.process_error(request_result)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.process_error(request_result)
|
105
|
+
error = Error.new
|
106
|
+
response_body = request_result[:body]
|
107
|
+
error.status = response_body['Response']['status']
|
108
|
+
error.code = response_body['Response']['Code']
|
109
|
+
error.message = response_body['Response']['Message']
|
110
|
+
error.http_status = request_result[:status]
|
111
|
+
error
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.camel_case(str)
|
115
|
+
return str if str !~ /_/ && str =~ /[A-Z]+.*/
|
116
|
+
str.split('_').map{|e| e.capitalize}.join
|
117
|
+
end
|
118
|
+
|
119
|
+
def camel_case(str)
|
120
|
+
self.class.camel_case(str)
|
121
|
+
end
|
122
|
+
|
123
|
+
def build_attributes
|
124
|
+
Nokogiri::XML::Builder.new do |xml|
|
125
|
+
xml.send("#{self.class}") {
|
126
|
+
self.attributes.each do |attr|
|
127
|
+
vals = self.send(attr)
|
128
|
+
if !vals.nil? && !vals.is_a?(Array)
|
129
|
+
xml.send("#{camel_case(attr.to_s)}_", self.send(attr))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
self.reflections.each do |refl|
|
133
|
+
if !refl.empty?
|
134
|
+
xml.send(camel_case(refl.to_s)) {
|
135
|
+
self.send(refl).each { |x| xml << x.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION) }
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def self.create_attributes(attrs)
|
146
|
+
attrs.each do |attr|
|
147
|
+
attr_accessor attr
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ZohoInvoice
|
2
|
+
class Client
|
3
|
+
include ZohoInvoice::Configurable
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
ZohoInvoice::Configurable.keys.each do |key|
|
7
|
+
instance_variable_set(:"@#{key}", options[key] || ZohoInvoice.instance_variable_get(:"@#{key}"))
|
8
|
+
end
|
9
|
+
@client_options = ZohoInvoice.instance_variable_get(:'@client_options').merge(options[:client_options] || {})
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(path, params={})
|
13
|
+
request(:get, path, credentials.merge(params))
|
14
|
+
end
|
15
|
+
|
16
|
+
def post(path, params={})
|
17
|
+
request(:post, path, credentials.merge(params))
|
18
|
+
end
|
19
|
+
|
20
|
+
def request(verb, path, params={})
|
21
|
+
connection.send(verb, path, params)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def connection
|
27
|
+
@connection ||= Faraday.new(@client_options) do |c|
|
28
|
+
c.use Faraday::Response::RaiseError
|
29
|
+
c.response :xml, :content_type => 'application/xml'
|
30
|
+
|
31
|
+
c.request :multipart
|
32
|
+
c.request :url_encoded
|
33
|
+
|
34
|
+
c.adapter Faraday.default_adapter
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ZohoInvoice
|
2
|
+
module Configurable
|
3
|
+
|
4
|
+
# @return [String] The permanent authtoken used to authenticate each API request
|
5
|
+
attr_accessor :authtoken
|
6
|
+
|
7
|
+
# @return [String] The value for this parameter has to be invoiceapi
|
8
|
+
attr_accessor :scope
|
9
|
+
|
10
|
+
# @return [String] The key used to authenticate the API caller
|
11
|
+
attr_accessor :apikey
|
12
|
+
|
13
|
+
# @return [Hash] Client configuration to pass to Faraday
|
14
|
+
attr_accessor :client_options
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def keys
|
19
|
+
@keys ||= [
|
20
|
+
:authtoken,
|
21
|
+
:scope,
|
22
|
+
:apikey,
|
23
|
+
:client_options
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def configure
|
30
|
+
yield self
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def config_hash
|
35
|
+
Hash[ZohoInvoice::Configurable.keys.map{ |key| [key, instance_variable_get(:"@#{key}")] }]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def credentials
|
41
|
+
{
|
42
|
+
:authtoken => @authtoken,
|
43
|
+
:scope => @scope,
|
44
|
+
:apikey => @apikey
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'zoho_invoice/base'
|
2
|
+
|
3
|
+
module ZohoInvoice
|
4
|
+
class Contact < Base
|
5
|
+
|
6
|
+
define_object_attrs :salutation,
|
7
|
+
:first_name,
|
8
|
+
:last_name,
|
9
|
+
:e_mail,
|
10
|
+
:phone,
|
11
|
+
:mobile
|
12
|
+
|
13
|
+
def self.create(client, options = {})
|
14
|
+
raise ZohoInvoice::ActionNotSupportedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def save
|
18
|
+
raise ZohoInvoice::ActionNotSupportedError
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'zoho_invoice/base'
|
2
|
+
require 'zoho_invoice/contact'
|
3
|
+
|
4
|
+
module ZohoInvoice
|
5
|
+
class Customer < Base
|
6
|
+
|
7
|
+
define_object_attrs :name,
|
8
|
+
:payments_due,
|
9
|
+
:currency_code,
|
10
|
+
:billing_address,
|
11
|
+
:billing_city,
|
12
|
+
:billing_zip,
|
13
|
+
:billing_country,
|
14
|
+
:billing_fax,
|
15
|
+
:shipping_address,
|
16
|
+
:shipping_city,
|
17
|
+
:shipping_state,
|
18
|
+
:shipping_country,
|
19
|
+
:shipping_fax,
|
20
|
+
:customer_id
|
21
|
+
|
22
|
+
has_many :contacts
|
23
|
+
|
24
|
+
def self.search(client, input_text)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'zoho_invoice/invoice_item'
|
2
|
+
|
3
|
+
module ZohoInvoice
|
4
|
+
class Invoice < Base
|
5
|
+
|
6
|
+
define_object_attrs :invoice_id,
|
7
|
+
:created_time, :exchange_rate,
|
8
|
+
:last_modified_time, :l_f_name,
|
9
|
+
:last_sync_time, :late_fee_amount,
|
10
|
+
:source, :total,
|
11
|
+
:reference_id, :invoice_item_total,
|
12
|
+
:invoice_number, :tax_total,
|
13
|
+
:p_o_number, :balance,
|
14
|
+
:status,
|
15
|
+
:customer_id,
|
16
|
+
:customer_name,
|
17
|
+
:invoice_date,
|
18
|
+
:payments_due,
|
19
|
+
:due_date,
|
20
|
+
:currency_code
|
21
|
+
|
22
|
+
has_many :invoice_items
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<Response status="0"><Code>2</Code><Message><![CDATA[Invalid value passed for XMLString]]></Message></Response>
|
@@ -0,0 +1 @@
|
|
1
|
+
<Response status="0"><Code>1</Code><Message><![CDATA[API can be called only over an HTTPS Post request]]></Message></Response>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><Response status="0"><Code>3004</Code><Message>The Customer field can neither be blank nor be incorrect. Please enter a correct customer name.</Message></Response>
|
@@ -0,0 +1 @@
|
|
1
|
+
<Response status="0"><Code>5</Code><Message><![CDATA[Invalid URL Passed]]></Message></Response>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><Response status="0"><Code>4016</Code><Message>Please select an item</Message></Response>
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Get everything loaded up per gemspec
|
2
|
+
#
|
3
|
+
require 'simplecov'
|
4
|
+
require 'coveralls'
|
5
|
+
|
6
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
7
|
+
SimpleCov::Formatter::HTMLFormatter,
|
8
|
+
Coveralls::SimpleCov::Formatter
|
9
|
+
]
|
10
|
+
SimpleCov.start
|
11
|
+
|
12
|
+
require 'rspec'
|
13
|
+
require 'zoho_invoice'
|
14
|
+
require 'webmock/rspec'
|
15
|
+
require 'pry'
|
16
|
+
|
17
|
+
WebMock.disable_net_connect!
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.expect_with(:rspec) do |c|
|
21
|
+
c.syntax = :expect
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def stub_get(path)
|
26
|
+
stub_request(:get, ZohoInvoice::Defaults::URL + path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def a_get(path)
|
30
|
+
a_request(:get, ZohoInvoice::Defaults::URL + path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def stub_post(path)
|
34
|
+
stub_request(:post, ZohoInvoice::Defaults::URL + path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def a_post(path)
|
38
|
+
a_request(:post, ZohoInvoice::Defaults::URL + path)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixture_path
|
42
|
+
File.expand_path('../fixtures', __FILE__)
|
43
|
+
end
|
44
|
+
|
45
|
+
def fixture(file)
|
46
|
+
File.new(fixture_path + '/' + file)
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_credentials
|
50
|
+
{
|
51
|
+
:authtoken => '1234',
|
52
|
+
:scope => ZohoInvoice::Defaults::SCOPE,
|
53
|
+
:apikey => '5678'
|
54
|
+
}
|
55
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ZohoInvoice::AuthToken do
|
4
|
+
|
5
|
+
it "should be able to generate a new authtoken" do
|
6
|
+
email_id = 'big_tuna@example.com'
|
7
|
+
password = 'tuna'
|
8
|
+
|
9
|
+
stub_request(:get, 'https://accounts.zoho.com/apiauthtoken/nb/create').
|
10
|
+
with(:query => default_auth_options(email_id, password)).
|
11
|
+
to_return(:body => fixture('successful_authtoken'))
|
12
|
+
|
13
|
+
result = ZohoInvoice::AuthToken.generate_authtoken(email_id, password)
|
14
|
+
expect(result.success?).to be_true
|
15
|
+
expect(result).to be_a ZohoInvoice::AuthToken::AuthTokenResult
|
16
|
+
expect(a_request(:get, 'https://accounts.zoho.com/apiauthtoken/nb/create')
|
17
|
+
.with(:query => default_auth_options(email_id, password)))
|
18
|
+
.to have_been_made
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "failure cases" do
|
22
|
+
|
23
|
+
it "should be unccessful if user name is incorrect" do
|
24
|
+
bad_request('invalid_user', 'tuna@example.com', 'tuna') do |auth_token_result|
|
25
|
+
expect(auth_token_result.cause).to eq('NO_SUCH_USER')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be unccessful if user name is incorrect" do
|
30
|
+
bad_request('invalid_password', 'big_tuna@example.com', 'tu') do |auth_token_result|
|
31
|
+
expect(auth_token_result.cause).to eq('INVALID_PASSWORD')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def bad_request(fixture_to_use, email_id, password)
|
36
|
+
stub_request(:get, 'https://accounts.zoho.com/apiauthtoken/nb/create').
|
37
|
+
with(:query => default_auth_options(email_id, password)).
|
38
|
+
to_return(:body => fixture(fixture_to_use))
|
39
|
+
|
40
|
+
result = ZohoInvoice::AuthToken.generate_authtoken(email_id, password)
|
41
|
+
expect(result.success?).to be_false
|
42
|
+
expect(result).to be_a ZohoInvoice::AuthToken::AuthTokenResult
|
43
|
+
expect(a_request(:get, 'https://accounts.zoho.com/apiauthtoken/nb/create')
|
44
|
+
.with(:query => default_auth_options(email_id, password)))
|
45
|
+
.to have_been_made
|
46
|
+
|
47
|
+
yield result
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should define an auth token result" do
|
53
|
+
result = ZohoInvoice::AuthToken::AuthTokenResult.new(nil, nil)
|
54
|
+
expect(result.respond_to?(:authtoken)).to be_true
|
55
|
+
expect(result.respond_to?(:cause)).to be_true
|
56
|
+
|
57
|
+
expect(result.success?).to be_false
|
58
|
+
|
59
|
+
result.authtoken = 'asdf'
|
60
|
+
expect(result.success?).to be_true
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def default_auth_options(email, password)
|
66
|
+
{
|
67
|
+
:SCOPE => 'invoiceapi',
|
68
|
+
:EMAIL_ID => email,
|
69
|
+
:PASSWORD => password
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ZohoInvoice::Base do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@client = ZohoInvoice::Client.new(default_credentials)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "requires a client upon initialization" do
|
10
|
+
expect{ ZohoInvoice::Base.new }.to raise_error(StandardError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can define the attributes of an instance object and assign them on initialization" do
|
14
|
+
class TestClass < ZohoInvoice::Base
|
15
|
+
define_object_attrs :test_it
|
16
|
+
end
|
17
|
+
|
18
|
+
test_obj = TestClass.new(@client)
|
19
|
+
expect(test_obj.respond_to?('test_it')).to be_true
|
20
|
+
expect(test_obj.respond_to?('test_it=')).to be_true
|
21
|
+
expect(test_obj.attributes).to eq([:test_it])
|
22
|
+
|
23
|
+
test_obj1 = TestClass.new(@client, :test_it => 1)
|
24
|
+
expect(test_obj1.test_it).to eq(1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can define associations to itself" do
|
28
|
+
class TestClass < ZohoInvoice::Base
|
29
|
+
has_many :things,
|
30
|
+
:more_things
|
31
|
+
end
|
32
|
+
|
33
|
+
test_obj = TestClass.new(@client)
|
34
|
+
expect(test_obj.things.is_a?(Array)).to be_true
|
35
|
+
expect(test_obj.things.length).to eq(0)
|
36
|
+
expect(test_obj.reflections).to eq([:things, :more_things])
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "generating an xml representation" do
|
40
|
+
before do
|
41
|
+
class Something < ZohoInvoice::Base
|
42
|
+
define_object_attrs :test_it,
|
43
|
+
:blah,
|
44
|
+
:something_id
|
45
|
+
|
46
|
+
has_many :things,
|
47
|
+
:more_things
|
48
|
+
end
|
49
|
+
|
50
|
+
@test_obj = Something.new(@client)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should specific an xml doctype" do
|
54
|
+
xml = @test_obj.to_xml
|
55
|
+
expect(xml).to include("<?xml version=\"1.0\"?>")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should have a root element" do
|
59
|
+
xml = Nokogiri::XML(@test_obj.to_xml)
|
60
|
+
expect(xml.children.length).to eq(1)
|
61
|
+
expect(xml.children.first.name).to eq("Something")
|
62
|
+
|
63
|
+
@test_obj.test_it = 1234
|
64
|
+
xml = Nokogiri::XML(@test_obj.to_xml)
|
65
|
+
expect(xml.children.length).to eq(1)
|
66
|
+
expect(xml.children.first.name).to eq("Something")
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should create the attributes correctly" do
|
70
|
+
@test_obj.test_it = 1234
|
71
|
+
xml = Nokogiri::XML(@test_obj.to_xml)
|
72
|
+
expect(xml.xpath('//TestIt').length).to eq(1)
|
73
|
+
expect(xml.xpath('//TestIt').first.text).to eq('1234')
|
74
|
+
|
75
|
+
@test_obj.test_it = nil
|
76
|
+
xml = Nokogiri::XML(@test_obj.to_xml)
|
77
|
+
expect(xml.xpath('//TestIt')).to be_empty
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should create the associations correctly" do
|
81
|
+
class Thing < Struct.new(:stuff)
|
82
|
+
def to_xml(*args)
|
83
|
+
"<Thing>#{stuff}</Thing>"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@test_obj.things << Thing.new('asdf')
|
87
|
+
@test_obj.things << Thing.new('asdf')
|
88
|
+
|
89
|
+
@test_obj.more_things << Thing.new('1234')
|
90
|
+
|
91
|
+
xml = Nokogiri::XML(@test_obj.to_xml)
|
92
|
+
expect(xml.xpath('//Things').length).to eq(1)
|
93
|
+
expect(xml.xpath('//Things/Thing').length).to eq(2)
|
94
|
+
expect(xml.xpath('//MoreThings/Thing').length).to eq(1)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "saving an object" do
|
99
|
+
before do
|
100
|
+
class Something < ZohoInvoice::Base
|
101
|
+
define_object_attrs :something_id, :blah
|
102
|
+
end
|
103
|
+
@test_obj = Something.new(@client)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "calls the create path if its a new record" do
|
107
|
+
@test_obj.something_id = nil
|
108
|
+
body_params = default_credentials.merge(:XMLString => @test_obj.to_xml)
|
109
|
+
stub_post('/api/somethings/create').
|
110
|
+
with(:body => body_params).
|
111
|
+
to_return(:status => 200, :body => successful_something_response('5555'), :headers => {:content_type => 'application/xml'})
|
112
|
+
@test_obj.save
|
113
|
+
expect(a_post('/api/somethings/create').with(:body => body_params)).to have_been_made
|
114
|
+
end
|
115
|
+
|
116
|
+
it "calls the update path if its a dirty record" do
|
117
|
+
@test_obj.something_id = '123456'
|
118
|
+
body_params = default_credentials.merge(:XMLString => @test_obj.to_xml)
|
119
|
+
stub_post('/api/somethings/update').
|
120
|
+
with(:body => body_params).
|
121
|
+
to_return(:status => 200, :body => successful_something_response('123456'), :headers => {:content_type => 'application/xml'})
|
122
|
+
@test_obj.save
|
123
|
+
expect(a_post('/api/somethings/update').with(:body => body_params)).to have_been_made
|
124
|
+
end
|
125
|
+
|
126
|
+
it "can happen via .create" do
|
127
|
+
@test_obj.blah = '1234'
|
128
|
+
body_params = default_credentials.merge(:XMLString => @test_obj.to_xml)
|
129
|
+
stub_post('/api/somethings/create').
|
130
|
+
with(:body => body_params).
|
131
|
+
to_return(:status => 200, :body => successful_something_response("1234"), :headers => { :content_type => 'application/xml' })
|
132
|
+
test_obj = Something.create(@client, :blah => '1234')
|
133
|
+
expect(a_post('/api/somethings/create').with(:body => body_params)).to have_been_made
|
134
|
+
expect(test_obj.something_id).to eq('1')
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns the object and has an error method" do
|
138
|
+
@test_obj.blah = '1234'
|
139
|
+
body_params = default_credentials.merge(:XMLString => @test_obj.to_xml)
|
140
|
+
stub_post('/api/somethings/create').with(:body => body_params).to_return(:status => 500, :body => fixture('500_internal_server_error'), :headers => { :content_type => 'application/xml' })
|
141
|
+
test_obj = Something.create(@client, :blah => '1234')
|
142
|
+
expect(test_obj.something_id).to be_nil
|
143
|
+
expect(test_obj.errors.length).to eq(1)
|
144
|
+
error = test_obj.errors.first
|
145
|
+
expect(error.message).to eq("Invalid value passed for XMLString")
|
146
|
+
expect(error.code).to eq('2')
|
147
|
+
expect(error.status).to eq('0')
|
148
|
+
expect(error.http_status).to eq(500)
|
149
|
+
end
|
150
|
+
|
151
|
+
def successful_something_response(blah_payload)
|
152
|
+
"<Something><SomethingID>1</SomethingID><Blah>#{blah_payload}</Blah></Something>"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "nested associations" do
|
157
|
+
class Tuna < ZohoInvoice::Base
|
158
|
+
define_object_attrs :blah
|
159
|
+
end
|
160
|
+
class TestIt < ZohoInvoice::Base
|
161
|
+
has_many :tunas
|
162
|
+
end
|
163
|
+
|
164
|
+
before do
|
165
|
+
@client = ZohoInvoice::Client.new(default_credentials)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "can be created at initialization" do
|
169
|
+
test = TestIt.new(@client, :tunas => [{:blah => 1234}, Tuna.new(@client, :blah => 5678)])
|
170
|
+
expect(test.tunas.length).to eq(2)
|
171
|
+
expect(test.tunas.first.blah).to eq(1234)
|
172
|
+
expect(test.tunas.last.blah).to eq(5678)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "outputted when coverted to xml", :focus => true do
|
176
|
+
test = TestIt.new(@client, :tunas => [{:blah => 1234}])
|
177
|
+
doc = Nokogiri::XML(test.to_xml)
|
178
|
+
expect(doc.xpath('//Tunas').length).to be >= 1
|
179
|
+
expect(doc.xpath('//Tuna').length).to eq(1)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ZohoInvoice::Client do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
ZohoInvoice::Client.new(default_credentials)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#get" do
|
10
|
+
it "can create custom requests" do
|
11
|
+
query_hash = default_credentials.merge({:rad => 'object'})
|
12
|
+
stub_get('/something/sweet').with(:query => query_hash)
|
13
|
+
subject.get('/something/sweet', {:rad => 'object'})
|
14
|
+
expect(a_get('/something/sweet').with(:query => query_hash)).to have_been_made
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#post" do
|
19
|
+
it "can create custom requests" do
|
20
|
+
query_hash = default_credentials.merge({:rad => 'object'})
|
21
|
+
stub_post('/something/awesome').with(:body => query_hash)
|
22
|
+
subject.post('/something/awesome', {:rad => 'object'})
|
23
|
+
expect(a_post('/something/awesome').with(:body => query_hash)).to have_been_made
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#request" do
|
28
|
+
it "can create custom requests" do
|
29
|
+
stub_post('/awesome').with(:body => {:rad => 'object'})
|
30
|
+
subject.request(:post, '/awesome', {:rad => 'object'})
|
31
|
+
expect(a_post('/awesome').with({:rad => 'object'})).to have_been_made
|
32
|
+
end
|
33
|
+
|
34
|
+
it "does not include default credentials in params" do
|
35
|
+
stub_get('/awesome')
|
36
|
+
subject.request(:get, '/awesome')
|
37
|
+
expect(a_get('/awesome')).to have_been_made
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "initialization" do
|
42
|
+
it "can pass options to faraday" do
|
43
|
+
client = ZohoInvoice::Client.new(
|
44
|
+
default_credentials.merge({
|
45
|
+
:client_options => {
|
46
|
+
:url => 'http://something.com'
|
47
|
+
}
|
48
|
+
})
|
49
|
+
)
|
50
|
+
stub_request(:get, 'http://something.com/awesome').with(:query => default_credentials)
|
51
|
+
client.get('/awesome')
|
52
|
+
expect(a_request(:get, 'http://something.com/awesome').with(:query => default_credentials)).to have_been_made
|
53
|
+
end
|
54
|
+
|
55
|
+
it "will inherit config from defaults" do
|
56
|
+
client = ZohoInvoice::Client.new
|
57
|
+
expect(client.scope).to eq(ZohoInvoice::Defaults::SCOPE)
|
58
|
+
expect(client.client_options).to eq({ :url => ZohoInvoice::Defaults::URL })
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ZohoInvoice::Contact do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@client = ZohoInvoice::Client.new(default_credentials)
|
7
|
+
end
|
8
|
+
|
9
|
+
it ".create should raise an error" do
|
10
|
+
expect{ ZohoInvoice::Contact.create(@client) }.to raise_error(ZohoInvoice::ActionNotSupportedError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "#save should raise an error" do
|
14
|
+
contact = ZohoInvoice::Contact.new(@client)
|
15
|
+
expect{ contact.save }.to raise_error(ZohoInvoice::ActionNotSupportedError)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ZohoInvoice do
|
4
|
+
|
5
|
+
it "should be able to define global options on the module" do
|
6
|
+
ZohoInvoice.configure do |config|
|
7
|
+
config.authtoken = '11111'
|
8
|
+
config.scope = 'scope'
|
9
|
+
config.apikey = 'apikey'
|
10
|
+
config.client_options = { :url => 'http://example.com' }
|
11
|
+
end
|
12
|
+
expect(ZohoInvoice.authtoken).to eq('11111')
|
13
|
+
expect(ZohoInvoice.scope).to eq('scope')
|
14
|
+
expect(ZohoInvoice.apikey).to eq('apikey')
|
15
|
+
expect(ZohoInvoice.client_options).to eq({ :url => 'http://example.com' })
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be able to return its current options" do
|
19
|
+
ZohoInvoice.configure do |config|
|
20
|
+
config.authtoken = '22222'
|
21
|
+
end
|
22
|
+
expect(ZohoInvoice.config_hash[:authtoken]).to eq('22222')
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'zoho_invoice/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "zoho_invoice"
|
8
|
+
gem.version = ZohoInvoice::VERSION
|
9
|
+
gem.authors = ["Rimas Silkaitis"]
|
10
|
+
gem.email = ["neovintage@gmail.com"]
|
11
|
+
gem.summary = %q{Zoho Invoice API}
|
12
|
+
gem.description = %q{Ruby wrapper for the Zoho Invoice API. Documentation for the Zoho Invoice API can be found at http://zoho.com}
|
13
|
+
gem.homepage = "https://github.com/neovintage/zoho_invoice"
|
14
|
+
|
15
|
+
gem.required_ruby_version = ">= 1.9.3"
|
16
|
+
gem.required_rubygems_version = ">= 1.3.6"
|
17
|
+
|
18
|
+
gem.add_development_dependency 'bundler', '~> 1.0'
|
19
|
+
|
20
|
+
gem.add_runtime_dependency "faraday", ">= 0.8.0"
|
21
|
+
gem.add_runtime_dependency "faraday_middleware", ">= 0.8.7"
|
22
|
+
gem.add_runtime_dependency "nokogiri"
|
23
|
+
gem.add_runtime_dependency "multi_xml"
|
24
|
+
|
25
|
+
gem.files = `git ls-files`.split($/)
|
26
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
27
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
28
|
+
gem.require_paths = ["lib"]
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zoho_invoice
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rimas Silkaitis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: faraday
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.8.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.8.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: faraday_middleware
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.7
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.7
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: nokogiri
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: multi_xml
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Ruby wrapper for the Zoho Invoice API. Documentation for the Zoho Invoice
|
95
|
+
API can be found at http://zoho.com
|
96
|
+
email:
|
97
|
+
- neovintage@gmail.com
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- .travis.yml
|
104
|
+
- Gemfile
|
105
|
+
- LICENSE.txt
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- lib/zoho_invoice.rb
|
109
|
+
- lib/zoho_invoice/api/customers.rb
|
110
|
+
- lib/zoho_invoice/auth_token.rb
|
111
|
+
- lib/zoho_invoice/base.rb
|
112
|
+
- lib/zoho_invoice/client.rb
|
113
|
+
- lib/zoho_invoice/configurable.rb
|
114
|
+
- lib/zoho_invoice/contact.rb
|
115
|
+
- lib/zoho_invoice/customer.rb
|
116
|
+
- lib/zoho_invoice/defaults.rb
|
117
|
+
- lib/zoho_invoice/error.rb
|
118
|
+
- lib/zoho_invoice/invoice.rb
|
119
|
+
- lib/zoho_invoice/invoice_item.rb
|
120
|
+
- lib/zoho_invoice/item.rb
|
121
|
+
- lib/zoho_invoice/version.rb
|
122
|
+
- spec/fixtures/500_internal_server_error
|
123
|
+
- spec/fixtures/incorrect_verb_used
|
124
|
+
- spec/fixtures/invalid_customer_id
|
125
|
+
- spec/fixtures/invalid_password
|
126
|
+
- spec/fixtures/invalid_url_passed
|
127
|
+
- spec/fixtures/invalid_user
|
128
|
+
- spec/fixtures/please_select_an_item
|
129
|
+
- spec/fixtures/successful_authtoken
|
130
|
+
- spec/spec_helper.rb
|
131
|
+
- spec/zoho_invoice/auth_token_spec.rb
|
132
|
+
- spec/zoho_invoice/base_spec.rb
|
133
|
+
- spec/zoho_invoice/client_spec.rb
|
134
|
+
- spec/zoho_invoice/contact_spec.rb
|
135
|
+
- spec/zoho_invoice_spec.rb
|
136
|
+
- zoho_invoice.gemspec
|
137
|
+
homepage: https://github.com/neovintage/zoho_invoice
|
138
|
+
licenses: []
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
none: false
|
145
|
+
requirements:
|
146
|
+
- - ! '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: 1.9.3
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ! '>='
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: 1.3.6
|
155
|
+
requirements: []
|
156
|
+
rubyforge_project:
|
157
|
+
rubygems_version: 1.8.21
|
158
|
+
signing_key:
|
159
|
+
specification_version: 3
|
160
|
+
summary: Zoho Invoice API
|
161
|
+
test_files:
|
162
|
+
- spec/fixtures/500_internal_server_error
|
163
|
+
- spec/fixtures/incorrect_verb_used
|
164
|
+
- spec/fixtures/invalid_customer_id
|
165
|
+
- spec/fixtures/invalid_password
|
166
|
+
- spec/fixtures/invalid_url_passed
|
167
|
+
- spec/fixtures/invalid_user
|
168
|
+
- spec/fixtures/please_select_an_item
|
169
|
+
- spec/fixtures/successful_authtoken
|
170
|
+
- spec/spec_helper.rb
|
171
|
+
- spec/zoho_invoice/auth_token_spec.rb
|
172
|
+
- spec/zoho_invoice/base_spec.rb
|
173
|
+
- spec/zoho_invoice/client_spec.rb
|
174
|
+
- spec/zoho_invoice/contact_spec.rb
|
175
|
+
- spec/zoho_invoice_spec.rb
|