effective_orders 4.0.0beta1 → 4.0.0beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0cf749b4cef2660e59b16b802211c75e79e7400
4
- data.tar.gz: c4c452a35a548596146b2fdf099916065361dd55
3
+ metadata.gz: da1a756900ec2369535464ac59524e04e480c05f
4
+ data.tar.gz: 593c2b74776dd66558b67efc5ddc2fb09b94203b
5
5
  SHA512:
6
- metadata.gz: af34590308483e7db60eb579b952167622809d2c0cfb9c1101221800e0a3ce51e5ffe6d8d7895755f7fe18282ac379e6de0406f47802c445e16a2492fd838a7a
7
- data.tar.gz: c872866386ab0490fd154cb8caf59119c75ea61cb2f601049d92a75ec0d9a97a7f4e939563a13807b53f3440fe8a0d636c40326da2aa6b89f2858a4fa321f73e
6
+ metadata.gz: d3d7d27ebe782735240eba20c79372d281c9ffa009305c853e2bdd6ed319cf19936051ce8e82b9859f3ee4f6265e67db02161c984b51e42f229b3d4fb2e2474e
7
+ data.tar.gz: a8ff40a48e296934603d9841df3a4854d36fe4ce4ffa59d896310a6176aae905b29aab7ca7b4e1ca2d35bdbd75846b3eeea2c6f2b96e6737410c57d80b42f89c
data/README.md CHANGED
@@ -533,10 +533,10 @@ The one gotcha with the above two scenarios, is that when `purchase!` is called,
533
533
  - `validates_numericality_of :total, greater_than_or_equal_to: minimum_charge` where minimum_charge is the configured value, once again from the initializer
534
534
  - `validates_presence_of :order_items` the Order must have at least one OrderItem
535
535
 
536
- You can skip validations with the following command, but be careful as this skips all validations:
536
+ You can skip some buyer validations with the following command:
537
537
 
538
538
  ```ruby
539
- Effective::Order.new(@product, user: @user).purchase!(validate: false)
539
+ Effective::Order.new(@product, user: @user).purchase!(skip_buyer_validations: true)
540
540
  ```
541
541
 
542
542
  The `@product` is now considered purchased.
@@ -940,136 +940,6 @@ The secret can be any string. Here's a good way to come up with a secret:
940
940
  This process should be very similar although you'll create and configure a seller account on paypal.com rather than the sandbox site.
941
941
  You should generate separate private and public certificates/keys for this and it is advisable to not keep production certificates/keys in version control.
942
942
 
943
- ## Paying via CCBill
944
-
945
- Effective Orders has implemented checkout with CCBill using their "Dynamic Pricing" API and does not
946
- integrate with CCBill subscriptions. If you need to make payments for CCBill subscriptions, please help
947
- by improving Effective Orders with this functionality.
948
-
949
- ### CCBill Account Setup
950
-
951
- You need a merchant account with CCBill so go sign up and login. To set up your account with Dynamic
952
- Pricing, you'll need to go through some hoops with CCBill:
953
-
954
- 1. Get approval to operate a merchant account from CCBill Merchant Services (they'll need to see your
955
- site in action)
956
- 2. Provide CCBill with two valid forms of ID and wait for them to approve your account
957
- 3. Create two additional sub accounts for a staging server and your localhost
958
- ("Account Info" > "Account Setup")
959
- 4. Get each new sub account approved by Merchant Services (mention that they are for testing only)
960
- 5. Ask CCBill tech support to set up all sub accounts with Dynamic Pricing
961
- 6. Set the postback urls for each sub account to be `"#{ your_domain_name }/orders/ccbill_postback`
962
- (Look for 'Approval Post URL' and 'Denial Post URL' in "Account Info" > "Sub Account Admin" > select sub account
963
- \> "Advanced" > under 'Background Post Information')
964
-
965
- ### Effective Orders Configuration
966
-
967
- Get the following information and add it
968
- to the Effective Orders initializer. CCBill live chat is generally quick and helpful. They can help you
969
- find any of this information.
970
-
971
- - Account number (`:client_accnum`)
972
- - Subaccount number (`:client_subacc`)
973
- - Checkout form id/name (`:form_name`)
974
- - Currency code (`:currency_code`)
975
- - Encryption key/salt (`:dynamic_pricing_salt`)("Account Info" > "Sub Account Admin" > select sub account
976
- \> "Advanced" > under 'Upgrade Security Setup Information' > 'Encryption key')
977
-
978
- Effective Orders will authorize to make changes to the customer's order during CCBill's post back after
979
- the transaction. Since, this is not an action that the customer takes directly, please make sure
980
- that the Effective Orders authorization method returns `true` for the controller/action
981
- `'Effective::OrdersController#ccbill_postback'` with an `Effective::Order` resource.
982
-
983
- ### Testing transactions with CCBill
984
-
985
- To test payments with CCBill:
986
-
987
- 1. Set up yourself as a user who is authorized to make test transactions
988
- ([See this guide](https://www.ccbill.com/cs/wiki/tiki-index.php?page=How+do+I+set+up+a+user+to+process+test+transactions%3F))
989
- 2. Use ngrok on localhost or a staging server to go through a normal payment (remember to configure the
990
- postback urls (see #6 of [CCBill Account Setup](#ccbill-account-setup))
991
- 3. Use one of the provided credit card numbers in the guide from step 1 for the associated response
992
-
993
- ### Helpful CCBill Documentation
994
-
995
- - [Dynamic Pricing](https://www.ccbill.com/cs/wiki/tiki-index.php?page=Dynamic+Pricing)
996
- - [Dynamic Pricing User Guide](https://www.ccbill.com/cs/wiki/tiki-index.php?page=Dynamic+Pricing+User+Guide)
997
- - [Background Post](https://www.ccbill.com/cs/wiki/tiki-index.php?page=Background+Post)
998
- - [Webhooks](https://www.ccbill.com/cs/wiki/tiki-index.php?page=Webhooks+User+Guide)
999
- - [How do I set up a user to process test transactions?](https://www.ccbill.com/cs/wiki/tiki-index.php?page=How+do+I+set+up+a+user+to+process+test+transactions%3F)
1000
-
1001
- ## Paying Using App Currency or Logic
1002
-
1003
- There are situations when you want to handle payment logic inside your application. For example, an app could
1004
- have it's own type of currency (tokens, points, kudos) that could be used to make payments.
1005
-
1006
- Let's look at a sample app checkout configuration to see how to get this kind of checkout working:
1007
-
1008
- ```ruby
1009
- config.app_checkout_enabled = true
1010
-
1011
- config.app_checkout = {
1012
- checkout_label: 'Checkout with Tokens',
1013
- service: TokenCheckoutService,
1014
- declined_flash: "Payment was unsuccessful. Please try again."
1015
- }
1016
- ```
1017
-
1018
- First, decide on a checkout button label (this is only used when there's more than one checkout option available).
1019
- Other checkout buttons follow the pattern of "Checkout with \_\_\_", like "Checkout with Moneris".
1020
-
1021
- Second, create a service object in your app and add a reference to it here ([see below for details](#the-app-checkout-service-object)).
1022
-
1023
- The last configuration option is the declined flash message displayed when the `successful?` method
1024
- returns `false`.
1025
-
1026
- Finally, *the app checkout button is hidden* unless effective orders receives authorzation to
1027
- display it. This is helpful if certain users don't use the in-app currency or in-app checkout.
1028
- To authorize effective orders and display the button, you should make sure that the effective
1029
- orders `authorization_method`, defined earlier in the config file, returns `true` if the three
1030
- arguments are: An instance of `Effective::OrdersController`, the Symbol `:app_checkout`, and the
1031
- instance of `Effective::Order`.
1032
-
1033
- ### The App Checkout Service Object
1034
-
1035
- The app checkout [service object](http://stevelorek.com/service-objects.html) is responsible for containing
1036
- the businiess logic of in-app payments (i.e. with tokens).
1037
-
1038
- There are two recommended ways to implement the service object:
1039
-
1040
- 1. Create a service object that inherits from `EffectiveOrders::AppCheckoutService`
1041
- 2. Use the [interactor gem](https://github.com/collectiveidea/interactor) (interactor is just another
1042
- term for service object)
1043
-
1044
- Here's a sample service object (and likely the minimal implementation that you'll want):
1045
-
1046
- ```ruby
1047
- # located in /app/services/token_checkout_service.rb
1048
-
1049
- # Instances of this class have access to the Effective::Order object in the instance variable, @order.
1050
- class TokenCheckoutService < EffectiveOrders::AppCheckoutService
1051
- # This method is responsible to complete the payment transaction
1052
- def call
1053
- cost_in_tokens = Token.cost_in_tokens(@order.price)
1054
- @order.user.tokens = @order.user.tokens - cost_in_tokens
1055
- @success = @order.user.save
1056
- end
1057
-
1058
- # Did the purchase finish correctly?
1059
- def successful?
1060
- @success
1061
- end
1062
-
1063
- # - optional -
1064
- # return a Hash or easily serializable object like a String
1065
- #
1066
- # The return value of this method will be serialized and stored on the `payment_details` attribute
1067
- # of the `Effective::Order`.
1068
- def payment_details
1069
- end
1070
- end
1071
- ```
1072
-
1073
943
 
1074
944
  ## License
1075
945
 
@@ -5,9 +5,9 @@ module Effective
5
5
 
6
6
  protected
7
7
 
8
- def order_purchased(provider:, card: 'none', details: 'none', email: true, skip_buyer_validations: false, purchased_url: nil, declined_url: nil)
8
+ def order_purchased(payment:, provider:, card: 'none', email: true, skip_buyer_validations: false, purchased_url: nil, declined_url: nil)
9
9
  begin
10
- @order.purchase!(provider: provider, card: card, details: details, email: email, skip_buyer_validations: skip_buyer_validations)
10
+ @order.purchase!(payment: payment, provider: provider, card: card, email: email, skip_buyer_validations: skip_buyer_validations)
11
11
 
12
12
  Effective::Cart.where(user_id: @order.user_id).destroy_all
13
13
 
@@ -26,8 +26,8 @@ module Effective
26
26
  end
27
27
  end
28
28
 
29
- def order_declined(provider:, card: 'none', details: 'none', message: nil, declined_url: nil)
30
- @order.decline!(provider: provider, card: card, details: details) rescue nil
29
+ def order_declined(payment:, provider:, card: 'none', message: nil, declined_url: nil)
30
+ @order.decline!(payment: payment, provider: provider, card: card) rescue nil
31
31
 
32
32
  flash[:danger] = message.presence || 'Payment was unsuccessful. Your credit card was declined by the payment processor. Please try again.'
33
33
 
@@ -15,7 +15,7 @@ module Effective
15
15
  end
16
16
 
17
17
  order_purchased(
18
- details: 'free order. no payment required.',
18
+ payment: 'free order. no payment required.',
19
19
  provider: 'free',
20
20
  card: 'none',
21
21
  purchased_url: params[:purchased_url],
@@ -12,7 +12,7 @@ module Effective
12
12
  @order.assign_attributes(mark_as_paid_params.except(:payment, :payment_provider, :payment_card))
13
13
 
14
14
  order_purchased(
15
- details: mark_as_paid_params[:payment],
15
+ payment: mark_as_paid_params[:payment],
16
16
  provider: mark_as_paid_params[:payment_provider],
17
17
  card: mark_as_paid_params[:payment_card],
18
18
  email: @order.send_mark_as_paid_email_to_buyer?,
@@ -1,3 +1,5 @@
1
+ require 'net/http'
2
+
1
3
  module Effective
2
4
  module Providers
3
5
  module Moneris
@@ -17,33 +19,40 @@ module Effective
17
19
  declined_url = params.delete(:rvar_declined_url)
18
20
 
19
21
  if @order.purchased? # Fallback to a success condition of the Order is already purchased
20
- order_purchased(details: params, provider: 'moneris', card: params[:card], purchased_url: purchased_url)
21
- return
22
+ return order_purchased(payment: params, provider: 'moneris', card: params[:card], purchased_url: purchased_url)
22
23
  end
23
24
 
24
- if params[:result].to_s == '1' && params[:transactionKey].present?
25
- verify_params = parse_moneris_response(send_moneris_verify_request(params[:transactionKey])) || {}
25
+ # Invalid Result
26
+ if params[:result].to_s != '1' || params[:transactionKey].blank?
27
+ return order_declined(payment: params, provider: 'moneris', card: params[:card], declined_url: declined_url)
28
+ end
26
29
 
27
- response_code = verify_params[:response_code].to_i # Sometimes moneris sends us the string 'null'
30
+ # Verify response from moneris
31
+ payment = params.merge(verify_moneris_transaction(params[:transactionKey]))
32
+ valid = (1..49).include?(payment[:response_code].to_i) # Must be > 0 and < 50 to be valid. Sometimes we get the string 'null'
28
33
 
29
- if response_code > 0 && response_code < 50 # Less than 50 means a successful validation
30
- order_purchased(details: params.merge(verify_params), provider: 'moneris', card: params[:card], purchased_url: purchased_url)
31
- else
32
- order_declined(details: params.merge(verify_params), provider: 'moneris', card: params[:card], declined_url: declined_url)
33
- end
34
- else
35
- order_declined(details: params, provider: 'moneris', card: params[:card], declined_url: declined_url)
34
+ if valid == false
35
+ return order_declined(payment: payment, provider: 'moneris', card: params[:card], declined_url: declined_url)
36
36
  end
37
+
38
+ order_purchased(payment: payment, provider: 'moneris', card: params[:card], purchased_url: purchased_url)
37
39
  end
38
40
 
39
41
  private
40
42
 
41
- def parse_moneris_response(text)
42
- text.split("<br>").inject(Hash.new()) { |h, i| h[i.split(' ').first.to_sym] = i.split(' ').last ; h } rescue {response: text}
43
- end
43
+ def verify_moneris_transaction(transactionKey)
44
+ # Send a verification POST request
45
+ uri = URI.parse(EffectiveOrders.moneris[:verify_url])
46
+ params = { ps_store_id: EffectiveOrders.moneris[:ps_store_id], hpp_key: EffectiveOrders.moneris[:hpp_key], transactionKey: transactionKey }
47
+ headers = { 'Referer': effective_orders.moneris_postback_orders_url }
48
+
49
+ http = Net::HTTP.new(uri.host, uri.port)
50
+ http.use_ssl = true
51
+
52
+ body = http.post(uri.path, params.to_query, headers).body
44
53
 
45
- def send_moneris_verify_request(verify_key)
46
- `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_orders_url} #{EffectiveOrders.moneris[:verify_url]}`
54
+ # Parse response into a Hash
55
+ body.split('<br>').inject({}) { |h, i| h[i.split(' ').first.to_sym] = i.split(' ').last; h }
47
56
  end
48
57
 
49
58
  end
@@ -16,11 +16,11 @@ module Effective
16
16
 
17
17
  if @order.present?
18
18
  if @order.purchased?
19
- order_purchased(details: params, provider: 'paypal', card: params[:payment_type])
19
+ order_purchased(payment: params, provider: 'paypal', card: params[:payment_type])
20
20
  elsif (params[:payment_status] == 'Completed' && params[:custom] == EffectiveOrders.paypal[:secret])
21
- order_purchased(details: params, provider: 'paypal', card: params[:payment_type])
21
+ order_purchased(payment: params, provider: 'paypal', card: params[:payment_type])
22
22
  else
23
- order_declined(details: params, provider: 'paypal', card: params[:payment_type])
23
+ order_declined(payment: params, provider: 'paypal', card: params[:payment_type])
24
24
  end
25
25
  end
26
26
 
@@ -9,7 +9,7 @@ module Effective
9
9
  EffectiveOrders.authorize!(self, :update, @order)
10
10
 
11
11
  order_purchased(
12
- details: 'for pretend',
12
+ payment: 'for pretend',
13
13
  provider: 'pretend',
14
14
  card: 'none',
15
15
  purchased_url: params[:purchased_url],
@@ -18,7 +18,7 @@ module Effective
18
18
  @order.assign_attributes(refund_params.except(:payment, :payment_provider, :payment_card))
19
19
 
20
20
  order_purchased(
21
- details: refund_params[:payment],
21
+ payment: refund_params[:payment],
22
22
  provider: refund_params[:payment_provider],
23
23
  card: refund_params[:payment_card],
24
24
  email: @order.send_mark_as_paid_email_to_buyer?,
@@ -15,7 +15,7 @@ module Effective
15
15
 
16
16
  if @stripe_charge.valid? && (response = process_stripe_charge(@stripe_charge)) != false
17
17
  order_purchased(
18
- details: response,
18
+ payment: response,
19
19
  provider: 'stripe',
20
20
  card: (response[:charge]['source']['brand'] rescue nil)
21
21
  )
@@ -35,7 +35,7 @@ module EffectiveCartsHelper
35
35
  label: 'My Cart',
36
36
  id: 'current_cart',
37
37
  rel: :nofollow,
38
- class: 'btn btn-default'
38
+ class: 'btn btn-secondary'
39
39
  }.merge(opts)
40
40
 
41
41
  label = options.delete(:label)
@@ -97,6 +97,12 @@ module Effective
97
97
  end
98
98
  end
99
99
 
100
+ with_options if: -> { confirmed? && !skip_buyer_validations? } do |order|
101
+ if EffectiveOrders.terms_and_conditions
102
+ order.validates :terms_and_conditions, presence: true
103
+ end
104
+ end
105
+
100
106
  # When Purchased
101
107
  with_options if: -> { purchased? } do |order|
102
108
  order.validates :purchased_at, presence: true
@@ -132,24 +138,22 @@ module Effective
132
138
  return unless atts.present?
133
139
 
134
140
  if atts.kind_of?(Hash)
135
- if (keywords = (atts.keys - [:item, :items, :user, :billing_address, :shipping_address])).present?
136
- raise ArgumentError.new("unknown keyword: #{keywords.join(' ')}")
137
- end
141
+ items = Array(atts.delete(:item)) + Array(atts.delete(:items))
138
142
 
139
- items = Array(atts[:item]) + Array(atts[:items])
143
+ self.user = atts.delete(:user) || (items.first.user if items.first.respond_to?(:user))
140
144
 
141
- self.user = atts[:user] || (items.first.user if items.first.respond_to?(:user))
142
-
143
- if atts.key?(:billing_address)
144
- self.billing_address = atts[:billing_address]
145
+ if (address = atts.delete(:billing_address)).present?
146
+ self.billing_address = address
145
147
  self.billing_address.full_name ||= user.to_s.presence
146
148
  end
147
149
 
148
- if atts.key?(:shipping_address)
149
- self.shipping_address = atts[:shipping_address]
150
+ if (address = atts.delete(:shipping_address)).present?
151
+ self.shipping_address = address
150
152
  self.shipping_address.full_name ||= user.to_s.presence
151
153
  end
152
154
 
155
+ atts.each { |key, value| self.send("#{key}=", value) }
156
+
153
157
  add(items) if items.present?
154
158
  else # Attributes are not a Hash
155
159
  self.user = atts.user if atts.respond_to?(:user)
@@ -304,42 +308,35 @@ module Effective
304
308
  false
305
309
  end
306
310
 
307
- # Effective::Order.new(Product.first, user: User.first).purchase!(details: 'manual purchase')
308
- # order.purchase!(details: {key: value})
309
- def purchase!(details: 'none', provider: 'none', card: 'none', validate: true, email: true, skip_buyer_validations: false)
311
+ # Effective::Order.new(items: Product.first, user: User.first).purchase!(email: false)
312
+ def purchase!(payment: 'none', provider: 'none', card: 'none', note: nil, email: true, skip_buyer_validations: false)
310
313
  return false if purchased?
311
-
312
- success = false
313
314
  error = nil
314
315
 
316
+ assign_attributes(
317
+ state: EffectiveOrders::PURCHASED,
318
+ purchased_at: Time.zone.now,
319
+ payment: payment_to_h(payment),
320
+ payment_provider: provider,
321
+ payment_card: (card.presence || 'none'),
322
+ skip_buyer_validations: skip_buyer_validations
323
+ )
324
+
315
325
  Effective::Order.transaction do
316
326
  begin
317
- self.state = EffectiveOrders::PURCHASED
318
- self.purchased_at ||= Time.zone.now
319
-
320
- self.payment = details.kind_of?(Hash) ? details : { details: details.to_s }
321
- self.payment_provider = provider.to_s
322
- self.payment_card = card.to_s.presence || 'none'
323
-
324
- self.skip_buyer_validations = skip_buyer_validations
325
-
326
- assign_purchased_order_to_purchasables
327
-
328
327
  run_purchasable_callbacks(:before_purchase)
329
-
330
- save!(validate: validate)
331
-
332
- success = true
328
+ save!
329
+ update_purchasables_purchased_order!
333
330
  rescue => e
334
331
  self.state = state_was
335
- self.purchased_at = purchased_at_was
332
+ self.purchased_at = nil
336
333
 
337
334
  error = e.message
338
335
  raise ::ActiveRecord::Rollback
339
336
  end
340
337
  end
341
338
 
342
- raise "Failed to purchase order: #{error || errors.full_messages.to_sentence}" unless success
339
+ raise "Failed to purchase order: #{error || errors.full_messages.to_sentence}" unless error.nil?
343
340
 
344
341
  send_order_receipts! if email
345
342
 
@@ -348,36 +345,34 @@ module Effective
348
345
  true
349
346
  end
350
347
 
351
- def decline!(details: 'none', provider: 'none', card: 'none', validate: true)
348
+ def decline!(payment: 'none', provider: 'none', card: 'none', validate: true)
352
349
  return false if declined?
353
350
 
354
351
  raise EffectiveOrders::AlreadyPurchasedException.new('order already purchased') if purchased?
355
352
 
356
- success = false
357
353
  error = nil
358
354
 
355
+ assign_attributes(
356
+ state: EffectiveOrders::DECLINED,
357
+ purchased_at: nil,
358
+ payment: payment_to_h(payment),
359
+ payment_provider: provider,
360
+ payment_card: (card.presence || 'none'),
361
+ skip_buyer_validations: true
362
+ )
363
+
359
364
  Effective::Order.transaction do
360
365
  begin
361
- self.state = EffectiveOrders::DECLINED
362
- self.purchased_at = nil
363
-
364
- self.payment = details.kind_of?(Hash) ? details : { details: details.to_s }
365
- self.payment_provider = provider.to_s
366
- self.payment_card = card.to_s.presence || 'none'
367
-
368
366
  save!(validate: validate)
369
-
370
- success = true
371
367
  rescue => e
372
368
  self.state = state_was
373
- self.purchased_at = purchased_at_was
374
369
 
375
370
  error = e.message
376
371
  raise ::ActiveRecord::Rollback
377
372
  end
378
373
  end
379
374
 
380
- raise "Failed to decline order: #{error || errors.full_messages.to_sentence}" unless success
375
+ raise "Failed to decline order: #{error || errors.full_messages.to_sentence}" unless error.nil?
381
376
 
382
377
  run_purchasable_callbacks(:after_decline)
383
378
 
@@ -452,8 +447,8 @@ module Effective
452
447
  end
453
448
  end
454
449
 
455
- def assign_purchased_order_to_purchasables
456
- order_items.each { |oi| oi.purchasable.purchased_order = self }
450
+ def update_purchasables_purchased_order!
451
+ order_items.each { |oi| oi.purchasable.update_column(:purchased_order_id, self.id) }
457
452
  end
458
453
 
459
454
  def run_purchasable_callbacks(name)
@@ -472,5 +467,15 @@ module Effective
472
467
  end
473
468
  end
474
469
 
470
+ def payment_to_h(payment)
471
+ if payment.respond_to?(:to_unsafe_h)
472
+ payment.to_unsafe_h.to_h
473
+ elsif payment.respond_to?(:to_h)
474
+ payment.to_h
475
+ else
476
+ { details: (payment.to_s.presence || 'none') }
477
+ end
478
+ end
479
+
475
480
  end
476
481
  end
@@ -16,7 +16,7 @@ module Effective
16
16
  # timestamps
17
17
 
18
18
  validates :purchasable, associated: true, presence: true
19
- accepts_nested_attributes_for :purchasable, allow_destroy: false, reject_if: :all_blank, update_only: true
19
+ accepts_nested_attributes_for :purchasable
20
20
 
21
21
  validates :title, presence: true
22
22
  validates :quantity, presence: true, numericality: { greater_than: 0 }
@@ -34,6 +34,10 @@ module Effective
34
34
  price * quantity
35
35
  end
36
36
 
37
+ def quantity
38
+ self[:quantity] || 1
39
+ end
40
+
37
41
  def tax
38
42
  return 0 if tax_exempt?
39
43
  raise 'parent Effective::Order must have a tax_rate to compute order item tax' unless order.try(:tax_rate).present?
@@ -1,7 +1,9 @@
1
1
  = dropdown(variation: :dropleft) do
2
2
  - if datatable.admin_namespace?
3
3
  = dropdown_link_to 'View', effective_orders.admin_order_path(order)
4
- = dropdown_link_to 'Edit', effective_orders.edit_admin_order_path(order)
4
+
5
+ - if order.purchased? == false
6
+ = dropdown_link_to 'Edit', effective_orders.edit_admin_order_path(order)
5
7
 
6
8
  - if order.purchased?
7
9
  = dropdown_link_to 'Email receipt to buyer', effective_orders.send_buyer_receipt_order_path(order),
@@ -2,6 +2,11 @@
2
2
 
3
3
  %p= flash[:danger]
4
4
 
5
- %p Your #{link_to_current_cart(label: 'Cart')} items have been saved. Please try again.
6
-
7
-
5
+ %p.effective-orders-page-content
6
+ = link_to 'Home', root_path, class: 'btn btn-primary'
7
+
8
+ %p.effective-orders-page-content
9
+ - if current_cart.present?
10
+ Your #{link_to_current_cart(label: 'Cart')} items have been saved. Please try again.
11
+ - else
12
+ Please try again.
@@ -139,8 +139,8 @@ module EffectiveOrders
139
139
  ('pretend' if pretend?),
140
140
  ('stripe' if stripe?),
141
141
  ('credit card' if mark_as_paid?),
142
- ('none' if mark_as_paid?),
143
142
  ('other' if mark_as_paid?),
143
+ 'none'
144
144
  ].compact
145
145
  end
146
146
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '4.0.0beta1'.freeze
2
+ VERSION = '4.0.0beta2'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_orders
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0beta1
4
+ version: 4.0.0beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-20 00:00:00.000000000 Z
11
+ date: 2018-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails