xeroizer 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.bundle/config +2 -2
  2. data/Gemfile +5 -0
  3. data/Rakefile +17 -1
  4. data/VERSION +1 -1
  5. data/lib/xeroizer.rb +5 -1
  6. data/lib/xeroizer/configuration.rb +19 -0
  7. data/lib/xeroizer/generic_application.rb +2 -1
  8. data/lib/xeroizer/logging.rb +8 -0
  9. data/lib/xeroizer/models/account.rb +2 -1
  10. data/lib/xeroizer/models/bank_account.rb +12 -0
  11. data/lib/xeroizer/models/bank_transaction.rb +74 -0
  12. data/lib/xeroizer/models/invoice.rb +17 -12
  13. data/lib/xeroizer/models/item.rb +3 -3
  14. data/lib/xeroizer/models/item_purchase_details.rb +19 -0
  15. data/lib/xeroizer/models/{item_purchase_sale_details.rb → item_sales_details.rb} +5 -3
  16. data/lib/xeroizer/models/line_amount_type.rb +11 -0
  17. data/lib/xeroizer/models/line_item.rb +2 -12
  18. data/lib/xeroizer/models/line_item_sum.rb +21 -0
  19. data/lib/xeroizer/models/payment.rb +2 -6
  20. data/lib/xeroizer/oauth.rb +1 -1
  21. data/lib/xeroizer/record/base.rb +21 -2
  22. data/lib/xeroizer/record/validation_helper.rb +14 -2
  23. data/lib/xeroizer/record/validators/block_validator.rb +22 -0
  24. data/lib/xeroizer/record/validators/validator.rb +14 -5
  25. data/lib/xeroizer/record/xml_helper.rb +24 -7
  26. data/test/acceptance/about_creating_bank_transactions_test.rb +162 -0
  27. data/test/acceptance/about_fetching_bank_transactions_test.rb +56 -0
  28. data/test/acceptance/acceptance_test.rb +53 -0
  29. data/test/acceptance/bank_transaction_reference_data.rb +31 -0
  30. data/test/test_helper.rb +11 -1
  31. data/test/unit/models/bank_transaction_model_parsing_test.rb +131 -0
  32. data/test/unit/models/bank_transaction_test.rb +47 -0
  33. data/test/unit/models/bank_transaction_validation_test.rb +87 -0
  34. data/test/unit/models/contact_test.rb +2 -2
  35. data/test/unit/models/credit_note_test.rb +2 -2
  36. data/test/unit/models/invoice_test.rb +43 -17
  37. data/test/unit/models/line_item_sum_test.rb +24 -0
  38. data/test/unit/models/line_item_test.rb +54 -0
  39. data/test/unit/oauth_config_test.rb +20 -0
  40. data/test/unit/oauth_test.rb +1 -1
  41. data/test/unit/private_application_test.rb +2 -2
  42. data/test/unit/record/base_model_test.rb +2 -2
  43. data/test/unit/record/base_test.rb +38 -1
  44. data/test/unit/record/block_validator_test.rb +125 -0
  45. data/test/unit/record/model_definition_test.rb +2 -2
  46. data/test/unit/record/parse_where_hash_test.rb +2 -2
  47. data/test/unit/record/record_association_test.rb +1 -1
  48. data/test/unit/record/validators_test.rb +51 -3
  49. data/test/unit/record_definition_test.rb +2 -2
  50. data/test/unit/report_definition_test.rb +2 -2
  51. data/test/unit/report_test.rb +1 -1
  52. data/xeroizer.gemspec +60 -6
  53. metadata +124 -66
  54. data/lib/.DS_Store +0 -0
@@ -0,0 +1,131 @@
1
+ require "test_helper"
2
+
3
+ class BankTransactionModelParsingTest < Test::Unit::TestCase
4
+ def setup
5
+ # See lib/xeroizer/record/base_model.rb
6
+ @instance = Xeroizer::Record::BankTransactionModel.new(nil, "BankTransaction")
7
+ end
8
+
9
+ must "parse all the root elements except sub_total, total_tax and total" do
10
+ some_xml = "
11
+ <Response>
12
+ <BankTransactions>
13
+ <BankTransaction>
14
+ <Date>2010-07-30T00:00:00</Date>
15
+ <LineAmountTypes>Inclusive</LineAmountTypes>
16
+ <SubTotal>15.00</SubTotal>
17
+ <TotalTax>0.00</TotalTax>
18
+ <Total>15.00</Total>
19
+ <UpdatedDateUTC>2008-02-20T12:19:56.657</UpdatedDateUTC>
20
+ <FullyPaidOnDate>2010-07-30T00:00:00</FullyPaidOnDate>
21
+ <BankTransactionID>d20b6c54-7f5d-4ce6-ab83-55f609719126</BankTransactionID>
22
+ <Type>SPEND</Type>
23
+ <IsReconciled>true</IsReconciled>
24
+ </BankTransaction>
25
+ </BankTransactions>
26
+ </Response>"
27
+
28
+ result = @instance.parse_response(some_xml)
29
+
30
+ the_bank_transaction = result.response_items.first
31
+
32
+ assert_equal Date.parse("2010-07-30T00:00:00"), the_bank_transaction.date
33
+ assert_equal "Inclusive", the_bank_transaction.line_amount_types
34
+ assert_equal Date.parse("2008-02-20T12:19:56.657"), the_bank_transaction.updated_date_utc
35
+ assert_equal Date.parse("2010-07-30T00:00:00"), the_bank_transaction.fully_paid_on_date
36
+ assert_equal "d20b6c54-7f5d-4ce6-ab83-55f609719126", the_bank_transaction.bank_transaction_id
37
+ assert_equal "SPEND", the_bank_transaction.type
38
+ assert the_bank_transaction.reconciled?, "Expected reconciled to be true"
39
+ end
40
+
41
+ must "parse the contact" do
42
+ some_xml_with_a_contact = "
43
+ <Response>
44
+ <BankTransactions>
45
+ <BankTransaction>
46
+ <Contact>
47
+ <ContactID>c09661a2-a954-4e34-98df-f8b6d1dc9b19</ContactID>
48
+ <ContactStatus>ACTIVE</ContactStatus>
49
+ <Name>BNZ</Name>
50
+ <Addresses>
51
+ <Address>
52
+ <AddressType>POBOX</AddressType>
53
+ </Address>
54
+ <Address>
55
+ <AddressType>STREET</AddressType>
56
+ </Address>
57
+ </Addresses>
58
+ <Phones>
59
+ <Phone>
60
+ <PhoneType>MOBILE</PhoneType>
61
+ </Phone>
62
+ </Phones>
63
+ <UpdatedDateUTC>2010-09-17T19:26:39.157</UpdatedDateUTC>
64
+ </Contact>
65
+ </BankTransaction>
66
+ </BankTransactions>
67
+ </Response>"
68
+
69
+ result = @instance.parse_response(some_xml_with_a_contact)
70
+ the_bank_transaction = result.response_items.first
71
+ the_contact = the_bank_transaction.contact
72
+
73
+ assert_equal(
74
+ "c09661a2-a954-4e34-98df-f8b6d1dc9b19",
75
+ the_contact.contact_id,
76
+ "Mismatched contact id for contact: #{the_contact.inspect}"
77
+ )
78
+ end
79
+
80
+ must "parse the correct number of line items" do
81
+ some_xml_with_a_line_item = "
82
+ <Response>
83
+ <BankTransactions>
84
+ <BankTransaction>
85
+ <LineItems>
86
+ <LineItem>
87
+ <Description>Monthly account fee</Description>
88
+ <UnitAmount>15</UnitAmount>
89
+ <TaxType>NONE</TaxType>
90
+ <TaxAmount>0.00</TaxAmount>
91
+ <LineAmount>15.00</LineAmount>
92
+ <AccountCode>404</AccountCode>
93
+ <Quantity>1.0000</Quantity>
94
+ </LineItem>
95
+ </LineItems>
96
+ </BankTransaction>
97
+ </BankTransactions>
98
+ </Response>"
99
+
100
+ result = @instance.parse_response(some_xml_with_a_line_item)
101
+ the_bank_transaction = result.response_items.first
102
+
103
+ assert_equal(1, the_bank_transaction.line_items.size,
104
+ "Mismatched number of line items: #{the_bank_transaction.inspect}"
105
+ )
106
+ end
107
+
108
+ must "parse the bank account" do
109
+ some_xml_with_a_bank_account = "
110
+ <Response>
111
+ <BankTransactions>
112
+ <BankTransaction>
113
+ <BankAccount>
114
+ <AccountID>297c2dc5-cc47-4afd-8ec8-74990b8761e9</AccountID>
115
+ <Code>BANK</Code>
116
+ </BankAccount>
117
+ </BankTransaction>
118
+ </BankTransactions>
119
+ </Response>"
120
+
121
+ result = @instance.parse_response(some_xml_with_a_bank_account)
122
+ the_bank_transaction = result.response_items.first
123
+
124
+ assert_not_nil(the_bank_transaction.bank_account,
125
+ "Missing bank_account: #{the_bank_transaction.inspect}"
126
+ )
127
+
128
+ assert_equal "297c2dc5-cc47-4afd-8ec8-74990b8761e9", the_bank_transaction.bank_account.account_id,
129
+ "Unexpected bank account id: #{the_bank_transaction.inspect}"
130
+ end
131
+ end
@@ -0,0 +1,47 @@
1
+ require "test_helper"
2
+
3
+ class BankTransactionTest < Test::Unit::TestCase
4
+ include Xeroizer::Record
5
+
6
+ def setup
7
+ fake_parent = Class.new do
8
+ attr_accessor :application
9
+ end.new
10
+
11
+ the_line_items = [
12
+ LineItem.build({:quantity => 1, :tax_amount => 0.15, :unit_amount => 1.00, :tax_amount => 0.50}, nil),
13
+ LineItem.build({:quantity => 1, :tax_amount => 0.15, :unit_amount => 1.00, :tax_amount => 0.50}, nil)
14
+ ]
15
+
16
+ @the_bank_transaction = BankTransaction.new fake_parent
17
+ @the_bank_transaction.line_items = the_line_items
18
+ end
19
+
20
+ context "given a bank_transaction with line_amount_types set to \"Exclusive\"" do
21
+ setup do
22
+ @the_bank_transaction.line_amount_types = "Exclusive"
23
+ end
24
+
25
+ must "calculate the total as the sum of its line item line_amount and tax_amount" do
26
+ assert_equal "3.0", @the_bank_transaction.total.to_s
27
+ end
28
+
29
+ must "calculate the sub_total as the sum of the line_amounts" do
30
+ assert_equal "2.0", @the_bank_transaction.sub_total.to_s
31
+ end
32
+ end
33
+
34
+ context "given a bank_transaction with line_amount_types set to \"Inclusive\"" do
35
+ setup do
36
+ @the_bank_transaction.line_amount_types = "Inclusive"
37
+ end
38
+
39
+ must "calculate the total as the sum of its line item line_amount and tax_amount" do
40
+ assert_equal "2.0", @the_bank_transaction.total.to_s
41
+ end
42
+
43
+ must "calculate the sub_total as the sum of the line_amounts minus the total tax" do
44
+ assert_equal "1.0", @the_bank_transaction.sub_total.to_s
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,87 @@
1
+ require "test_helper"
2
+
3
+ class BankTransactionValidationTest < Test::Unit::TestCase
4
+ include Xeroizer::Record
5
+
6
+ must "supply either SPEND or RECEIVE as the type" do
7
+ instance = BankTransaction.build({:type => "xxx"}, nil)
8
+
9
+ assert false == instance.valid?, "Expected invalid because of invalid type"
10
+
11
+ expected_error = "Invalid type. Expected either SPEND or RECEIVE."
12
+
13
+ assert_equal expected_error, instance.errors_for(:type).first, "Expected an error about type"
14
+
15
+ instance = BankTransaction.build({:type => "SPEND"}, nil)
16
+
17
+ instance.valid?
18
+
19
+ assert_empty instance.errors_for(:type), "Expected no error about type"
20
+
21
+ instance = BankTransaction.build({:type => "RECEIVE"}, nil)
22
+
23
+ instance.valid?
24
+
25
+ assert_empty instance.errors_for(:type), "Expected no error about type"
26
+ end
27
+
28
+ must "supply a non-blank contact" do
29
+ instance = BankTransaction.build({}, nil)
30
+
31
+ assert false == instance.valid?, "Expected invalid because of missing contact"
32
+
33
+ assert_equal "can't be blank", instance.errors_for(:contact).first,
34
+ "Expected an error about blank contact"
35
+ end
36
+
37
+ must "supply at least one line item" do
38
+ zero_line_items = []
39
+
40
+ instance = BankTransaction.build({:line_items => zero_line_items}, nil)
41
+
42
+ assert false == instance.valid?, "Expected invalid because of empty line items"
43
+
44
+ assert_equal "Invalid line items. Must supply at least one.", instance.errors_for(:line_items).first,
45
+ "Expected an error about blank line items"
46
+
47
+ one_line_item = [LineItem.build({}, nil)]
48
+
49
+ instance.errors.clear
50
+ instance.line_items = one_line_item
51
+
52
+ assert_empty instance.errors_for(:line_items), "expected no errors for one line item, #{instance.errors_for(:line_items)}"
53
+
54
+ more_than_one_line_item = [LineItem.build({}, nil), LineItem.build({}, nil)]
55
+
56
+ instance.errors.clear
57
+ instance.line_items = more_than_one_line_item
58
+
59
+ assert_empty instance.errors_for(:line_items), "expected no errors for more than one line item, #{instance.errors_for(:line_items)}"
60
+ end
61
+
62
+ must "supply a non-blank bank account" do
63
+ instance = BankTransaction.build({}, nil)
64
+
65
+ assert false == instance.valid?, "Expected invalid because of missing bank account"
66
+
67
+ assert_equal "can't be blank", instance.errors_for(:bank_account).first,
68
+ "Expected an error about blank contact"
69
+ end
70
+
71
+ must "supply valid line_amount_types value" do
72
+ instance = BankTransaction.build({
73
+ :line_amount_types => "XXX_ANYTHING_INVALID_XXX"
74
+ }, nil)
75
+
76
+ assert false == instance.valid?, "Expected invalid because of missing bank account"
77
+
78
+ assert_equal "not one of Exclusive, Inclusive, NoTax", instance.errors_for(:line_amount_types).first,
79
+ "Expected an error about blank contact"
80
+ end
81
+
82
+ must "line_amount_type defaults to \"Exclusive\"" do
83
+ instance = BankTransaction.build({}, nil)
84
+
85
+ assert_equal "Exclusive", instance.line_amount_types
86
+ end
87
+ end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '../../test_helper.rb')
1
+ require 'test_helper'
2
2
 
3
3
  class ContactTest < Test::Unit::TestCase
4
4
  include TestHelper
@@ -23,4 +23,4 @@ class ContactTest < Test::Unit::TestCase
23
23
 
24
24
  end
25
25
 
26
- end
26
+ end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '../../test_helper.rb')
1
+ require 'test_helper'
2
2
 
3
3
  class CreditNoteTest < Test::Unit::TestCase
4
4
  include TestHelper
@@ -34,4 +34,4 @@ class CreditNoteTest < Test::Unit::TestCase
34
34
 
35
35
  end
36
36
 
37
- end
37
+ end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '../../test_helper.rb')
1
+ require 'test_helper'
2
2
 
3
3
  class InvoiceTest < Test::Unit::TestCase
4
4
  include TestHelper
@@ -8,7 +8,23 @@ class InvoiceTest < Test::Unit::TestCase
8
8
  mock_api('Invoices')
9
9
  @invoice = @client.Invoice.first
10
10
  end
11
-
11
+
12
+ def build_valid_authorised_invoice
13
+ @client.Invoice.build({
14
+ :type => "ACCREC",
15
+ :contact => { :name => "ABC Limited" },
16
+ :status => "AUTHORISED",
17
+ :date => Date.today,
18
+ :due_date => Date.today,
19
+ :line_items => [{
20
+ :description => "Consulting services as agreed",
21
+ :quantity => 0.005,
22
+ :unit_amount => 1,
23
+ :account_code => 200
24
+ }]
25
+ })
26
+ end
27
+
12
28
  context "invoice types" do
13
29
 
14
30
  should "have helpers to determine invoice type" do
@@ -45,7 +61,7 @@ class InvoiceTest < Test::Unit::TestCase
45
61
  assert_equal(invoice.attributes[:total], invoice.total)
46
62
  end
47
63
  end
48
-
64
+
49
65
  end
50
66
 
51
67
  context "invoice validations" do
@@ -65,22 +81,32 @@ class InvoiceTest < Test::Unit::TestCase
65
81
  end
66
82
 
67
83
  should "build a valid AUTHORISED invoice with complete attributes" do
68
- invoice = @client.Invoice.build({
69
- :type => "ACCREC",
70
- :contact => { :name => "ABC Limited" },
71
- :status => "AUTHORISED",
72
- :date => Date.today,
73
- :due_date => Date.today,
74
- :line_items => [{
75
- :description => "Consulting services as agreed",
76
- :quantity => 5,
77
- :unit_amount => 120,
78
- :account_code => 200
79
- }]
80
- })
84
+ invoice = build_valid_authorised_invoice
81
85
  assert_equal(true, invoice.valid?)
82
86
  end
83
87
 
84
88
  end
85
89
 
86
- end
90
+ context "line items" do
91
+
92
+ should "round line item amounts to two decimal places" do
93
+ invoice = build_valid_authorised_invoice
94
+ assert_equal(0.01, invoice.line_items.first.line_amount)
95
+ end
96
+
97
+ end
98
+
99
+ context "contact shortcuts" do
100
+
101
+ should "have valid #contact_name and #contact_id without downloading full invoice" do
102
+ invoices = @client.Invoice.all
103
+ invoices.each do |invoice|
104
+ assert_not_equal("", invoice.contact_name)
105
+ assert_not_equal("", invoice.contact_id)
106
+ assert_equal(false, invoice.complete_record_downloaded?)
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,24 @@
1
+ require "test_helper"
2
+
3
+ class LineItemSumTest < Test::Unit::TestCase
4
+ include Xeroizer::Record
5
+
6
+ def setup
7
+ @the_line_items = [
8
+ LineItem.build({:quantity => 1, :unit_amount => 1.00, :tax_amount => 0.15}, nil),
9
+ LineItem.build({:quantity => 1, :unit_amount => 1.00, :tax_amount => 0.30}, nil)
10
+ ]
11
+ end
12
+
13
+ it "sub_total is the sum of the line_amounts" do
14
+ assert_equal BigDecimal("2.00"), LineItemSum.sub_total(@the_line_items)
15
+ end
16
+
17
+ it "total_tax is the sum of the tax_amounts" do
18
+ assert_equal BigDecimal("0.45"), LineItemSum.total_tax(@the_line_items)
19
+ end
20
+
21
+ it "total is the sum of sub_total and total_tax" do
22
+ assert_equal BigDecimal("2.45"), LineItemSum.total(@the_line_items)
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ require "test_helper"
2
+
3
+ class LineItemTest < Test::Unit::TestCase
4
+ include Xeroizer::Record
5
+
6
+ it "line_amount equals unit_price times quantity" do
7
+ line_item = LineItem.new(nil)
8
+
9
+ line_item.quantity = 1
10
+ line_item.unit_amount = BigDecimal("1337.00")
11
+ line_item.tax_amount = BigDecimal("0.15")
12
+
13
+ expected = BigDecimal((line_item.quantity * (line_item.unit_amount)).to_s).round(2)
14
+
15
+ assert_equal expected.to_s, line_item.line_amount.to_s
16
+ end
17
+
18
+ it "line_amount is zero when quantity is nil or zero" do
19
+ line_item = LineItem.new(nil)
20
+
21
+ line_item.quantity = nil
22
+ line_item.unit_amount = BigDecimal("1.00")
23
+ line_item.tax_amount = BigDecimal("0.15")
24
+
25
+ assert_equal "0.0", line_item.line_amount.to_s, "expected line amount zero when quantity is nil"
26
+
27
+ line_item.quantity = 0
28
+ assert_equal "0.0", line_item.line_amount.to_s, "expected line amount zero when quantity is zero"
29
+ end
30
+
31
+ it "is not possible to set unit_amount to zero" do
32
+ line_item = LineItem.new(nil)
33
+
34
+ line_item.quantity = 1
35
+ line_item.unit_amount = nil
36
+ line_item.tax_amount = BigDecimal("0.15")
37
+
38
+ assert_equal 0.0, line_item.unit_amount,
39
+ "Expected setting unit_amount to nil to be ignored, i.e., it should remain zero"
40
+ end
41
+
42
+ it "line_amount is zero when unit_amount is nil or zero" do
43
+ line_item = LineItem.new(nil)
44
+
45
+ line_item.quantity = 1
46
+ line_item.unit_amount = nil
47
+ line_item.tax_amount = BigDecimal("0.15")
48
+
49
+ assert_equal "0.0", line_item.line_amount.to_s, "expected line amount zero when unit_amount is nil"
50
+
51
+ line_item.unit_amount = BigDecimal("0.00")
52
+ assert_equal "0.0", line_item.line_amount.to_s, "expected line amount zero when unit_amount is zero"
53
+ end
54
+ end