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, #total, #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



110
111
112
# File 'lib/xero_gateway/invoice.rb', line 110

def contact
  @contact ||= build_contact
end

#currency_codeObject

All accessible fields



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

def currency_code
  @currency_code
end

#currency_rateObject

All accessible fields



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

def currency_rate
  @currency_rate
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).



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/xero_gateway/invoice.rb', line 130

def line_items
  if line_items_downloaded?
    @line_items
  elsif invoice_id =~ GUID_REGEX && @gateway
    # There is an invoice_id so we can assume this record was loaded from Xero.
    # Let's attempt to download the line_item records (if there is a gateway)
    @line_items = download_line_items
  else
    # Otherwise, this is a new invoice, so return the line_items reference.
    @line_items
  end
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



203
204
205
206
207
208
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
# File 'lib/xero_gateway/invoice.rb', line 203

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 "CurrencyRate" then invoice.currency_rate = BigDecimal.new(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 "UpdatedDateUTC" then invoice.updated_date_utc = 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 "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 "ValidationErrors" then invoice.errors = element.children.map { |error| Error.parse(error) }
    end
  end
  invoice
end

Instance Method Details

#==(other) ⇒ Object



143
144
145
146
147
148
149
150
151
152
# File 'lib/xero_gateway/invoice.rb', line 143

def ==(other)
  ["invoice_number", "invoice_type", "invoice_status", "reference", "currency_code", "currency_rate", "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:



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

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.



156
157
158
159
160
161
162
# File 'lib/xero_gateway/invoice.rb', line 156

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

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



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/xero_gateway/invoice.rb', line 178

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 currency_code if currency_code
    b.CurrencyRate currency_rate if currency_rate
    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
    b.SentToContact sent_to_contact unless sent_to_contact.nil?
  }
end

#updateObject

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

Raises:



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

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