qbwc 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +34 -0
- data/README.md +79 -39
- data/lib/generators/qbwc/install/install_generator.rb +24 -3
- data/lib/generators/qbwc/install/templates/db/migrate/change_request_index.rb +5 -0
- data/lib/generators/qbwc/install/templates/db/migrate/index_qbwc_jobs.rb +6 -0
- data/lib/generators/qbwc/install/templates/db/migrate/session_pending_jobs_text.rb +6 -0
- data/lib/qbwc.rb +11 -2
- data/lib/qbwc/active_record/job.rb +30 -16
- data/lib/qbwc/controller.rb +19 -7
- data/lib/qbwc/job.rb +47 -31
- data/lib/qbwc/session.rb +17 -3
- data/lib/qbwc/version.rb +1 -1
- data/lib/qbwc/worker.rb +2 -2
- data/test/qbwc/controllers/controller_test.rb +39 -3
- data/test/qbwc/integration/job_management_test.rb +59 -5
- data/test/qbwc/integration/request_generation_test.rb +32 -16
- data/test/qbwc/integration/response_test.rb +5 -5
- data/test/qbwc/integration/session_test.rb +50 -14
- data/test/test_helper.rb +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bbaec3ca34a9a960128b6933f41fc78682d8ba4
|
4
|
+
data.tar.gz: 7738ce71948875a6ea4a44753eddcfa37528ac64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8c027bfc0527d79c5b6bb2a5e1c19f68ef7be4ea90a4d0e39a3b111c62a12ac57ef601dac756f0e951887e4de53955a4b681bf5881b9b5e4e66c374c2cf7a0f
|
7
|
+
data.tar.gz: e52f3419dcc33fe1212600038f90586604603953a3c5a07795f8598e9fe55e8ffbc0018dc6fb18f8ea7ebfe72266a09087a174b081cc88a1025cc3a00fe69120
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
# Change Log
|
3
|
+
|
4
|
+
## [1.0.0](https://github.com/qbwc/qbwc/releases/tag/v1.0.0) (2016-03-02)
|
5
|
+
[Full Changelog](https://github.com/qbwc/qbwc/compare/0.1.0...1.0.0)
|
6
|
+
|
7
|
+
**Upgrading:**
|
8
|
+
|
9
|
+
Upgrading from previous versions requires running new migrations.
|
10
|
+
|
11
|
+
Run the generator:
|
12
|
+
|
13
|
+
`rails generate qbwc:install`
|
14
|
+
|
15
|
+
Then the migrations:
|
16
|
+
|
17
|
+
`rake db:migrate`
|
18
|
+
`rake RAILS_ENV=test db:migrate`
|
19
|
+
|
20
|
+
In production, ensure that no jobs are queued, then:
|
21
|
+
`rake RAILS_ENV=production db:migrate`
|
22
|
+
|
23
|
+
The `requests` and `should_run?` methods of `QBWC::Worker` now take three parameters: `job`, `session`, and `data`. Any workers that implement these methods should be updated to accept the additional parameters.
|
24
|
+
|
25
|
+
**Fixed bugs:**
|
26
|
+
|
27
|
+
- Removed 1000-character restriction on list of pending jobs [\#76](https://github.com/qbwc/qbwc/pull/76) ([rchekaluk](https://github.com/rchekaluk))
|
28
|
+
|
29
|
+
**New features:**
|
30
|
+
|
31
|
+
- App name and FileID provided to QuickBooks can now be overridden by implementing `app_name` and `file_id` in the generated QbwcController. [\#72](https://github.com/qbwc/qbwc/pull/72) ([r38y](https://github.com/r38y))
|
32
|
+
- `requests` and `should_run?` now receive the session and data Hash as arguments. This allows for greater control over which requests happen in a run. [\#80](https://github.com/qbwc/qbwc/pull/80) ([bkroeker](https://github.com/bkroeker))
|
33
|
+
- Added the `session_complete_success` configuration to specify a block to execute when the session completes. [\#80](https://github.com/qbwc/qbwc/pull/80) ([bkroeker](https://github.com/bkroeker))
|
34
|
+
- Added some indexes to qbwc_jobs for better performance with many jobs are defined. [\#80](https://github.com/qbwc/qbwc/pull/80) ([bkroeker](https://github.com/bkroeker))
|
data/README.md
CHANGED
@@ -14,6 +14,10 @@ and run
|
|
14
14
|
|
15
15
|
`bundle install`
|
16
16
|
|
17
|
+
## Upgrade
|
18
|
+
|
19
|
+
Read [the changelog](CHANGELOG.md) if upgrading from previous versions.
|
20
|
+
|
17
21
|
## Configuration
|
18
22
|
|
19
23
|
Run the generator:
|
@@ -54,12 +58,11 @@ At this point, QuickBooks Web Connector should be able to send requests to your
|
|
54
58
|
|
55
59
|
### Multiple users and multiple company files ###
|
56
60
|
|
57
|
-
If you want to have more than one person to connect to the same QuickBooks company file, you will need to manually edit the QWC file to change the
|
61
|
+
If you want to have more than one person to connect to the same QuickBooks company file, you will need to manually edit the QWC file to change the OwnerID (any GUID will do) before giving it to QuickBooks Web Connector.
|
58
62
|
|
59
63
|
If you want each person to have their own login, set up authentication per [Authentication and multiple company files](#authentication-and-multiple-company-files). In the QWC file, you will need to change `UserName`.
|
60
64
|
|
61
|
-
If you are connecting to multiple company files, you will additionally need to change `AppName` and `FileID` (any GUID) to be unique to each file.
|
62
|
-
|
65
|
+
If you are connecting to multiple company files, you will additionally need to change `AppName` and `FileID` (any GUID) to be unique to each file. In the generated `QbwcController` you can override the `file_id` method to customize `FileID` and `app_name` to customize `AppName`.
|
63
66
|
|
64
67
|
## Creating jobs
|
65
68
|
|
@@ -80,9 +83,9 @@ QBWC.add_job(:list_customers, true, '', CustomerTestWorker)
|
|
80
83
|
Your job will be persisted in your database and will remain active and run every time QuickBooks Web Connector runs an update. If you don't want this to happen, you can have have your job disable or delete itself after completion. For example:
|
81
84
|
|
82
85
|
```ruby
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
def handle_response(r, session, job, request, data)
|
87
|
+
QBWC.delete_job(job)
|
88
|
+
end
|
86
89
|
|
87
90
|
```
|
88
91
|
|
@@ -93,8 +96,8 @@ Alternately, you can custom logic in your worker's `requests` and `should_run?`
|
|
93
96
|
|
94
97
|
A job is associated to a worker, which is an object descending from `QBWC::Worker` that can define three methods:
|
95
98
|
|
96
|
-
- `requests(job)` - defines the request(s) that QuickBooks should process - returns a `Hash` or an `Array` of `Hash`es.
|
97
|
-
- `should_run?(job)` - whether this job should run (e.g. you can have a job run only under certain circumstances) - returns `Boolean` and defaults to `true`.
|
99
|
+
- `requests(job, session, data)` - defines the request(s) that QuickBooks should process - returns a `Hash` or an `Array` of `Hash`es.
|
100
|
+
- `should_run?(job, session, data)` - whether this job should run (e.g. you can have a job run only under certain circumstances) - returns `Boolean` and defaults to `true`.
|
98
101
|
- `handle_response(response, session, job, request, data)` - defines what to do with the response from Quickbooks.
|
99
102
|
|
100
103
|
All three methods are not invoked until a QuickBooks Web Connector session has been established with your web service.
|
@@ -106,25 +109,25 @@ require 'qbwc'
|
|
106
109
|
|
107
110
|
class CustomerTestWorker < QBWC::Worker
|
108
111
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
112
|
+
def requests(job, session, data)
|
113
|
+
{
|
114
|
+
:customer_query_rq => {
|
115
|
+
:xml_attributes => { "requestID" =>"1", 'iterator' => "Start" },
|
116
|
+
:max_returned => 100
|
117
|
+
}
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def handle_response(r, session, job, request, data)
|
122
|
+
# handle_response will get customers in groups of 100. When this is 0, we're done.
|
123
|
+
complete = r['xml_attributes']['iteratorRemainingCount'] == '0'
|
124
|
+
|
125
|
+
r['customer_ret'].each do |qb_cus|
|
126
|
+
qb_id = qb_cus['list_id']
|
127
|
+
qb_name = qb_cus['name']
|
128
|
+
Rails.logger.info("#{qb_id} #{qb_name}")
|
129
|
+
end
|
130
|
+
end
|
128
131
|
|
129
132
|
end
|
130
133
|
```
|
@@ -132,15 +135,41 @@ end
|
|
132
135
|
|
133
136
|
Use the [Onscreen Reference for Intuit Software Development Kits](https://developer-static.intuit.com/qbSDK-current/Common/newOSR/index.html) (use Format: qbXML) to see request and response formats to use in your jobs. Use underscored, lowercased versions of all tags (e.g. `customer_query_rq`, not `CustomerQueryRq`).
|
134
137
|
|
135
|
-
###
|
138
|
+
### Defining requests outside of a worker ###
|
139
|
+
|
140
|
+
You can pass requests (via a `Hash`, `String`, or array of `Hash`es and `String`s) to `QBWC.add_job` rather than having `QBWC::Worker#requests` define them.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
require 'qbwc'
|
144
|
+
requests = {
|
145
|
+
:customer_query_rq => {
|
146
|
+
:xml_attributes => { "requestID" =>"1", 'iterator' => "Start" },
|
147
|
+
:max_returned => 100
|
148
|
+
}
|
149
|
+
}
|
150
|
+
# QBWC will run the contents of the requests variable, and will not use CustomerTestWorker#requests.
|
151
|
+
QBWC.add_job(:list_customers, true, '', CustomerTestWorker, requests)
|
152
|
+
```
|
153
|
+
|
154
|
+
### Passing data to a worker ###
|
155
|
+
|
156
|
+
`QBWC::Worker#handle_response` method cannot access variables that are in-memory at the time that `QBWC.add_job` is called; however, you can optionally pass a serializable value (for example, `String`, `Array`, or `Hash`) to `QBWC.add_job`. This data will be passed to `QBWC::Worker#handle_response` during a QuickBooks Web Connector session.
|
136
157
|
|
137
|
-
|
158
|
+
```ruby
|
159
|
+
require 'qbwc'
|
160
|
+
extra_data = "something important"
|
161
|
+
QBWC.add_job(:list_customers, true, '', CustomerTestWorker, nil, extra_data)
|
162
|
+
|
163
|
+
class CustomerTestWorker < QBWC::Worker
|
138
164
|
|
139
|
-
|
165
|
+
# ...
|
140
166
|
|
141
|
-
|
167
|
+
def handle_response(r, session, job, request, data)
|
168
|
+
# data here is "something important"
|
169
|
+
end
|
142
170
|
|
143
|
-
|
171
|
+
end
|
172
|
+
```
|
144
173
|
|
145
174
|
## Sessions ##
|
146
175
|
|
@@ -158,21 +187,32 @@ c.session_initializer = Proc.new{|session|
|
|
158
187
|
|
159
188
|
In application code:
|
160
189
|
```ruby
|
161
|
-
|
190
|
+
require 'qbwc'
|
162
191
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
192
|
+
QBWC.set_session_initializer() do |session|
|
193
|
+
puts "New QuickBooks Web Connector session has been established (overridden session initializer)"
|
194
|
+
@information_from_jobs = {}
|
195
|
+
end if the_application_needs_a_different_session_initializer
|
167
196
|
|
168
|
-
|
197
|
+
QBWC.add_job(:list_customers, false, '', CustomerTestWorker)
|
169
198
|
|
170
199
|
```
|
171
200
|
|
172
|
-
Note: If you `
|
201
|
+
Note: If you `set_session_initializer` in your application code, you're only affecting the process that your application code runs in. A request to another process (e.g. if you're multiprocess or you restarted the server) means that QBWC won't see the session initializer.
|
173
202
|
|
174
203
|
Note: a QuickBooks Web Connector session is established when you manually run (update) an application's web service in QuickBooks Web Connector, or when QuickBooks Web Connector automatically executes a scheduled update.
|
175
204
|
|
205
|
+
Similarly, it is possible to set a block to be run upon successful completion of a session.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
QBWC.session_complete_success = lambda do |session|
|
209
|
+
total_time = Time.now - session.began_at
|
210
|
+
puts "Total run time of this session was #{total_time}s"
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
Note that if `QBWC.on_error == :stop` and an error is encountered, this block will not be run.
|
215
|
+
|
176
216
|
## Handling errors ##
|
177
217
|
|
178
218
|
By default, when an error response is received from QuickBooks, `QBWC::Worker#handle_response` will be invoked but no further requests will be processed in the current job or in subsequent jobs. However, the job will remain persisted and so will be attempted again at next QuickBooks Web Connector session. Unless there is some intervention, presumably the job will fail again and block all remaining jobs and their requests from being serviced.
|
@@ -12,6 +12,10 @@ module QBWC
|
|
12
12
|
source_root File.expand_path('../templates', __FILE__)
|
13
13
|
argument :controller_name, :type => :string, :default => 'qbwc'
|
14
14
|
|
15
|
+
def routes_rb
|
16
|
+
"config/routes.rb"
|
17
|
+
end
|
18
|
+
|
15
19
|
def copy_config
|
16
20
|
template('config/qbwc.rb', "config/initializers/qbwc.rb")
|
17
21
|
end
|
@@ -23,16 +27,33 @@ module QBWC
|
|
23
27
|
def active_record
|
24
28
|
migration_template 'db/migrate/create_qbwc_jobs.rb', 'db/migrate/create_qbwc_jobs.rb'
|
25
29
|
migration_template 'db/migrate/create_qbwc_sessions.rb', 'db/migrate/create_qbwc_sessions.rb'
|
30
|
+
migration_template 'db/migrate/index_qbwc_jobs.rb', 'db/migrate/index_qbwc_jobs.rb'
|
31
|
+
migration_template 'db/migrate/change_request_index.rb', 'db/migrate/change_request_index.rb'
|
32
|
+
migration_template 'db/migrate/session_pending_jobs_text.rb', 'db/migrate/session_pending_jobs_text.rb'
|
26
33
|
end
|
27
34
|
|
28
35
|
def self.next_migration_number(dirname)
|
29
36
|
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
30
37
|
end
|
31
38
|
|
39
|
+
def route1
|
40
|
+
"wash_out :#{controller_name}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def route2
|
44
|
+
"get '#{controller_name}/qwc' => '#{controller_name}#qwc'"
|
45
|
+
end
|
46
|
+
|
47
|
+
def route3
|
48
|
+
"get '#{controller_name}/action' => '#{controller_name}#_generate_wsdl'"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Idempotent routes inspired by https://github.com/thoughtbot/administrate/issues/232
|
52
|
+
# Idempotent routes fixed permanently by https://github.com/rails/rails/issues/22082
|
32
53
|
def setup_routes
|
33
|
-
route(
|
34
|
-
route(
|
35
|
-
route(
|
54
|
+
route(route1) unless File.new(routes_rb).read.include?(route1)
|
55
|
+
route(route2) unless File.new(routes_rb).read.include?(route2)
|
56
|
+
route(route3) unless File.new(routes_rb).read.include?(route3)
|
36
57
|
end
|
37
58
|
|
38
59
|
end
|
data/lib/qbwc.rb
CHANGED
@@ -54,6 +54,10 @@ module QBWC
|
|
54
54
|
mattr_accessor :session_initializer
|
55
55
|
@@session_initializer = nil
|
56
56
|
|
57
|
+
# Code to execute after each session has completed all jobs without errors
|
58
|
+
mattr_accessor :session_complete_success
|
59
|
+
@@session_complete_success = nil
|
60
|
+
|
57
61
|
# In the event of an error running requests, :stop all work or :continue with the next request?
|
58
62
|
mattr_reader :on_error
|
59
63
|
@@on_error = 'stopOnError'
|
@@ -89,10 +93,10 @@ module QBWC
|
|
89
93
|
storage_module::Job.delete_job_with_name(name)
|
90
94
|
end
|
91
95
|
|
92
|
-
def pending_jobs(company)
|
96
|
+
def pending_jobs(company, session = QBWC::Session.get)
|
93
97
|
js = jobs
|
94
98
|
QBWC.logger.info "#{js.length} jobs exist, checking for pending jobs for company '#{company}'."
|
95
|
-
storage_module::Job.sort_in_time_order(js.select {|job| job.company == company && job.pending?})
|
99
|
+
storage_module::Job.sort_in_time_order(js.select {|job| job.company == company && job.pending?(session)})
|
96
100
|
end
|
97
101
|
|
98
102
|
def set_session_initializer(&block)
|
@@ -100,6 +104,11 @@ module QBWC
|
|
100
104
|
self
|
101
105
|
end
|
102
106
|
|
107
|
+
def set_session_complete_success(&block)
|
108
|
+
@@session_complete_success = block
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
103
112
|
def on_error=(reaction)
|
104
113
|
raise 'Quickbooks on_error must be :stop or :continue' unless [:stop, :continue].include?(reaction)
|
105
114
|
@@on_error = "stopOnError" if reaction == :stop
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class QBWC::ActiveRecord::Job < QBWC::Job
|
2
2
|
class QbwcJob < ActiveRecord::Base
|
3
3
|
validates :name, :uniqueness => true, :presence => true
|
4
|
-
serialize :requests,
|
4
|
+
serialize :requests, Hash
|
5
|
+
serialize :request_index, Hash
|
5
6
|
serialize :data
|
6
7
|
|
7
8
|
def to_qbwc_job
|
@@ -12,20 +13,22 @@ class QBWC::ActiveRecord::Job < QBWC::Job
|
|
12
13
|
|
13
14
|
# Creates and persists a job.
|
14
15
|
def self.add_job(name, enabled, company, worker_class, requests, data)
|
15
|
-
|
16
16
|
worker_class = worker_class.to_s
|
17
17
|
ar_job = find_ar_job_with_name(name).first_or_initialize
|
18
18
|
ar_job.company = company
|
19
19
|
ar_job.enabled = enabled
|
20
|
-
ar_job.request_index = 0
|
21
20
|
ar_job.worker_class = worker_class
|
22
21
|
ar_job.save!
|
23
22
|
|
24
23
|
jb = self.new(name, enabled, company, worker_class, requests, data)
|
25
|
-
|
24
|
+
unless requests.nil? || requests.empty?
|
25
|
+
request_hash = { [nil, company] => [requests].flatten }
|
26
|
+
|
27
|
+
jb.requests = request_hash
|
28
|
+
ar_job.update_attribute :requests, request_hash
|
29
|
+
end
|
26
30
|
jb.requests_provided_when_job_added = (! requests.nil? && ! requests.empty?)
|
27
31
|
jb.data = data
|
28
|
-
|
29
32
|
jb
|
30
33
|
end
|
31
34
|
|
@@ -56,13 +59,14 @@ class QBWC::ActiveRecord::Job < QBWC::Job
|
|
56
59
|
find_ar_job.where(:enabled => true).exists?
|
57
60
|
end
|
58
61
|
|
59
|
-
def requests
|
60
|
-
find_ar_job.pluck(:requests).first
|
62
|
+
def requests(session = QBWC::Session.get)
|
63
|
+
@requests = find_ar_job.pluck(:requests).first
|
64
|
+
super
|
61
65
|
end
|
62
66
|
|
63
|
-
def requests
|
64
|
-
find_ar_job.update_all(:requests => r)
|
67
|
+
def set_requests(session, requests)
|
65
68
|
super
|
69
|
+
find_ar_job.update_all(:requests => @requests)
|
66
70
|
end
|
67
71
|
|
68
72
|
def requests_provided_when_job_added
|
@@ -83,17 +87,27 @@ class QBWC::ActiveRecord::Job < QBWC::Job
|
|
83
87
|
super
|
84
88
|
end
|
85
89
|
|
86
|
-
def request_index
|
87
|
-
find_ar_job.pluck(:request_index).first
|
90
|
+
def request_index(session)
|
91
|
+
(find_ar_job.pluck(:request_index).first || {})[session.key] || 0
|
88
92
|
end
|
89
93
|
|
90
|
-
def
|
91
|
-
find_ar_job.
|
94
|
+
def set_request_index(session, index)
|
95
|
+
find_ar_job.each do |jb|
|
96
|
+
jb.request_index[session.key] = index
|
97
|
+
jb.save
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def advance_next_request(session)
|
102
|
+
nr = request_index(session)
|
103
|
+
set_request_index session, nr + 1
|
92
104
|
end
|
93
105
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
106
|
+
def reset
|
107
|
+
super
|
108
|
+
job = find_ar_job
|
109
|
+
job.update_all :request_index => {}
|
110
|
+
job.update_all(:requests => {}) unless self.requests_provided_when_job_added
|
97
111
|
end
|
98
112
|
|
99
113
|
def self.list_jobs
|
data/lib/qbwc/controller.rb
CHANGED
@@ -72,14 +72,14 @@ SB
|
|
72
72
|
|
73
73
|
qwc = <<QWC
|
74
74
|
<QBWCXML>
|
75
|
-
<AppName>#{
|
75
|
+
<AppName>#{app_name}</AppName>
|
76
76
|
<AppID></AppID>
|
77
77
|
<AppURL>#{qbwc_action_url(:only_path => false)}</AppURL>
|
78
78
|
<AppDescription>Quickbooks integration</AppDescription>
|
79
79
|
<AppSupport>#{QBWC.support_site_url || root_url(:protocol => 'https://')}</AppSupport>
|
80
80
|
<UserName>#{@username || QBWC.username}</UserName>
|
81
81
|
<OwnerID>#{QBWC.owner_id}</OwnerID>
|
82
|
-
<FileID>{
|
82
|
+
<FileID>{#{file_id}}</FileID>
|
83
83
|
<QBType>QBFS</QBType>
|
84
84
|
<Style>Document</Style>
|
85
85
|
#{scheduler_block}
|
@@ -115,13 +115,17 @@ QWC
|
|
115
115
|
if company_file_path.nil?
|
116
116
|
QBWC.logger.info "Authentication of user '#{username}' failed."
|
117
117
|
company_file_path = AUTHENTICATE_NOT_VALID_USER
|
118
|
-
elsif !QBWC.pending_jobs(company_file_path).present?
|
119
|
-
QBWC.logger.info "Authentication of user '#{username}' succeeded, but no jobs pending for '#{company_file_path}'."
|
120
|
-
company_file_path = AUTHENTICATE_NO_WORK
|
121
118
|
else
|
122
|
-
QBWC.logger.info "Authentication of user '#{username}' succeeded, jobs are pending for '#{company_file_path}'."
|
123
119
|
ticket = QBWC.storage_module::Session.new(username, company_file_path).ticket
|
124
|
-
|
120
|
+
session = get_session(ticket)
|
121
|
+
|
122
|
+
if !QBWC.pending_jobs(company_file_path, session).present?
|
123
|
+
QBWC.logger.info "Authentication of user '#{username}' succeeded, but no jobs pending for '#{company_file_path}'."
|
124
|
+
company_file_path = AUTHENTICATE_NO_WORK
|
125
|
+
else
|
126
|
+
QBWC.logger.info "Authentication of user '#{username}' succeeded, jobs are pending for '#{company_file_path}'."
|
127
|
+
QBWC.session_initializer.call(session) unless QBWC.session_initializer.nil?
|
128
|
+
end
|
125
129
|
end
|
126
130
|
render :soap => {"tns:authenticateResult" => {"tns:string" => [ticket || '', company_file_path]}}
|
127
131
|
end
|
@@ -157,6 +161,14 @@ QWC
|
|
157
161
|
render :soap => {'tns:getLastErrorResult' => @session.error || ''}
|
158
162
|
end
|
159
163
|
|
164
|
+
def app_name
|
165
|
+
"#{Rails.application.class.parent_name} #{Rails.env} #{@app_name_suffix}"
|
166
|
+
end
|
167
|
+
|
168
|
+
def file_id
|
169
|
+
'90A44FB5-33D9-4815-AC85-BC87A7E7D1EB'
|
170
|
+
end
|
171
|
+
|
160
172
|
protected
|
161
173
|
|
162
174
|
def get_session(ticket = params[:ticket])
|
data/lib/qbwc/job.rb
CHANGED
@@ -7,9 +7,14 @@ class QBWC::Job
|
|
7
7
|
@enabled = enabled
|
8
8
|
@company = company || QBWC.company_file_path
|
9
9
|
@worker_class = worker_class
|
10
|
-
@requests = requests
|
11
10
|
@data = data
|
12
|
-
|
11
|
+
|
12
|
+
default_key = [nil, company]
|
13
|
+
requests = [requests].compact unless Hash === requests || Array === requests
|
14
|
+
requests = { default_key => requests } unless Hash === requests || requests.empty?
|
15
|
+
@requests = requests
|
16
|
+
|
17
|
+
@request_index = { default_key => 0 }
|
13
18
|
end
|
14
19
|
|
15
20
|
def worker
|
@@ -18,16 +23,17 @@ class QBWC::Job
|
|
18
23
|
|
19
24
|
def process_response(qbxml_response, response, session, advance)
|
20
25
|
QBWC.logger.info "Processing response."
|
21
|
-
|
22
|
-
|
26
|
+
request_list = requests(session)
|
27
|
+
completed_request = request_list[request_index(session)] if request_list
|
28
|
+
advance_next_request(session) if advance
|
23
29
|
QBWC.logger.info "Job '#{name}' received response: '#{qbxml_response}'." if QBWC.log_requests_and_responses
|
24
30
|
worker.handle_response(response, session, self, completed_request, data)
|
25
31
|
end
|
26
32
|
|
27
|
-
def advance_next_request
|
28
|
-
new_index = request_index + 1
|
33
|
+
def advance_next_request(session)
|
34
|
+
new_index = request_index(session) + 1
|
29
35
|
QBWC.logger.info "Job '#{name}' advancing to request #'#{new_index}'."
|
30
|
-
|
36
|
+
@request_index[session.key] = new_index
|
31
37
|
end
|
32
38
|
|
33
39
|
def enable
|
@@ -38,12 +44,12 @@ class QBWC::Job
|
|
38
44
|
self.enabled = false
|
39
45
|
end
|
40
46
|
|
41
|
-
def pending?
|
47
|
+
def pending?(session)
|
42
48
|
if !enabled?
|
43
49
|
QBWC.logger.info "Job '#{name}' not enabled."
|
44
50
|
return false
|
45
51
|
end
|
46
|
-
sr = worker.should_run?(self)
|
52
|
+
sr = worker.should_run?(self, session, @data)
|
47
53
|
QBWC.logger.info "Job '#{name}' should_run?: #{sr}."
|
48
54
|
return sr
|
49
55
|
end
|
@@ -52,12 +58,23 @@ class QBWC::Job
|
|
52
58
|
@enabled
|
53
59
|
end
|
54
60
|
|
55
|
-
def requests
|
56
|
-
|
61
|
+
def requests(session)
|
62
|
+
secondary_key = session.key.dup
|
63
|
+
secondary_key[0] = nil # username = nil
|
64
|
+
result = nil
|
65
|
+
[session.key, secondary_key].each do |k|
|
66
|
+
result ||= (@requests || {})[k]
|
67
|
+
end
|
68
|
+
result
|
57
69
|
end
|
58
70
|
|
59
|
-
def requests
|
60
|
-
@requests
|
71
|
+
def set_requests(session, requests)
|
72
|
+
@requests ||= {}
|
73
|
+
@requests[session.key] = requests
|
74
|
+
end
|
75
|
+
|
76
|
+
def requests=(requests)
|
77
|
+
@requests = requests
|
61
78
|
end
|
62
79
|
|
63
80
|
def data
|
@@ -68,12 +85,8 @@ class QBWC::Job
|
|
68
85
|
@data = d
|
69
86
|
end
|
70
87
|
|
71
|
-
def request_index
|
72
|
-
@request_index
|
73
|
-
end
|
74
|
-
|
75
|
-
def request_index=(ri)
|
76
|
-
@request_index = ri
|
88
|
+
def request_index(session)
|
89
|
+
@request_index[session.key] || 0
|
77
90
|
end
|
78
91
|
|
79
92
|
def requests_provided_when_job_added
|
@@ -84,27 +97,30 @@ class QBWC::Job
|
|
84
97
|
@requests_provided_when_job_added = value
|
85
98
|
end
|
86
99
|
|
87
|
-
def next_request
|
100
|
+
def next_request(session = QBWC::Session.get)
|
101
|
+
reqs = requests session
|
102
|
+
|
88
103
|
# Generate and save the requests to run when starting the job.
|
89
|
-
if (
|
90
|
-
|
91
|
-
|
92
|
-
|
104
|
+
if (reqs.nil? || reqs.empty?) && ! self.requests_provided_when_job_added
|
105
|
+
greqs = worker.requests(self, session, @data)
|
106
|
+
greqs = [greqs] unless greqs.nil? || greqs.is_a?(Array)
|
107
|
+
set_requests session, greqs
|
108
|
+
reqs = requests session
|
93
109
|
end
|
94
110
|
|
95
|
-
QBWC.logger.info("Requests available are '#{
|
96
|
-
ri = request_index
|
111
|
+
QBWC.logger.info("Requests available are '#{reqs}'.") if QBWC.log_requests_and_responses
|
112
|
+
ri = request_index session
|
97
113
|
QBWC.logger.info("Request index is '#{ri}'.")
|
98
|
-
return nil if ri.nil? ||
|
99
|
-
nr =
|
114
|
+
return nil if ri.nil? || reqs.nil? || ri >= reqs.length
|
115
|
+
nr = reqs[ri]
|
100
116
|
QBWC.logger.info("Next request is '#{nr}'.") if QBWC.log_requests_and_responses
|
101
|
-
return QBWC::Request.new(nr)
|
117
|
+
return QBWC::Request.new(nr) if nr
|
102
118
|
end
|
103
119
|
alias :next :next_request # Deprecated method name 'next'
|
104
120
|
|
105
121
|
def reset
|
106
|
-
|
107
|
-
|
122
|
+
@request_index = {}
|
123
|
+
@requests = {} unless self.requests_provided_when_job_added
|
108
124
|
end
|
109
125
|
|
110
126
|
end
|
data/lib/qbwc/session.rb
CHANGED
@@ -5,7 +5,7 @@ class QBWC::Session
|
|
5
5
|
|
6
6
|
@@session = nil
|
7
7
|
|
8
|
-
def self.get(ticket)
|
8
|
+
def self.get(ticket = nil)
|
9
9
|
@@session
|
10
10
|
end
|
11
11
|
|
@@ -24,6 +24,10 @@ class QBWC::Session
|
|
24
24
|
reset(ticket.nil?)
|
25
25
|
end
|
26
26
|
|
27
|
+
def key
|
28
|
+
[user, company]
|
29
|
+
end
|
30
|
+
|
27
31
|
def response_is_error?
|
28
32
|
self.error && self.status_severity == 'Error'
|
29
33
|
end
|
@@ -39,14 +43,16 @@ class QBWC::Session
|
|
39
43
|
def next_request
|
40
44
|
if current_job.nil? || error_and_stop_requested?
|
41
45
|
self.progress = 100
|
46
|
+
complete_with_success unless response_is_error?
|
42
47
|
return nil
|
43
48
|
end
|
44
|
-
until (request = current_job.next_request) do
|
49
|
+
until (request = current_job.next_request(self)) do
|
45
50
|
pending_jobs.shift
|
46
51
|
reset(true) or break
|
47
52
|
end
|
48
53
|
jobs_completed = @initial_job_count - pending_jobs.length
|
49
54
|
self.progress = ((jobs_completed.to_f / @initial_job_count.to_f ) * 100).to_i
|
55
|
+
complete_with_success if finished?
|
50
56
|
request
|
51
57
|
end
|
52
58
|
alias :next :next_request # Deprecated method name 'next'
|
@@ -92,6 +98,10 @@ class QBWC::Session
|
|
92
98
|
def save
|
93
99
|
end
|
94
100
|
|
101
|
+
def began_at
|
102
|
+
@session.created_at
|
103
|
+
end
|
104
|
+
|
95
105
|
def destroy
|
96
106
|
self.freeze
|
97
107
|
@@session = nil
|
@@ -111,7 +121,11 @@ class QBWC::Session
|
|
111
121
|
end
|
112
122
|
|
113
123
|
def pending_jobs
|
114
|
-
@pending_jobs ||= QBWC.pending_jobs(@company)
|
124
|
+
@pending_jobs ||= QBWC.pending_jobs(@company, self)
|
125
|
+
end
|
126
|
+
|
127
|
+
def complete_with_success
|
128
|
+
QBWC.session_complete_success.call(self) if QBWC.session_complete_success
|
115
129
|
end
|
116
130
|
|
117
131
|
def parse_response_header(response)
|
data/lib/qbwc/version.rb
CHANGED
data/lib/qbwc/worker.rb
CHANGED
@@ -9,6 +9,7 @@ class QBWCControllerTest < ActionController::TestCase
|
|
9
9
|
def setup
|
10
10
|
@routes = Rails.application.routes # https://github.com/blowmage/minitest-rails/issues/133#issuecomment-36401436
|
11
11
|
@controller = QbwcController.new # http://stackoverflow.com/a/7743176
|
12
|
+
@session = QBWC::Session.new('foo', '')
|
12
13
|
|
13
14
|
@controller.prepend_view_path("#{Gem::Specification.find_by_name("wash_out").gem_dir}/app/views")
|
14
15
|
#p @controller.view_paths
|
@@ -21,6 +22,11 @@ class QBWCControllerTest < ActionController::TestCase
|
|
21
22
|
$HANDLE_RESPONSE_EXECUTED = false
|
22
23
|
end
|
23
24
|
|
25
|
+
def teardown
|
26
|
+
QBWC.session_initializer = nil
|
27
|
+
QBWC.session_complete_success = nil
|
28
|
+
end
|
29
|
+
|
24
30
|
test "qwc" do
|
25
31
|
#_inspect_routes
|
26
32
|
process(:qwc)
|
@@ -31,17 +37,18 @@ class QBWCControllerTest < ActionController::TestCase
|
|
31
37
|
assert_match /AppDescription.*Quickbooks integration.*AppDescription/, @response.body
|
32
38
|
assert_match /AppSupport.*https:\/\/test.host\/.*AppSupport/, @response.body
|
33
39
|
assert_match /UserName.*#{QBWC_USERNAME}.*UserName/, @response.body
|
40
|
+
assert_match /FileID.*{90A44FB5-33D9-4815-AC85-BC87A7E7D1EB}.*FileID/, @response.body
|
34
41
|
end
|
35
42
|
|
36
43
|
test "authenticate with no jobs" do
|
37
44
|
_authenticate
|
38
|
-
assert_equal 0, QBWC.pending_jobs(COMPANY).count
|
45
|
+
assert_equal 0, QBWC.pending_jobs(COMPANY, @session).count
|
39
46
|
assert @response.body.include?(QBWC::Controller::AUTHENTICATE_NO_WORK), @response.body
|
40
47
|
end
|
41
48
|
|
42
49
|
test "authenticate with jobs" do
|
43
50
|
_authenticate_with_queued_job
|
44
|
-
assert_equal 1, QBWC.pending_jobs(COMPANY).count
|
51
|
+
assert_equal 1, QBWC.pending_jobs(COMPANY, @session).count
|
45
52
|
assert @response.body.include?(COMPANY), @response.body
|
46
53
|
end
|
47
54
|
|
@@ -102,7 +109,7 @@ class QBWCControllerTest < ActionController::TestCase
|
|
102
109
|
raise "#{tag} is not correct" if expected_value != value && ! expected_value.blank?
|
103
110
|
end
|
104
111
|
|
105
|
-
def requests(job)
|
112
|
+
def requests(job, session, data)
|
106
113
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
107
114
|
end
|
108
115
|
|
@@ -153,5 +160,34 @@ class QBWCControllerTest < ActionController::TestCase
|
|
153
160
|
_receive_response_error_helper(50, true)
|
154
161
|
end
|
155
162
|
|
163
|
+
|
164
|
+
test "session_complete_success block called upon successful completion" do
|
165
|
+
block_called = false
|
166
|
+
QBWC.on_error = :stop
|
167
|
+
QBWC.set_session_complete_success do |session|
|
168
|
+
block_called = true
|
169
|
+
assert_not_nil session
|
170
|
+
assert_equal QBWC_USERNAME, session.user
|
171
|
+
assert_equal 100, session.progress
|
172
|
+
assert_not_nil session.began_at
|
173
|
+
end
|
174
|
+
|
175
|
+
_authenticate_with_queued_job
|
176
|
+
_simulate_soap_request('receive_response', RECEIVE_RESPONSE_SOAP_ACTION, RECEIVE_RESPONSE_PARAMS)
|
177
|
+
assert block_called
|
178
|
+
end
|
179
|
+
|
180
|
+
test "session_complete_success block not called upon failed completion" do
|
181
|
+
block_called = false
|
182
|
+
QBWC.on_error = :stop
|
183
|
+
QBWC.session_complete_success = lambda do |session|
|
184
|
+
block_called = true
|
185
|
+
end
|
186
|
+
|
187
|
+
_authenticate_with_queued_job
|
188
|
+
_simulate_soap_request('receive_response', RECEIVE_RESPONSE_SOAP_ACTION, RECEIVE_RESPONSE_ERROR_PARAMS)
|
189
|
+
assert !block_called
|
190
|
+
end
|
191
|
+
|
156
192
|
end
|
157
193
|
|
@@ -3,10 +3,14 @@ require 'test_helper.rb'
|
|
3
3
|
|
4
4
|
class JobManagementTest < ActionDispatch::IntegrationTest
|
5
5
|
|
6
|
+
REQUESTS_AS_HASH = {:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
7
|
+
REQUESTS_AS_STRING = QBWC_CUSTOMER_ADD_RQ
|
8
|
+
|
6
9
|
def setup
|
7
10
|
JobManagementTest.app = Rails.application
|
8
11
|
Rails.logger = Logger.new('/dev/null') # or STDOUT
|
9
12
|
QBWC.clear_jobs
|
13
|
+
@session = QBWC::Session.new('foo', '')
|
10
14
|
end
|
11
15
|
|
12
16
|
test "add_job" do
|
@@ -18,7 +22,57 @@ class JobManagementTest < ActionDispatch::IntegrationTest
|
|
18
22
|
assert_equal 1, QBWC.jobs.length
|
19
23
|
end
|
20
24
|
|
25
|
+
test "add_job requests as hash" do
|
26
|
+
QBWC.add_job(:integration_test, true, '', QBWC::Worker, REQUESTS_AS_HASH)
|
27
|
+
assert_equal 1, QBWC.jobs.length
|
28
|
+
end
|
29
|
+
|
30
|
+
test "add_job requests as array of hashes" do
|
31
|
+
QBWC.add_job(:integration_test, true, '', QBWC::Worker, [REQUESTS_AS_HASH])
|
32
|
+
assert_equal 1, QBWC.jobs.length
|
33
|
+
end
|
34
|
+
|
35
|
+
test "add_job requests as string" do
|
36
|
+
QBWC.add_job(:integration_test, true, '', QBWC::Worker, REQUESTS_AS_STRING)
|
37
|
+
assert_equal 1, QBWC.jobs.length
|
38
|
+
end
|
39
|
+
|
40
|
+
test "add_job requests as array of strings" do
|
41
|
+
QBWC.add_job(:integration_test, true, '', QBWC::Worker, [REQUESTS_AS_STRING])
|
42
|
+
assert_equal 1, QBWC.jobs.length
|
43
|
+
end
|
44
|
+
|
45
|
+
test "requests" do
|
46
|
+
job = QBWC.add_job(:integration_test, true, '', QBWC::Worker)
|
47
|
+
session = QBWC::Session.new('foo', '')
|
48
|
+
assert_nil job.requests(session)
|
49
|
+
end
|
50
|
+
|
51
|
+
test "requests with default session" do
|
52
|
+
job = QBWC.add_job(:integration_test, true, '', QBWC::Worker)
|
53
|
+
session = QBWC::Session.new('foo', '')
|
54
|
+
assert_nil job.requests
|
55
|
+
end
|
56
|
+
|
57
|
+
test "next_request" do
|
58
|
+
job = QBWC.add_job(:integration_test, true, '', QBWC::Worker)
|
59
|
+
session = QBWC::Session.new('foo', '')
|
60
|
+
assert_nil job.next_request(session)
|
61
|
+
end
|
62
|
+
|
63
|
+
test "next_request with default session" do
|
64
|
+
job = QBWC.add_job(:integration_test, true, '', QBWC::Worker)
|
65
|
+
session = QBWC::Session.new('foo', '')
|
66
|
+
assert_nil job.next_request
|
67
|
+
end
|
68
|
+
|
21
69
|
test "pending_jobs" do
|
70
|
+
QBWC.add_job(:integration_test, true, 'my-company', QBWC::Worker)
|
71
|
+
assert_equal 1, QBWC.pending_jobs('my-company', @session).length
|
72
|
+
assert_empty QBWC.pending_jobs('another-company', @session)
|
73
|
+
end
|
74
|
+
|
75
|
+
test "pending_jobs with default session" do
|
22
76
|
QBWC.add_job(:integration_test, true, 'my-company', QBWC::Worker)
|
23
77
|
assert_equal 1, QBWC.pending_jobs('my-company').length
|
24
78
|
assert_empty QBWC.pending_jobs('another-company')
|
@@ -26,7 +80,7 @@ class JobManagementTest < ActionDispatch::IntegrationTest
|
|
26
80
|
|
27
81
|
test "pending_jobs_disabled" do
|
28
82
|
QBWC.add_job(:integration_test, false, 'my-company', QBWC::Worker)
|
29
|
-
assert_empty QBWC.pending_jobs('my-company')
|
83
|
+
assert_empty QBWC.pending_jobs('my-company', @session)
|
30
84
|
end
|
31
85
|
|
32
86
|
test "get_job" do
|
@@ -65,8 +119,8 @@ class JobManagementTest < ActionDispatch::IntegrationTest
|
|
65
119
|
end
|
66
120
|
|
67
121
|
class DeleteJobWorker < QBWC::Worker
|
68
|
-
def requests(job)
|
69
|
-
|
122
|
+
def requests(job, session, data)
|
123
|
+
REQUESTS_AS_HASH
|
70
124
|
end
|
71
125
|
|
72
126
|
def handle_response(resp, session, job, request, data)
|
@@ -76,11 +130,11 @@ class JobManagementTest < ActionDispatch::IntegrationTest
|
|
76
130
|
|
77
131
|
test "job deletes itself after running" do
|
78
132
|
QBWC.add_job(:job_deletes_itself_after_running, true, COMPANY, DeleteJobWorker)
|
79
|
-
assert_equal 1, QBWC.pending_jobs(COMPANY).length
|
80
133
|
session = QBWC::Session.new('foo', COMPANY)
|
134
|
+
assert_equal 1, QBWC.pending_jobs(COMPANY, session).length
|
81
135
|
assert_not_nil session.next_request
|
82
136
|
simulate_response(session)
|
83
|
-
assert_equal 0, QBWC.pending_jobs(COMPANY).length
|
137
|
+
assert_equal 0, QBWC.pending_jobs(COMPANY, session).length
|
84
138
|
end
|
85
139
|
|
86
140
|
end
|
@@ -15,7 +15,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
15
15
|
end
|
16
16
|
|
17
17
|
class NilRequestWorker < QBWC::Worker
|
18
|
-
def requests(job)
|
18
|
+
def requests(job, session, data)
|
19
19
|
nil
|
20
20
|
end
|
21
21
|
end
|
@@ -29,7 +29,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
29
29
|
end
|
30
30
|
|
31
31
|
class SingleRequestWorker < QBWC::Worker
|
32
|
-
def requests(job)
|
32
|
+
def requests(job, session, data)
|
33
33
|
$SINGLE_REQUESTS_INVOKED_COUNT += 1 if $SINGLE_REQUESTS_INVOKED_COUNT.is_a?(Integer)
|
34
34
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
35
35
|
end
|
@@ -47,7 +47,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
47
47
|
end
|
48
48
|
|
49
49
|
class SingleStringRequestWorker < QBWC::Worker
|
50
|
-
def requests(job)
|
50
|
+
def requests(job, session, data)
|
51
51
|
$SINGLE_REQUESTS_INVOKED_COUNT += 1 if $SINGLE_REQUESTS_INVOKED_COUNT.is_a?(Integer)
|
52
52
|
QBWC_CUSTOMER_QUERY_RQ
|
53
53
|
end
|
@@ -65,7 +65,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
65
65
|
end
|
66
66
|
|
67
67
|
class MultipleRequestWorker < QBWC::Worker
|
68
|
-
def requests(job)
|
68
|
+
def requests(job, session, data)
|
69
69
|
$MULTIPLE_REQUESTS_INVOKED_COUNT += 1 if $MULTIPLE_REQUESTS_INVOKED_COUNT.is_a?(Integer)
|
70
70
|
[
|
71
71
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}},
|
@@ -97,9 +97,9 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
97
97
|
|
98
98
|
# requests should be generated once per session
|
99
99
|
session2 = QBWC::Session.new('foo', '')
|
100
|
-
assert_not_nil session2.
|
100
|
+
assert_not_nil session2.next_request
|
101
101
|
simulate_response(session2)
|
102
|
-
assert_not_nil session2.
|
102
|
+
assert_not_nil session2.next_request
|
103
103
|
simulate_response(session2)
|
104
104
|
assert_nil session2.next
|
105
105
|
|
@@ -113,7 +113,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
113
113
|
{:customer_query_rq => {:full_name => 'Quigley Brian Wally Colin'}},
|
114
114
|
]
|
115
115
|
|
116
|
-
def requests(job)
|
116
|
+
def requests(job, session, data)
|
117
117
|
$REQUESTS_FROM_DB
|
118
118
|
end
|
119
119
|
|
@@ -178,12 +178,14 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
178
178
|
QBWC.jobs.each {|job| assert job.requests_provided_when_job_added == (job.name == 'integration_test_2')}
|
179
179
|
session = QBWC::Session.new('foo', '')
|
180
180
|
|
181
|
+
assert_equal 2, QBWC.pending_jobs('', session).count
|
182
|
+
|
181
183
|
# one request from SingleRequestWorker
|
182
|
-
assert_not_nil session.
|
184
|
+
assert_not_nil session.next_request
|
183
185
|
simulate_response(session)
|
184
186
|
|
185
187
|
# Requests from MultipleRequestWorker are suppressed; instead use one request passed when job added
|
186
|
-
assert_not_nil session.
|
188
|
+
assert_not_nil session.next_request
|
187
189
|
simulate_response(session)
|
188
190
|
assert_nil session.next
|
189
191
|
|
@@ -206,14 +208,14 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
206
208
|
end
|
207
209
|
|
208
210
|
class ShouldntRunWorker < QBWC::Worker
|
209
|
-
def requests(job)
|
211
|
+
def requests(job, session, data)
|
210
212
|
[
|
211
213
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}},
|
212
214
|
{:customer_query_rq => {:full_name => 'Quentin Billy Wyatt Charles'}}
|
213
215
|
]
|
214
216
|
end
|
215
217
|
|
216
|
-
def should_run?(job)
|
218
|
+
def should_run?(job, session, data)
|
217
219
|
false
|
218
220
|
end
|
219
221
|
end
|
@@ -226,7 +228,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
226
228
|
|
227
229
|
$VARIABLE_REQUEST_COUNT = 2
|
228
230
|
class VariableRequestWorker < QBWC::Worker
|
229
|
-
def requests(job)
|
231
|
+
def requests(job, session, data)
|
230
232
|
r = []
|
231
233
|
$VARIABLE_REQUEST_COUNT.times do
|
232
234
|
r << {:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
@@ -263,7 +265,7 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
263
265
|
simulate_response(session)
|
264
266
|
assert_nil session.next_request
|
265
267
|
|
266
|
-
assert_match /CustomerAddRq.*\/CustomerAddRq/m, QBWC::ActiveRecord::Job::QbwcJob.first[
|
268
|
+
assert_match /CustomerAddRq.*\/CustomerAddRq/m, extract_request(QBWC::ActiveRecord::Job::QbwcJob.first, session)[0]
|
267
269
|
QBWC.jobs.each {|job| assert job.requests_provided_when_job_added == true}
|
268
270
|
end
|
269
271
|
|
@@ -293,9 +295,11 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
293
295
|
|
294
296
|
session = QBWC::Session.new('foo', '')
|
295
297
|
request = session.next_request
|
298
|
+
assert_not_nil request
|
296
299
|
assert_match /FullName.#{QBWC_USERNAME}.\/FullName/, request.request
|
297
300
|
|
298
|
-
|
301
|
+
expected = {[nil, ""] => [{:customer_query_rq => {:full_name => QBWC_USERNAME}}]}
|
302
|
+
assert_equal expected, QBWC::ActiveRecord::Job::QbwcJob.first[:requests]
|
299
303
|
QBWC.jobs.each {|job| assert job.requests_provided_when_job_added == true}
|
300
304
|
end
|
301
305
|
|
@@ -332,9 +336,21 @@ class RequestGenerationTest < ActionDispatch::IntegrationTest
|
|
332
336
|
|
333
337
|
assert_nil session.next_request
|
334
338
|
|
335
|
-
assert_equal multiple_requests[0], QBWC::ActiveRecord::Job::QbwcJob.first[
|
336
|
-
assert_equal multiple_requests[1], QBWC::ActiveRecord::Job::QbwcJob.first[
|
339
|
+
assert_equal multiple_requests[0], extract_request(QBWC::ActiveRecord::Job::QbwcJob.first, session)[0]
|
340
|
+
assert_equal multiple_requests[1], extract_request(QBWC::ActiveRecord::Job::QbwcJob.first, session)[1]
|
337
341
|
QBWC.jobs.each {|job| assert job.requests_provided_when_job_added == true}
|
338
342
|
end
|
339
343
|
|
344
|
+
|
345
|
+
def extract_request(ar_job, session)
|
346
|
+
requests = ar_job[:requests]
|
347
|
+
secondary_key = session.key.dup
|
348
|
+
secondary_key[0] = nil # username = nil
|
349
|
+
result = nil
|
350
|
+
[session.key, secondary_key].each do |k|
|
351
|
+
result ||= (requests || {})[k]
|
352
|
+
end
|
353
|
+
result
|
354
|
+
end
|
355
|
+
|
340
356
|
end
|
@@ -74,7 +74,7 @@ class ResponseTest < ActionDispatch::IntegrationTest
|
|
74
74
|
end
|
75
75
|
|
76
76
|
class HandleResponseWithDataWorker < QBWC::Worker
|
77
|
-
def requests(job)
|
77
|
+
def requests(job, session, data)
|
78
78
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
79
79
|
end
|
80
80
|
def handle_response(response, session, job, request, data)
|
@@ -95,7 +95,7 @@ class ResponseTest < ActionDispatch::IntegrationTest
|
|
95
95
|
end
|
96
96
|
|
97
97
|
class HandleResponseRaisesExceptionWorker < QBWC::Worker
|
98
|
-
def requests(job)
|
98
|
+
def requests(job, session, data)
|
99
99
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
100
100
|
end
|
101
101
|
def handle_response(response, session, job, request, data)
|
@@ -113,7 +113,7 @@ class ResponseTest < ActionDispatch::IntegrationTest
|
|
113
113
|
end
|
114
114
|
|
115
115
|
class HandleResponseOmitsJobWorker < QBWC::Worker
|
116
|
-
def requests(job)
|
116
|
+
def requests(job, session, data)
|
117
117
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
118
118
|
end
|
119
119
|
def handle_response(*response)
|
@@ -131,7 +131,7 @@ class ResponseTest < ActionDispatch::IntegrationTest
|
|
131
131
|
end
|
132
132
|
|
133
133
|
class QueryAndDeleteWorker < QBWC::Worker
|
134
|
-
def requests(job)
|
134
|
+
def requests(job, session, data)
|
135
135
|
{:name => 'mrjoecustomer'}
|
136
136
|
end
|
137
137
|
|
@@ -211,7 +211,7 @@ class ResponseTest < ActionDispatch::IntegrationTest
|
|
211
211
|
end
|
212
212
|
|
213
213
|
class MultiRequestWorker < QBWC::Worker
|
214
|
-
def requests(job)
|
214
|
+
def requests(job, session, data)
|
215
215
|
[
|
216
216
|
{:customer_query_rq => {:full_name => 'First Request'}},
|
217
217
|
{:customer_query_rq => {:full_name => 'Second Request'}},
|
@@ -9,7 +9,7 @@ class SessionTest < ActionDispatch::IntegrationTest
|
|
9
9
|
end
|
10
10
|
|
11
11
|
class ProgressTestWorker < QBWC::Worker
|
12
|
-
def requests(job)
|
12
|
+
def requests(job, session, data)
|
13
13
|
{:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
|
14
14
|
end
|
15
15
|
end
|
@@ -20,11 +20,11 @@ class SessionTest < ActionDispatch::IntegrationTest
|
|
20
20
|
QBWC.add_job(:session_test_1, true, COMPANY, ProgressTestWorker)
|
21
21
|
QBWC.add_job(:session_test_2, true, COMPANY, ProgressTestWorker)
|
22
22
|
|
23
|
-
assert_equal 2, QBWC.jobs.count
|
24
|
-
assert_equal 2, QBWC.pending_jobs(COMPANY).count
|
25
|
-
|
26
23
|
session = QBWC::Session.new(nil, COMPANY)
|
27
24
|
|
25
|
+
assert_equal 2, QBWC.jobs.count
|
26
|
+
assert_equal 2, QBWC.pending_jobs(COMPANY, session).count
|
27
|
+
|
28
28
|
# Simulate controller 1st send_request and receive_response
|
29
29
|
request = session.current_request
|
30
30
|
session.response = QBWC_CUSTOMER_QUERY_RESPONSE_INFO
|
@@ -42,11 +42,11 @@ class SessionTest < ActionDispatch::IntegrationTest
|
|
42
42
|
QBWC.add_job(:session_test_1, true, COMPANY, QBWC::Worker, QBWC_CUSTOMER_ADD_RQ)
|
43
43
|
QBWC.add_job(:session_test_2, true, COMPANY, QBWC::Worker, QBWC_CUSTOMER_QUERY_RQ)
|
44
44
|
|
45
|
-
assert_equal 2, QBWC.jobs.count
|
46
|
-
assert_equal 2, QBWC.pending_jobs(COMPANY).count
|
47
|
-
|
48
45
|
session = QBWC::Session.new(nil, COMPANY)
|
49
46
|
|
47
|
+
assert_equal 2, QBWC.jobs.count
|
48
|
+
assert_equal 2, QBWC.pending_jobs(COMPANY, session).count
|
49
|
+
|
50
50
|
# Simulate controller 1st send_request and receive_response
|
51
51
|
request = session.current_request
|
52
52
|
session.response = QBWC_CUSTOMER_ADD_RESPONSE_LONG
|
@@ -63,8 +63,12 @@ class SessionTest < ActionDispatch::IntegrationTest
|
|
63
63
|
# Add a job and pass a request
|
64
64
|
QBWC.add_job(:add_joe_customer, true, COMPANY, QBWC::Worker, QBWC_CUSTOMER_ADD_RQ_LONG)
|
65
65
|
|
66
|
+
# Simulate controller receive_response
|
67
|
+
session = QBWC::Session.new(nil, COMPANY)
|
68
|
+
session.response = QBWC_CUSTOMER_ADD_RESPONSE_LONG
|
69
|
+
|
66
70
|
assert_equal 1, QBWC.jobs.count
|
67
|
-
assert_equal 1, QBWC.pending_jobs(COMPANY).count
|
71
|
+
assert_equal 1, QBWC.pending_jobs(COMPANY, session).count
|
68
72
|
|
69
73
|
# Omit these controller calls that normally occur during a QuickBooks Web Connector session:
|
70
74
|
# - server_version
|
@@ -72,10 +76,6 @@ class SessionTest < ActionDispatch::IntegrationTest
|
|
72
76
|
# - authenticate
|
73
77
|
# - send_request
|
74
78
|
|
75
|
-
# Simulate controller receive_response
|
76
|
-
session = QBWC::Session.new(nil, COMPANY)
|
77
|
-
session.response = QBWC_CUSTOMER_ADD_RESPONSE_LONG
|
78
|
-
|
79
79
|
assert_equal 100, session.progress
|
80
80
|
end
|
81
81
|
|
@@ -83,12 +83,48 @@ class SessionTest < ActionDispatch::IntegrationTest
|
|
83
83
|
|
84
84
|
QBWC.add_job(:add_joe_customer, true, COMPANY, QBWC::Worker, [])
|
85
85
|
|
86
|
+
session = QBWC::Session.new(nil, COMPANY)
|
87
|
+
|
86
88
|
assert_equal 1, QBWC.jobs.count
|
87
|
-
assert_equal 1, QBWC.pending_jobs(COMPANY).count
|
89
|
+
assert_equal 1, QBWC.pending_jobs(COMPANY, session).count
|
88
90
|
|
89
91
|
# Simulate controller send_request
|
90
|
-
session = QBWC::Session.new(nil, COMPANY)
|
91
92
|
request = session.request_to_send
|
92
93
|
end
|
93
94
|
|
95
|
+
class ConditionalTestWorker < QBWC::Worker
|
96
|
+
def should_run?(job, session, data)
|
97
|
+
session.user != "margaret"
|
98
|
+
end
|
99
|
+
|
100
|
+
def requests(job, session, data)
|
101
|
+
{:customer_query_rq => {:full_name => session.user}}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
test "worker can filter on user" do
|
106
|
+
QBWC.add_job(:session_test_1, true, COMPANY, ConditionalTestWorker)
|
107
|
+
|
108
|
+
timothy_session = QBWC::Session.new("timothy", COMPANY)
|
109
|
+
margaret_session = QBWC::Session.new("margaret", COMPANY)
|
110
|
+
susan_session = QBWC::Session.new("susan", COMPANY)
|
111
|
+
|
112
|
+
# Should run for everyone except margaret
|
113
|
+
assert_equal 1, QBWC.pending_jobs(COMPANY, timothy_session).count
|
114
|
+
assert_equal 0, QBWC.pending_jobs(COMPANY, margaret_session).count
|
115
|
+
assert_equal 1, QBWC.pending_jobs(COMPANY, susan_session).count
|
116
|
+
|
117
|
+
# Simulate requests
|
118
|
+
timothy_request = timothy_session.current_request
|
119
|
+
assert timothy_request.request.include?("timothy")
|
120
|
+
timothy_session.response = QBWC_CUSTOMER_QUERY_RESPONSE_INFO
|
121
|
+
assert_equal 100, timothy_session.progress
|
122
|
+
|
123
|
+
susan_request = susan_session.current_request
|
124
|
+
assert susan_request.request.include?("susan")
|
125
|
+
susan_session.response = QBWC_CUSTOMER_QUERY_RESPONSE_INFO
|
126
|
+
assert_equal 100, susan_session.progress
|
127
|
+
end
|
128
|
+
|
129
|
+
|
94
130
|
end
|
data/test/test_helper.rb
CHANGED
@@ -41,8 +41,12 @@ module QbwcTestApplication
|
|
41
41
|
end
|
42
42
|
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
43
43
|
require '../qbwc/lib/generators/qbwc/install/templates/db/migrate/create_qbwc_jobs'
|
44
|
+
require '../qbwc/lib/generators/qbwc/install/templates/db/migrate/index_qbwc_jobs'
|
45
|
+
require '../qbwc/lib/generators/qbwc/install/templates/db/migrate/change_request_index'
|
44
46
|
require '../qbwc/lib/generators/qbwc/install/templates/db/migrate/create_qbwc_sessions'
|
45
47
|
ActiveRecord::Migration.run(CreateQbwcJobs)
|
48
|
+
ActiveRecord::Migration.run(IndexQbwcJobs)
|
49
|
+
ActiveRecord::Migration.run(ChangeRequestIndex)
|
46
50
|
ActiveRecord::Migration.run(CreateQbwcSessions)
|
47
51
|
QBWC.configure do |c|
|
48
52
|
c.username = QBWC_USERNAME
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qbwc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Skryl
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2016-03-03 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: qbxml
|
@@ -209,6 +209,7 @@ files:
|
|
209
209
|
- ".gitignore"
|
210
210
|
- ".rspec"
|
211
211
|
- ".travis.yml"
|
212
|
+
- CHANGELOG.md
|
212
213
|
- Gemfile
|
213
214
|
- Guardfile
|
214
215
|
- LICENSE.txt
|
@@ -217,8 +218,11 @@ files:
|
|
217
218
|
- lib/generators/qbwc/install/install_generator.rb
|
218
219
|
- lib/generators/qbwc/install/templates/config/qbwc.rb
|
219
220
|
- lib/generators/qbwc/install/templates/controllers/qbwc_controller.rb
|
221
|
+
- lib/generators/qbwc/install/templates/db/migrate/change_request_index.rb
|
220
222
|
- lib/generators/qbwc/install/templates/db/migrate/create_qbwc_jobs.rb
|
221
223
|
- lib/generators/qbwc/install/templates/db/migrate/create_qbwc_sessions.rb
|
224
|
+
- lib/generators/qbwc/install/templates/db/migrate/index_qbwc_jobs.rb
|
225
|
+
- lib/generators/qbwc/install/templates/db/migrate/session_pending_jobs_text.rb
|
222
226
|
- lib/generators/qbwc/install/usage.md
|
223
227
|
- lib/qbwc.rb
|
224
228
|
- lib/qbwc/active_record.rb
|