effective_qb_sync 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +94 -0
  4. data/Rakefile +21 -0
  5. data/app/controllers/admin/qb_syncs_controller.rb +60 -0
  6. data/app/controllers/effective/qb_sync_controller.rb +40 -0
  7. data/app/models/effective/access_denied.rb +17 -0
  8. data/app/models/effective/datatables/qb_syncs.rb +30 -0
  9. data/app/models/effective/qb_log.rb +13 -0
  10. data/app/models/effective/qb_machine.rb +281 -0
  11. data/app/models/effective/qb_order_item.rb +13 -0
  12. data/app/models/effective/qb_order_items_form.rb +55 -0
  13. data/app/models/effective/qb_request.rb +262 -0
  14. data/app/models/effective/qb_ticket.rb +55 -0
  15. data/app/models/effective/qbwc_supervisor.rb +89 -0
  16. data/app/views/admin/qb_syncs/_actions.html.haml +2 -0
  17. data/app/views/admin/qb_syncs/_qb_item_names.html.haml +9 -0
  18. data/app/views/admin/qb_syncs/index.html.haml +24 -0
  19. data/app/views/admin/qb_syncs/instructions.html.haml +136 -0
  20. data/app/views/admin/qb_syncs/show.html.haml +52 -0
  21. data/app/views/effective/orders_mailer/qb_sync_error.html.haml +56 -0
  22. data/app/views/effective/qb_sync/authenticate.erb +12 -0
  23. data/app/views/effective/qb_sync/clientVersion.erb +8 -0
  24. data/app/views/effective/qb_sync/closeConnection.erb +8 -0
  25. data/app/views/effective/qb_sync/connectionError.erb +9 -0
  26. data/app/views/effective/qb_sync/getLastError.erb +9 -0
  27. data/app/views/effective/qb_sync/receiveResponseXML.erb +8 -0
  28. data/app/views/effective/qb_sync/sendRequestXML.erb +8 -0
  29. data/app/views/effective/qb_sync/serverVersion.erb +8 -0
  30. data/app/views/effective/qb_web_connector/quickbooks.qwc.erb +12 -0
  31. data/config/routes.rb +16 -0
  32. data/db/migrate/01_create_effective_qb_sync.rb.erb +68 -0
  33. data/lib/effective_qb_sync/engine.rb +42 -0
  34. data/lib/effective_qb_sync/version.rb +3 -0
  35. data/lib/effective_qb_sync.rb +42 -0
  36. data/lib/generators/effective_qb_sync/install_generator.rb +42 -0
  37. data/lib/generators/templates/effective_qb_sync.rb +61 -0
  38. data/lib/generators/templates/effective_qb_sync_mailer_preview.rb +39 -0
  39. data/spec/dummy/README.rdoc +8 -0
  40. data/spec/dummy/Rakefile +6 -0
  41. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  42. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  43. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  44. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  45. data/spec/dummy/app/models/product.rb +14 -0
  46. data/spec/dummy/app/models/product_with_float_price.rb +13 -0
  47. data/spec/dummy/app/models/user.rb +14 -0
  48. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  49. data/spec/dummy/bin/bundle +3 -0
  50. data/spec/dummy/bin/rails +4 -0
  51. data/spec/dummy/bin/rake +4 -0
  52. data/spec/dummy/config/application.rb +32 -0
  53. data/spec/dummy/config/boot.rb +5 -0
  54. data/spec/dummy/config/database.yml +25 -0
  55. data/spec/dummy/config/environment.rb +5 -0
  56. data/spec/dummy/config/environments/development.rb +37 -0
  57. data/spec/dummy/config/environments/production.rb +80 -0
  58. data/spec/dummy/config/environments/test.rb +36 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  61. data/spec/dummy/config/initializers/devise.rb +254 -0
  62. data/spec/dummy/config/initializers/effective_addresses.rb +15 -0
  63. data/spec/dummy/config/initializers/effective_orders.rb +154 -0
  64. data/spec/dummy/config/initializers/effective_qb_sync.rb +41 -0
  65. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  66. data/spec/dummy/config/initializers/inflections.rb +16 -0
  67. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  68. data/spec/dummy/config/initializers/session_store.rb +3 -0
  69. data/spec/dummy/config/initializers/simple_form.rb +189 -0
  70. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  71. data/spec/dummy/config/locales/en.yml +23 -0
  72. data/spec/dummy/config/routes.rb +3 -0
  73. data/spec/dummy/config/secrets.yml +22 -0
  74. data/spec/dummy/config.ru +4 -0
  75. data/spec/dummy/db/schema.rb +208 -0
  76. data/spec/dummy/db/test.sqlite3 +0 -0
  77. data/spec/dummy/log/development.log +90 -0
  78. data/spec/dummy/log/test.log +1 -0
  79. data/spec/dummy/public/404.html +67 -0
  80. data/spec/dummy/public/422.html +67 -0
  81. data/spec/dummy/public/500.html +66 -0
  82. data/spec/dummy/public/favicon.ico +0 -0
  83. data/spec/fixtures/qbxml_response_error.xml +6 -0
  84. data/spec/fixtures/qbxml_response_success.xml +621 -0
  85. data/spec/models/acts_as_purchasable_spec.rb +131 -0
  86. data/spec/models/factories_spec.rb +32 -0
  87. data/spec/models/qb_machine_spec.rb +554 -0
  88. data/spec/models/qb_request_spec.rb +327 -0
  89. data/spec/models/qb_ticket_spec.rb +62 -0
  90. data/spec/spec_helper.rb +45 -0
  91. data/spec/support/factories.rb +97 -0
  92. metadata +397 -0
@@ -0,0 +1,327 @@
1
+ require 'spec_helper'
2
+
3
+ module Effective::QbRequestSpecHelper
4
+
5
+ # valid attributes for qb requests
6
+ def valid_request_attributes
7
+ {
8
+ :state=>'Processing',
9
+ :qb_ticket => Effective::QbTicket.new,
10
+ :order => Effective::Order.new,
11
+ :request_type=>'OrderItemSynchronization'
12
+ }
13
+ end
14
+
15
+ end
16
+
17
+ describe Effective::QbRequest, "Generating Request QbXML" do
18
+
19
+ include Effective::QbRequestSpecHelper
20
+
21
+ before :each do
22
+ # let's generate an order that the request will need to use.
23
+ @order = FactoryGirl.create(:purchased_order)
24
+ @user = @order.user
25
+
26
+ @qb_request = Effective::QbRequest.new(valid_request_attributes)
27
+ @qb_request.order = @order
28
+ @qb_request.save!
29
+ end
30
+
31
+ # safety check before we get crazy
32
+ it "should be valid" do
33
+ @qb_request.should be_valid
34
+ end
35
+
36
+ it "should generate valid qb_xml for the CustomerQuery state" do
37
+ @qb_request.state = 'CustomerQuery'
38
+ @qb_request.should be_valid
39
+ qb_xml = @qb_request.generate_request_xml
40
+
41
+ @doc = Nokogiri::XML(qb_xml)
42
+
43
+ @doc.xpath("//CustomerQueryRq").first["requestID"].should == (@qb_request.id.to_s)
44
+
45
+ @doc.at_xpath("//CustomerQueryRq//FullName").content.should eq(@order.billing_name)
46
+ end
47
+
48
+ it "should generate valid qb_xml for the CreateCustomer state" do
49
+ @qb_request.state = 'CreateCustomer'
50
+ @qb_request.should be_valid
51
+ qb_xml = @qb_request.generate_request_xml
52
+
53
+ @doc = Nokogiri::XML(qb_xml)
54
+
55
+ @doc.xpath("//CustomerAddRq").first["requestID"].should == (@qb_request.id.to_s)
56
+
57
+ @doc.xpath("//CustomerAddRq//CustomerAdd").present?.should == true
58
+
59
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//Name").content.should eq(@order.billing_name)
60
+
61
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//FirstName").content.present?.should eq true
62
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//LastName").content.present?.should eq true
63
+
64
+ @doc.xpath("//CustomerAddRq//CustomerAdd//BillAddress").present?.should == true
65
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//BillAddress//Addr2").content.should eq(@order.billing_address.address1)
66
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//BillAddress//City").content.should eq(@order.billing_address.city)
67
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//BillAddress//PostalCode").content.should eq(@order.billing_address.postal_code)
68
+
69
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//Phone").content.should eq(@user.phone)
70
+ @doc.at_xpath("//CustomerAddRq//CustomerAdd//Email").content.should eq(@user.email)
71
+
72
+ end
73
+
74
+ it "should generate valid qb_xml for the OrderSync state" do
75
+ @qb_request.state = 'OrderSync'
76
+
77
+ @qb_request.should be_valid
78
+ qb_xml = @qb_request.generate_request_xml
79
+
80
+ @doc = Nokogiri::XML(qb_xml)
81
+
82
+ @doc.xpath("//SalesReceiptAddRq").first["requestID"].should == (@qb_request.id.to_s)
83
+
84
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd").present?.should == true
85
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//CustomerRef").present?.should == true
86
+
87
+ @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//CustomerRef//FullName").content.should eq(@order.billing_name)
88
+
89
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//TxnDate").present?.should == true
90
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//Memo").present?.should == true
91
+ @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//IsToBePrinted").content.should == 'false'
92
+ @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//IsToBeEmailed").content.should == 'false'
93
+
94
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd").present?.should == true
95
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//ItemRef").present?.should == true
96
+ @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//ItemRef//FullName").content.should eq(@order.order_items.first.qb_item_name)
97
+ @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//Desc").content.should eq(@order.order_items.first.title)
98
+ @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//Amount").content.to_f.should eq(@order.order_items.first.subtotal / 100.0)
99
+
100
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd").count.should == @order.order_items.length + 1
101
+
102
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd//Desc").count.should == @order.order_items.length + 1
103
+
104
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd//Desc").last.content.should eq(EffectiveQbSync.quickbooks_tax_name)
105
+ @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd//Amount").last.content.to_f.should eq(@order.tax / 100.0)
106
+ end
107
+
108
+ it "should raise an exception if there is no qb_item_name on the order_item" do
109
+ @qb_request.state = 'OrderSync'
110
+ allow(@qb_request.order.order_items.first).to receive(:qb_item_name).and_return(nil)
111
+
112
+ # This should raise an error
113
+ (@qb_request.generate_request_xml rescue :error).should eq :error
114
+ end
115
+
116
+ it "should raise an exception if there is no attached order to the request" do
117
+ @qb_request.order = nil
118
+ Effective::QbRequest::PROCESSING_STATES.each do |state|
119
+ @qb_request.state = state
120
+ (@qb_request.generate_request_xml rescue :failed).should eq :failed
121
+ end
122
+ end
123
+
124
+ it "handle_response_xml should transition to the CreateCustomer state if passed a 500 status Code" do
125
+ @qb_request.state = 'CustomerQuery'
126
+ @qb_request.should be_valid
127
+
128
+ @xml = "<root><CustomerQueryRs statusCode=\"500\"></CustomerQueryRs></root>"
129
+
130
+ @qb_request.handle_response_xml(@xml)
131
+
132
+ @qb_request.state.should == 'CreateCustomer'
133
+ end
134
+
135
+ it "handle_response_xml should transition to the OrderSync state if passed a non-500 status Code" do
136
+ @qb_request.state = 'CustomerQuery'
137
+ @qb_request.should be_valid
138
+
139
+ @xml = "<root><CustomerQueryRs statusCode=\"499\"></CustomerQueryRs></root>"
140
+
141
+ @qb_request.handle_response_xml(@xml)
142
+
143
+ @qb_request.state.should == 'OrderSync'
144
+ end
145
+
146
+ it "should be able to find the first response with a requestID" do
147
+ @xml = "<root><Something request=\"0\"></Something><AThing requestID=\"500\"></AThing><AThing requestID=\"300\"></AThing></root>"
148
+
149
+ Effective::QbRequest.find_first_response_having_a_request_id(@xml).attr('requestID').should eq('500')
150
+
151
+ end
152
+
153
+
154
+ it "handle_create_customer_response_xml should return true if passed a valid status code" do
155
+ customer_response_xml = "<root><CustomerAddRs statusCode=\"0\"></CustomerAddRs></root>"
156
+
157
+ @qb_request.handle_create_customer_response_xml(customer_response_xml).should eq(true)
158
+ end
159
+
160
+ it "should raise an error if malformed xml is passed" do
161
+ @customer_response_xml = "<root><noxml></noxml></root>"
162
+
163
+ (@qb_request.handle_create_customer_response_xml(@customer_response_xml) rescue :error).should eq :error
164
+ end
165
+
166
+ end
167
+
168
+ describe Effective::QbRequest do
169
+
170
+ include Effective::QbRequestSpecHelper
171
+
172
+ before(:each) do
173
+ @qbxml_success = File.read(Rails.root.to_s + '/../fixtures/qbxml_response_success.xml')
174
+
175
+ # let's generate an order that the request will need to use.
176
+ @order = FactoryGirl.create(:purchased_order)
177
+ @user = @order.user
178
+
179
+ @qb_request = Effective::QbRequest.new(valid_request_attributes)
180
+ @qb_request.order = @order
181
+ @qb_request.save!
182
+ end
183
+
184
+ it "should be valid" do
185
+ @qb_request.should be_valid
186
+ end
187
+
188
+ it "should show an error on missing QbTicket" do
189
+ @qb_request.qb_ticket = nil
190
+ @qb_request.save
191
+ @qb_request.errors[:qb_ticket].present?.should eq true
192
+ end
193
+
194
+ it "should show an error if request type is OrderItemSynchronization and there is no order" do
195
+ @qb_request.attributes = valid_request_attributes
196
+ @qb_request.request_type = 'OrderItemSynchronization'
197
+ @qb_request.order = nil
198
+ @qb_request.save
199
+ @qb_request.errors[:order].present?.should eq true
200
+ end
201
+
202
+ it "should return Processing when state is empty" do
203
+ @qb_request.state = nil
204
+ @qb_request.state.should eq 'Processing'
205
+ end
206
+
207
+ it "should show an error on an invalid state" do
208
+ @attributes = valid_request_attributes
209
+ @attributes[:state] = 'InvalidState'
210
+
211
+ @qb_request.attributes = @attributes
212
+ @qb_request.save
213
+ @qb_request.errors[:state].present?.should eq true
214
+ end
215
+
216
+ it "should return a found record using response qb xml" do
217
+ allow(Effective::QbRequest).to receive(:find_by_id).and_return(@qb_request)
218
+ request = Effective::QbRequest.find_using_response_qbxml(@qbxml_success)
219
+ request.should eql(@qb_request)
220
+ end
221
+
222
+ it "should return nil if it cannot find the corresponding request using the response qb xml" do
223
+ response_qbxml = '<QBXML><QBXMLMsgsRs></QBXMLMsgsRs></QBXML>'
224
+ allow(Effective::QbRequest).to receive(:find_by_id).and_return(@qb_request)
225
+ request = Effective::QbRequest.find_using_response_qbxml(response_qbxml)
226
+ request.should be_nil
227
+ end
228
+ end
229
+
230
+ describe Effective::QbRequest, "Working with Synchronizing Orders" do
231
+
232
+ include Effective::QbRequestSpecHelper
233
+
234
+ # we will create an order with five order items attached to it
235
+ before :each do
236
+ @qb_machine = Effective::QbMachine.new
237
+
238
+ # let's generate an order that the request will need to use.
239
+ @order = FactoryGirl.create(:purchased_order)
240
+ @user = @order.user
241
+ end
242
+
243
+ it "Order should be valid" do
244
+ @order.should be_valid
245
+ end
246
+
247
+ it "test should verify that the order items are attached to the order" do
248
+ (Effective::Order.first.order_items.size > 1).should eq true
249
+ end
250
+
251
+ it "should return an empty array if there are no order items to be synchronized" do
252
+ Effective::Order.delete_all
253
+ requests = Effective::QbRequest.new_requests_for_unsynced_items
254
+ requests.should_not be_nil
255
+ requests.size.should eql(0)
256
+ end
257
+
258
+ it "should create a request for each order that has no corresponding QbRequest attached to it" do
259
+ requests = Effective::QbRequest.new_requests_for_unsynced_items
260
+ requests.size.should eql(1)
261
+ end
262
+
263
+ it "should not return a request for an OrderItem if its Order has a 'Failed' status" do
264
+ @order.purchase_state = 'declined'
265
+ @order.save(validate: false)
266
+
267
+ # return 0 requests because they all belong to the same Failed order
268
+ Effective::QbRequest.new_requests_for_unsynced_items.size.should eql(0)
269
+ end
270
+
271
+ it "should not return a request for an Order if a request has already been created for it" do
272
+ requests = Effective::QbRequest.new_requests_for_unsynced_items
273
+ request = requests.first
274
+
275
+ # save and persist this request
276
+ request.qb_ticket = @qb_machine.ticket
277
+ request.save!
278
+ request.transition_state('Finished') # This was changed for effective_qb_sync
279
+
280
+ new_requests = Effective::QbRequest.new_requests_for_unsynced_items
281
+ new_requests.size.should eql(requests.size-1)
282
+ end
283
+
284
+ it "should return an array of type QbRequest" do
285
+ Effective::QbRequest.new_requests_for_unsynced_items.each do |req|
286
+ req.class.should eql(Effective::QbRequest)
287
+ end
288
+ end
289
+
290
+ it "should return each request as having a member OrderItem" do
291
+ Effective::QbRequest.new_requests_for_unsynced_items.each do |req|
292
+ req.order.should_not be_nil
293
+ end
294
+ end
295
+
296
+ it "should return each OrderItem having the correct fields filled in" do
297
+ Effective::QbRequest.new_requests_for_unsynced_items.each do |req|
298
+ order_item = req.order.order_items.first
299
+
300
+ order_item.purchasable.kind_of?(Product).should eq true
301
+ order_item.qb_item_name.should eq 'Product'
302
+ order_item.price.should eq 1000
303
+ order_item.quantity.should eq 1
304
+ end
305
+ end
306
+
307
+ it 'should create one qb_order_item for each order_item' do
308
+ Effective::QbRequest.new_requests_for_unsynced_items.each do |req|
309
+ req.qb_ticket = Effective::QbTicket.new()
310
+ req.transition_to_finished
311
+
312
+ # One QbOrderItem per OrderItem
313
+ Effective::QbOrderItem.count.should eq req.order.order_items.length
314
+
315
+ Effective::OrderItem.all.each { |oi| oi.qb_order_item.present?.should eq true }
316
+ end
317
+ end
318
+
319
+ # it "should not return any OrderItem that has no QuickBooks item name" do
320
+ # requests = Effective::QbRequest.new_requests_for_unsynced_items
321
+ # Effective::OrderItem.update_all(:qb_item_name => '')
322
+ # new_requests = Effective::QbRequest.new_requests_for_unsynced_items
323
+
324
+ # requests.size.should_not eq new_requests.size
325
+ # end
326
+
327
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Effective::QbTicket do
4
+
5
+ before(:each) do
6
+ @qb_ticket = Effective::QbTicket.new
7
+ end
8
+
9
+ it "should be valid when initialized without any values" do
10
+ @qb_ticket.should be_valid
11
+ end
12
+
13
+ it "should report a zero percent by default" do
14
+ @qb_ticket.percent.should eql(0)
15
+ end
16
+
17
+ it "should report an error on state" do
18
+ @qb_ticket.state = nil
19
+ @qb_ticket.save
20
+ @qb_ticket.errors[:state].present?.should eq true
21
+ end
22
+
23
+ it "should start out in the Ready state" do
24
+ @qb_ticket.state.should eql('Ready')
25
+ end
26
+
27
+ it "should load the same one when finding by username" do
28
+ @qb_ticket.save
29
+ @ticket = Effective::QbTicket.find_by_username(@qb_ticket.username)
30
+ @ticket.id.should eql(@qb_ticket.id)
31
+ end
32
+
33
+ it "should be able to contain other QbRequests" do
34
+ @qb_ticket.save
35
+ @qb_request = Effective::QbRequest.new(order: Effective::Order.new, request_type: 'OrderItemSynchronization')
36
+ @qb_ticket.qb_requests.push @qb_request
37
+ @qb_ticket.save!
38
+
39
+ @qb_ticket.qb_requests.should_not be_empty
40
+ @qb_request.id.should_not be_nil
41
+ end
42
+
43
+ it "should return a recorded log message when #log is called" do
44
+ @qb_ticket.save
45
+ log = @qb_ticket.log('This is a log message')
46
+ log.should_not be_nil
47
+ log.should_not be_new_record # make sure it's saved
48
+ end
49
+
50
+ it "should increase the number of log messages when #log is called" do
51
+ @qb_ticket.save
52
+
53
+ @before = Effective::QbLog.count
54
+ @qb_ticket.log('This is a message')
55
+ @after = Effective::QbLog.count
56
+
57
+ @before.should eql(0)
58
+ @after.should eql(1)
59
+ @qb_ticket.qb_logs.count.should eql(1)
60
+ end
61
+
62
+ end
@@ -0,0 +1,45 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ require File.expand_path("../dummy/config/environment", __FILE__)
4
+
5
+ require 'rspec/rails'
6
+ require 'factory_girl_rails'
7
+ require 'pry'
8
+
9
+ # Requires supporting ruby files with custom matchers and macros, etc,
10
+ # in spec/support/ and its subdirectories.
11
+ Dir[Rails.root.join("../../spec/support/**/*.rb")].each {|f| require f }
12
+
13
+ RSpec.configure do |config|
14
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
15
+
16
+ config.include Devise::TestHelpers, :type => :controller
17
+
18
+ Rails.logger.level = 4 # Output only minimal stuff to test.log
19
+
20
+ config.expect_with(:rspec) { |c| c.syntax = :should }
21
+
22
+ config.use_transactional_fixtures = true # Make this false to once again use DatabaseCleaner
23
+ config.order = 'random'
24
+ end
25
+
26
+ class ActiveRecord::Base
27
+ mattr_accessor :shared_connection
28
+ @@shared_connection = nil
29
+
30
+ def self.connection
31
+ @@shared_connection || retrieve_connection
32
+ end
33
+ end
34
+
35
+ # Forces all threads to share the same connection. This works on
36
+ # Capybara because it starts the web server in a thread.
37
+ ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
38
+
39
+
40
+ # To set up this gem for testing:
41
+ # spec/dummy> ln -s ../../spec spec
42
+ #
43
+ # spec/dummy> rails generate effective_qb_sync:install
44
+ # spec/dummy> rake db:migrate
45
+ # spec/dummy> rake db:test:prepare
@@ -0,0 +1,97 @@
1
+ require 'factory_girl'
2
+
3
+ FactoryGirl.define do
4
+ factory :address, class: Effective::Address do
5
+ category 'billing'
6
+ full_name 'Peter Pan'
7
+ sequence(:address1) { |n| "1234#{n} Fake Street" }
8
+ city 'A canadian city'
9
+ state_code ['AB', 'BC', 'MB', 'NB', 'NL', 'NT', 'NS', 'ON', 'PE', 'QC', 'SK', 'YT', 'NU'].sample
10
+ country_code 'CA'
11
+ postal_code 'T5T2T1'
12
+ end
13
+
14
+ factory :product do # This only exists in the dummy/ app
15
+ sequence(:title) { |n| "Product #{n}" }
16
+
17
+ price 1000
18
+ tax_exempt false
19
+ end
20
+
21
+ factory :product_with_float_price do # This only exists in the dummy/ app
22
+ sequence(:title) { |n| "Product #{n}" }
23
+
24
+ price 10.00
25
+ tax_exempt false
26
+ end
27
+
28
+ factory :user do # This only exists in the dummy/ app
29
+ sequence(:email) { |n| "user_#{n}@effective_qb_sync.test"}
30
+
31
+ password '12345678'
32
+
33
+ after(:build) { |user| user.skip_confirmation! if user.respond_to?(:skip_confirmation!) }
34
+ end
35
+
36
+ factory :cart, class: Effective::Cart do
37
+ association :user
38
+
39
+ before(:create) do |cart|
40
+ 3.times { cart.cart_items << FactoryGirl.create(:cart_item, cart: cart) }
41
+ end
42
+ end
43
+
44
+ factory :cart_item, class: Effective::CartItem do
45
+ association :purchasable, factory: :product
46
+ association :cart, factory: :cart
47
+
48
+ quantity 1
49
+ end
50
+
51
+ factory :cart_with_items, class: Effective::Cart do
52
+ association :user
53
+
54
+ before(:create) do |cart|
55
+ 3.times { cart.cart_items << FactoryGirl.create(:cart_item, cart: cart) }
56
+ end
57
+ end
58
+
59
+ factory :order, class: Effective::Order do
60
+ association :user
61
+
62
+ before(:create) do |order|
63
+ order.billing_address = FactoryGirl.build(:address, addressable: order)
64
+ order.shipping_address = FactoryGirl.build(:address, addressable: order)
65
+
66
+ 3.times { order.order_items << FactoryGirl.create(:order_item, order: order) }
67
+ end
68
+ end
69
+
70
+ factory :order_item, class: Effective::OrderItem do
71
+ association :purchasable, factory: :product
72
+ association :order, factory: :order
73
+
74
+ sequence(:title) { |n| "Order Item #{n}" }
75
+ quantity 1
76
+ price 1000
77
+ tax_exempt false
78
+ end
79
+
80
+ factory :purchased_order, parent: :order do
81
+ payment_provider 'admin'
82
+ payment_card 'unknown'
83
+
84
+ after(:create) { |order| order.purchase! }
85
+ end
86
+
87
+ factory :declined_order, parent: :order do
88
+ payment_provider 'admin'
89
+
90
+ after(:create) { |order| order.decline! }
91
+ end
92
+
93
+ factory :pending_order, parent: :order do
94
+ purchase_state 'pending'
95
+ end
96
+
97
+ end