xeroizer 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.bundle/config +2 -2
- data/Gemfile +5 -0
- data/Rakefile +17 -1
- data/VERSION +1 -1
- data/lib/xeroizer.rb +5 -1
- data/lib/xeroizer/configuration.rb +19 -0
- data/lib/xeroizer/generic_application.rb +2 -1
- data/lib/xeroizer/logging.rb +8 -0
- data/lib/xeroizer/models/account.rb +2 -1
- data/lib/xeroizer/models/bank_account.rb +12 -0
- data/lib/xeroizer/models/bank_transaction.rb +74 -0
- data/lib/xeroizer/models/invoice.rb +17 -12
- data/lib/xeroizer/models/item.rb +3 -3
- data/lib/xeroizer/models/item_purchase_details.rb +19 -0
- data/lib/xeroizer/models/{item_purchase_sale_details.rb → item_sales_details.rb} +5 -3
- data/lib/xeroizer/models/line_amount_type.rb +11 -0
- data/lib/xeroizer/models/line_item.rb +2 -12
- data/lib/xeroizer/models/line_item_sum.rb +21 -0
- data/lib/xeroizer/models/payment.rb +2 -6
- data/lib/xeroizer/oauth.rb +1 -1
- data/lib/xeroizer/record/base.rb +21 -2
- data/lib/xeroizer/record/validation_helper.rb +14 -2
- data/lib/xeroizer/record/validators/block_validator.rb +22 -0
- data/lib/xeroizer/record/validators/validator.rb +14 -5
- data/lib/xeroizer/record/xml_helper.rb +24 -7
- data/test/acceptance/about_creating_bank_transactions_test.rb +162 -0
- data/test/acceptance/about_fetching_bank_transactions_test.rb +56 -0
- data/test/acceptance/acceptance_test.rb +53 -0
- data/test/acceptance/bank_transaction_reference_data.rb +31 -0
- data/test/test_helper.rb +11 -1
- data/test/unit/models/bank_transaction_model_parsing_test.rb +131 -0
- data/test/unit/models/bank_transaction_test.rb +47 -0
- data/test/unit/models/bank_transaction_validation_test.rb +87 -0
- data/test/unit/models/contact_test.rb +2 -2
- data/test/unit/models/credit_note_test.rb +2 -2
- data/test/unit/models/invoice_test.rb +43 -17
- data/test/unit/models/line_item_sum_test.rb +24 -0
- data/test/unit/models/line_item_test.rb +54 -0
- data/test/unit/oauth_config_test.rb +20 -0
- data/test/unit/oauth_test.rb +1 -1
- data/test/unit/private_application_test.rb +2 -2
- data/test/unit/record/base_model_test.rb +2 -2
- data/test/unit/record/base_test.rb +38 -1
- data/test/unit/record/block_validator_test.rb +125 -0
- data/test/unit/record/model_definition_test.rb +2 -2
- data/test/unit/record/parse_where_hash_test.rb +2 -2
- data/test/unit/record/record_association_test.rb +1 -1
- data/test/unit/record/validators_test.rb +51 -3
- data/test/unit/record_definition_test.rb +2 -2
- data/test/unit/report_definition_test.rb +2 -2
- data/test/unit/report_test.rb +1 -1
- data/xeroizer.gemspec +60 -6
- metadata +124 -66
- 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
|
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 =
|
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
|
-
|
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
|