Class: Effective::QbMachine

Inherits:
Object
  • Object
show all
Defined in:
app/models/effective/qb_machine.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ticket_id = nil) ⇒ QbMachine

creates a new machine. this implicitly creates a new ticket unless one is supplied



11
12
13
14
15
16
17
# File 'app/models/effective/qb_machine.rb', line 11

def initialize(ticket_id = nil)
  if ticket_id
    @ticket = Effective::QbTicket.find_by_id(ticket_id)
  else
    @ticket = Effective::QbTicket.create
  end
end

Instance Attribute Details

#last_log_messageObject (readonly)

Returns the value of attribute last_log_message.



8
9
10
# File 'app/models/effective/qb_machine.rb', line 8

def last_log_message
  @last_log_message
end

#ticketObject (readonly)

Returns the value of attribute ticket.



7
8
9
# File 'app/models/effective/qb_machine.rb', line 7

def ticket
  @ticket
end

Instance Method Details

#fail_unexpectedly(message) ⇒ Object

sets the ticket as failed and records the message



248
249
250
251
# File 'app/models/effective/qb_machine.rb', line 248

def fail_unexpectedly(message)
  log "An unexpected error occurred: #{message}"
  @ticket.request_error! @last_log_message
end

#log(message) ⇒ Object

logs a message to the ticket if it exists



241
242
243
244
245
# File 'app/models/effective/qb_machine.rb', line 241

def log(message)
  @ticket.log(message) unless message.blank?
  # always save the last log message
  @last_log_message = message
end

#op_authenticate(username, password) ⇒ Object

authenticates a user for a particular session

returns

  • ‘nvu’ if the user login was invalid

  • ‘none’ if the user login was valid but there is no work to be done

  • ” if the user login was valid and there is work to be done



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'app/models/effective/qb_machine.rb', line 25

def op_authenticate(username, password)
  return 'nvu' unless valid?

  unless authentication_valid?(username, password)
    log "Authentication failed for user #{username}"
    @ticket.update_attributes!(username: username, state: 'Finished', last_error: @last_log_message)
    return 'nvu' # not valid user
  end

  if has_work?
    log "Authentication successful. Reporting to QuickBooks that there is work to be done."
    @ticket.update_attributes!(username: username, state: 'Authenticated')
    ''  # "Any other string value = use this name for company file"
  else
    log "Authentication successful, but there is no work to be done"
    @ticket.update_attributes!(username: username, state: 'Finished')
    'none'
  end
end

#op_close_connectionObject

processes a message from the QBWC that corresponds to

string closeConnection(string ticket)

in the QBWC api, signifying that this connection should be terminated.

returns the connection closing result (e.g. ‘OK’)



214
215
216
217
218
219
220
221
# File 'app/models/effective/qb_machine.rb', line 214

def op_close_connection
  return 'Close error: invalid ticket' unless valid?

  @ticket.update_attributes!(state: 'Finished') unless ['ConnectionError', 'RequestError'].include?(@ticket.state)
  log "Closed connection with QuickBooks"

  'OK'
end

#op_connection_error(hresult, message) ⇒ Object

processes a message from the QBWC that corresponds to

string connectionError(string ticket, string hresult, string message)

in the QBWC api, signfiying that the connection with QuickBooks was lost

The params input should have members that correspond to the above parameters except for ticket

Returns: ‘done’ to indicate that activity on this ticket should not be resumed



197
198
199
200
201
202
203
204
205
# File 'app/models/effective/qb_machine.rb', line 197

def op_connection_error(hresult,message)
  if valid?
    @ticket.connection_error_hresult = hresult
    @ticket.connection_error_message = message
    @ticket.state = 'ConnectionError'
  end

  'done'
end

#op_last_errorObject

processes a message from the QBWC that corresponds to

string getLastError(string ticket)

in the QBWC api

Returns: the last error recorded for that ticket



230
231
232
233
# File 'app/models/effective/qb_machine.rb', line 230

def op_last_error
  return 'Invalid Ticket Id' unless valid?
  @ticket.last_error || ''
end

#op_receive_response_xml(params) ⇒ Object

processes a message from the QBWC that corresponds to

int receiveResponseXML(ticket, response, hresult, message)

in the QBWC api

The params input should have members that correspond to the above parameters except for ticket

Returns:

- negative value for error
- postive value < 100 for percent complete (more work is to be done)
- 100 if there is no more work


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'app/models/effective/qb_machine.rb', line 116

def op_receive_response_xml(params)
  return -1 unless valid?

  # only process when in the 'Processing' state
  unless @ticket.state == 'Processing'
    log "Ticket state #{@ticket.state} not valid for processing responses"
    @ticket.request_error! @last_log_message
    return -1
  end

  responseXML = params[:response]
  log "Received response XML from QuickBooks"

  # handle a connection error
  unless params[:hresult].blank? and params[:message].blank?
    log "Connection error with QuickBooks: #{params[:hresult]} : #{params[:message]}"

    @ticket.request_error!(@last_log_message, connection_error_hresult: params[:hresult], connection_error_message: params[:message])

    # also update the request if it is able to be found
    request = find_outstanding_request(responseXML)
    request.update_attributes!(response_qbxml: responseXML, state: 'Error') if request

    return -1
  end

  # find the corresponding request
  request = find_outstanding_request(responseXML)

  unless request
    log "Received response back from QuickBooks but it did not correspond to any outstanding ticket request"
    @ticket.request_error! @last_log_message
    return -1
  end

  log "Found corresponding request [#{request.state}]"

  # safety check. we should always get a response back for the current request
  unless request == @ticket.qb_request
    log "Received response from QuickBooks but it references a request other than the current request"
    @ticket.request_error! @last_log_message
    return -1
  end

  # process the response XML now
  unless request.consume_response_xml(responseXML)
    # this request for some reason did not succeeed. Update the request and the ticket
    log "Request [#{request.state}] could not process the QuickBooks response: #{request.error}"
    request.update_attributes!(response_qbxml: responseXML, state: 'Error')
    @ticket.error! @last_log_message
    return -1
  end

  request.update_attributes!(response_qbxml: responseXML) # This was changed for effective_qb_sync

  # the request has processed the response XML. if it does not have any more work to do, then detach it

  if request.has_more_work?
    log "Request [#{request.state}] has more work to do on the next request"
  else
    # detach the current request
    @ticket.update_attributes!(qb_request: nil)
    log "Request [#{request.state}] has completed its work"
  end

  work_done = @ticket.qb_requests.size
  work_left = how_much_more_work
  work_left = work_left + 1 if @ticket.qb_request # if there is still a current request we need to add that to the work_left

  work_left == 0 ? 100 : (work_done * 100 / (work_done + work_left))
end

#op_send_request_xml(params) ⇒ Object

processes a message from the QBWC that corresponds to

string sendRequestXML(ticket, hcpresponse, company, country, major_ver, minor_ver)

in the QBWC api

The params input should have members that correspond to the above parameters except for ticket, since the ticket has already been used to build this state machine.

Returns:

  • ” if there is no work to be done

  • Some qbXML if there is work to be done



57
58
59
60
61
62
63
64
65
66
67
68
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
# File 'app/models/effective/qb_machine.rb', line 57

def op_send_request_xml(params)
  return '' unless valid?

  # update the ticket with the metadata sent at the first request for XML (i.e. if not blank)
  @ticket.update_attributes!(
    hpc_response: (@ticket.hpc_response || params[:hcpresponse]),
    company_file_name: (@ticket.company_file_name || params[:company]),
    country: (@ticket.country || params[:country]),
    qbxml_major_version: (@ticket.qbxml_major_version || params[:major_ver]),
    qbxml_minor_version: (@ticket.qbxml_minor_version || params[:minor_ver])
  )

  # only process when in the Authenticated or Processing states
  unless ['Authenticated', 'Processing'].include?(@ticket.state)
    @ticket.request_error!(@last_log_message)
    return ''
  end

  # either grab the current request or create a new one
  request = @ticket.qb_request
  unless request
    request = create_request
    @ticket.qb_request = request
  end

  # if we don't have a request, then we are done.
  unless request
    log "There is no more work to be done. Marking ticket state as finished"
    @ticket.update_attributes!(state: 'Finished')
    return ''
  end

  request.update_attributes!(qb_ticket: @ticket, request_sent_at: Time.zone.now)
  qb_xml = request.to_qb_xml
  request.update_attributes!(request_qbxml: qb_xml)

  # set the ticket into a Processing state
  @ticket.state = 'Processing'

  # save the changes.
  @ticket.save!

  log "Sending request [#{request.state}] XML to QuickBooks"

  qb_xml
end

#valid?Boolean

returns true if this machine is a valid machine

Returns:

  • (Boolean)


236
237
238
# File 'app/models/effective/qb_machine.rb', line 236

def valid?
  @ticket.present?
end