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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +856 -0
- data/Rakefile +24 -0
- data/app/assets/images/effective_orders/stripe_connect.png +0 -0
- data/app/assets/javascripts/effective_orders/shipping_address_toggle.js.coffee +30 -0
- data/app/assets/javascripts/effective_orders/stripe_charges.js.coffee +26 -0
- data/app/assets/javascripts/effective_orders/stripe_subscriptions.js.coffee +28 -0
- data/app/assets/javascripts/effective_orders.js +2 -0
- data/app/assets/stylesheets/effective_orders/_order.scss +30 -0
- data/app/assets/stylesheets/effective_orders.css.scss +1 -0
- data/app/controllers/admin/customers_controller.rb +15 -0
- data/app/controllers/admin/orders_controller.rb +22 -0
- data/app/controllers/effective/carts_controller.rb +70 -0
- data/app/controllers/effective/orders_controller.rb +191 -0
- data/app/controllers/effective/providers/moneris.rb +94 -0
- data/app/controllers/effective/providers/paypal.rb +29 -0
- data/app/controllers/effective/providers/stripe.rb +125 -0
- data/app/controllers/effective/providers/stripe_connect.rb +47 -0
- data/app/controllers/effective/subscriptions_controller.rb +123 -0
- data/app/controllers/effective/webhooks_controller.rb +86 -0
- data/app/helpers/effective_carts_helper.rb +90 -0
- data/app/helpers/effective_orders_helper.rb +108 -0
- data/app/helpers/effective_paypal_helper.rb +37 -0
- data/app/helpers/effective_stripe_helper.rb +63 -0
- data/app/mailers/effective/orders_mailer.rb +64 -0
- data/app/models/concerns/acts_as_purchasable.rb +134 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/app/models/effective/cart.rb +65 -0
- data/app/models/effective/cart_item.rb +40 -0
- data/app/models/effective/customer.rb +61 -0
- data/app/models/effective/datatables/customers.rb +45 -0
- data/app/models/effective/datatables/orders.rb +53 -0
- data/app/models/effective/order.rb +247 -0
- data/app/models/effective/order_item.rb +69 -0
- data/app/models/effective/stripe_charge.rb +35 -0
- data/app/models/effective/subscription.rb +95 -0
- data/app/models/inputs/price_field.rb +63 -0
- data/app/models/inputs/price_form_input.rb +7 -0
- data/app/models/inputs/price_formtastic_input.rb +9 -0
- data/app/models/inputs/price_input.rb +19 -0
- data/app/models/inputs/price_simple_form_input.rb +8 -0
- data/app/models/validators/effective/sold_out_validator.rb +7 -0
- data/app/views/active_admin/effective_orders/orders/_show.html.haml +70 -0
- data/app/views/admin/customers/_actions.html.haml +2 -0
- data/app/views/admin/customers/index.html.haml +10 -0
- data/app/views/admin/orders/index.html.haml +7 -0
- data/app/views/admin/orders/show.html.haml +11 -0
- data/app/views/effective/carts/_cart.html.haml +33 -0
- data/app/views/effective/carts/show.html.haml +18 -0
- data/app/views/effective/orders/_checkout_step_1.html.haml +39 -0
- data/app/views/effective/orders/_checkout_step_2.html.haml +18 -0
- data/app/views/effective/orders/_my_purchases.html.haml +15 -0
- data/app/views/effective/orders/_order.html.haml +4 -0
- data/app/views/effective/orders/_order_header.html.haml +21 -0
- data/app/views/effective/orders/_order_items.html.haml +39 -0
- data/app/views/effective/orders/_order_payment_details.html.haml +11 -0
- data/app/views/effective/orders/_order_shipping.html.haml +19 -0
- data/app/views/effective/orders/_order_user_fields.html.haml +10 -0
- data/app/views/effective/orders/checkout.html.haml +3 -0
- data/app/views/effective/orders/declined.html.haml +10 -0
- data/app/views/effective/orders/moneris/_form.html.haml +34 -0
- data/app/views/effective/orders/my_purchases.html.haml +6 -0
- data/app/views/effective/orders/my_sales.html.haml +28 -0
- data/app/views/effective/orders/new.html.haml +4 -0
- data/app/views/effective/orders/paypal/_form.html.haml +5 -0
- data/app/views/effective/orders/purchased.html.haml +10 -0
- data/app/views/effective/orders/show.html.haml +17 -0
- data/app/views/effective/orders/stripe/_form.html.haml +8 -0
- data/app/views/effective/orders/stripe/_subscription_fields.html.haml +7 -0
- data/app/views/effective/orders_mailer/order_receipt_to_admin.html.haml +8 -0
- data/app/views/effective/orders_mailer/order_receipt_to_buyer.html.haml +8 -0
- data/app/views/effective/orders_mailer/order_receipt_to_seller.html.haml +30 -0
- data/app/views/effective/subscriptions/index.html.haml +16 -0
- data/app/views/effective/subscriptions/new.html.haml +10 -0
- data/app/views/effective/subscriptions/show.html.haml +49 -0
- data/config/routes.rb +57 -0
- data/db/migrate/01_create_effective_orders.rb.erb +91 -0
- data/db/upgrade/02_upgrade_effective_orders_from03x.rb.erb +29 -0
- data/db/upgrade/upgrade_price_column_on_table.rb.erb +17 -0
- data/lib/effective_orders/engine.rb +52 -0
- data/lib/effective_orders/version.rb +3 -0
- data/lib/effective_orders.rb +76 -0
- data/lib/generators/effective_orders/install_generator.rb +38 -0
- data/lib/generators/effective_orders/upgrade_from03x_generator.rb +34 -0
- data/lib/generators/effective_orders/upgrade_price_column_generator.rb +34 -0
- data/lib/generators/templates/README +1 -0
- data/lib/generators/templates/effective_orders.rb +210 -0
- data/spec/controllers/carts_controller_spec.rb +143 -0
- data/spec/controllers/moneris_orders_controller_spec.rb +245 -0
- data/spec/controllers/orders_controller_spec.rb +418 -0
- data/spec/controllers/stripe_orders_controller_spec.rb +127 -0
- data/spec/controllers/webhooks_controller_spec.rb +79 -0
- data/spec/dummy/README.rdoc +8 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/product.rb +17 -0
- data/spec/dummy/app/models/product_with_float_price.rb +17 -0
- data/spec/dummy/app/models/user.rb +28 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +31 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +83 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/devise.rb +254 -0
- data/spec/dummy/config/initializers/effective_addresses.rb +15 -0
- data/spec/dummy/config/initializers/effective_orders.rb +22 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +142 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +487 -0
- data/spec/dummy/log/test.log +347 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/helpers/effective_orders_helper_spec.rb +21 -0
- data/spec/models/acts_as_purchasable_spec.rb +107 -0
- data/spec/models/customer_spec.rb +71 -0
- data/spec/models/factories_spec.rb +13 -0
- data/spec/models/order_item_spec.rb +35 -0
- data/spec/models/order_spec.rb +323 -0
- data/spec/models/stripe_charge_spec.rb +39 -0
- data/spec/models/subscription_spec.rb +103 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/factories.rb +118 -0
- 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
|
|
Binary file
|
|
@@ -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,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
|