xero_gateway 2.0.14 → 2.0.15

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
- require 'rake/rdoctask'
3
+ require 'rdoc/task'
4
4
 
5
5
  desc 'Default: run unit tests.'
6
6
  task :default => :test
@@ -1,10 +1,6 @@
1
1
  module XeroGateway
2
2
  class AccountsList
3
3
 
4
- class Error < RuntimeError; end
5
- class NoGatewayError < Error; end
6
- class AccountsListNotLoadedError < Error; end
7
-
8
4
  # Xero::Gateway associated with this invoice.
9
5
  attr_accessor :gateway
10
6
 
@@ -3,8 +3,6 @@ module XeroGateway
3
3
  include Dates
4
4
  include LineItemCalculations
5
5
 
6
- class NoGatewayError < Error; end
7
-
8
6
  GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ unless defined?(GUID_REGEX)
9
7
 
10
8
  TYPES = {
@@ -27,7 +25,7 @@ module XeroGateway
27
25
  attr_accessor :line_items_downloaded
28
26
 
29
27
  # accessible fields
30
- attr_accessor :bank_transaction_id, :type, :date, :reference, :status, :contact, :line_items, :bank_account, :url
28
+ attr_accessor :bank_transaction_id, :type, :date, :reference, :status, :contact, :line_items, :bank_account, :url, :is_reconciled
31
29
 
32
30
  def initialize(params = {})
33
31
  @errors ||= []
@@ -128,11 +126,12 @@ module XeroGateway
128
126
  b.BankTransactionID bank_transaction_id if bank_transaction_id
129
127
  b.Type type
130
128
  # b.CurrencyCode self.currency_code if self.currency_code
131
- contact.to_xml(b)
132
- bank_account.to_xml(b, :name => 'BankAccount')
129
+ contact.to_xml(b) if contact
130
+ bank_account.to_xml(b, :name => 'BankAccount') if bank_account
133
131
  b.Date BankTransaction.format_date(date || Date.today)
134
132
  b.Status status if status
135
133
  b.Reference reference if reference
134
+ b.IsReconciled true if self.is_reconciled
136
135
  b.LineItems {
137
136
  self.line_items.each do |line_item|
138
137
  line_item.to_xml(b)
@@ -165,6 +164,7 @@ module XeroGateway
165
164
  # when "AmountPaid" then invoice.amount_paid = BigDecimal.new(element.text)
166
165
  # when "AmountCredited" then invoice.amount_credited = BigDecimal.new(element.text)
167
166
  # when "SentToContact" then invoice.sent_to_contact = (element.text.strip.downcase == "true")
167
+ when "IsReconciled" then bank_transaction.is_reconciled = (element.text.strip.downcase == "true")
168
168
  when "Url" then bank_transaction.url = element.text
169
169
  end
170
170
  end
@@ -1,10 +1,7 @@
1
1
  module XeroGateway
2
2
  class Contact
3
3
  include Dates
4
-
5
- class Error < RuntimeError; end
6
- class NoGatewayError < Error; end
7
-
4
+
8
5
  GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ unless defined?(GUID_REGEX)
9
6
 
10
7
  CONTACT_STATUS = {
@@ -126,14 +123,14 @@ module XeroGateway
126
123
  end
127
124
 
128
125
  # Creates this contact record (using gateway.create_contact) with the associated gateway.
129
- # If no gateway set, raise a Xero::Contact::NoGatewayError exception.
126
+ # If no gateway set, raise a NoGatewayError exception.
130
127
  def create
131
128
  raise NoGatewayError unless gateway
132
129
  gateway.create_contact(self)
133
130
  end
134
131
 
135
132
  # Creates this contact record (using gateway.update_contact) with the associated gateway.
136
- # If no gateway set, raise a Xero::Contact::NoGatewayError exception.
133
+ # If no gateway set, raise a NoGatewayError exception.
137
134
  def update
138
135
  raise NoGatewayError unless gateway
139
136
  gateway.update_contact(self)
@@ -4,8 +4,6 @@ module XeroGateway
4
4
  include Money
5
5
  include LineItemCalculations
6
6
 
7
- class NoGatewayError < Error; end
8
-
9
7
  CREDIT_NOTE_TYPE = {
10
8
  'ACCRECCREDIT' => 'Accounts Receivable',
11
9
  'ACCPAYCREDIT' => 'Accounts Payable'
@@ -163,7 +161,7 @@ module XeroGateway
163
161
  end
164
162
 
165
163
  # Creates this credit_note record (using gateway.create_credit_note) with the associated gateway.
166
- # If no gateway set, raise a Xero::CreditNote::NoGatewayError exception.
164
+ # If no gateway set, raise a NoGatewayError exception.
167
165
  def create
168
166
  raise NoGatewayError unless gateway
169
167
  gateway.create_credit_note(self)
@@ -1,4 +1,8 @@
1
1
  module XeroGateway
2
+ class NoGatewayError < StandardError; end
3
+ class AccountsListNotLoadedError < StandardError; end
4
+ class InvalidLineItemError < StandardError; end
5
+
2
6
  class ApiException < StandardError
3
7
 
4
8
  def initialize(type, message, request_xml, response_xml)
@@ -43,4 +47,5 @@ module XeroGateway
43
47
  class InvoiceNotFoundError < StandardError; end
44
48
  class BankTransactionNotFoundError < StandardError; end
45
49
  class CreditNoteNotFoundError < StandardError; end
50
+ class ManualJournalNotFoundError < StandardError; end
46
51
  end
@@ -418,6 +418,56 @@ module XeroGateway
418
418
  parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/BankTransaction'})
419
419
  end
420
420
 
421
+ # Creates a manual journal in Xero based on a manual journal object.
422
+ #
423
+ # Manual journal and line item totals are calculated automatically.
424
+ #
425
+ # Usage : # TODO
426
+
427
+ def create_manual_journal(manual_journal)
428
+ save_manual_journal(manual_journal)
429
+ end
430
+
431
+ #
432
+ # Updates an existing Xero manual journal
433
+ #
434
+ # Usage :
435
+ #
436
+ # manual_journal = xero_gateway.get_manual_journal(some_manual_journal_id)
437
+ #
438
+ # xero_gateway.update_manual_journal(manual_journal)
439
+ def update_manual_journal(manual_journal)
440
+ raise "manual_journal_id is required for updating manual journals" if manual_journal.manual_journal_id.nil?
441
+ save_manual_journal(manual_journal)
442
+ end
443
+
444
+ # Retrieves all manual journals from Xero
445
+ #
446
+ # Usage : get_manual_journal
447
+ # getmanual_journal(:manual_journal_id => " 297c2dc5-cc47-4afd-8ec8-74990b8761e9")
448
+ #
449
+ # Note : modified_since is in UTC format (i.e. Brisbane is UTC+10)
450
+ def get_manual_journals(options = {})
451
+ request_params = {}
452
+ request_params[:ManualJournalID] = options[:manual_journal_id] if options[:manual_journal_id]
453
+ request_params[:ModifiedAfter] = options[:modified_since] if options[:modified_since]
454
+
455
+ response_xml = http_get(@client, "#{@xero_url}/ManualJournals", request_params)
456
+
457
+ parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/ManualJournals'})
458
+ end
459
+
460
+ # Retrieves a single manual journal
461
+ #
462
+ # Usage : get_manual_journal("297c2dc5-cc47-4afd-8ec8-74990b8761e9") # By ID
463
+ # get_manual_journal("OIT-12345") # By number
464
+ def get_manual_journal(manual_journal_id)
465
+ request_params = {}
466
+ url = "#{@xero_url}/ManualJournals/#{URI.escape(manual_journal_id)}"
467
+ response_xml = http_get(@client, url, request_params)
468
+ parse_response(response_xml, {:request_params => request_params}, {:request_signature => 'GET/ManualJournal'})
469
+ end
470
+
421
471
  #
422
472
  # Gets all accounts for a specific organization in Xero.
423
473
  #
@@ -555,6 +605,33 @@ module XeroGateway
555
605
  response
556
606
  end
557
607
 
608
+ # Create or update a manual journal record based on if it has an manual_journal_id.
609
+ def save_manual_journal(manual_journal)
610
+ request_xml = manual_journal.to_xml
611
+ response_xml = nil
612
+ create_or_save = nil
613
+
614
+ if manual_journal.manual_journal_id.nil?
615
+ # Create new manual journal record.
616
+ response_xml = http_put(@client, "#{@xero_url}/ManualJournals", request_xml, {})
617
+ create_or_save = :create
618
+ else
619
+ # Update existing manual journal record.
620
+ response_xml = http_post(@client, "#{@xero_url}/ManualJournals", request_xml, {})
621
+ create_or_save = :save
622
+ end
623
+
624
+ response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => "#{create_or_save == :create ? 'PUT' : 'POST'}/ManualJournals"})
625
+
626
+ # Xero returns manual journals inside an <ManualJournals> tag, even though there's only ever
627
+ # one for this request
628
+ response.response_item = response.manual_journals.first
629
+
630
+ manual_journal.manual_journal_id = response.manual_journal.manual_journal_id if response.success? && response.manual_journal && response.manual_journal.manual_journal_id
631
+
632
+ response
633
+ end
634
+
558
635
  def parse_response(raw_response, request = {}, options = {})
559
636
 
560
637
  response = XeroGateway::Response.new
@@ -576,12 +653,18 @@ module XeroGateway
576
653
  when "Invoice" then response.response_item = Invoice.from_xml(element, self, {:line_items_downloaded => options[:request_signature] != "GET/Invoices"})
577
654
  when "BankTransaction"
578
655
  response.response_item = BankTransaction.from_xml(element, self, {:line_items_downloaded => options[:request_signature] != "GET/BankTransactions"})
656
+ when "ManualJournal"
657
+ response.response_item = ManualJournal.from_xml(element, self, {:journal_lines_downloaded => options[:request_signature] != "GET/ManualJournals"})
579
658
  when "Contacts" then element.children.each {|child| response.response_item << Contact.from_xml(child, self) }
580
659
  when "Invoices" then element.children.each {|child| response.response_item << Invoice.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/Invoices"}) }
581
660
  when "BankTransactions"
582
661
  element.children.each do |child|
583
662
  response.response_item << BankTransaction.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/BankTransactions"})
584
663
  end
664
+ when "ManualJournals"
665
+ element.children.each do |child|
666
+ response.response_item << ManualJournal.from_xml(child, self, {:journal_lines_downloaded => options[:request_signature] != "GET/ManualJournals"})
667
+ end
585
668
  when "CreditNotes" then element.children.each {|child| response.response_item << CreditNote.from_xml(child, self, {:line_items_downloaded => options[:request_signature] != "GET/CreditNotes"}) }
586
669
  when "Accounts" then element.children.each {|child| response.response_item << Account.from_xml(child) }
587
670
  when "TaxRates" then element.children.each {|child| response.response_item << TaxRate.from_xml(child) }
@@ -125,6 +125,7 @@ module XeroGateway
125
125
  def handle_object_not_found!(response, request_url)
126
126
  case(request_url)
127
127
  when /Invoices/ then raise InvoiceNotFoundError.new("Invoice not found in Xero.")
128
+ when /BankTransactions/ then raise BankTransactionNotFoundError.new("Bank Transaction not found in Xero.")
128
129
  when /CreditNotes/ then raise CreditNoteNotFoundError.new("Credit Note not found in Xero.")
129
130
  else raise ObjectNotFound.new(request_url)
130
131
  end
@@ -4,8 +4,6 @@ module XeroGateway
4
4
  include Money
5
5
  include LineItemCalculations
6
6
 
7
- class NoGatewayError < Error; end
8
-
9
7
  INVOICE_TYPE = {
10
8
  'ACCREC' => 'Accounts Receivable',
11
9
  'ACCPAY' => 'Accounts Payable'
@@ -165,14 +163,14 @@ module XeroGateway
165
163
  end
166
164
 
167
165
  # Creates this invoice record (using gateway.create_invoice) with the associated gateway.
168
- # If no gateway set, raise a Xero::Invoice::NoGatewayError exception.
166
+ # If no gateway set, raise a NoGatewayError exception.
169
167
  def create
170
168
  raise NoGatewayError unless gateway
171
169
  gateway.create_invoice(self)
172
170
  end
173
171
 
174
172
  # Updates this invoice record (using gateway.update_invoice) with the associated gateway.
175
- # If no gateway set, raise a Xero::Invoice::NoGatewayError exception.
173
+ # If no gateway set, raise a NoGatewayError exception.
176
174
  def update
177
175
  raise NoGatewayError unless gateway
178
176
  gateway.update_invoice(self)
@@ -0,0 +1,102 @@
1
+ require File.join(File.dirname(__FILE__), 'account')
2
+
3
+ module XeroGateway
4
+ class JournalLine
5
+ include Money
6
+
7
+ TAX_TYPE = Account::TAX_TYPE unless defined?(TAX_TYPE)
8
+
9
+ # Any errors that occurred when the #valid? method called.
10
+ attr_reader :errors
11
+
12
+ # All accessible fields
13
+ attr_accessor :journal_line_id, :line_amount, :account_code, :description, :tax_type, :tracking
14
+
15
+ def initialize(params = {})
16
+ @errors ||= []
17
+ @tracking ||= []
18
+
19
+ params.each do |k,v|
20
+ self.send("#{k}=", v)
21
+ end
22
+ end
23
+
24
+ # Validate the JournalLineItem record according to what will be valid by the gateway.
25
+ #
26
+ # Usage:
27
+ # journal_line_item.valid? # Returns true/false
28
+ #
29
+ # Additionally sets journal_line_item.errors array to an array of field/error.
30
+ def valid?
31
+ @errors = []
32
+
33
+ if !journal_line_id.nil? && journal_line_id !~ GUID_REGEX
34
+ @errors << ['journal_line_id', 'must be blank or a valid Xero GUID']
35
+ end
36
+
37
+ unless line_amount
38
+ @errors << ['line_amount', "can't be blank"]
39
+ end
40
+
41
+ unless account_code
42
+ @errors << ['account_code', "can't be blank"]
43
+ end
44
+
45
+ @errors.size == 0
46
+ end
47
+
48
+ def has_tracking?
49
+ return false if tracking.nil?
50
+
51
+ if tracking.is_a?(Array)
52
+ return tracking.any?
53
+ else
54
+ return tracking.is_a?(TrackingCategory)
55
+ end
56
+ end
57
+
58
+ def to_xml(b = Builder::XmlMarkup.new)
59
+ b.JournalLine {
60
+ b.LineAmount line_amount # mandatory
61
+ b.AccountCode account_code # mandatory
62
+ b.Description description if description # optional
63
+ b.TaxType tax_type if tax_type # optional
64
+ if has_tracking?
65
+ b.Tracking { # optional
66
+ # Due to strange retardness in the Xero API, the XML structure for a tracking category within
67
+ # an invoice is different to a standalone tracking category.
68
+ # This means rather than going category.to_xml we need to call the special category.to_xml_for_invoice_messages
69
+ (tracking.is_a?(TrackingCategory) ? [tracking] : tracking).each do |category|
70
+ category.to_xml_for_invoice_messages(b)
71
+ end
72
+ }
73
+ end
74
+ }
75
+ end
76
+
77
+ def self.from_xml(journal_line_element)
78
+ journal_line = JournalLine.new
79
+ journal_line_element.children.each do |element|
80
+ case(element.name)
81
+ when "LineAmount" then journal_line.line_amount = BigDecimal.new(element.text)
82
+ when "AccountCode" then journal_line.account_code = element.text
83
+ when "JournalLineID" then journal_line.journal_line_id = element.text
84
+ when "Description" then journal_line.description = element.text
85
+ when "TaxType" then journal_line.tax_type = element.text
86
+ when "Tracking" then
87
+ element.children.each do | tracking_element |
88
+ journal_line.tracking << TrackingCategory.from_xml(tracking_element)
89
+ end
90
+ end
91
+ end
92
+ journal_line
93
+ end
94
+
95
+ def ==(other)
96
+ [:description, :line_amount, :account_code, :tax_type].each do |field|
97
+ return false if send(field) != other.send(field)
98
+ end
99
+ return true
100
+ end
101
+ end
102
+ end
@@ -1,9 +1,5 @@
1
1
  module XeroGateway
2
2
  module LineItemCalculations
3
-
4
- class Error < RuntimeError; end
5
- class InvalidLineItemError < Error; end
6
-
7
3
  def add_line_item(params = {})
8
4
  line_item = nil
9
5
  case params
@@ -0,0 +1,163 @@
1
+ module XeroGateway
2
+ class ManualJournal
3
+ include Dates
4
+
5
+ GUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ unless defined?(GUID_REGEX)
6
+
7
+ STATUSES = {
8
+ 'DRAFT' => 'Draft Manual Journal',
9
+ 'POSTED' => 'Posted Manual Journal',
10
+ 'DELETED' => 'Deleted Draft Manual Journal',
11
+ 'VOIDED' => 'Voided Posted Manual Journal'
12
+ } unless defined?(STATUSES)
13
+
14
+ # Xero::Gateway associated with this invoice.
15
+ attr_accessor :gateway
16
+
17
+ # Any errors that occurred when the #valid? method called.
18
+ attr_reader :errors
19
+
20
+ # Represents whether the journal lines have been downloaded when getting from GET /API.XRO/2.0/ManualJournals
21
+ attr_accessor :journal_lines_downloaded
22
+
23
+ # accessible fields
24
+ attr_accessor :manual_journal_id, :narration, :date, :status, :journal_lines, :url, :show_on_cash_basis_reports
25
+
26
+ def initialize(params = {})
27
+ @errors ||= []
28
+ @payments ||= []
29
+
30
+ # Check if the line items have been downloaded.
31
+ @journal_lines_downloaded = (params.delete(:journal_lines_downloaded) == true)
32
+
33
+ params.each do |k,v|
34
+ self.send("#{k}=", v)
35
+ end
36
+
37
+ @journal_lines ||= []
38
+ end
39
+
40
+ def ==(other)
41
+ ['narration', 'status', 'journal_lines', 'show_on_cash_basis_reports'].each do |field|
42
+ return false if send(field) != other.send(field)
43
+ end
44
+
45
+ ["date"].each do |field|
46
+ return false if send(field).to_s != other.send(field).to_s
47
+ end
48
+ return true
49
+ end
50
+
51
+ # Validate the ManualJournal record according to what will be valid by the gateway.
52
+ #
53
+ # Usage:
54
+ # manual_journal.valid? # Returns true/false
55
+ #
56
+ # Additionally sets manual_journal.errors array to an array of field/error.
57
+ def valid?
58
+ @errors = []
59
+
60
+ if !manual_journal_id.nil? && manual_journal_id !~ GUID_REGEX
61
+ @errors << ['manual_journal_id', 'must be blank or a valid Xero GUID']
62
+ end
63
+
64
+ if narration.blank?
65
+ @errors << ['narration', "can't be blank"]
66
+ end
67
+
68
+ unless date
69
+ @errors << ['date', "can't be blank"]
70
+ end
71
+
72
+ # Make sure all journal_items are valid.
73
+ unless journal_lines.all? { | journal_line | journal_line.valid? }
74
+ @errors << ['journal_lines', "at least one journal line invalid"]
75
+ end
76
+
77
+ # make sure there are at least 2 journal lines
78
+ unless journal_lines.length > 1
79
+ @errors << ['journal_lines', "journal must contain at least two individual journal lines"]
80
+ end
81
+
82
+ if journal_lines.length > 100
83
+ @errors << ['journal_lines', "journal must contain less than one hundred journal lines"]
84
+ end
85
+
86
+ unless journal_lines.sum(&:line_amount).to_f == 0.0
87
+ @errors << ['journal_lines', "the total debits must be equal to total credits"]
88
+ end
89
+
90
+ @errors.size == 0
91
+ end
92
+
93
+
94
+ def journal_lines_downloaded?
95
+ @journal_lines_downloaded
96
+ end
97
+
98
+ # If line items are not downloaded, then attempt a download now (if this record was found to begin with).
99
+ def journal_lines
100
+ if journal_lines_downloaded?
101
+ @journal_lines
102
+
103
+ elsif manual_journal_id =~ GUID_REGEX && @gateway
104
+ # There is a manual_journal_id so we can assume this record was loaded from Xero.
105
+ # Let's attempt to download the journal_line records (if there is a gateway)
106
+
107
+ response = @gateway.get_manual_journal(manual_journal_id)
108
+ raise ManualJournalNotFoundError, "Manual Journal with ID #{manual_journal_id} not found in Xero." unless response.success? && response.manual_journal.is_a?(XeroGateway::ManualJournal)
109
+
110
+ @journal_lines = response.manual_journal.journal_lines
111
+ @journal_lines_downloaded = true
112
+
113
+ @journal_lines
114
+
115
+ # Otherwise, this is a new manual journal, so return the journal_lines reference.
116
+ else
117
+ @journal_lines
118
+ end
119
+ end
120
+
121
+ def to_xml(b = Builder::XmlMarkup.new)
122
+ b.ManualJournal {
123
+ b.ManualJournalID manual_journal_id if manual_journal_id
124
+ b.Narration narration
125
+ b.JournalLines {
126
+ self.journal_lines.each do |journal_line|
127
+ journal_line.to_xml(b)
128
+ end
129
+ }
130
+ b.Date ManualJournal.format_date(date || Date.today)
131
+ b.Status status if status
132
+ b.Url url if url
133
+ }
134
+ end
135
+
136
+ def self.from_xml(manual_journal_element, gateway = nil, options = {})
137
+ manual_journal = ManualJournal.new(options.merge({:gateway => gateway}))
138
+ manual_journal_element.children.each do |element|
139
+ case(element.name)
140
+ when "ManualJournalID" then manual_journal.manual_journal_id = element.text
141
+ when "Date" then manual_journal.date = parse_date(element.text)
142
+ when "Status" then manual_journal.status = element.text
143
+ when "Narration" then manual_journal.narration = element.text
144
+ when "JournalLines" then element.children.each {|journal_line| manual_journal.journal_lines_downloaded = true; manual_journal.journal_lines << JournalLine.from_xml(journal_line) }
145
+ when "Url" then manual_journal.url = element.text
146
+ end
147
+ end
148
+ manual_journal
149
+ end # from_xml
150
+
151
+ def add_journal_line(params = {})
152
+ journal_line = nil
153
+ case params
154
+ when Hash then journal_line = JournalLine.new(params)
155
+ when JournalLine then journal_line = params
156
+ else raise InvalidLineItemError
157
+ end
158
+ @journal_lines << journal_line
159
+ journal_line
160
+ end
161
+
162
+ end
163
+ end
@@ -9,11 +9,13 @@ module XeroGateway
9
9
  alias_method :invoice, :response_item
10
10
  alias_method :credit_note, :response_item
11
11
  alias_method :bank_transaction, :response_item
12
+ alias_method :manual_journal, :response_item
12
13
  alias_method :contact, :response_item
13
14
  alias_method :organisation, :response_item
14
15
  alias_method :invoices, :array_wrapped_response_item
15
16
  alias_method :credit_notes, :array_wrapped_response_item
16
17
  alias_method :bank_transactions, :array_wrapped_response_item
18
+ alias_method :manual_journals, :array_wrapped_response_item
17
19
  alias_method :contacts, :array_wrapped_response_item
18
20
  alias_method :accounts, :array_wrapped_response_item
19
21
  alias_method :tracking_categories, :array_wrapped_response_item
data/lib/xero_gateway.rb CHANGED
@@ -26,6 +26,8 @@ require File.join(File.dirname(__FILE__), 'xero_gateway', 'payment')
26
26
  require File.join(File.dirname(__FILE__), 'xero_gateway', 'invoice')
27
27
  require File.join(File.dirname(__FILE__), 'xero_gateway', 'bank_transaction')
28
28
  require File.join(File.dirname(__FILE__), 'xero_gateway', 'credit_note')
29
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'journal_line')
30
+ require File.join(File.dirname(__FILE__), 'xero_gateway', 'manual_journal')
29
31
  require File.join(File.dirname(__FILE__), 'xero_gateway', 'address')
30
32
  require File.join(File.dirname(__FILE__), 'xero_gateway', 'phone')
31
33
  require File.join(File.dirname(__FILE__), 'xero_gateway', 'organisation')
@@ -21,10 +21,10 @@ class AccountsListTest < Test::Unit::TestCase
21
21
  def test_raise_error_on_not_loaded
22
22
  accounts_list = @gateway.get_accounts_list(false)
23
23
  assert_equal(false, accounts_list.loaded?)
24
- assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list[200] }
25
- assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_by_code(200) }
26
- assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_all_by_type('EXPENSE') }
27
- assert_raise(XeroGateway::AccountsList::AccountsListNotLoadedError) { accounts_list.find_all_by_tax_type('OUTPUT') }
24
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list[200] }
25
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list.find_by_code(200) }
26
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list.find_all_by_type('EXPENSE') }
27
+ assert_raise(XeroGateway::AccountsListNotLoadedError) { accounts_list.find_all_by_tax_type('OUTPUT') }
28
28
  end
29
29
 
30
30
  # Test simple lookup by account code (from cache).
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class CreateManualJournalTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ @gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
8
+
9
+ if STUB_XERO_CALLS
10
+ @gateway.xero_url = "DUMMY_URL"
11
+
12
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /ManualJournals$/ }.returns(get_file_as_string("create_manual_journal.xml"))
13
+ @gateway.stubs(:http_post).with {|client, url, body, params| url =~ /ManualJournals$/ }.returns(get_file_as_string("manual_journal.xml"))
14
+ end
15
+ end
16
+
17
+ def test_create_manual_journal
18
+ example_manual_journal = create_test_manual_journal.dup
19
+
20
+ result = @gateway.create_manual_journal(example_manual_journal)
21
+ assert_kind_of XeroGateway::Response, result
22
+ assert result.success?
23
+ assert !result.request_xml.nil?
24
+ assert !result.response_xml.nil?
25
+ assert !result.manual_journal.manual_journal_id.nil?
26
+ assert example_manual_journal.manual_journal_id =~ GUID_REGEX
27
+ end
28
+
29
+ def test_create_manual_journal_valid
30
+ example_manual_journal = create_test_manual_journal.dup
31
+ assert_equal true, example_manual_journal.valid?,
32
+ "manual_journal is invalid - errors:\n\t#{example_manual_journal.errors.map { | error | "#{error[0]} #{error[1]}"}.join("\n\t")}"
33
+ end
34
+
35
+ end
@@ -25,6 +25,7 @@ class GetBankTransactionTest < Test::Unit::TestCase
25
25
  assert !result.response_xml.nil?
26
26
  assert_equal result.bank_transaction.bank_transaction_id, bank_transaction.bank_transaction_id
27
27
  assert_equal result.bank_transaction.reference, bank_transaction.reference
28
+ assert result.bank_transaction.is_reconciled
28
29
 
29
30
  result = @gateway.get_bank_transaction(bank_transaction.bank_transaction_id)
30
31
  assert result.success?
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetManualJournalTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ @gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
8
+
9
+ if STUB_XERO_CALLS
10
+ @gateway.xero_url = "DUMMY_URL"
11
+
12
+ @gateway.stubs(:http_get).with {|client, url, params| url =~ /ManualJournals(\/[0-9a-z\-]+)?$/i }.returns(get_file_as_string("manual_journal.xml"))
13
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /ManualJournals$/ }.returns(get_file_as_string("create_manual_journal.xml"))
14
+ end
15
+ end
16
+
17
+ def test_get_manual_journal
18
+ # Make sure there is a manual journal in Xero to retrieve
19
+ response = @gateway.create_manual_journal(create_test_manual_journal)
20
+ manual_journal = response.manual_journal
21
+
22
+ result = @gateway.get_manual_journal(manual_journal.manual_journal_id)
23
+ assert result.success?
24
+ assert !result.request_params.nil?
25
+ assert !result.response_xml.nil?
26
+ assert_equal result.manual_journal.manual_journal_id, manual_journal.manual_journal_id
27
+ assert_equal result.manual_journal.narration, manual_journal.narration
28
+
29
+ result = @gateway.get_manual_journal(manual_journal.manual_journal_id)
30
+ assert result.success?
31
+ assert !result.request_params.nil?
32
+ assert !result.response_xml.nil?
33
+ assert_equal result.manual_journal.manual_journal_id, manual_journal.manual_journal_id
34
+ end
35
+
36
+ def test_journal_lines_downloaded_set_correctly
37
+ # Make sure there is a manual journal in Xero to retrieve.
38
+ example_manual_journal = @gateway.create_manual_journal(create_test_manual_journal).manual_journal
39
+
40
+ # No line items.
41
+ response = @gateway.get_manual_journal(example_manual_journal.manual_journal_id)
42
+ assert response.success?
43
+
44
+ manual_journal = response.manual_journal
45
+ assert_kind_of(XeroGateway::JournalLine, manual_journal.journal_lines.first)
46
+ assert_kind_of(XeroGateway::ManualJournal, manual_journal)
47
+ assert manual_journal.journal_lines_downloaded?
48
+ end
49
+
50
+ end
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class GetManualJournalsTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ INVALID_MANUAL_JOURNAL_ID = "99999999-9999-9999-9999-999999999999" unless defined?(INVALID_MANUAL_JOURNAL_ID)
7
+
8
+ def setup
9
+ @gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
10
+
11
+ if STUB_XERO_CALLS
12
+ @gateway.xero_url = "DUMMY_URL"
13
+
14
+ @gateway.stubs(:http_get).with {|client, url, params| url =~ /ManualJournals(\/[0-9a-z\-]+)?$/i }.returns(get_file_as_string("manual_journals.xml"))
15
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /ManualJournals$/ }.returns(get_file_as_string("create_manual_journal.xml"))
16
+
17
+ # Get a manual journal with an invalid ID.
18
+ @gateway.stubs(:http_get).with {|client, url, params| url =~ Regexp.new("ManualJournals/#{INVALID_MANUAL_JOURNAL_ID}") }.returns(get_file_as_string("manual_journal_not_found_error.xml"))
19
+ end
20
+ end
21
+
22
+ def test_get_manual_journals
23
+ # Make sure there is a manual journal in Xero to retrieve
24
+ manual_journal = @gateway.create_manual_journal(create_test_manual_journal).manual_journal
25
+
26
+ result = @gateway.get_manual_journals
27
+ assert result.success?
28
+ assert !result.request_params.nil?
29
+ assert !result.response_xml.nil?
30
+ assert result.manual_journals.collect {|i| i.narration}.include?(manual_journal.narration)
31
+ assert result.manual_journals.collect {|i| i.manual_journal_id}.include?(manual_journal.manual_journal_id)
32
+ end
33
+
34
+ def test_get_manual_journals_with_modified_since_date
35
+ # Create a test manual journal
36
+ @gateway.create_manual_journal(create_test_manual_journal)
37
+
38
+ # Check that it is returned
39
+ result = @gateway.get_manual_journals(:modified_since => Date.today - 1)
40
+ assert result.success?
41
+ assert !result.request_params.nil?
42
+ assert !result.response_xml.nil?
43
+ assert result.request_params.keys.include?(:ModifiedAfter) # make sure the flag was sent
44
+ end
45
+
46
+ def test_journal_lines_downloaded_set_correctly
47
+ # No line items.
48
+ response = @gateway.get_manual_journals
49
+ assert_equal(true, response.success?)
50
+
51
+ manual_journal = response.manual_journals.first
52
+ assert_kind_of(XeroGateway::ManualJournal, manual_journal)
53
+ assert !manual_journal.journal_lines_downloaded?
54
+ end
55
+
56
+ # Make sure that a reference to gateway is passed when the get_manual_journals response is parsed.
57
+ def test_get_manual_journals_gateway_reference
58
+ result = @gateway.get_manual_journals
59
+ assert(result.success?)
60
+ assert_not_equal(0, result.manual_journals.size)
61
+
62
+ result.manual_journals.each do |manual_journal|
63
+ assert(manual_journal.gateway === @gateway)
64
+ end
65
+ end
66
+
67
+ # Test to make sure that we correctly error when a manual journal doesn't have an ID.
68
+ # This should usually never be ecountered.
69
+ def test_to_ensure_that_a_manual_journal_with_invalid_id_errors
70
+ # Make sure there is a manual journal to retrieve, even though we will mangle it later.
71
+ manual_journal = @gateway.create_manual_journal(create_test_manual_journal).manual_journal
72
+
73
+ result = @gateway.get_manual_journals
74
+ assert_equal(true, result.success?)
75
+
76
+ manual_journal = result.manual_journals.first
77
+ assert !manual_journal.journal_lines_downloaded?
78
+
79
+ # Mangle invoice_id to invalid one.
80
+ manual_journal.manual_journal_id = INVALID_MANUAL_JOURNAL_ID
81
+
82
+ # Make sure we fail here.
83
+ journal_lines = nil
84
+ assert_raise(XeroGateway::ManualJournalNotFoundError) { journal_lines = manual_journal.journal_lines }
85
+ assert_nil(journal_lines)
86
+ end
87
+
88
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UpdateManualJournalTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ @gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
8
+
9
+ if STUB_XERO_CALLS
10
+ @gateway.xero_url = "DUMMY_URL"
11
+
12
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /ManualJournals$/ }.returns(get_file_as_string("create_manual_journal.xml"))
13
+ @gateway.stubs(:http_post).with {|client, url, body, params| url =~ /ManualJournals$/ }.returns(get_file_as_string("manual_journal.xml"))
14
+ end
15
+ end
16
+
17
+ def test_update_manual_journal
18
+ manual_journal = @gateway.create_manual_journal(create_test_manual_journal).manual_journal
19
+
20
+ today = Date.today
21
+ manual_journal.date = today
22
+
23
+ result = @gateway.update_manual_journal(manual_journal)
24
+
25
+ assert result.success?
26
+ assert !result.request_xml.nil?
27
+ assert !result.response_xml.nil?
28
+ assert_equal manual_journal.manual_journal_id, result.manual_journal.manual_journal_id
29
+ assert_equal today, result.manual_journal.date if !STUB_XERO_CALLS
30
+ end
31
+ end
data/test/test_helper.rb CHANGED
@@ -176,4 +176,42 @@ module TestHelper
176
176
  contact
177
177
  end
178
178
 
179
+ def create_test_manual_journal(params={}, journal_line_params={})
180
+ params = {
181
+ :date => Date.today,
182
+ :narration => 'test narration',
183
+ :status => 'POSTED'
184
+ }.merge(params)
185
+ manual_journal = XeroGateway::ManualJournal.new(params)
186
+ add_test_journal_lines(manual_journal, journal_line_params)
187
+ end
188
+
189
+ def add_test_journal_lines(manual_journal, journal_line_params)
190
+ if journal_line_params
191
+ journal_line_params = [journal_line_params].flatten # always use an array, even if only a single hash passed in
192
+
193
+ # At least one line item, make first have some defaults.
194
+ journal_line_params << {} if journal_line_params.size == 0
195
+ journal_line_params[0] = {
196
+ :description => "FIRST LINE",
197
+ :account_code => "200",
198
+ :line_amount => BigDecimal.new("100"),
199
+ :tracking => XeroGateway::TrackingCategory.new(:name => "blah", :options => "hello")
200
+ }.merge(journal_line_params[0])
201
+ params_line_1 = journal_line_params[1] || {}
202
+ journal_line_params[1] = {
203
+ :description => "SECOND LINE",
204
+ :account_code => "200",
205
+ :line_amount => BigDecimal.new("-100"),
206
+ :tracking => XeroGateway::TrackingCategory.new(:name => "blah2", :options => "hello2")
207
+ }.merge(params_line_1)
208
+
209
+ # Create line_items from line_item_params
210
+ journal_line_params.each do |journal_line|
211
+ manual_journal.add_journal_line(journal_line)
212
+ end
213
+ end
214
+ manual_journal
215
+ end
216
+
179
217
  end
@@ -65,7 +65,7 @@ class BankTransactionTest < Test::Unit::TestCase
65
65
 
66
66
  # Test that pushing anything else into add_line_item fails.
67
67
  ["invalid", 100, nil, []].each do | invalid_object |
68
- assert_raise(XeroGateway::Invoice::InvalidLineItemError) { @bank_transaction.add_line_item(invalid_object) }
68
+ assert_raise(XeroGateway::InvalidLineItemError) { @bank_transaction.add_line_item(invalid_object) }
69
69
  assert_equal(2, @bank_transaction.line_items.size)
70
70
  end
71
71
  end
@@ -100,6 +100,18 @@ class BankTransactionTest < Test::Unit::TestCase
100
100
  parsed_bank_transaction = XeroGateway::BankTransaction.from_xml(bank_transaction_element)
101
101
  assert_equal 'http://example.com?with=params&and=more', parsed_bank_transaction.url
102
102
  end
103
+
104
+ should "ignore missing contact" do
105
+ bank_transaction = create_test_bank_transaction
106
+ bank_transaction.contact = nil
107
+ bank_transaction.to_xml
108
+ end
109
+
110
+ should "ignore missing bank account" do
111
+ bank_transaction = create_test_bank_transaction
112
+ bank_transaction.bank_account = nil
113
+ bank_transaction.to_xml
114
+ end
103
115
  end
104
116
 
105
117
  private
@@ -215,7 +215,7 @@ class CreditNoteTest < Test::Unit::TestCase
215
215
 
216
216
  # Test that pushing anything else into add_line_item fails.
217
217
  ["invalid", 100, nil, []].each do | invalid_object |
218
- assert_raise(XeroGateway::CreditNote::InvalidLineItemError) { credit_note.add_line_item(invalid_object) }
218
+ assert_raise(XeroGateway::InvalidLineItemError) { credit_note.add_line_item(invalid_object) }
219
219
  assert_equal(2, credit_note.line_items.size)
220
220
  end
221
221
  end
@@ -7,7 +7,7 @@ class GatewayTest < Test::Unit::TestCase
7
7
  @gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
8
8
  end
9
9
 
10
- context "with oauth error handling" do
10
+ context "with error handling" do
11
11
 
12
12
  should "handle token expired" do
13
13
  XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("token_expired"), :code => "401"))
@@ -56,7 +56,31 @@ class GatewayTest < Test::Unit::TestCase
56
56
  @gateway.create_invoice(XeroGateway::Invoice.new)
57
57
  end
58
58
  end
59
-
59
+
60
+ should "handle invoices not found" do
61
+ XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("api_exception.xml"), :code => "404"))
62
+
63
+ assert_raises XeroGateway::InvoiceNotFoundError do
64
+ @gateway.get_invoice('unknown-invoice-id')
65
+ end
66
+ end
67
+
68
+ should "handle bank transactions not found" do
69
+ XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("api_exception.xml"), :code => "404"))
70
+
71
+ assert_raises XeroGateway::BankTransactionNotFoundError do
72
+ @gateway.get_bank_transaction('unknown-bank-transaction-id')
73
+ end
74
+ end
75
+
76
+ should "handle credit notes not found" do
77
+ XeroGateway::OAuth.any_instance.stubs(:get).returns(stub(:plain_body => get_file_as_string("api_exception.xml"), :code => "404"))
78
+
79
+ assert_raises XeroGateway::CreditNoteNotFoundError do
80
+ @gateway.get_credit_note('unknown-credit-note-id')
81
+ end
82
+ end
83
+
60
84
  should "handle random root elements" do
61
85
  XeroGateway::OAuth.any_instance.stubs(:put).returns(stub(:plain_body => "<RandomRootElement></RandomRootElement>", :code => "200"))
62
86
 
@@ -229,7 +229,7 @@ class InvoiceTest < Test::Unit::TestCase
229
229
 
230
230
  # Test that pushing anything else into add_line_item fails.
231
231
  ["invalid", 100, nil, []].each do | invalid_object |
232
- assert_raise(XeroGateway::Invoice::InvalidLineItemError) { invoice.add_line_item(invalid_object) }
232
+ assert_raise(XeroGateway::InvalidLineItemError) { invoice.add_line_item(invalid_object) }
233
233
  assert_equal(2, invoice.line_items.size)
234
234
  end
235
235
  end
@@ -0,0 +1,93 @@
1
+ require File.join(File.dirname(__FILE__), '../test_helper.rb')
2
+
3
+ class ManualJournalTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ context "creating test manual journals" do
7
+ should "work" do
8
+ manual_journal = create_test_manual_journal
9
+
10
+ # test transaction defaults
11
+ assert_equal 'POSTED', manual_journal.status
12
+ assert_kind_of Date, manual_journal.date
13
+ assert_equal 'test narration', manual_journal.narration
14
+
15
+ # Test the journal_line defaults.
16
+ journal_line = manual_journal.journal_lines.first
17
+ assert_equal('FIRST LINE', journal_line.description)
18
+ assert_equal('200', journal_line.account_code)
19
+ assert_equal(BigDecimal.new('100'), journal_line.line_amount)
20
+ end
21
+
22
+ should "allow overriding transaction defaults" do
23
+ assert_equal 'DRAFT', create_test_manual_journal(:status => 'DRAFT').status
24
+ end
25
+ end
26
+
27
+ context "adding journal lines" do
28
+ setup do
29
+ @manual_journal = create_test_manual_journal
30
+ end
31
+
32
+ should "work" do
33
+ assert_equal 2, @manual_journal.journal_lines.size
34
+ assert @manual_journal.valid?
35
+
36
+ journal_line_params = {:description => "Test Item 1", :line_amount => 100, :account_code => '200'}
37
+
38
+ # Test adding line item by hash
39
+ journal_line = @manual_journal.add_journal_line(journal_line_params)
40
+ assert_kind_of(XeroGateway::JournalLine, journal_line)
41
+ assert_equal(journal_line_params[:description], journal_line.description)
42
+ assert_equal(journal_line_params[:line_amount], journal_line.line_amount)
43
+ assert_equal(3, @manual_journal.journal_lines.size)
44
+
45
+ # Test adding line item by XeroGateway::JournalLine
46
+ journal_line = @manual_journal.add_journal_line(journal_line_params)
47
+ assert_kind_of(XeroGateway::JournalLine, journal_line)
48
+ assert_equal(journal_line_params[:description], journal_line.description)
49
+ assert_equal(journal_line_params[:line_amount], journal_line.line_amount)
50
+ assert_equal(4, @manual_journal.journal_lines.size)
51
+
52
+ # Test that having only 1 journal line fails.
53
+ @manual_journal.journal_lines = []
54
+ @manual_journal.add_journal_line(journal_line_params)
55
+ assert !@manual_journal.valid?
56
+ end
57
+ end
58
+
59
+
60
+ context "building and parsing XML" do
61
+ should "work vice versa" do
62
+ manual_journal = create_test_manual_journal
63
+ manual_journal_as_xml = manual_journal.to_xml
64
+ manual_journal_element = REXML::XPath.first(REXML::Document.new(manual_journal_as_xml), "/ManualJournal")
65
+
66
+ # checking for mandatory fields
67
+ assert_xml_field manual_journal_element, 'Date'
68
+ assert_xml_field manual_journal_element, 'Narration', :value => 'test narration'
69
+ assert_xml_field manual_journal_element, 'Status', :value => 'POSTED'
70
+
71
+ parsed_manual_journal = XeroGateway::ManualJournal.from_xml(manual_journal_element)
72
+ assert_equal(manual_journal, parsed_manual_journal)
73
+ end
74
+
75
+ should "work for optional params" do
76
+ manual_journal = create_test_manual_journal(:url => 'http://example.com?with=params&and=more')
77
+ manual_journal_element = REXML::XPath.first(REXML::Document.new(manual_journal.to_xml), "/ManualJournal")
78
+
79
+ assert_xml_field manual_journal_element, 'Url', :value => 'http://example.com\?with=params&amp;and=more'
80
+
81
+ parsed_manual_journal = XeroGateway::ManualJournal.from_xml(manual_journal_element)
82
+ assert_equal 'http://example.com?with=params&and=more', parsed_manual_journal.url
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def assert_xml_field(xml, field_name, options={})
89
+ assert_match /#{field_name}/, xml.to_s, "Didn't find the field #{field_name} in the XML document!"
90
+ assert_match /#{field_name}.*#{options[:value]}.*#{field_name}/, xml.to_s, "The field #{field_name} was expected to be '#{options[:value]}'!" if options[:value]
91
+ end
92
+
93
+ end
data/xero_gateway.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "xero_gateway"
3
- s.version = "2.0.14"
4
- s.date = "2012-05-07"
3
+ s.version = "2.0.15"
4
+ s.date = "2012-06-15"
5
5
  s.summary = "Enables ruby based applications to communicate with the Xero API"
6
6
  s.email = "tim@connorsoftware.com"
7
7
  s.homepage = "http://github.com/tlconnor/xero_gateway"
metadata CHANGED
@@ -1,56 +1,79 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: xero_gateway
3
- version: !ruby/object:Gem::Version
4
- version: 2.0.14
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
5
  prerelease:
6
+ segments:
7
+ - 2
8
+ - 0
9
+ - 15
10
+ version: 2.0.15
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Tim Connor
9
14
  - Nik Wakelin
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2012-05-07 00:00:00.000000000Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
18
+
19
+ date: 2012-06-15 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
16
23
  name: builder
17
- requirement: &70356902601560 !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
18
26
  none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 15
31
+ segments:
32
+ - 2
33
+ - 1
34
+ - 2
22
35
  version: 2.1.2
23
36
  type: :runtime
24
- prerelease: false
25
- version_requirements: *70356902601560
26
- - !ruby/object:Gem::Dependency
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
27
39
  name: oauth
28
- requirement: &70356902601080 !ruby/object:Gem::Requirement
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
29
42
  none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 31
47
+ segments:
48
+ - 0
49
+ - 3
50
+ - 6
33
51
  version: 0.3.6
34
52
  type: :runtime
35
- prerelease: false
36
- version_requirements: *70356902601080
37
- - !ruby/object:Gem::Dependency
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
38
55
  name: activesupport
39
- requirement: &70356902600700 !ruby/object:Gem::Requirement
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
40
58
  none: false
41
- requirements:
42
- - - ! '>='
43
- - !ruby/object:Gem::Version
44
- version: '0'
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
45
66
  type: :runtime
46
- prerelease: false
47
- version_requirements: *70356902600700
67
+ version_requirements: *id003
48
68
  description: Enables ruby based applications to communicate with the Xero API
49
69
  email: tim@connorsoftware.com
50
70
  executables: []
71
+
51
72
  extensions: []
73
+
52
74
  extra_rdoc_files: []
53
- files:
75
+
76
+ files:
54
77
  - Gemfile
55
78
  - LICENSE
56
79
  - Rakefile
@@ -74,8 +97,10 @@ files:
74
97
  - lib/xero_gateway/http.rb
75
98
  - lib/xero_gateway/http_encoding_helper.rb
76
99
  - lib/xero_gateway/invoice.rb
100
+ - lib/xero_gateway/journal_line.rb
77
101
  - lib/xero_gateway/line_item.rb
78
102
  - lib/xero_gateway/line_item_calculations.rb
103
+ - lib/xero_gateway/manual_journal.rb
79
104
  - lib/xero_gateway/money.rb
80
105
  - lib/xero_gateway/oauth.rb
81
106
  - lib/xero_gateway/organisation.rb
@@ -92,6 +117,7 @@ files:
92
117
  - test/integration/create_contact_test.rb
93
118
  - test/integration/create_credit_note_test.rb
94
119
  - test/integration/create_invoice_test.rb
120
+ - test/integration/create_manual_journal_test.rb
95
121
  - test/integration/get_accounts_test.rb
96
122
  - test/integration/get_bank_transaction_test.rb
97
123
  - test/integration/get_bank_transactions_test.rb
@@ -102,12 +128,15 @@ files:
102
128
  - test/integration/get_currencies_test.rb
103
129
  - test/integration/get_invoice_test.rb
104
130
  - test/integration/get_invoices_test.rb
131
+ - test/integration/get_manual_journal_test.rb
132
+ - test/integration/get_manual_journals_test.rb
105
133
  - test/integration/get_organisation_test.rb
106
134
  - test/integration/get_tax_rates_test.rb
107
135
  - test/integration/get_tracking_categories_test.rb
108
136
  - test/integration/update_bank_transaction_test.rb
109
137
  - test/integration/update_contact_test.rb
110
138
  - test/integration/update_invoice_test.rb
139
+ - test/integration/update_manual_journal_test.rb
111
140
  - test/test_helper.rb
112
141
  - test/unit/account_test.rb
113
142
  - test/unit/bank_transaction_test.rb
@@ -116,33 +145,45 @@ files:
116
145
  - test/unit/currency_test.rb
117
146
  - test/unit/gateway_test.rb
118
147
  - test/unit/invoice_test.rb
148
+ - test/unit/manual_journal_test.rb
119
149
  - test/unit/oauth_test.rb
120
150
  - test/unit/organisation_test.rb
121
151
  - test/unit/tax_rate_test.rb
122
152
  - test/unit/tracking_category_test.rb
123
153
  - lib/xero_gateway/ca-certificates.crt
154
+ has_rdoc: true
124
155
  homepage: http://github.com/tlconnor/xero_gateway
125
156
  licenses: []
157
+
126
158
  post_install_message:
127
159
  rdoc_options: []
128
- require_paths:
160
+
161
+ require_paths:
129
162
  - lib
130
- required_ruby_version: !ruby/object:Gem::Requirement
163
+ required_ruby_version: !ruby/object:Gem::Requirement
131
164
  none: false
132
- requirements:
133
- - - ! '>='
134
- - !ruby/object:Gem::Version
135
- version: '0'
136
- required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ hash: 3
169
+ segments:
170
+ - 0
171
+ version: "0"
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
173
  none: false
138
- requirements:
139
- - - ! '>='
140
- - !ruby/object:Gem::Version
141
- version: '0'
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ hash: 3
178
+ segments:
179
+ - 0
180
+ version: "0"
142
181
  requirements: []
182
+
143
183
  rubyforge_project:
144
- rubygems_version: 1.8.10
184
+ rubygems_version: 1.6.2
145
185
  signing_key:
146
186
  specification_version: 3
147
187
  summary: Enables ruby based applications to communicate with the Xero API
148
188
  test_files: []
189
+