freshbooks.rb 3.0.18 → 3.0.25

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/History.txt +8 -0
  4. data/Manifest.txt +21 -1
  5. data/README.md +61 -0
  6. data/Rakefile +8 -13
  7. data/freshbooks.rb.gemspec +43 -0
  8. data/lib/freshbooks.rb +16 -2
  9. data/lib/freshbooks/address.rb +7 -0
  10. data/lib/freshbooks/api.rb +7 -0
  11. data/lib/freshbooks/autobill.rb +9 -0
  12. data/lib/freshbooks/base.rb +35 -9
  13. data/lib/freshbooks/budget.rb +7 -0
  14. data/lib/freshbooks/card.rb +9 -0
  15. data/lib/freshbooks/client.rb +3 -0
  16. data/lib/freshbooks/connection.rb +34 -25
  17. data/lib/freshbooks/contact.rb +9 -0
  18. data/lib/freshbooks/credits.rb +7 -0
  19. data/lib/freshbooks/estimate.rb +3 -3
  20. data/lib/freshbooks/expiration.rb +8 -0
  21. data/lib/freshbooks/gateway.rb +10 -0
  22. data/lib/freshbooks/gateway_transaction.rb +8 -0
  23. data/lib/freshbooks/invoice.rb +2 -2
  24. data/lib/freshbooks/language.rb +9 -0
  25. data/lib/freshbooks/line.rb +2 -0
  26. data/lib/freshbooks/links.rb +1 -1
  27. data/lib/freshbooks/payment.rb +2 -1
  28. data/lib/freshbooks/project.rb +4 -3
  29. data/lib/freshbooks/recurring.rb +5 -2
  30. data/lib/freshbooks/schema/definition.rb +2 -2
  31. data/lib/freshbooks/staff.rb +5 -0
  32. data/lib/freshbooks/system.rb +14 -0
  33. data/lib/freshbooks/tax.rb +12 -0
  34. data/lib/freshbooks/time_entry.rb +1 -0
  35. data/lib/freshbooks/xml_serializer.rb +5 -0
  36. data/lib/freshbooks/xml_serializer/serializers.rb +2 -2
  37. data/test/fixtures/freshbooks_credentials.yml +3 -0
  38. data/test/fixtures/recurring_create_response.xml +4 -0
  39. data/test/fixtures/recurring_get_response.xml +59 -0
  40. data/test/fixtures/recurring_list_response.xml +61 -0
  41. data/test/live_connection_test.rb +28 -0
  42. data/test/test_base.rb +59 -0
  43. data/test/test_connection.rb +39 -32
  44. data/test/test_helper.rb +20 -5
  45. data/test/test_invoice.rb +23 -37
  46. data/test/test_recurring.rb +98 -0
  47. metadata +67 -46
  48. data/README +0 -44
@@ -0,0 +1,9 @@
1
+ module FreshBooks
2
+ class Contact < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.string :email, :username, :first_name, :last_name, :phone1, :phone2
5
+ end
6
+
7
+ actions :list, :get, :create, :update, :delete
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module FreshBooks
2
+ class Credits < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.string :credit, :currency, :read_only => true
5
+ end
6
+ end
7
+ end
@@ -1,10 +1,10 @@
1
1
  module FreshBooks
2
2
  class Estimate < FreshBooks::Base
3
3
  define_schema do |s|
4
- s.string :estimate_id, :status, :date, :notes, :terms, :first_name
4
+ s.string :estimate_id, :status, :date, :notes, :terms, :first_name, :number
5
5
  s.string :last_name, :organization, :p_street1, :p_street2, :p_city
6
- s.string :p_state, :p_country, :p_code
7
- s.fixnum :client_id, :po_number
6
+ s.string :p_state, :p_country, :p_code, :currency_code, :language
7
+ s.fixnum :client_id, :po_number, :staff_id
8
8
  s.float :discount, :amount
9
9
  s.array :lines
10
10
  s.object :links, :read_only => true
@@ -0,0 +1,8 @@
1
+ module FreshBooks
2
+ class Expiration < FreshBooks::Base
3
+
4
+ define_schema do |s|
5
+ s.string :month, :year
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ module FreshBooks
2
+ class Gateway < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.string :name
5
+ s.boolean :autobill_capable
6
+ end
7
+
8
+ actions :list
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module FreshBooks
2
+ class GatewayTransaction < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.fixnum :reference_id
5
+ s.string :gateway_name
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  module FreshBooks
2
2
  class Invoice < FreshBooks::Base
3
3
  define_schema do |s|
4
- s.fixnum :invoice_id, :client_id, :po_number
4
+ s.fixnum :invoice_id, :client_id, :po_number, :staff_id
5
5
  s.fixnum :recurring_id, :read_only => true
6
6
  s.float :amount, :discount
7
7
  s.float :amount_outstanding, :paid, :read_only => true
@@ -9,7 +9,7 @@ module FreshBooks
9
9
  s.date_time :updated, :read_only => true
10
10
  s.array :lines
11
11
  s.object :links, :read_only => true
12
- s.string :number, :organization, :status, :notes, :terms, :first_name, :last_name
12
+ s.string :number, :organization, :status, :notes, :terms, :first_name, :last_name, :currency_code, :language
13
13
  s.string :p_street1, :p_street2, :p_city, :p_state, :p_country, :p_code
14
14
  s.string :return_uri
15
15
  end
@@ -0,0 +1,9 @@
1
+ module FreshBooks
2
+ class Language < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.string :code, :name
5
+ end
6
+
7
+ actions :list
8
+ end
9
+ end
@@ -1,7 +1,9 @@
1
1
  module FreshBooks
2
2
  class Line < FreshBooks::Base
3
+
3
4
  define_schema do |s|
4
5
  s.string :name, :description, :tax1_name, :tax2_name
6
+ s.string :type
5
7
  s.float :unit_cost, :tax1_percent, :tax2_percent
6
8
  s.float :amount, :read_only => true
7
9
  s.float :quantity
@@ -1,7 +1,7 @@
1
1
  module FreshBooks
2
2
  class Links < FreshBooks::Base
3
3
  define_schema do |s|
4
- s.string :client_view, :view, :edit, :read_only => true
4
+ s.string :client_view, :view, :edit, :statement, :read_only => true
5
5
  end
6
6
  end
7
7
  end
@@ -5,7 +5,8 @@ module FreshBooks
5
5
  s.float :amount
6
6
  s.date :date
7
7
  s.date_time :updated, :read_only => true
8
- s.string :type, :notes
8
+ s.string :type, :notes, :currency_code
9
+ s.object :gateway_transaction
9
10
  end
10
11
 
11
12
  actions :list, :get, :create, :update, :delete
@@ -3,10 +3,11 @@ module FreshBooks
3
3
  define_schema do |s|
4
4
  s.string :name, :bill_method, :description
5
5
  s.fixnum :project_id, :client_id
6
- s.float :rate
7
- s.array :tasks
6
+ s.float :rate, :hour_budget
7
+ s.array :tasks, :staff
8
+ s.object :budget
8
9
  end
9
10
 
10
11
  actions :list, :get, :create, :update, :delete
11
12
  end
12
- end
13
+ end
@@ -2,14 +2,17 @@ module FreshBooks
2
2
  class Recurring < FreshBooks::Base
3
3
  define_schema do |s|
4
4
  s.string :first_name, :last_name, :organization, :p_street1, :p_street2, :p_city
5
- s.string :p_state, :p_country, :p_code, :lines, :status, :notes, :terms, :frequency
5
+ s.string :p_state, :p_country, :p_code, :lines, :notes, :terms, :frequency
6
+ s.string :currency_code, :language
6
7
  s.date :date
7
8
  s.fixnum :recurring_id, :client_id, :po_number, :occurrences
8
9
  s.float :discount, :amount
9
10
  s.array :lines
10
11
  s.boolean :stopped, :send_email, :send_snail_mail
12
+ s.string :return_uri
13
+ s.object :autobill
11
14
  end
12
-
15
+
13
16
  actions :list, :get, :create, :update, :delete
14
17
  end
15
18
  end
@@ -4,7 +4,7 @@ module FreshBooks
4
4
  attr_reader :members
5
5
 
6
6
  def initialize
7
- @members = {}
7
+ @members = ActiveSupport::OrderedHash.new
8
8
  end
9
9
 
10
10
  def method_missing(method, *attributes)
@@ -17,4 +17,4 @@ module FreshBooks
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -9,5 +9,10 @@ module FreshBooks
9
9
  end
10
10
 
11
11
  actions :list, :get
12
+
13
+ def self.current
14
+ response = FreshBooks::Base.connection.call_api("#{api_class_name}.current")
15
+ response.success? ? self.new_from_xml(response.elements[1]) : nil
16
+ end
12
17
  end
13
18
  end
@@ -0,0 +1,14 @@
1
+ module FreshBooks
2
+ class System < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.string :company_name, :profession
5
+ s.object :address
6
+ s.object :api
7
+ end
8
+
9
+ def self.current
10
+ response = FreshBooks::Base.connection.call_api("#{api_class_name}.current")
11
+ response.success? ? self.new_from_xml(response.elements[1]) : nil
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module FreshBooks
2
+ class Tax < FreshBooks::Base
3
+ define_schema do |s|
4
+ s.fixnum :tax_id
5
+ s.float :rate
6
+ s.boolean :compound
7
+ s.string :name, :number
8
+ end
9
+
10
+ actions :list, :get, :create, :update, :delete
11
+ end
12
+ end
@@ -5,6 +5,7 @@ module FreshBooks
5
5
  s.float :hours
6
6
  s.date :date
7
7
  s.string :notes
8
+ s.boolean :billed
8
9
  end
9
10
 
10
11
  actions :list, :get, :create, :update, :delete
@@ -13,5 +13,10 @@ module FreshBooks
13
13
  def self.create_serializer(type)
14
14
  "FreshBooks::XmlSerializer::#{type.to_s.classify}Serializer".constantize
15
15
  end
16
+
17
+ def self.deprecated?(node)
18
+ !node.attribute('deprecated').nil?
19
+ end
20
+
16
21
  end
17
22
  end
@@ -86,8 +86,8 @@ module FreshBooks
86
86
 
87
87
  def self.to_value(xml_val)
88
88
  xml_val.elements.map { |elem|
89
- FreshBooks::const_get(elem.name.camelize)::new_from_xml(elem)
90
- }
89
+ FreshBooks::const_get(elem.name.camelize)::new_from_xml(elem) unless XmlSerializer.deprecated? elem
90
+ }.compact
91
91
  end
92
92
  end
93
93
 
@@ -0,0 +1,3 @@
1
+ fresh_books_test_account:
2
+ account_url: outright.freshbooks.com
3
+ api_key: 569916aa36f9f52a3a84424a8e55fc05
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <response status="ok">
3
+ <recurring_id>1</recurring_id>
4
+ </response>
@@ -0,0 +1,59 @@
1
+ <?xml version="1.0"?>
2
+ <response status="ok">
3
+ <recurring>
4
+ <recurring_id>1</recurring_id>
5
+
6
+ <frequency>m</frequency>
7
+ <occurrences>1</occurrences>
8
+ <stopped>0</stopped>
9
+
10
+ <client_id>1</client_id>
11
+ <amount>100.0</amount>
12
+ <date>2011-04-01</date>
13
+
14
+ <po_number>1</po_number>
15
+ <discount>1.0</discount>
16
+ <notes>notes1</notes>
17
+ <terms>terms1</terms>
18
+
19
+ <first_name>first_name1</first_name>
20
+ <last_name>last_name1</last_name>
21
+ <organization>organization1</organization>
22
+ <p_street1>p_street11</p_street1>
23
+ <p_street2>p_street21</p_street2>
24
+ <p_city>p_city1</p_city>
25
+ <p_state>p_state1</p_state>
26
+ <p_country>p_country1</p_country>
27
+ <p_code>p_code1</p_code>
28
+
29
+ <return_uri>return_uri1</return_uri>
30
+ <send_email>1</send_email>
31
+ <send_snail_mail>0</send_snail_mail>
32
+
33
+ <autobill>
34
+ <gateway_name>gateway1</gateway_name>
35
+ <card>
36
+ <number>1</number>
37
+ <name>name1</name>
38
+ <expiration>
39
+ <month>01</month>
40
+ <year>2001</year>
41
+ </expiration>
42
+ </card>
43
+ </autobill>
44
+
45
+ <lines>
46
+ <line>
47
+ <amount>1.0</amount>
48
+ <name>name1</name>
49
+ <description>description1</description>
50
+ <tax1_name>tax1_name1</tax1_name>
51
+ <tax2_name>tax2_name1</tax2_name>
52
+ <unit_cost>1.0</unit_cost>
53
+ <tax1_percent>1.0</tax1_percent>
54
+ <tax2_percent>1.0</tax2_percent>
55
+ <quantity>1</quantity>
56
+ </line>
57
+ </lines>
58
+ </recurring>
59
+ </response>
@@ -0,0 +1,61 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <response xmlns="http://www.freshbooks.com/api/" status="ok">
3
+ <recurrings page="1" per_page="1" pages="1" total="1">
4
+ <recurring>
5
+ <recurring_id>1</recurring_id>
6
+
7
+ <frequency>m</frequency>
8
+ <occurrences>1</occurrences>
9
+ <stopped>0</stopped>
10
+
11
+ <client_id>1</client_id>
12
+ <amount>100.0</amount>
13
+ <date>2011-04-01</date>
14
+
15
+ <po_number>1</po_number>
16
+ <discount>1.0</discount>
17
+ <notes>notes1</notes>
18
+ <terms>terms1</terms>
19
+
20
+ <first_name>first_name1</first_name>
21
+ <last_name>last_name1</last_name>
22
+ <organization>organization1</organization>
23
+ <p_street1>p_street11</p_street1>
24
+ <p_street2>p_street21</p_street2>
25
+ <p_city>p_city1</p_city>
26
+ <p_state>p_state1</p_state>
27
+ <p_country>p_country1</p_country>
28
+ <p_code>p_code1</p_code>
29
+
30
+ <return_uri>return_uri1</return_uri>
31
+ <send_email>1</send_email>
32
+ <send_snail_mail>0</send_snail_mail>
33
+
34
+ <autobill>
35
+ <gateway_name>gateway1</gateway_name>
36
+ <card>
37
+ <number>1</number>
38
+ <name>name1</name>
39
+ <expiration>
40
+ <month>01</month>
41
+ <year>2001</year>
42
+ </expiration>
43
+ </card>
44
+ </autobill>
45
+
46
+ <lines>
47
+ <line>
48
+ <amount>1.0</amount>
49
+ <name>name1</name>
50
+ <description>description1</description>
51
+ <tax1_name>tax1_name1</tax1_name>
52
+ <tax2_name>tax2_name1</tax2_name>
53
+ <unit_cost>1.0</unit_cost>
54
+ <tax1_percent>1.0</tax1_percent>
55
+ <tax2_percent>1.0</tax2_percent>
56
+ <quantity>1</quantity>
57
+ </line>
58
+ </lines>
59
+ </recurring>
60
+ </recurrings>
61
+ </response>
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ # this tests a live conection
4
+ class LiveConnectionTest < Test::Unit::TestCase
5
+ fixtures :freshbooks_credentials
6
+
7
+ def setup
8
+ fb_account_info = freshbooks_credentials(:fresh_books_test_account)
9
+ FreshBooks::Base.establish_connection(fb_account_info['account_url'], fb_account_info['api_key'])
10
+ end
11
+
12
+ # just go out there and get a live connection and see if it returns anything
13
+ def test_live_connection_with_start_session
14
+ FreshBooks::Base.connection.start_session do
15
+ clients = FreshBooks::Client.list("per_page" => 1)
16
+ FreshBooks::Invoice.list("per_page" => 100).collect do |invoice|
17
+ assert FreshBooks::Invoice.get(invoice.invoice_id)
18
+ end
19
+ end
20
+ end
21
+
22
+ def test_live_connection_without_start_session
23
+ clients = FreshBooks::Client.list("per_page" => 1)
24
+ FreshBooks::Invoice.list("per_page" => 100).collect do |invoice|
25
+ assert FreshBooks::Invoice.get(invoice.invoice_id)
26
+ end
27
+ end
28
+ end
@@ -66,6 +66,56 @@ class TestBase < Test::Unit::TestCase
66
66
  assert xml_out.include?("<my_lines><my_line><description>description</description></my_line></my_lines>")
67
67
  end
68
68
 
69
+ def test_create_objects_with_initializer_arguments
70
+ invoice_1 = FreshBooks::Invoice.new
71
+ invoice_1.client_id = 1
72
+ invoice_1.lines = [FreshBooks::Line.new, FreshBooks::Line.new]
73
+ invoice_1.lines[0].name = "Awesomeness"
74
+ invoice_1.lines[0].unit_cost = 9999
75
+ invoice_1.lines[0].quantity = 42
76
+ invoice_1.lines[1].name = "Ninja skills"
77
+ invoice_1.lines[1].unit_cost = 349
78
+ invoice_1.lines[1].quantity = 100
79
+
80
+ invoice_2 = FreshBooks::Invoice.new(
81
+ :client_id => 1,
82
+ :lines => [
83
+ FreshBooks::Line.new(
84
+ :name => "Awesomeness",
85
+ :unit_cost => 9999,
86
+ :quantity => 42
87
+ ),
88
+ FreshBooks::Line.new(
89
+ :name => "Ninja skills",
90
+ :unit_cost => 349,
91
+ :quantity => 100
92
+ )
93
+ ]
94
+ )
95
+
96
+ assert_equal invoice_1.to_xml, invoice_2.to_xml
97
+ end
98
+
99
+ def test_can_handle_all_zero_updated_at
100
+ xml = <<-END_XML
101
+ <my_client>
102
+ <client_id>3</client_id>
103
+ <first_name>Test</first_name>
104
+ <last_name>User</last_name>
105
+ <organization>User Testing</organization>
106
+ <updated>0000-00-00 00:00:00</updated>
107
+ </my_client>
108
+ END_XML
109
+ doc = REXML::Document.new(xml)
110
+
111
+ item = FreshBooks::MyClient.new_from_xml(doc.root)
112
+ assert_equal nil, item.updated
113
+ end
114
+
115
+ def test_actions
116
+ assert FreshBooks::MyItem.respond_to?(:get)
117
+ assert !Class.new.respond_to?(:get)
118
+ end
69
119
  end
70
120
 
71
121
  module FreshBooks
@@ -81,6 +131,15 @@ module FreshBooks
81
131
  s.object :my_address
82
132
  s.array :my_lines
83
133
  end
134
+ actions :get
135
+ end
136
+
137
+ class MyClient < FreshBooks::Base
138
+ define_schema do |s|
139
+ s.string :first_name, :last_name, :organization
140
+ s.fixnum :client_id
141
+ s.date_time :updated
142
+ end
84
143
  end
85
144
 
86
145
  class MyAddress < FreshBooks::Base