Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #23 from isaac/master

Adds support for updating invoices via HTTP POST
  • Loading branch information...
commit 732d59718d97a76cbd318ba1f66c8330e3d859ff 2 parents 87679a5 + 24e9d95
@tlconnor tlconnor authored
View
9 README.textile
@@ -230,6 +230,15 @@ Invoice and line item totals are calculated automatically.
invoice.create</code></pre>
+
+h3. POST /api.xro/2.0/invoice
+
+Updates an existing invoice record.
+<pre><code> invoice_retrieved_from_xero.due_date = Date.today
+ invoice_retrieved_from_xero.save</code></pre>
+
+
+
h3. PUT /api.xro/2.0/invoices
Inserts multiple invoices for a specific organization in Xero (currently only adding new invoices is allowed).
View
60 lib/xero_gateway/gateway.rb
@@ -197,21 +197,24 @@ def build_invoice(invoice = {})
#
# create_invoice(invoice)
def create_invoice(invoice)
- request_xml = invoice.to_xml
- response_xml = http_put(@client, "#{@xero_url}/Invoices", request_xml)
- response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => 'PUT/invoice'})
-
- # Xero returns invoices inside an <Invoices> tag, even though there's only ever
- # one for this request
- response.response_item = response.invoices.first
-
- if response.success? && response.invoice && response.invoice.invoice_id
- invoice.invoice_id = response.invoice.invoice_id
- end
-
- response
+ save_invoice(invoice)
end
-
+
+ #
+ # Updates an existing Xero invoice
+ #
+ # Usage :
+ #
+ # invoice = xero_gateway.get_invoice(some_invoice_id)
+ # invoice.due_date = Date.today
+ #
+ # xero_gateway.update_invoice(invoice)
+
+ def update_invoice(invoice)
+ raise "invoice_id is required for updating invoices" if invoice.invoice_id.nil?
+ save_invoice(invoice)
+ end
+
#
# Creates an array of invoices with a single API request.
#
@@ -425,6 +428,35 @@ def save_contact(contact)
response
end
+ # Create or update an invoice record based on if it has an invoice_id.
+ def save_invoice(invoice)
+ request_xml = invoice.to_xml
+
+ response_xml = nil
+ create_or_save = nil
+ if invoice.invoice_id.nil?
+ # Create new invoice record.
+ response_xml = http_put(@client, "#{@xero_url}/Invoices", request_xml, {})
+ create_or_save = :create
+ else
+ # Update existing invoice record.
+ response_xml = http_post(@client, "#{@xero_url}/Invoices", request_xml, {})
+ create_or_save = :save
+ end
+
+ response = parse_response(response_xml, {:request_xml => request_xml}, {:request_signature => "#{create_or_save == :create ? 'PUT' : 'POST'}/invoice"})
+
+ # Xero returns invoices inside an <Invoices> tag, even though there's only ever
+ # one for this request
+ response.response_item = response.invoices.first
+
+ if response.success? && response.invoice && response.invoice.invoice_id
+ invoice.invoice_id = response.invoice.invoice_id
+ end
+
+ response
+ end
+
def parse_response(raw_response, request = {}, options = {})
response = XeroGateway::Response.new
View
26 lib/xero_gateway/invoice.rb
@@ -209,10 +209,14 @@ def ==(other)
return true
end
- # General purpose createsave method.
- # If contact_id and contact_number are nil then create, otherwise, attempt to save.
+ # General purpose create/save method.
+ # If invoice_id is nil then create, otherwise, attempt to save.
def save
- create
+ if invoice_id.nil?
+ create
+ else
+ update
+ end
end
# Creates this invoice record (using gateway.create_invoice) with the associated gateway.
@@ -222,19 +226,24 @@ def create
gateway.create_invoice(self)
end
- # Alias create as save as this is currently the only write action.
- alias_method :save, :create
-
+ # Updates this invoice record (using gateway.update_invoice) with the associated gateway.
+ # If no gateway set, raise a Xero::Invoice::NoGatewayError exception.
+ def update
+ raise NoGatewayError unless gateway
+ gateway.update_invoice(self)
+ end
+
def to_xml(b = Builder::XmlMarkup.new)
b.Invoice {
+ b.InvoiceID self.invoice_id if self.invoice_id
+ b.InvoiceNumber self.invoice_number if invoice_number
b.Type self.invoice_type
+ b.CurrencyCode self.currency_code if self.currency_code
contact.to_xml(b)
b.Date Invoice.format_date(self.date || Date.today)
b.DueDate Invoice.format_date(self.due_date) if self.due_date
b.Status self.invoice_status if self.invoice_status
- b.InvoiceNumber self.invoice_number if invoice_number
b.Reference self.reference if self.reference
- b.CurrencyCode self.currency_code if self.currency_code
b.LineAmountTypes self.line_amount_types
b.LineItems {
self.line_items.each do |line_item|
@@ -253,7 +262,6 @@ def self.from_xml(invoice_element, gateway = nil, options = {})
when "InvoiceNumber" then invoice.invoice_number = element.text
when "Type" then invoice.invoice_type = element.text
when "CurrencyCode" then invoice.currency_code = element.text
- when "Type" then invoice.invoice_type = element.text
when "Contact" then invoice.contact = Contact.from_xml(element)
when "Date" then invoice.date = parse_date(element.text)
when "DueDate" then invoice.due_date = parse_date(element.text)
View
31 test/integration/update_invoice_test.rb
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class UpdateInvoiceTest < Test::Unit::TestCase
+ include TestHelper
+
+ def setup
+ @gateway = XeroGateway::Gateway.new(CONSUMER_KEY, CONSUMER_SECRET)
+
+ if STUB_XERO_CALLS
+ @gateway.xero_url = "DUMMY_URL"
+
+ @gateway.stubs(:http_put).with {|client, url, body, params| url =~ /Invoices$/ }.returns(get_file_as_string("create_invoice.xml"))
+ @gateway.stubs(:http_post).with {|client, url, body, params| url =~ /Invoices$/ }.returns(get_file_as_string("invoice.xml"))
+ end
+ end
+
+ def test_update_invoice
+ invoice = @gateway.create_invoice(dummy_invoice).invoice
+
+ today = Date.today
+ invoice.due_date = today
+
+ result = @gateway.update_invoice(invoice)
+
+ assert result.success?
+ assert !result.request_xml.nil?
+ assert !result.response_xml.nil?
+ assert_equal invoice.invoice_id, result.invoice.invoice_id
+ assert_equal today, result.invoice.due_date if !STUB_XERO_CALLS
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.