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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29001e1940a32d3b067eccfb012a676fef8791e5
4
- data.tar.gz: 5700d148297caecaf087fb73c8ac4aebe27f2cba
3
+ metadata.gz: 5bbaec3ca34a9a960128b6933f41fc78682d8ba4
4
+ data.tar.gz: 7738ce71948875a6ea4a44753eddcfa37528ac64
5
5
  SHA512:
6
- metadata.gz: c12ab12caac68c60bbfc08977acc0c60346ee5d53870e45175ae1f02cd06d2237ed6b80e06a799129b8f41f5491ea00fae502fe74069d2d266b99e729ef15286
7
- data.tar.gz: 1bece5acbd95f05a7eaf06f23df0c2726718e1082571e630ac0ba8fe296b708c7727fdcafa8d914bc5eb7f0299f7dda735baaa64895730026b3d186e8cd136ba
6
+ metadata.gz: e8c027bfc0527d79c5b6bb2a5e1c19f68ef7be4ea90a4d0e39a3b111c62a12ac57ef601dac756f0e951887e4de53955a4b681bf5881b9b5e4e66c374c2cf7a0f
7
+ data.tar.gz: e52f3419dcc33fe1212600038f90586604603953a3c5a07795f8598e9fe55e8ffbc0018dc6fb18f8ea7ebfe72266a09087a174b081cc88a1025cc3a00fe69120
@@ -4,3 +4,5 @@ rvm:
4
4
  - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
+ before_install:
8
+ - gem update bundler
@@ -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 `OwnerID` (any GUID will do) before giving it to QuickBooks Web Connector.
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
- def handle_response(r, session, job, request, data)
84
- QBWC.delete_job(job)
85
- end
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
- def requests(job)
110
- {
111
- :customer_query_rq => {
112
- :xml_attributes => { "requestID" =>"1", 'iterator' => "Start" },
113
- :max_returned => 100
114
- }
115
- }
116
- end
117
-
118
- def handle_response(r, session, job, request, data)
119
- # handle_response will get customers in groups of 100. When this is 0, we're done.
120
- complete = r['xml_attributes']['iteratorRemainingCount'] == '0'
121
-
122
- r['customer_ret'].each do |qb_cus|
123
- qb_id = qb_cus['list_id']
124
- qb_name = qb_cus['name']
125
- Rails.logger.info("#{qb_id} #{qb_name}")
126
- end
127
- end
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
- ### Referencing memory values when constructing requests ###
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
- A `QBWC::Worker#requests` method cannot access values that are in-memory (global variables, local variables, model attributes, etc.) at the time that `QBWC.add_job` is called; however, in lieu of using `QBWC::Worker#requests`, you can construct and pass requests directly to `QBWC.add_job` (`Hash`, `String`, or array of `Hash`es and `String`s). These requests will be immediately persisted by `QBWC.add_job` (in contrast to requests constructed by `QBWC::Worker#requests`, which are persisted during a QuickBooks Web Connector session).
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
- If requests are passed to `QBWC.add_job`, the `requests` method on your worker will be ignored.
165
+ # ...
140
166
 
141
- ### Referencing memory values when handling responses ###
167
+ def handle_response(r, session, job, request, data)
168
+ # data here is "something important"
169
+ end
142
170
 
143
- Similarly, a `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 immediately be persisted by `QBWC.add_job`, then later passed to `QBWC::Worker#handle_response` during a QuickBooks Web Connector session.
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
- require 'qbwc'
190
+ require 'qbwc'
162
191
 
163
- QBWC.set_session_initializer() do |session|
164
- puts "New QuickBooks Web Connector session has been established (overridden session initializer)"
165
- @information_from_jobs = {}
166
- end if the_application_needs_a_different_session_initializer
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
- QBWC.add_job(:list_customers, false, '', CustomerTestWorker)
197
+ QBWC.add_job(:list_customers, false, '', CustomerTestWorker)
169
198
 
170
199
  ```
171
200
 
172
- 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.
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("wash_out :#{controller_name}")
34
- route("get '#{controller_name}/qwc' => '#{controller_name}#qwc'")
35
- route("get '#{controller_name}/action' => '#{controller_name}#_generate_wsdl'")
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
@@ -0,0 +1,5 @@
1
+ class ChangeRequestIndex < ActiveRecord::Migration
2
+ def change
3
+ change_column :qbwc_jobs, :request_index, :text, null: true, default: nil
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class IndexQbwcJobs < ActiveRecord::Migration
2
+ def change
3
+ add_index :qbwc_jobs, :name, unique: true
4
+ add_index :qbwc_jobs, :company, length: 150
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class SessionPendingJobsText < ActiveRecord::Migration
2
+ def change
3
+ change_column_default(:qbwc_sessions, :pending_jobs, nil)
4
+ change_column :qbwc_sessions, :pending_jobs, :text, :limit => 1000, :null => false
5
+ end
6
+ end
@@ -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, Array
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
- jb.requests = requests.is_a?(Array) ? requests : [requests] unless requests.nil?
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=(r)
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 request_index=(nr)
91
- find_ar_job.update_all(:request_index => nr)
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 advance_next_request
95
- nr = request_index
96
- self.request_index = nr + 1
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
@@ -72,14 +72,14 @@ SB
72
72
 
73
73
  qwc = <<QWC
74
74
  <QBWCXML>
75
- <AppName>#{Rails.application.class.parent_name} #{Rails.env} #{@app_name_suffix}</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>{90A44FB5-33D9-4815-AC85-BC87A7E7D1EB}</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
- QBWC.session_initializer.call(get_session(ticket)) unless QBWC.session_initializer.nil?
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])
@@ -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
- @request_index = 0
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
- completed_request = requests[request_index]
22
- advance_next_request if advance
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
- self.request_index = new_index
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
- @requests
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=(r)
60
- @requests = r
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 (requests.nil? || requests.empty?) && ! self.requests_provided_when_job_added
90
- r = worker.requests(self)
91
- r = [r] unless r.nil? || r.is_a?(Array)
92
- self.requests = r
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 '#{requests}'.") if QBWC.log_requests_and_responses
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? || requests.nil? || ri >= requests.length
99
- nr = requests[ri]
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
- self.request_index = 0
107
- self.requests = [] unless self.requests_provided_when_job_added
122
+ @request_index = {}
123
+ @requests = {} unless self.requests_provided_when_job_added
108
124
  end
109
125
 
110
126
  end
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module QBWC
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,11 +1,11 @@
1
1
  module QBWC
2
2
  class Worker
3
3
 
4
- def requests(job)
4
+ def requests(job, session, data)
5
5
  []
6
6
  end
7
7
 
8
- def should_run?(job)
8
+ def should_run?(job, session, data)
9
9
  true
10
10
  end
11
11
 
@@ -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
- {:customer_query_rq => {:full_name => 'Quincy Bob William Carlos'}}
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.next
100
+ assert_not_nil session2.next_request
101
101
  simulate_response(session2)
102
- assert_not_nil session2.next
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.next
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.next
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[:requests][0]
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
- assert_equal [{:customer_query_rq => {:full_name => QBWC_USERNAME}}], QBWC::ActiveRecord::Job::QbwcJob.first[:requests]
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[:requests][0]
336
- assert_equal multiple_requests[1], QBWC::ActiveRecord::Job::QbwcJob.first[:requests][1]
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
@@ -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: 0.1.0
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: 2015-04-04 00:00:00.000000000 Z
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