xero_gateway 2.0.14 → 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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
+