effective_orders 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 (146) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +856 -0
  4. data/Rakefile +24 -0
  5. data/app/assets/images/effective_orders/stripe_connect.png +0 -0
  6. data/app/assets/javascripts/effective_orders/shipping_address_toggle.js.coffee +30 -0
  7. data/app/assets/javascripts/effective_orders/stripe_charges.js.coffee +26 -0
  8. data/app/assets/javascripts/effective_orders/stripe_subscriptions.js.coffee +28 -0
  9. data/app/assets/javascripts/effective_orders.js +2 -0
  10. data/app/assets/stylesheets/effective_orders/_order.scss +30 -0
  11. data/app/assets/stylesheets/effective_orders.css.scss +1 -0
  12. data/app/controllers/admin/customers_controller.rb +15 -0
  13. data/app/controllers/admin/orders_controller.rb +22 -0
  14. data/app/controllers/effective/carts_controller.rb +70 -0
  15. data/app/controllers/effective/orders_controller.rb +191 -0
  16. data/app/controllers/effective/providers/moneris.rb +94 -0
  17. data/app/controllers/effective/providers/paypal.rb +29 -0
  18. data/app/controllers/effective/providers/stripe.rb +125 -0
  19. data/app/controllers/effective/providers/stripe_connect.rb +47 -0
  20. data/app/controllers/effective/subscriptions_controller.rb +123 -0
  21. data/app/controllers/effective/webhooks_controller.rb +86 -0
  22. data/app/helpers/effective_carts_helper.rb +90 -0
  23. data/app/helpers/effective_orders_helper.rb +108 -0
  24. data/app/helpers/effective_paypal_helper.rb +37 -0
  25. data/app/helpers/effective_stripe_helper.rb +63 -0
  26. data/app/mailers/effective/orders_mailer.rb +64 -0
  27. data/app/models/concerns/acts_as_purchasable.rb +134 -0
  28. data/app/models/effective/access_denied.rb +17 -0
  29. data/app/models/effective/cart.rb +65 -0
  30. data/app/models/effective/cart_item.rb +40 -0
  31. data/app/models/effective/customer.rb +61 -0
  32. data/app/models/effective/datatables/customers.rb +45 -0
  33. data/app/models/effective/datatables/orders.rb +53 -0
  34. data/app/models/effective/order.rb +247 -0
  35. data/app/models/effective/order_item.rb +69 -0
  36. data/app/models/effective/stripe_charge.rb +35 -0
  37. data/app/models/effective/subscription.rb +95 -0
  38. data/app/models/inputs/price_field.rb +63 -0
  39. data/app/models/inputs/price_form_input.rb +7 -0
  40. data/app/models/inputs/price_formtastic_input.rb +9 -0
  41. data/app/models/inputs/price_input.rb +19 -0
  42. data/app/models/inputs/price_simple_form_input.rb +8 -0
  43. data/app/models/validators/effective/sold_out_validator.rb +7 -0
  44. data/app/views/active_admin/effective_orders/orders/_show.html.haml +70 -0
  45. data/app/views/admin/customers/_actions.html.haml +2 -0
  46. data/app/views/admin/customers/index.html.haml +10 -0
  47. data/app/views/admin/orders/index.html.haml +7 -0
  48. data/app/views/admin/orders/show.html.haml +11 -0
  49. data/app/views/effective/carts/_cart.html.haml +33 -0
  50. data/app/views/effective/carts/show.html.haml +18 -0
  51. data/app/views/effective/orders/_checkout_step_1.html.haml +39 -0
  52. data/app/views/effective/orders/_checkout_step_2.html.haml +18 -0
  53. data/app/views/effective/orders/_my_purchases.html.haml +15 -0
  54. data/app/views/effective/orders/_order.html.haml +4 -0
  55. data/app/views/effective/orders/_order_header.html.haml +21 -0
  56. data/app/views/effective/orders/_order_items.html.haml +39 -0
  57. data/app/views/effective/orders/_order_payment_details.html.haml +11 -0
  58. data/app/views/effective/orders/_order_shipping.html.haml +19 -0
  59. data/app/views/effective/orders/_order_user_fields.html.haml +10 -0
  60. data/app/views/effective/orders/checkout.html.haml +3 -0
  61. data/app/views/effective/orders/declined.html.haml +10 -0
  62. data/app/views/effective/orders/moneris/_form.html.haml +34 -0
  63. data/app/views/effective/orders/my_purchases.html.haml +6 -0
  64. data/app/views/effective/orders/my_sales.html.haml +28 -0
  65. data/app/views/effective/orders/new.html.haml +4 -0
  66. data/app/views/effective/orders/paypal/_form.html.haml +5 -0
  67. data/app/views/effective/orders/purchased.html.haml +10 -0
  68. data/app/views/effective/orders/show.html.haml +17 -0
  69. data/app/views/effective/orders/stripe/_form.html.haml +8 -0
  70. data/app/views/effective/orders/stripe/_subscription_fields.html.haml +7 -0
  71. data/app/views/effective/orders_mailer/order_receipt_to_admin.html.haml +8 -0
  72. data/app/views/effective/orders_mailer/order_receipt_to_buyer.html.haml +8 -0
  73. data/app/views/effective/orders_mailer/order_receipt_to_seller.html.haml +30 -0
  74. data/app/views/effective/subscriptions/index.html.haml +16 -0
  75. data/app/views/effective/subscriptions/new.html.haml +10 -0
  76. data/app/views/effective/subscriptions/show.html.haml +49 -0
  77. data/config/routes.rb +57 -0
  78. data/db/migrate/01_create_effective_orders.rb.erb +91 -0
  79. data/db/upgrade/02_upgrade_effective_orders_from03x.rb.erb +29 -0
  80. data/db/upgrade/upgrade_price_column_on_table.rb.erb +17 -0
  81. data/lib/effective_orders/engine.rb +52 -0
  82. data/lib/effective_orders/version.rb +3 -0
  83. data/lib/effective_orders.rb +76 -0
  84. data/lib/generators/effective_orders/install_generator.rb +38 -0
  85. data/lib/generators/effective_orders/upgrade_from03x_generator.rb +34 -0
  86. data/lib/generators/effective_orders/upgrade_price_column_generator.rb +34 -0
  87. data/lib/generators/templates/README +1 -0
  88. data/lib/generators/templates/effective_orders.rb +210 -0
  89. data/spec/controllers/carts_controller_spec.rb +143 -0
  90. data/spec/controllers/moneris_orders_controller_spec.rb +245 -0
  91. data/spec/controllers/orders_controller_spec.rb +418 -0
  92. data/spec/controllers/stripe_orders_controller_spec.rb +127 -0
  93. data/spec/controllers/webhooks_controller_spec.rb +79 -0
  94. data/spec/dummy/README.rdoc +8 -0
  95. data/spec/dummy/Rakefile +6 -0
  96. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  97. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  98. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  99. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  100. data/spec/dummy/app/models/product.rb +17 -0
  101. data/spec/dummy/app/models/product_with_float_price.rb +17 -0
  102. data/spec/dummy/app/models/user.rb +28 -0
  103. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  104. data/spec/dummy/bin/bundle +3 -0
  105. data/spec/dummy/bin/rails +4 -0
  106. data/spec/dummy/bin/rake +4 -0
  107. data/spec/dummy/config/application.rb +31 -0
  108. data/spec/dummy/config/boot.rb +5 -0
  109. data/spec/dummy/config/database.yml +25 -0
  110. data/spec/dummy/config/environment.rb +5 -0
  111. data/spec/dummy/config/environments/development.rb +37 -0
  112. data/spec/dummy/config/environments/production.rb +83 -0
  113. data/spec/dummy/config/environments/test.rb +39 -0
  114. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  115. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  116. data/spec/dummy/config/initializers/devise.rb +254 -0
  117. data/spec/dummy/config/initializers/effective_addresses.rb +15 -0
  118. data/spec/dummy/config/initializers/effective_orders.rb +22 -0
  119. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  120. data/spec/dummy/config/initializers/inflections.rb +16 -0
  121. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  122. data/spec/dummy/config/initializers/session_store.rb +3 -0
  123. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  124. data/spec/dummy/config/locales/en.yml +23 -0
  125. data/spec/dummy/config/routes.rb +3 -0
  126. data/spec/dummy/config/secrets.yml +22 -0
  127. data/spec/dummy/config.ru +4 -0
  128. data/spec/dummy/db/schema.rb +142 -0
  129. data/spec/dummy/db/test.sqlite3 +0 -0
  130. data/spec/dummy/log/development.log +487 -0
  131. data/spec/dummy/log/test.log +347 -0
  132. data/spec/dummy/public/404.html +67 -0
  133. data/spec/dummy/public/422.html +67 -0
  134. data/spec/dummy/public/500.html +66 -0
  135. data/spec/dummy/public/favicon.ico +0 -0
  136. data/spec/helpers/effective_orders_helper_spec.rb +21 -0
  137. data/spec/models/acts_as_purchasable_spec.rb +107 -0
  138. data/spec/models/customer_spec.rb +71 -0
  139. data/spec/models/factories_spec.rb +13 -0
  140. data/spec/models/order_item_spec.rb +35 -0
  141. data/spec/models/order_spec.rb +323 -0
  142. data/spec/models/stripe_charge_spec.rb +39 -0
  143. data/spec/models/subscription_spec.rb +103 -0
  144. data/spec/spec_helper.rb +44 -0
  145. data/spec/support/factories.rb +118 -0
  146. metadata +387 -0
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ # Our tasks
9
+ load 'lib/tasks/effective_orders_tasks.rake'
10
+
11
+ # Testing tasks
12
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
13
+ load 'rails/tasks/engine.rake'
14
+
15
+ require "bundler/vendored_thor"
16
+ Bundler::GemHelper.install_tasks
17
+
18
+ require 'rspec/core'
19
+ require 'rspec/core/rake_task'
20
+
21
+ desc "Run all specs in spec directory (excluding plugin specs)"
22
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
23
+
24
+ task :default => :spec
@@ -0,0 +1,30 @@
1
+ hideShippingAddressFields = (shipping_address) ->
2
+ shipping_address.hide().find('input,select').prop('required', false)
3
+
4
+ showShippingAddressFields = (shipping_address) ->
5
+ shipping_address.show().find("input:not([name$='[address2]']),select:not([name$='[state_code]'])").prop('required', true)
6
+
7
+ initShippingAddressFields = ->
8
+ effective_order = $('.effective-order').first()
9
+
10
+ if effective_order.length > 0
11
+ shipping_address_same_as_billing = effective_order.find('#effective_order_shipping_address_same_as_billing')
12
+ shipping_address = effective_order.find('.shipping_address_fields')
13
+
14
+ if shipping_address_same_as_billing.length > 0 && shipping_address.length > 0
15
+ if shipping_address_same_as_billing.is(':checked')
16
+ hideShippingAddressFields(shipping_address)
17
+ else
18
+ showShippingAddressFields(shipping_address)
19
+
20
+ $ -> initShippingAddressFields()
21
+ $(document).on 'page:change', -> initShippingAddressFields()
22
+
23
+ $(document).on 'change', '#effective_order_shipping_address_same_as_billing', (event) ->
24
+ obj = $(event.currentTarget)
25
+ shipping_address = obj.closest('form').find('.shipping_address_fields')
26
+
27
+ if obj.is(':checked')
28
+ hideShippingAddressFields(shipping_address)
29
+ else
30
+ showShippingAddressFields(shipping_address)
@@ -0,0 +1,26 @@
1
+ stripeCheckoutHandler = (key, form) ->
2
+ StripeCheckout.configure
3
+ key: key
4
+ token: (token, args) ->
5
+ if token.error
6
+ form.find("input[type='submit']").prop('disabled', false)
7
+ alert("An error ocurred when contacting Stripe. Your card has not been charged. Please refresh the page and try again. #{token.error.message}")
8
+ else
9
+ form.find("input[type='submit']").prop('disabled', true)
10
+ form.find('input#effective_stripe_charge_token').val('' + token['id'])
11
+ form.submit()
12
+
13
+ $(document).on 'click', "#effective-orders-new-charge-form form input[type='submit']", (event) ->
14
+ event.preventDefault()
15
+
16
+ obj = $('#effective-orders-new-charge-form')
17
+ form = obj.find('form').first()
18
+
19
+ form.find("input[type='submit']").prop('disabled', true)
20
+
21
+ stripeCheckoutHandler(obj.data('stripe-publishable-key'), form).open
22
+ name: obj.data('site-title')
23
+ email: obj.data('user-email')
24
+ description: obj.data('description')
25
+ amount: obj.data('amount')
26
+ closed: -> form.find("input[type='submit']").prop('disabled', false)
@@ -0,0 +1,28 @@
1
+ stripeCheckoutHandler = (key, form) ->
2
+ StripeCheckout.configure
3
+ key: key
4
+ token: (token, args) ->
5
+ if token.error
6
+ form.find("input[type='submit']").prop('disabled', false)
7
+ alert("An error ocurred when contacting Stripe. Your card has not been charged. Please refresh the page and try again. #{token.error.message}")
8
+ else
9
+ form.find("input[type='submit']").prop('disabled', true)
10
+ form.find('input#effective_stripe_subscription_token').val('' + token['id'])
11
+ form.submit()
12
+
13
+ $(document).on 'click', "#effective-orders-new-subscription-form form input[type='submit']", (event) ->
14
+ event.preventDefault()
15
+
16
+ obj = $('#effective-orders-new-subscription-form')
17
+ form = obj.find('form').first()
18
+ plan = form.find('option:selected')
19
+
20
+ if plan.length > 0
21
+ form.find("input[type='submit']").prop('disabled', true)
22
+
23
+ stripeCheckoutHandler(obj.data('stripe-publishable-key'), form).open
24
+ name: obj.data('site-title')
25
+ email: obj.data('user-email')
26
+ description: plan.text()
27
+ panelLabel: 'Start Subscription'
28
+ closed: -> form.find("input[type='submit']").prop('disabled', false)
@@ -0,0 +1,2 @@
1
+ //= require_tree ./effective_orders
2
+
@@ -0,0 +1,30 @@
1
+ .effective-order {
2
+ .table {
3
+ clear: both;
4
+
5
+ tfoot {
6
+ > tr:first-child {
7
+ border-top: 20px solid transparent;
8
+ }
9
+
10
+ th {
11
+ border: none;
12
+ text-align: right;
13
+ padding-right: 65px;
14
+ }
15
+
16
+ .actions { border: none; }
17
+ }
18
+
19
+ .price { text-align: right; }
20
+ }
21
+
22
+ .effective-stripe-subscription {
23
+ input {
24
+ margin-top: 5px;
25
+ width: 30%;
26
+ min-width: 200px;
27
+ }
28
+ }
29
+
30
+ }
@@ -0,0 +1 @@
1
+ @import "effective_orders/order";
@@ -0,0 +1,15 @@
1
+ module Admin
2
+ class CustomersController < ApplicationController
3
+ before_filter :authenticate_user! # This is devise, ensure we're logged in.
4
+
5
+ layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:admin_customers] : EffectiveOrders.layout)
6
+
7
+ def index
8
+ @datatable = Effective::Datatables::Customers.new() if defined?(EffectiveDatatables)
9
+ @page_title = 'Customers'
10
+
11
+ EffectiveOrders.authorized?(self, :index, Effective::Customer)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module Admin
2
+ class OrdersController < ApplicationController
3
+ before_filter :authenticate_user! # This is devise, ensure we're logged in.
4
+
5
+ layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:admin_orders] : EffectiveOrders.layout)
6
+
7
+ def index
8
+ @datatable = Effective::Datatables::Orders.new() if defined?(EffectiveDatatables)
9
+ @page_title = 'Orders'
10
+
11
+ EffectiveOrders.authorized?(self, :index, Effective::Order)
12
+ end
13
+
14
+ def show
15
+ @order = Effective::Order.find(params[:id])
16
+ @page_title = "Order ##{@order.to_param}"
17
+
18
+ EffectiveOrders.authorized?(self, :show, @order)
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ module Effective
2
+ class CartsController < ApplicationController
3
+ include EffectiveCartsHelper
4
+ layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:carts] : EffectiveOrders.layout)
5
+
6
+ def show
7
+ @cart = current_cart
8
+ @page_title ||= 'Shopping Cart'
9
+ EffectiveOrders.authorized?(self, :show, @cart)
10
+ end
11
+
12
+ def destroy
13
+ @cart = current_cart
14
+
15
+ EffectiveOrders.authorized?(self, :destroy, @cart)
16
+
17
+ if @cart.destroy
18
+ flash[:success] = 'Successfully emptied cart'
19
+ else
20
+ flash[:danger] = 'Unable to destroy cart:' + e.message
21
+ end
22
+
23
+ request.referrer ? (redirect_to :back) : (redirect_to effective_orders.cart_path)
24
+ end
25
+
26
+ def add_to_cart
27
+ @purchasable = (add_to_cart_params[:purchasable_type].constantize.find(add_to_cart_params[:purchasable_id].to_i) rescue nil)
28
+
29
+ EffectiveOrders.authorized?(self, :update, current_cart)
30
+
31
+ begin
32
+ raise "please select a valid #{add_to_cart_params[:purchasable_type] || 'item' }" unless @purchasable
33
+
34
+ current_cart.add_to_cart(@purchasable, [add_to_cart_params[:quantity].to_i, 1].max)
35
+ flash[:success] = 'Successfully added item to cart'
36
+ rescue EffectiveOrders::SoldOutException
37
+ flash[:warning] = 'This item is sold out'
38
+ rescue => e
39
+ flash[:danger] = 'Unable to add item to cart: ' + e.message
40
+ end
41
+
42
+ request.referrer ? (redirect_to :back) : (redirect_to effective_orders.cart_path)
43
+ end
44
+
45
+ def remove_from_cart
46
+ @cart_item = current_cart.cart_items.find(remove_from_cart_params[:id])
47
+
48
+ EffectiveOrders.authorized?(self, :update, current_cart)
49
+
50
+ if @cart_item.destroy
51
+ flash[:success] = 'Successfully removed item from cart'
52
+ else
53
+ flash[:danger] = 'Unable to remove item from cart: ' + e.message
54
+ end
55
+
56
+ request.referrer ? (redirect_to :back) : (redirect_to effective_orders.cart_path)
57
+ end
58
+
59
+ private
60
+
61
+ def add_to_cart_params
62
+ params.permit(:purchasable_type, :purchasable_id, :quantity)
63
+ end
64
+
65
+ def remove_from_cart_params
66
+ params.permit(:id)
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,191 @@
1
+ module Effective
2
+ class OrdersController < ApplicationController
3
+ include EffectiveCartsHelper
4
+
5
+ include Providers::Moneris if EffectiveOrders.moneris_enabled
6
+ include Providers::Paypal if EffectiveOrders.paypal_enabled
7
+ include Providers::Stripe if EffectiveOrders.stripe_enabled
8
+ include Providers::StripeConnect if EffectiveOrders.stripe_connect_enabled
9
+
10
+ layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:orders] : EffectiveOrders.layout)
11
+
12
+ before_filter :authenticate_user!, :except => [:paypal_postback]
13
+ before_filter :set_page_title
14
+
15
+ # This is the entry point for the "Checkout" buttons
16
+ def new
17
+ @order ||= Order.new(current_cart, current_user)
18
+
19
+ EffectiveOrders.authorized?(self, :new, @order)
20
+
21
+ # We're only going to check for a subset of errors on this step,
22
+ # with the idea that we don't want to create an Order object if the Order is totally invalid
23
+ @order.valid?
24
+
25
+ if @order.errors[:order_items].present?
26
+ flash[:danger] = @order.errors[:order_items].first
27
+ redirect_to effective_orders.cart_path
28
+ elsif @order.errors[:total].present?
29
+ flash[:danger] = @order.errors[:total].first.gsub(EffectiveOrders.minimum_charge.to_i.to_s, view_context.price_to_currency(EffectiveOrders.minimum_charge.to_i))
30
+ redirect_to effective_orders.cart_path
31
+ end
32
+ end
33
+
34
+ def create
35
+ @order = Order.new(current_cart, current_user)
36
+ @order.attributes = order_params
37
+ @order.shipping_address = @order.billing_address if @order.shipping_address_same_as_billing?
38
+
39
+ EffectiveOrders.authorized?(self, :create, @order)
40
+
41
+ Effective::Order.transaction do
42
+ begin
43
+ if @order.save_billing_address? && @order.user.respond_to?(:billing_address)
44
+ @order.user.billing_address = @order.billing_address
45
+ end
46
+
47
+ if @order.save_shipping_address? && @order.user.respond_to?(:shipping_address)
48
+ @order.user.shipping_address = @order.shipping_address
49
+ end
50
+
51
+ @order.save!
52
+
53
+ if @order.total < 0.01 && @order.total >= 0.00 && EffectiveOrders.allow_free_orders
54
+ order_purchased('zero-dollar order')
55
+ else
56
+ redirect_to(effective_orders.order_path(@order))
57
+ end
58
+
59
+ return
60
+ rescue => e
61
+ Rails.logger.info e.message
62
+ flash[:danger] = "An error has ocurred. Please try again. Message: #{e.message}"
63
+ raise ActiveRecord::Rollback
64
+ end
65
+ end
66
+
67
+ render :action => :new
68
+ end
69
+
70
+ def show
71
+ @order = Order.find(params[:id])
72
+ EffectiveOrders.authorized?(self, :show, @order)
73
+
74
+ if @order.purchased? == false
75
+ @page_title = 'Checkout'
76
+ render(:checkout) and return
77
+ end
78
+
79
+ end
80
+
81
+ def index
82
+ redirect_to effective_orders.my_purchases_path
83
+ end
84
+
85
+ # Basically an index page.
86
+ # Purchases is an Order History page. List of purchased orders
87
+ def my_purchases
88
+ @orders = Order.purchased_by(current_user)
89
+
90
+ EffectiveOrders.authorized?(self, :index, Effective::Order)
91
+ end
92
+
93
+ # Sales is a list of what products beign sold by me have been purchased
94
+ def my_sales
95
+ @order_items = OrderItem.sold_by(current_user)
96
+
97
+ EffectiveOrders.authorized?(self, :index, Effective::Order)
98
+ end
99
+
100
+ # Thank you for Purchasing this Order. This is where a successfully purchased order ends up
101
+ def purchased # Thank You!
102
+ @order = Order.find(params[:id])
103
+ EffectiveOrders.authorized?(self, :show, @order)
104
+ end
105
+
106
+ # An error has occurred, please try again
107
+ def declined # An error occurred!
108
+ @order = Order.find(params[:id])
109
+ EffectiveOrders.authorized?(self, :show, @order)
110
+ end
111
+
112
+ def resend_buyer_receipt
113
+ @order = Effective::Order.find(params[:id])
114
+ EffectiveOrders.authorized?(self, :show, @order)
115
+
116
+ if (Effective::OrdersMailer.order_receipt_to_buyer(@order).deliver rescue false)
117
+ flash[:success] = "Successfully resent order receipt to #{@order.user.email}"
118
+ else
119
+ flash[:danger] = "Unable to send order receipt"
120
+ end
121
+
122
+ begin
123
+ redirect_to :back
124
+ rescue => e
125
+ redirect_to effective_orders.admin_orders_path
126
+ end
127
+ end
128
+
129
+ def pretend_purchase
130
+ if Rails.env.development? || EffectiveOrders.allow_pretend_purchase_in_production
131
+ @order = Order.find(params[:id])
132
+ EffectiveOrders.authorized?(self, :update, @order)
133
+ order_purchased('for pretend', params[:purchased_redirect_url], params[:declined_redirect_url])
134
+ end
135
+ end
136
+
137
+ protected
138
+
139
+ def order_purchased(details = nil, redirect_url = nil, declined_redirect_url = nil)
140
+ begin
141
+ @order.purchase!(details)
142
+ current_cart.try(:destroy)
143
+
144
+ flash[:success] = "Successfully purchased order"
145
+
146
+ redirect_to (redirect_url.presence || effective_orders.order_purchased_path(@order)).gsub(':id', @order.id.to_s)
147
+ rescue => e
148
+ binding.pry
149
+ flash[:danger] = "Unable to process your order. Your card has not been charged. Your Cart items have been restored. Please try again. Error Message: #{e.message}"
150
+ redirect_to (declined_redirect_url.presence || effective_orders.cart_path).gsub(':id', @order.id.to_s)
151
+ end
152
+ end
153
+
154
+ def order_declined(details = nil, redirect_url = nil)
155
+ @order.decline!(details) rescue nil
156
+
157
+ flash[:danger] = "Unable to process your order. Your Cart items have been restored."
158
+
159
+ redirect_to (redirect_url.presence || effective_orders.order_declined_path(@order)).gsub(':id', @order.id.to_s)
160
+ end
161
+
162
+ private
163
+
164
+ # StrongParameters
165
+ def order_params
166
+ begin
167
+ params.require(:effective_order).permit(
168
+ :save_billing_address, :save_shipping_address, :shipping_address_same_as_billing,
169
+ :billing_address => [:full_name, :address1, :address2, :city, :country_code, :state_code, :postal_code],
170
+ :shipping_address => [:full_name, :address1, :address2, :city, :country_code, :state_code, :postal_code],
171
+ :user_attributes => (EffectiveOrders.collect_user_fields || []),
172
+ :order_items_attributes => [:stripe_coupon_id, :class, :id]
173
+ )
174
+ rescue => e
175
+ params[:effective_order] || {}
176
+ end
177
+ end
178
+
179
+ def set_page_title
180
+ @page_title ||= case params[:action]
181
+ when 'my_purchases' ; 'Order History'
182
+ when 'my_sales' ; 'Sales History'
183
+ when 'purchased' ; 'Thank You'
184
+ when 'declined' ; 'Unable to process payment'
185
+ when 'show' ; 'Order Receipt'
186
+ else 'Checkout'
187
+ end
188
+ end
189
+
190
+ end
191
+ end
@@ -0,0 +1,94 @@
1
+ module Effective
2
+ module Providers
3
+ module Moneris
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ prepend_before_filter :find_authenticity_token_from_moneris, :only => [:moneris_postback]
8
+ end
9
+
10
+ def moneris_postback
11
+ @order ||= Effective::Order.find(params[:response_order_id].to_i - EffectiveOrders.moneris[:order_nudge].to_i)
12
+
13
+ EffectiveOrders.authorized?(self, :update, @order)
14
+
15
+ # Store the Order Nudge if present, so we can have this information in our order_purchased hash
16
+ params[:order_nudge] = EffectiveOrders.moneris[:order_nudge] if EffectiveOrders.moneris[:order_nudge].to_i > 0
17
+
18
+ # Delete the Purchased and Declined Redirect URLs
19
+ purchased_redirect_url = params.delete(:rvar_purchased_redirect_url)
20
+ declined_redirect_url = params.delete(:rvar_declined_redirect_url)
21
+
22
+ if params[:result].to_s == '1' && params[:transactionKey].present?
23
+ verify_params = parse_moneris_response(send_moneris_verify_request(params[:transactionKey])) || {}
24
+
25
+ response_code = verify_params[:response_code].to_i # Sometimes moneris sends us the string 'null'
26
+
27
+ if response_code > 0 && response_code < 50 # Less than 50 means a successful validation
28
+ order_purchased(params.merge(verify_params), purchased_redirect_url)
29
+ else
30
+ order_declined(params.merge(verify_params), declined_redirect_url)
31
+ end
32
+ else
33
+ order_declined(params, declined_redirect_url)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def parse_moneris_response(text)
40
+ text.split("<br>").inject(Hash.new()) { |h, i| h[i.split(' ').first.to_sym] = i.split(' ').last ; h } rescue {:response => text}
41
+ end
42
+
43
+ def send_moneris_verify_request(verify_key)
44
+ `curl -F ps_store_id='#{EffectiveOrders.moneris[:ps_store_id]}' -F hpp_key='#{EffectiveOrders.moneris[:hpp_key]}' -F transactionKey='#{verify_key}' --referer #{effective_orders.moneris_postback_url} #{EffectiveOrders.moneris[:verify_url]}`
45
+ end
46
+
47
+ def find_authenticity_token_from_moneris
48
+ params[:authenticity_token] = params.delete(:rvar_authenticity_token)
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ # Instructions to set up a Test Moneris Store
57
+
58
+ # https://esqa.moneris.com/mpg/index.php
59
+
60
+ # demouser
61
+ # store2
62
+ # password
63
+
64
+ # Click on the ADMIN -> hosted config
65
+
66
+ # Generate a Version3 Configuration
67
+
68
+ # This should bring us to a "hosted Paypage Configuration"
69
+
70
+ # == Basic Configuration ==
71
+ # - Transaction Type: Purchase
72
+ # - Response Method Sent to your server as a POST
73
+ # - Approved URL: http://ourwebsite.com/orders/moneris_postback
74
+ # - Declined URL: http://ourwebsite.com/orders/moneris_postback
75
+
76
+ # == Appearance ==
77
+ # - Display item details
78
+ # - Display customer details
79
+ # - Display billing address details
80
+ # - Display merchant name
81
+ # - Cancel Button Text: Cancel Transaction
82
+ # - Cancel Button URL http://ourwebsite.com
83
+
84
+ # == Response Fields ==
85
+ # - Ignore, leave blank, the asynchronous data post
86
+ # - Do not Perform an asynchronous data post. Leave Async Response URL blank
87
+
88
+ # == Security ==
89
+ # Add a URL http://ourwebsite.com/orders/new
90
+ # Click YES Enable Transaction Verification
91
+ # Sent to your server as a POST
92
+ # Response URL: http://ourwebsite.com/orders/moneris_postback
93
+
94
+ # Displayed as key/value pairs on our server. ????
@@ -0,0 +1,29 @@
1
+ module Effective
2
+ module Providers
3
+ module Paypal
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ skip_before_filter :verify_authenticity_token, :only => [:paypal_postback]
8
+ end
9
+
10
+ def paypal_postback
11
+ @order ||= Effective::Order.where(:id => params[:invoice].to_i).first
12
+
13
+ EffectiveOrders.authorized?(self, :update, @order)
14
+
15
+ if @order.present?
16
+ if params[:payment_status] == 'Completed' && params[:custom] == EffectiveOrders.paypal[:secret]
17
+ order_purchased(params)
18
+ else
19
+ order_declined(params)
20
+ end
21
+ end
22
+
23
+ head(:ok)
24
+ end
25
+
26
+
27
+ end
28
+ end
29
+ end