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 +4 -4
- data/README.md +2 -132
- data/app/controllers/effective/concerns/purchase.rb +4 -4
- data/app/controllers/effective/providers/free.rb +1 -1
- data/app/controllers/effective/providers/mark_as_paid.rb +1 -1
- data/app/controllers/effective/providers/moneris.rb +26 -17
- data/app/controllers/effective/providers/paypal.rb +3 -3
- data/app/controllers/effective/providers/pretend.rb +1 -1
- data/app/controllers/effective/providers/refund.rb +1 -1
- data/app/controllers/effective/providers/stripe.rb +1 -1
- data/app/helpers/effective_carts_helper.rb +1 -1
- data/app/models/effective/order.rb +52 -47
- data/app/models/effective/order_item.rb +5 -1
- data/app/views/admin/orders/_actions.html.haml +3 -1
- data/app/views/effective/orders/declined.html.haml +8 -3
- data/lib/effective_orders.rb +1 -1
- data/lib/effective_orders/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da1a756900ec2369535464ac59524e04e480c05f
|
4
|
+
data.tar.gz: 593c2b74776dd66558b67efc5ddc2fb09b94203b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
536
|
+
You can skip some buyer validations with the following command:
|
537
537
|
|
538
538
|
```ruby
|
539
|
-
Effective::Order.new(@product, user: @user).purchase!(
|
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',
|
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,
|
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',
|
30
|
-
@order.decline!(provider: provider, card: card
|
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
|
|
@@ -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
|
-
|
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(
|
21
|
-
return
|
22
|
+
return order_purchased(payment: params, provider: 'moneris', card: params[:card], purchased_url: purchased_url)
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
-
|
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
|
-
|
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
|
-
|
30
|
-
|
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
|
42
|
-
|
43
|
-
|
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
|
-
|
46
|
-
|
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(
|
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(
|
21
|
+
order_purchased(payment: params, provider: 'paypal', card: params[:payment_type])
|
22
22
|
else
|
23
|
-
order_declined(
|
23
|
+
order_declined(payment: params, provider: 'paypal', card: params[:payment_type])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -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
|
-
|
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
|
-
|
18
|
+
payment: response,
|
19
19
|
provider: 'stripe',
|
20
20
|
card: (response[:charge]['source']['brand'] rescue nil)
|
21
21
|
)
|
@@ -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
|
-
|
136
|
-
raise ArgumentError.new("unknown keyword: #{keywords.join(' ')}")
|
137
|
-
end
|
141
|
+
items = Array(atts.delete(:item)) + Array(atts.delete(:items))
|
138
142
|
|
139
|
-
|
143
|
+
self.user = atts.delete(:user) || (items.first.user if items.first.respond_to?(:user))
|
140
144
|
|
141
|
-
|
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.
|
149
|
-
self.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!(
|
308
|
-
|
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
|
-
|
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 =
|
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
|
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!(
|
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
|
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
|
456
|
-
order_items.each { |oi| oi.purchasable.
|
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
|
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
|
-
|
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
|
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.
|
data/lib/effective_orders.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2018-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|