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.



58
59
60
61
# File 'app/models/effective/qb_request.rb', line 58

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.



41
42
43
44
45
46
# File 'app/models/effective/qb_request.rb', line 41

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



33
34
35
36
37
# File 'app/models/effective/qb_request.rb', line 33

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



65
66
67
68
# File 'app/models/effective/qb_request.rb', line 65

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



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

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



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'app/models/effective/qb_request.rb', line 134

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



71
72
73
74
75
76
77
78
79
80
81
82
# File 'app/models/effective/qb_request.rb', line 71

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)


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

def has_more_work?
  PROCESSING_STATES.include?(state)
end

#stateObject



52
53
54
# File 'app/models/effective/qb_request.rb', line 52

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

#to_qb_xmlObject

outputs this request in qb_xml_format



85
86
87
88
89
90
91
92
93
# File 'app/models/effective/qb_request.rb', line 85

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



117
118
119
120
121
# File 'app/models/effective/qb_request.rb', line 117

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



123
124
125
126
127
128
129
130
131
# File 'app/models/effective/qb_request.rb', line 123

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