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,42 @@
1
+ module EffectiveQbSync
2
+ class Engine < ::Rails::Engine
3
+ engine_name 'effective_qb_sync'
4
+
5
+ config.autoload_paths += Dir["#{config.root}/app/models/**/"]
6
+
7
+ # Set up our default configuration options.
8
+ initializer "effective_qb_sync.defaults", before: :load_config_initializers do |app|
9
+ eval File.read("#{config.root}/lib/generators/templates/effective_qb_sync.rb")
10
+ end
11
+
12
+ # Ensure every acts_as_purchasable object responds to qb_item_name
13
+ initializer 'effective_qb_sync.assert_qb_item_names_present' do |app|
14
+ if Rails.env.development?
15
+ Rails.application.eager_load!
16
+
17
+ invalids = ActsAsPurchasable.descendants.reject { |klass| klass.new().try(:qb_item_name).present? }
18
+
19
+ if invalids.present?
20
+ raise "expected acts_as_purchasable objects #{invalids.map(&:to_s).to_sentence} .qb_item_name() to be present."
21
+ end
22
+ end
23
+ end
24
+
25
+ # Include acts_as_addressable concern and allow any ActiveRecord object to call it
26
+ initializer 'effective_qb_sync.active_record' do |app|
27
+ Rails.application.config.to_prepare do
28
+ ActiveSupport.on_load :active_record do
29
+ Effective::OrderItem.class_eval do
30
+ has_one :qb_order_item
31
+
32
+ # first or build
33
+ def qb_item_name
34
+ (qb_order_item || build_qb_order_item(name: purchasable.try(:qb_item_name))).name
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module EffectiveQbSync
2
+ VERSION = '1.0.0'.freeze
3
+ end
@@ -0,0 +1,42 @@
1
+ require 'haml-rails'
2
+ require 'simple_form'
3
+ require 'effective_orders'
4
+ require 'effective_qb_sync/engine'
5
+ require 'effective_qb_sync/version'
6
+
7
+ module EffectiveQbSync
8
+ # The following are all valid config keys
9
+ mattr_accessor :qb_requests_table_name
10
+ mattr_accessor :qb_tickets_table_name
11
+ mattr_accessor :qb_logs_table_name
12
+ mattr_accessor :qb_order_items_table_name
13
+
14
+ mattr_accessor :authorization_method
15
+
16
+ mattr_accessor :quickbooks_username
17
+ mattr_accessor :quickbooks_password
18
+ mattr_accessor :quickbooks_tax_name
19
+
20
+ mattr_accessor :error_email
21
+
22
+ mattr_accessor :layout
23
+ mattr_accessor :admin_simple_form_options
24
+
25
+ def self.setup
26
+ yield self
27
+ end
28
+
29
+ def self.authorized?(controller, action, resource)
30
+ if authorization_method.respond_to?(:call) || authorization_method.kind_of?(Symbol)
31
+ raise Effective::AccessDenied.new() unless (controller || self).instance_exec(controller, action, resource, &authorization_method)
32
+ end
33
+ true
34
+ end
35
+
36
+ def self.permitted_params
37
+ [
38
+ :note
39
+ ]
40
+ end
41
+
42
+ end
@@ -0,0 +1,42 @@
1
+ module EffectiveQbSync
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+
6
+ desc "Creates an EffectiveQbSync initializer in your application."
7
+
8
+ source_root File.expand_path("../../templates", __FILE__)
9
+
10
+ def self.next_migration_number(dirname)
11
+ if not ActiveRecord::Base.timestamped_migrations
12
+ Time.new.utc.strftime("%Y%m%d%H%M%S")
13
+ else
14
+ "%.3d" % (current_migration_number(dirname) + 1)
15
+ end
16
+ end
17
+
18
+ def copy_initializer
19
+ template "effective_qb_sync.rb", "config/initializers/effective_qb_sync.rb"
20
+ end
21
+
22
+ def copy_mailer_preview
23
+ mailer_preview_path = (Rails.application.config.action_mailer.preview_path rescue nil)
24
+
25
+ if mailer_preview_path.present?
26
+ template 'effective_qb_sync_mailer_preview.rb', File.join(mailer_preview_path, 'effective_qb_sync_mailer_preview.rb')
27
+ else
28
+ puts "couldn't find action_mailer.preview_path. Skipping effective_qb_sync_mailer_preview."
29
+ end
30
+ end
31
+
32
+ def create_migration_file
33
+ @qb_requests_table_name = ':' + EffectiveQbSync.qb_requests_table_name.to_s
34
+ @qb_tickets_table_name = ':' + EffectiveQbSync.qb_tickets_table_name.to_s
35
+ @qb_logs_table_name = ':' + EffectiveQbSync.qb_logs_table_name.to_s
36
+ @qb_order_items_table_name = ':' + EffectiveQbSync.qb_order_items_table_name.to_s
37
+
38
+ migration_template '../../../db/migrate/01_create_effective_qb_sync.rb.erb', 'db/migrate/create_effective_qb_sync.rb'
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,61 @@
1
+ # EffectiveQbSync Rails Engine
2
+
3
+ EffectiveQbSync.setup do |config|
4
+ # Configure Database Tables
5
+ config.qb_requests_table_name = :qb_requests
6
+ config.qb_tickets_table_name = :qb_tickets
7
+ config.qb_logs_table_name = :qb_logs
8
+ config.qb_order_items_table_name = :qb_order_items
9
+
10
+ # Authorization Method
11
+ #
12
+ # This method is called by all controller actions with the appropriate action and resource
13
+ # If the method returns false, an Effective::AccessDenied Error will be raised (see README.md for complete info)
14
+ #
15
+ # Use via Proc (and with CanCan):
16
+ # config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) }
17
+ #
18
+ # Use via custom method:
19
+ # config.authorization_method = :my_authorization_method
20
+ #
21
+ # And then in your application_controller.rb:
22
+ #
23
+ # def my_authorization_method(action, resource)
24
+ # current_user.is?(:admin)
25
+ # end
26
+ #
27
+ # Or disable the check completely:
28
+ # config.authorization_method = false
29
+ config.authorization_method = Proc.new { |controller, action, resource| true }
30
+
31
+ # All EffectiveQbSync controllers will use this layout
32
+ config.layout = 'application'
33
+
34
+ # SimpleForm Options
35
+ # This Hash of options will be passed into any admin facing simple_form_for() calls
36
+ config.admin_simple_form_options = {} # For the /admin/qb_syncs form
37
+
38
+ # Quickbooks Company File Settings
39
+
40
+ # The username / password of the Quickbooks user that should be allowed to synchronize.
41
+ # This must match the user configured in the Quickbooks .qwc file
42
+ config.quickbooks_username = ''
43
+ config.quickbooks_password = ''
44
+
45
+ # Sales tax can be added to an order in two ways:
46
+ # 1. Sales tax should be added by Quickbooks
47
+ # - Set below: config.quickbooks_tax_name = ''
48
+ # - In Quickbooks: Edit -> Preferences -> Sales Tax -> Company Preferences -> Do you charge sales tax? Yes
49
+ # 2. Sales tax should be added by the website
50
+ # - Set below: config.quickbooks_tax_name = 'GST Collected'
51
+ # - In Quickbooks: Edit -> Preferences -> Sales Tax -> Company Preferences -> Do you charge sales tax? No
52
+ # - In Quickbooks: Add a regular Quickbooks Item matching the config.quickbooks_tax_name
53
+ # See /admin/qb_syncs/instructions for more information.
54
+ config.quickbooks_tax_name = ''
55
+
56
+ # If a synchronization errors occurs, send an email with steps to fix the error, to this address
57
+ # Uses effective_orders mailer layout and settings
58
+ # Leave nil to use EffectiveOrders.mailer[:admin_email] value, or provide a to email address here
59
+ config.error_email = nil
60
+
61
+ end
@@ -0,0 +1,39 @@
1
+ # In Rails 4.1 and above, visit:
2
+ # http://localhost:3000/rails/mailers
3
+ # to see a preview of the following emails:
4
+
5
+ class EffectiveQbSyncMailerPreview < ActionMailer::Preview
6
+ # All order_errors are called from QbTicket.error!
7
+ # There are 3 general types of errors that occur
8
+
9
+ def error_record_does_not_exist
10
+ order_error('Invalid argument. The specified record does not exist in the list.')
11
+ end
12
+
13
+ def error_invalid_reference_to_item
14
+ order_error('There is an invalid reference to QuickBooks Item "Tax On Sale" in the SalesReceipt line.')
15
+ end
16
+
17
+ def error_element_already_in_use
18
+ order_error('The name "Peter Pan" of the list element is already in use.')
19
+ end
20
+
21
+ def error_unknown
22
+ order_error('unknown')
23
+ end
24
+
25
+ private
26
+
27
+ def order_error(error)
28
+ order = Effective::Order.new()
29
+
30
+ Effective::OrdersMailer.order_error(
31
+ order: order,
32
+ error: error,
33
+ to: EffectiveQbSync.error_email,
34
+ subject: "Quickbooks failed to synchronize order ##{order.to_param}",
35
+ template: 'qb_sync_error'
36
+ )
37
+ end
38
+
39
+ end
@@ -0,0 +1,8 @@
1
+ == README
2
+
3
+ To change the test database in this dummy app:
4
+
5
+ - Delete the existing test.sqlite3
6
+ - No migrations, so just make whatever changes you want to schema.rb
7
+
8
+ bundle exec rake app:db:test:prepare
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,14 @@
1
+ class Product < ActiveRecord::Base
2
+ acts_as_purchasable
3
+
4
+ after_purchase do |order, order_item|
5
+ end
6
+
7
+ after_decline do |order, order_item|
8
+ end
9
+
10
+ def qb_item_name
11
+ 'Product'
12
+ end
13
+
14
+ end
@@ -0,0 +1,13 @@
1
+ class ProductWithFloatPrice < ActiveRecord::Base
2
+ acts_as_purchasable
3
+
4
+ after_purchase do |order, order_item|
5
+ end
6
+
7
+ after_decline do |order, order_item|
8
+ end
9
+
10
+ def qb_item_name
11
+ 'ProductWithFloatPrice'
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ class User < ActiveRecord::Base
2
+ devise :database_authenticatable, :registerable, :rememberable, :recoverable, :trackable, :validatable, :authentication_keys => [:email]
3
+
4
+ acts_as_addressable :billing, :shipping
5
+
6
+ def to_s
7
+ email
8
+ end
9
+
10
+ def phone
11
+ '555-555-5555'
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require 'rails/all'
4
+
5
+ Bundler.require(*Rails.groups)
6
+ require 'devise'
7
+ require 'haml'
8
+ require 'effective_addresses'
9
+ require 'effective_orders'
10
+ require 'effective_qb_sync'
11
+
12
+ module Dummy
13
+ class Application < Rails::Application
14
+ # Settings in config/environments/* take precedence over those specified here.
15
+ # Application configuration should go into files in config/initializers
16
+ # -- all .rb files in that directory are automatically loaded.
17
+
18
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
19
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
20
+ # config.time_zone = 'Central Time (US & Canada)'
21
+
22
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
23
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
24
+ # config.i18n.default_locale = :de
25
+
26
+ config.generators do |g|
27
+ g.template_engine :haml
28
+ end
29
+
30
+ end
31
+ end
32
+
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,25 @@
1
+ # SQLite version 3.x
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem 'sqlite3'
6
+ #
7
+ default: &default
8
+ adapter: sqlite3
9
+ pool: 5
10
+ timeout: 5000
11
+
12
+ development:
13
+ <<: *default
14
+ database: db/development.sqlite3
15
+
16
+ # Warning: The database defined as "test" will be erased and
17
+ # re-generated from your development database when you run "rake".
18
+ # Do not set this db to the same as development or production.
19
+ test:
20
+ <<: *default
21
+ database: db/test.sqlite3
22
+
23
+ production:
24
+ <<: *default
25
+ database: db/production.sqlite3