effective_orders 4.6.3 → 5.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +14 -86
  4. data/app/controllers/admin/customers_controller.rb +5 -16
  5. data/app/controllers/admin/order_items_controller.rb +6 -9
  6. data/app/controllers/admin/orders_controller.rb +18 -82
  7. data/app/controllers/effective/carts_controller.rb +10 -6
  8. data/app/controllers/effective/concerns/purchase.rb +12 -19
  9. data/app/controllers/effective/customers_controller.rb +4 -2
  10. data/app/controllers/effective/orders_controller.rb +26 -23
  11. data/app/controllers/effective/providers/cheque.rb +3 -1
  12. data/app/controllers/effective/providers/free.rb +3 -2
  13. data/app/controllers/effective/providers/mark_as_paid.rb +5 -4
  14. data/app/controllers/effective/providers/moneris.rb +3 -1
  15. data/app/controllers/effective/providers/paypal.rb +3 -2
  16. data/app/controllers/effective/providers/phone.rb +3 -1
  17. data/app/controllers/effective/providers/pretend.rb +4 -3
  18. data/app/controllers/effective/providers/refund.rb +4 -3
  19. data/app/controllers/effective/providers/stripe.rb +4 -3
  20. data/app/controllers/effective/subscripter_controller.rb +4 -2
  21. data/app/controllers/effective/webhooks_controller.rb +12 -3
  22. data/app/datatables/admin/effective_customers_datatable.rb +7 -3
  23. data/app/datatables/admin/effective_orders_datatable.rb +4 -7
  24. data/app/datatables/effective_orders_datatable.rb +3 -7
  25. data/app/helpers/effective_orders_helper.rb +1 -7
  26. data/app/mailers/effective/orders_mailer.rb +131 -96
  27. data/app/models/concerns/acts_as_purchasable.rb +0 -11
  28. data/app/models/concerns/acts_as_subscribable.rb +0 -6
  29. data/app/models/effective/cart.rb +7 -5
  30. data/app/models/effective/cart_item.rb +7 -4
  31. data/app/models/effective/customer.rb +7 -6
  32. data/app/models/effective/order.rb +58 -61
  33. data/app/models/effective/order_item.rb +20 -8
  34. data/app/models/effective/product.rb +11 -6
  35. data/app/models/effective/subscription.rb +13 -12
  36. data/app/views/admin/orders/_form.html.haml +5 -9
  37. data/app/views/admin/orders/_order_item_fields.html.haml +8 -12
  38. data/app/views/effective/orders/_checkout_step2.html.haml +1 -2
  39. data/app/views/effective/orders/_order_actions.html.haml +2 -2
  40. data/app/views/effective/orders/show.html.haml +4 -0
  41. data/config/effective_orders.rb +8 -32
  42. data/config/routes.rb +16 -17
  43. data/db/migrate/01_create_effective_orders.rb.erb +4 -0
  44. data/lib/effective_orders.rb +34 -76
  45. data/lib/effective_orders/engine.rb +0 -7
  46. data/lib/effective_orders/version.rb +1 -1
  47. data/lib/generators/templates/effective_orders_mailer_preview.rb +13 -13
  48. data/lib/tasks/effective_orders_tasks.rake +2 -2
  49. metadata +2 -3
  50. data/app/models/effective/access_denied.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0619b2dc6fc02860fcf6100f107133d2bb47133cb43eb03e60905a1932acca06'
4
- data.tar.gz: a2cb49a3e9fba575b7f95941b64f58b02bd81e4030b4ddb14130ea2fb3f041f3
3
+ metadata.gz: '09e7e3354a9268cf3f5c7f000fe685c96c63e519c37269e534fb41669654c2ac'
4
+ data.tar.gz: b117ad0187b25c59a496c658eee479af26bf0843951676065e7bc82633e9803f
5
5
  SHA512:
6
- metadata.gz: 8b39ed3047b11b55ddb153a4465c3c31e11304cef618eb70ed1eb237f522e1ddd7267cd1507b7a2c25ee737dc3f31654940c676a9ef4419565f7b776f4a5622c
7
- data.tar.gz: 36a94c2eb539e2beb23996fb97d14b2befe62ae9154cd1cd578cac1bf9f886f0a9c3eca05f453b92d4bd4fdf6c17f84c621cce270732e70360cb272ee1db6ddd
6
+ metadata.gz: 22e01baa9aeced210808a95d75fd18ef77a40d5de9f0ae34c6c6e86a42f4e51292d5dfa43d43d1647f5ba6a0dcd06532511571c6d72bd04de811294d453f1134
7
+ data.tar.gz: bb0995769c746838c40cd58e905f6c1079db824ab521342bd59c9b2b492c8805d7b55e2f0568cf86b2f3db14c727f61c1c97fe96831d95db359e1812e1296cb5
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Code and Effect Inc.
1
+ Copyright 2021 Code and Effect Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Carts, Orders, and collecting payment via Stripe, PayPal and Moneris.
4
4
 
5
- A Rails Engine to handle the purchase workflow in a Rails 3.2.x / Rails 4 application.
5
+ A Rails Engine to handle the purchase workflow in a Rails application.
6
6
 
7
7
  Also works with Stripe Subscriptions.
8
8
 
@@ -10,17 +10,9 @@ Sends order receipt emails automatically.
10
10
 
11
11
  Has Order History, My Purchases, My Sales and Admin screens.
12
12
 
13
- ## Upgrade to effective_orders 4.3
13
+ ## effective_orders 5.0
14
14
 
15
- Add the migration
16
-
17
- ```
18
- add_column :customers, :payment_method_id, :string
19
- ```
20
-
21
- ## effective_orders 4.0
22
-
23
- This is the 4.0 series of effective_orders.
15
+ This is the 5.0 series of effective_orders.
24
16
 
25
17
  This requires Twitter Bootstrap 4 and Rails 5.1+
26
18
 
@@ -160,32 +152,18 @@ Once the database has been migrated, it is time to scaffold/build the CRUD Produ
160
152
 
161
153
  ### Products#new/#edit
162
154
 
163
- Use an [effective_form_inputs](https://github.com/code-and-effect/effective_form_inputs#effective-price) effective_price input to enter the price.
155
+ Use an [effective_bootstrap](https://github.com/code-and-effect/effective_bootstrap#effective-price) f.price_field input to enter the price.
164
156
 
165
157
  It displays the underlying Integer price as a currency formatted value, ensures that a properly formatted price is entered by the user, and POSTs the appropriate Integer value back to the server.
166
158
 
167
159
  This is available for simple_form, formtastic and Rails default FormBuilder.
168
160
 
169
161
  ```haml
170
- = simple_form_for(@product) do |f|
171
- = f.input :name
172
- = f.input :tax_exempt
173
- = f.input :price, as: :effective_price
174
- = f.button :submit
175
- ```
176
-
177
- or
178
-
179
- ```ruby
180
- = semantic_form_for(@product) do |f|
181
- = f.input :price, as: :effective_price
182
- ```
183
-
184
- or
185
-
186
- ```haml
187
- = form_for(@product) do |f|
188
- = f.effective_price :price
162
+ = effective_form_with(model: @product) do |f|
163
+ = f.text_field :name
164
+ = f.checkbox :tax_exempt
165
+ = f.price_field :price
166
+ = f.submit
189
167
  ```
190
168
 
191
169
  ### Products#show
@@ -287,8 +265,6 @@ end
287
265
 
288
266
  Of course, there's no mechanism here to prevent someone from just copy&pasting this URL to a friend.
289
267
 
290
- If you're interested in that kind of restricted-download functionality, please check out [effective_assets](https://github.com/code-and-effect/effective_assets) and the authenticated-read temporary URLs.
291
-
292
268
 
293
269
  ### Tax Exempt
294
270
 
@@ -367,54 +343,7 @@ end
367
343
 
368
344
  ## Authorization
369
345
 
370
- All authorization checks are handled via the config.authorization_method found in the `config/initializers/effective_orders.rb` file.
371
-
372
- It is intended for flow through to CanCan or Pundit, but neither of those gems are required.
373
-
374
- This method is called by the controller action with the appropriate action and resource.
375
-
376
- Action will be one of [:index, :show, :new, :create, :edit, :update, :destroy]
377
-
378
- Resource will the appropriate Effective::Order, Effective::Cart or Effective::Subscription ActiveRecord object or class
379
-
380
- The authorization method is defined in the initializer file:
381
-
382
- ```ruby
383
- # As a Proc (with CanCan)
384
- config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) }
385
- ```
386
-
387
- ```ruby
388
- # As a Custom Method
389
- config.authorization_method = :my_authorization_method
390
- ```
391
-
392
- and then in your application_controller.rb:
393
-
394
- ```ruby
395
- def my_authorization_method(action, resource)
396
- current_user.is?(:admin) || EffectivePunditPolicy.new(current_user, resource).send('#{action}?')
397
- end
398
- ```
399
-
400
- or disabled entirely:
401
-
402
- ```ruby
403
- config.authorization_method = false
404
- ```
405
-
406
- If the method or proc returns false (user is not authorized) an Effective::AccessDenied exception will be raised
407
-
408
- You can rescue from this exception by adding the following to your application_controller.rb:
409
-
410
- ```ruby
411
- rescue_from Effective::AccessDenied do |exception|
412
- respond_to do |format|
413
- format.html { render 'static_pages/access_denied', status: 403 }
414
- format.any { render text: 'Access Denied', status: 403 }
415
- end
416
- end
417
- ```
346
+ All authorization checks are handled via the effective_resources gem found in the `config/initializers/effective_resources.rb` file.
418
347
 
419
348
  ### Permissions
420
349
 
@@ -422,7 +351,10 @@ The permissions you actually want to define for a regular user are as follows (u
422
351
 
423
352
  ```ruby
424
353
  can [:manage], Effective::Cart, user_id: user.id
354
+
425
355
  can [:manage], Effective::Order, user_id: user.id # Orders cannot be deleted
356
+ cannot [:edit, :update], Effective::Order, state: 'purchased'
357
+
426
358
  can [:manage], Effective::Subscription, user_id: user.id
427
359
  ```
428
360
 
@@ -452,7 +384,6 @@ Only when the user proceeds to Checkout will they be required to login.
452
384
  Upon log in, the session Cart will be assigned to that User's ID, and if the User had a previous existing cart, all CartItems will be merged.
453
385
 
454
386
 
455
-
456
387
  You shouldn't need to deal with the Cart object at all, except to make a link from your Site Menu to the 'My Cart' page (as documented above).
457
388
 
458
389
  However, if you want to render a Cart on another page, or play with the Cart object directly, you totally can.
@@ -500,9 +431,6 @@ If you are using effective_orders to roll your own custom payment workflow, you
500
431
 
501
432
  Emails will be sent immediately unless `config.mailer[:deliver_method] == :deliver_later`.
502
433
 
503
- If you are using [Delayed::Job](https://github.com/collectiveidea/delayed_job) to send emails in a background process then you should set the `delayed_job_deliver` option so that `config.mailer[:delayed_job_deliver] == true`.
504
-
505
-
506
434
  ### Effective::Order Model
507
435
 
508
436
  There may be times where you want to deal with the `Effective::Order` object directly.
@@ -997,7 +925,7 @@ You should generate separate private and public certificates/keys for this and i
997
925
 
998
926
  ## License
999
927
 
1000
- MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
928
+ MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
1001
929
 
1002
930
  ## Contributing
1003
931
 
@@ -1,23 +1,12 @@
1
1
  module Admin
2
2
  class CustomersController < ApplicationController
3
- before_action :authenticate_user!
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_orders) }
4
5
 
5
- layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:admin_customers] : EffectiveOrders.layout)
6
+ include Effective::CrudController
6
7
 
7
- def index
8
- @datatable = Admin::EffectiveCustomersDatatable.new(self)
9
-
10
- @page_title = 'Customers'
11
-
12
- EffectiveOrders.authorize!(self, :admin, :effective_orders)
13
- EffectiveOrders.authorize!(self, :index, Effective::Customer)
14
- end
15
-
16
- def show
17
- @customer = Effective::Customer.find(params[:id])
18
-
19
- @page_title ||= @customer.to_s
20
- EffectiveOrders.authorize!(self, :show, Effective::Customer)
8
+ if (config = EffectiveOrders.layout)
9
+ layout(config.kind_of?(Hash) ? config[:admin] : config)
21
10
  end
22
11
 
23
12
  end
@@ -1,16 +1,13 @@
1
1
  module Admin
2
2
  class OrderItemsController < ApplicationController
3
- before_action :authenticate_user!
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_orders) }
4
5
 
5
- layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:admin_orders] : EffectiveOrders.layout)
6
+ include Effective::CrudController
6
7
 
7
- def index
8
- @datatable = Admin::EffectiveOrderItemsDatatable.new(self)
9
-
10
- @page_title = 'Order Items'
11
-
12
- EffectiveOrders.authorize!(self, :admin, :effective_orders)
13
- EffectiveOrders.authorize!(self, :index, Effective::OrderItem)
8
+ if (config = EffectiveOrders.layout)
9
+ layout(config.kind_of?(Hash) ? config[:admin] : config)
14
10
  end
11
+
15
12
  end
16
13
  end
@@ -1,32 +1,21 @@
1
1
  module Admin
2
2
  class OrdersController < ApplicationController
3
- before_action :authenticate_user!
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_orders) }
4
5
 
5
- layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:admin_orders] : EffectiveOrders.layout)
6
+ include Effective::CrudController
6
7
 
7
- def new
8
- @order = Effective::Order.new
9
-
10
- if params[:user_id]
11
- @order.user = User.where(id: params[:user_id]).first
12
- end
13
-
14
- if params[:duplicate_id]
15
- @duplicate = Effective::Order.deep.find(params[:duplicate_id])
16
- EffectiveOrders.authorize!(self, :show, @duplicate)
17
-
18
- @order.add(@duplicate)
19
- end
20
-
21
- @page_title = 'New Order'
22
-
23
- raise 'please install cocoon gem to use this page' unless defined?(Cocoon)
24
-
25
- authorize_effective_order!
8
+ if (config = EffectiveOrders.layout)
9
+ layout(config.kind_of?(Hash) ? config[:admin] : config)
26
10
  end
27
11
 
12
+ submit :save, 'Continue', redirect: :index
13
+ submit :save, 'Add New', redirect: -> { effective_orders.new_admin_order_path(user_id: resource.user&.to_param) }
14
+ submit :save, 'Duplicate', redirect: -> { effective_posts.new_admin_post_path(duplicate_id: resource.id) }
15
+ submit :save, 'Checkout', redirect: -> { effective_orders.checkout_admin_order_path(resource) }
16
+
28
17
  def create
29
- @user = User.find_by_id(order_params[:user_id])
18
+ @user = current_user.class.find_by_id(order_params[:user_id])
30
19
  @order = Effective::Order.new(user: @user)
31
20
 
32
21
  authorize_effective_order!
@@ -54,50 +43,14 @@ module Admin
54
43
  end
55
44
 
56
45
  @page_title = 'New Order'
57
- flash.now[:danger] = flash_danger(@order)
46
+ flash.now[:danger] = flash_danger(@order) + error.to_s
58
47
  render :new
59
48
  end
60
49
 
61
- def edit
62
- @order = Effective::Order.find(params[:id])
63
- @page_title ||= @order.to_s
64
-
65
- authorize_effective_order!
66
- end
67
-
68
- def update
69
- @order = Effective::Order.find(params[:id])
70
-
71
- @page_title ||= @order.to_s
72
-
73
- authorize_effective_order!
74
-
75
- Effective::Order.transaction do
76
- begin
77
- @order.assign_attributes(order_params)
78
- @order.save!
79
- redirect_to(admin_redirect_path) and return
80
- rescue => e
81
- raise ActiveRecord::Rollback
82
- end
83
- end
84
-
85
- flash.now[:danger] = "Unable to update order: #{@order.errors.full_messages.to_sentence}"
86
- render :edit
87
- end
88
-
89
- def show
90
- @order = Effective::Order.find(params[:id])
91
-
92
- @page_title ||= @order.to_s
93
-
94
- authorize_effective_order!
95
- end
96
-
97
50
  # The show page posts to this action
98
51
  # See Effective::OrdersController checkout
99
52
  def checkout
100
- @order = Effective::Order.find(params[:id])
53
+ @order = Effective::Order.not_purchased.find(params[:id])
101
54
 
102
55
  authorize_effective_order!
103
56
 
@@ -122,14 +75,6 @@ module Admin
122
75
  render :checkout
123
76
  end
124
77
 
125
- def index
126
- @datatable = Admin::EffectiveOrdersDatatable.new(self)
127
-
128
- @page_title = 'Orders'
129
-
130
- authorize_effective_order!
131
- end
132
-
133
78
  def destroy
134
79
  @order = Effective::Order.all.not_purchased.find(params[:id])
135
80
 
@@ -179,12 +124,12 @@ module Admin
179
124
  private
180
125
 
181
126
  def order_params
182
- params.require(:effective_order).permit(:user_id, :cc,
127
+ params.require(:effective_order).permit(:user_id, :user_type, :cc,
183
128
  :send_payment_request_to_buyer, :note_internal, :note_to_buyer,
184
129
  :payment_provider, :payment_card, :payment, :send_mark_as_paid_email_to_buyer,
185
130
  order_items_attributes: [
186
131
  :quantity, :_destroy, purchasable_attributes: [
187
- :name, :price, :tax_exempt
132
+ :name, :qb_item_name, :price, :tax_exempt
188
133
  ]
189
134
  ]
190
135
  )
@@ -195,27 +140,18 @@ module Admin
195
140
  end
196
141
 
197
142
  def authorize_effective_order!
198
- EffectiveOrders.authorize!(self, :admin, :effective_orders)
199
- EffectiveOrders.authorize!(self, action_name.to_sym, @order || Effective::Order)
143
+ EffectiveResources.authorize!(self, action_name.to_sym, @order || Effective::Order)
200
144
  end
201
145
 
202
146
  def admin_redirect_path
203
- # Allow an app to define effective_orders_admin_redirect_path in their ApplicationController
204
- path = if self.respond_to?(:effective_orders_admin_redirect_path)
205
- effective_orders_admin_redirect_path(params[:commit], @order)
206
- end
207
-
208
- return path if path.present?
209
-
210
147
  case params[:commit].to_s
211
148
  when 'Save' ; effective_orders.admin_order_path(@order)
212
-
213
149
  when 'Continue' ; effective_orders.admin_orders_path
214
150
  when 'Add New' ; effective_orders.new_admin_order_path(user_id: @order.user.try(:to_param))
215
151
  when 'Duplicate' ; effective_orders.new_admin_order_path(duplicate_id: @order.to_param)
216
152
  when 'Checkout' ; effective_orders.checkout_admin_order_path(@order.to_param)
217
-
218
- else effective_orders.admin_order_path(@order)
153
+ else
154
+ effective_orders.admin_order_path(@order)
219
155
  end
220
156
  end
221
157
 
@@ -1,21 +1,25 @@
1
1
  module Effective
2
2
  class CartsController < ApplicationController
3
- layout (EffectiveOrders.layout.kind_of?(Hash) ? EffectiveOrders.layout[:carts] : EffectiveOrders.layout)
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
4
 
5
- before_action :authenticate_user!
5
+ include Effective::CrudController
6
+
7
+ if (config = EffectiveOrders.layout)
8
+ layout(config.kind_of?(Hash) ? (config[:carts] || config[:application]) : config)
9
+ end
6
10
 
7
11
  def show
8
12
  @cart = current_cart
9
13
  @pending_orders = Effective::Order.not_purchased.where(user: current_user) if current_user.present?
10
14
 
11
15
  @page_title ||= 'My Cart'
12
- EffectiveOrders.authorize!(self, :show, @cart)
16
+ EffectiveResources.authorize!(self, :show, @cart)
13
17
  end
14
18
 
15
19
  def destroy
16
20
  @cart = current_cart
17
21
 
18
- EffectiveOrders.authorize!(self, :destroy, @cart)
22
+ EffectiveResources.authorize!(self, :destroy, @cart)
19
23
 
20
24
  if @cart.destroy
21
25
  flash[:success] = 'Successfully emptied cart.'
@@ -29,7 +33,7 @@ module Effective
29
33
  def add_to_cart
30
34
  @purchasable = (add_to_cart_params[:purchasable_type].constantize.find(add_to_cart_params[:purchasable_id].to_i) rescue nil)
31
35
 
32
- EffectiveOrders.authorize!(self, :update, current_cart)
36
+ EffectiveResources.authorize!(self, :update, current_cart)
33
37
 
34
38
  begin
35
39
  raise "Please select a valid #{add_to_cart_params[:purchasable_type] || 'item' }." unless @purchasable
@@ -48,7 +52,7 @@ module Effective
48
52
  def remove_from_cart
49
53
  @cart_item = current_cart.cart_items.find(remove_from_cart_params[:id])
50
54
 
51
- EffectiveOrders.authorize!(self, :update, current_cart)
55
+ EffectiveResources.authorize!(self, :update, current_cart)
52
56
 
53
57
  if @cart_item.destroy
54
58
  flash[:success] = 'Successfully removed item from cart.'
@@ -5,28 +5,21 @@ module Effective
5
5
 
6
6
  protected
7
7
 
8
- def order_purchased(payment:, provider:, card: 'none', email: true, skip_buyer_validations: false, purchased_url: nil, declined_url: nil)
9
- begin
10
- @order.purchase!(payment: payment, provider: provider, card: card, email: email, skip_buyer_validations: skip_buyer_validations)
11
-
12
- Effective::Cart.where(user: @order.user).destroy_all
13
-
14
- if flash[:success].blank?
15
- if EffectiveOrders.mailer[:send_order_receipt_to_buyer] && email
16
- flash[:success] = "Payment successful! A receipt has been sent to #{@order.emails_send_to}"
17
- else
18
- flash[:success] = "Payment successful! An email receipt has not been sent."
19
- end
20
- end
8
+ def order_purchased(payment:, provider:, card: 'none', email: true, skip_buyer_validations: false, purchased_url: nil)
9
+ @order.purchase!(payment: payment, provider: provider, card: card, email: email, skip_buyer_validations: skip_buyer_validations)
21
10
 
22
- purchased_url ||= effective_orders.purchased_order_path(':id')
23
- redirect_to purchased_url.gsub(':id', @order.to_param.to_s)
24
- rescue => e
25
- flash[:danger] = "An error occurred while processing your payment: #{e.message}. Please try again."
11
+ Effective::Cart.where(user: @order.user).destroy_all
26
12
 
27
- declined_url ||= effective_orders.declined_order_path(':id')
28
- redirect_to declined_url.gsub(':id', @order.to_param.to_s)
13
+ if flash[:success].blank?
14
+ if email && EffectiveOrders.mailer[:send_order_receipt_to_buyer]
15
+ flash[:success] = "Payment successful! A receipt has been sent to #{@order.emails_send_to}"
16
+ else
17
+ flash[:success] = "Payment successful! An email receipt has not been sent."
18
+ end
29
19
  end
20
+
21
+ purchased_url ||= effective_orders.purchased_order_path(':id')
22
+ redirect_to purchased_url.gsub(':id', @order.to_param.to_s)
30
23
  end
31
24
 
32
25
  def order_deferred(provider:, email: true, deferred_url: nil)