Class: Effective::QbRequest

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/effective/qb_request.rb

Constant Summary collapse

COMPLETED_STATES =

these are the states that signal a request is finished

['Finished', 'Error']
PROCESSING_STATES =
['Processing', 'CustomerQuery', 'CreateCustomer', 'OrderSync']

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.find_first_response_having_a_request_id(xml) ⇒ Object

searches the XML and returns the first element having a requestID attribute. Since the application does not bundle requests (yet), this should work.



55
56
57
58
# File 'app/models/effective/qb_request.rb', line 55

def self.find_first_response_having_a_request_id(xml)
  doc = Nokogiri::XML(xml)
  doc.xpath('//*[@requestID]')[0]
end

.find_using_response_qbxml(xml) ⇒ Object

Finds a QbRequest using response qb_xml. If the response could not be parsed, or if there was no corresponding record, nil will be returned.



38
39
40
41
42
43
# File 'app/models/effective/qb_request.rb', line 38

def self.find_using_response_qbxml(xml)
  return nil if xml.blank?
  element = Effective::QbRequest.find_first_response_having_a_request_id(xml)

  Effective::QbRequest.find_by_id(element.attr('requestID').to_i) if element
end

.new_requests_for_unsynced_itemsObject

creates (does not persist) QbRequests for outstanding orders. The caller may choose to persist a request when that request starts communicating with QuickBooks



30
31
32
33
34
# File 'app/models/effective/qb_request.rb', line 30

def self.new_requests_for_unsynced_items
  finished_order_ids = Effective::QbRequest.where(state: 'Finished').pluck(:order_id)
  Effective::Order.purchased.includes(order_items: [:purchasable, :qb_order_item])
    .where.not(id: finished_order_ids).map { |order| Effective::QbRequest.new(order: order) }
end

Instance Method Details

#consume_response_xml(xml) ⇒ Object

parses the response XML and processes it. returns true if the responseXML indicates success, false otherwise



62
63
64
65
# File 'app/models/effective/qb_request.rb', line 62

def consume_response_xml(xml)
  update_attributes!(response_qbxml: xml)
  handle_response_xml(xml)
end

#generate_request_xmlObject

generates the actual request XML that will be wrapped in a qbxml_request



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'app/models/effective/qb_request.rb', line 93

def generate_request_xml
  # safety checks to make sure we are linked in to the order
  raise 'Missing Order' unless order

  if order.order_items.any? { |order_item| order_item.qb_item_name.blank? }
    raise 'expected .qb_item_name() to be present on Effective::OrderItem'
  end

  case self.state
  when 'CustomerQuery'
    generate_customer_query_request_xml
  when 'OrderSync'
    generate_order_sync_request_xml
  when 'CreateCustomer'
    generate_create_customer_request_xml
  else
    raise "Unsupported state for generating request XML: #{state}"
  end
end

#handle_create_customer_response_xml(xml) ⇒ Object

This should be private too, but test needs it



131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'app/models/effective/qb_request.rb', line 131

def handle_create_customer_response_xml(xml)
  queryResponse = Nokogiri::XML(xml).xpath('//CustomerAddRs').first['statusCode']
  statusMessage = Nokogiri::XML(xml).xpath('//CustomerAddRs').first['statusMessage']

  if '0' == queryResponse
    # the customer was created
    log "Customer #{order.billing_name} created successfully"
    transition_state 'OrderSync'
  else
    raise "[Order ##{order.id}] Customer #{order.billing_name} could not be created in QuickBooks: #{statusMessage}"
  end

  true # indicate success
end

#handle_response_xml(xml) ⇒ Object

handle response xml



68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/models/effective/qb_request.rb', line 68

def handle_response_xml(xml)
  case state
  when 'CustomerQuery'
    handle_customer_query_response_xml(xml)
  when 'CreateCustomer'
    handle_create_customer_response_xml(xml)
  when 'OrderSync'
    handle_order_sync_response_xml(xml)
  else
    raise "Request in state #{state} was not expecting a response from the server"
  end
end

#has_more_work?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'app/models/effective/qb_request.rb', line 45

def has_more_work?
  PROCESSING_STATES.include?(state)
end

#stateObject



49
50
51
# File 'app/models/effective/qb_request.rb', line 49

def state
  self[:state] || 'Processing'
end

#to_qb_xmlObject

outputs this request in qb_xml_format



82
83
84
85
86
87
88
89
90
# File 'app/models/effective/qb_request.rb', line 82

def to_qb_xml
  if state == 'Processing'
    # this is a dummy state -- we need to transition to the CustomerQuery state before any XML goes out.
    transition_state 'CustomerQuery'
  end

  xml = generate_request_xml
  wrap_qbxml_request(xml)
end

#transition_state(state) ⇒ Object

transitions the request state and also outputs a log statement



114
115
116
117
118
# File 'app/models/effective/qb_request.rb', line 114

def transition_state(state)
  old_state = self.state
  update_attributes!(state: state)
  log "Transitioned request state from [#{old_state}] to [#{state}]"
end

#transition_to_finishedObject



120
121
122
123
124
125
126
127
128
# File 'app/models/effective/qb_request.rb', line 120

def transition_to_finished
  # We create one QbOrderItem for each OrderItem here.
  order.order_items.each do |order_item|
    order_item.qb_item_name
    order_item.qb_order_item.save
  end

  transition_state('Finished')
end