Class: XeroGateway::Invoice

Inherits:
Object
  • Object
show all
Includes:
Dates, LineItemCalculations, Money
Defined in:
lib/xero_gateway/invoice.rb

Constant Summary collapse

INVOICE_TYPE =
{
  'ACCREC' =>           'Accounts Receivable',
  'ACCPAY' =>           'Accounts Payable'
}
LINE_AMOUNT_TYPES =
{
  "Inclusive" =>        'Invoice lines are inclusive tax',
  "Exclusive" =>        'Invoice lines are exclusive of tax (default)',
  "NoTax"     =>        'Invoices lines have no tax'
}
INVOICE_STATUS =
{
  'AUTHORISED' =>       'Approved invoices awaiting payment',
  'DELETED' =>          'Draft invoices that are deleted',
  'DRAFT' =>            'Invoices saved as draft or entered via API',
  'PAID' =>             'Invoices approved and fully paid',
  'SUBMITTED' =>        'Invoices entered by an employee awaiting approval',
  'VOID' =>             'Approved invoices that are voided'
}
GUID_REGEX =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LineItemCalculations

#add_line_item, #sub_total, #sub_total=, #total, #total=, #total_tax, #total_tax=

Methods included from Money

included

Methods included from Dates

included

Constructor Details

#initialize(params = {}) ⇒ Invoice

Returns a new instance of Invoice.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/xero_gateway/invoice.rb', line 45

def initialize(params = {})
  @errors ||= []
  @payments ||= []
  
  # Check if the line items have been downloaded.
  @line_items_downloaded = (params.delete(:line_items_downloaded) == true)
  
  params = {
    :line_amount_types => "Exclusive"
  }.merge(params)
  
  params.each do |k,v|
    self.send("#{k}=", v)
  end
  
  @line_items ||= []
end

Instance Attribute Details

#amount_creditedObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def amount_credited
  @amount_credited
end

#amount_dueObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def amount_due
  @amount_due
end

#amount_paidObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def amount_paid
  @amount_paid
end

#branding_theme_idObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def branding_theme_id
  @branding_theme_id
end

#contactObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def contact
  @contact
end

#currency_codeObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def currency_code
  @currency_code
end

#dateObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def date
  @date
end

#due_dateObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def due_date
  @due_date
end

#errorsObject

Any errors that occurred when the #valid? method called. Or errors that were within the XML payload from Xero



34
35
36
# File 'lib/xero_gateway/invoice.rb', line 34

def errors
  @errors
end

#fully_paid_onObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def fully_paid_on
  @fully_paid_on
end

#gatewayObject

Xero::Gateway associated with this invoice.



30
31
32
# File 'lib/xero_gateway/invoice.rb', line 30

def gateway
  @gateway
end

#invoice_idObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def invoice_id
  @invoice_id
end

#invoice_numberObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def invoice_number
  @invoice_number
end

#invoice_statusObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def invoice_status
  @invoice_status
end

#invoice_typeObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def invoice_type
  @invoice_type
end

#line_amount_typesObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def line_amount_types
  @line_amount_types
end

#line_itemsObject

If line items are not downloaded, then attempt a download now (if this record was found to begin with).



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def line_items
  @line_items
end

#line_items_downloadedObject

Represents whether the line_items have been downloaded when getting from GET /API.XRO/2.0/INVOICES



37
38
39
# File 'lib/xero_gateway/invoice.rb', line 37

def line_items_downloaded
  @line_items_downloaded
end

#paymentsObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def payments
  @payments
end

#referenceObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def reference
  @reference
end

#sent_to_contactObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def sent_to_contact
  @sent_to_contact
end

#updated_date_utcObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def updated_date_utc
  @updated_date_utc
end

#urlObject

All accessible fields



40
41
42
# File 'lib/xero_gateway/invoice.rb', line 40

def url
  @url
end

Class Method Details

.from_xml(invoice_element, gateway = nil, options = {}) ⇒ Object

TODO UpdatedDateUTC



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/xero_gateway/invoice.rb', line 209

def self.from_xml(invoice_element, gateway = nil, options = {})
  invoice = Invoice.new(options.merge({:gateway => gateway}))
  invoice_element.children.each do |element|
    case(element.name)
      when "InvoiceID" then invoice.invoice_id = element.text
      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 "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)
      when "FullyPaidOnDate" then invoice.fully_paid_on = parse_date(element.text)
      when "Status" then invoice.invoice_status = element.text
      when "Reference" then invoice.reference = element.text
      when "BrandingThemeID" then invoice.branding_theme_id = element.text
      when "LineAmountTypes" then invoice.line_amount_types = element.text
      when "LineItems" then element.children.each {|line_item| invoice.line_items_downloaded = true; invoice.line_items << LineItem.from_xml(line_item) }
      when "SubTotal" then invoice.sub_total = BigDecimal.new(element.text)
      when "TotalTax" then invoice.total_tax = BigDecimal.new(element.text)
      when "Total" then invoice.total = BigDecimal.new(element.text)
      when "InvoiceID" then invoice.invoice_id = element.text
      when "InvoiceNumber" then invoice.invoice_number = element.text
      when "Payments" then element.children.each { | payment | invoice.payments << Payment.from_xml(payment) }
      when "AmountDue" then invoice.amount_due = BigDecimal.new(element.text)
      when "AmountPaid" then invoice.amount_paid = BigDecimal.new(element.text)
      when "AmountCredited" then invoice.amount_credited = BigDecimal.new(element.text)
      when "SentToContact" then invoice.sent_to_contact = (element.text.strip.downcase == "true")
      when "Url" then invoice.url = element.text
      when "UpdatedDateUTC" then invoice.updated_date_utc = parse_utc_date_time(element.text)
      when "ValidationErrors" then invoice.errors = element.children.map { |error| Error.parse(error) }
    end
  end
  invoice
end

Instance Method Details

#==(other) ⇒ Object



151
152
153
154
155
156
157
158
159
160
# File 'lib/xero_gateway/invoice.rb', line 151

def ==(other)
  ["invoice_number", "invoice_type", "invoice_status", "reference", "currency_code", "line_amount_types", "contact", "line_items"].each do |field|
    return false if send(field) != other.send(field)
  end
  
  ["date", "due_date"].each do |field|
    return false if send(field).to_s != other.send(field).to_s
  end
  return true
end

#accounts_payable?Boolean

Helper method to check if the invoice is accounts payable.

Returns:

  • (Boolean)


115
116
117
# File 'lib/xero_gateway/invoice.rb', line 115

def accounts_payable?
  invoice_type == 'ACCPAY'
end

#accounts_receivable?Boolean

Helper method to check if the invoice is accounts receivable.

Returns:

  • (Boolean)


120
121
122
# File 'lib/xero_gateway/invoice.rb', line 120

def accounts_receivable?
  invoice_type == 'ACCREC'
end

#build_contact(params = {}) ⇒ Object

Helper method to create the associated contact object.



106
107
108
# File 'lib/xero_gateway/invoice.rb', line 106

def build_contact(params = {})
  self.contact = gateway ? gateway.build_contact(params) : Contact.new(params)
end

#createObject

Creates this invoice record (using gateway.create_invoice) with the associated gateway. If no gateway set, raise a NoGatewayError exception.

Raises:



174
175
176
177
# File 'lib/xero_gateway/invoice.rb', line 174

def create
  raise NoGatewayError unless gateway
  gateway.create_invoice(self)
end

#line_items_downloaded?Boolean

Whether or not the line_items have been downloaded (GET/invoices does not download line items).

Returns:

  • (Boolean)


125
126
127
# File 'lib/xero_gateway/invoice.rb', line 125

def line_items_downloaded?
  @line_items_downloaded
end

#saveObject

General purpose create/save method. If invoice_id is nil then create, otherwise, attempt to save.



164
165
166
167
168
169
170
# File 'lib/xero_gateway/invoice.rb', line 164

def save
  if invoice_id.nil?
    create
  else
    update
  end
end

#to_xml(b = Builder::XmlMarkup.new) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/xero_gateway/invoice.rb', line 186

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.Reference self.reference if self.reference
    b.BrandingThemeID self.branding_theme_id if self.branding_theme_id
    b.LineAmountTypes self.line_amount_types
    b.LineItems {
      self.line_items.each do |line_item|
        line_item.to_xml(b)
      end
    }
    b.Url url if url
  }
end

#updateObject

Updates this invoice record (using gateway.update_invoice) with the associated gateway. If no gateway set, raise a NoGatewayError exception.

Raises:



181
182
183
184
# File 'lib/xero_gateway/invoice.rb', line 181

def update
  raise NoGatewayError unless gateway
  gateway.update_invoice(self)
end

#valid?Boolean

Validate the Address record according to what will be valid by the gateway.

Usage:

address.valid?     # Returns true/false

Additionally sets address.errors array to an array of field/error.

Returns:

  • (Boolean)


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/xero_gateway/invoice.rb', line 69

def valid?
  @errors = []
  
  if !INVOICE_TYPE[invoice_type]
    @errors << ['invoice_type', "must be one of #{INVOICE_TYPE.keys.join('/')}"]
  end

  if !invoice_id.nil? && invoice_id !~ GUID_REGEX
    @errors << ['invoice_id', 'must be blank or a valid Xero GUID']
  end
        
  if invoice_status && !INVOICE_STATUS[invoice_status]
    @errors << ['invoice_status', "must be one of #{INVOICE_STATUS.keys.join('/')}"]
  end

  if line_amount_types && !LINE_AMOUNT_TYPES[line_amount_types]
    @errors << ['line_amount_types', "must be one of #{LINE_AMOUNT_TYPES.keys.join('/')}"]
  end
  
  unless date
    @errors << ['invoice_date', "can't be blank"]
  end
  
  # Make sure contact is valid.
  unless @contact && @contact.valid?
    @errors << ['contact', 'is invalid']
  end
  
  # Make sure all line_items are valid.
  unless line_items.all? { | line_item | line_item.valid? }
    @errors << ['line_items', "at least one line item invalid"]
  end
  
  @errors.size == 0
end