spree_wallet 2.0.7 → 2.0.8
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.
- data/LICENSE +26 -0
- data/README.md +39 -0
- data/app/assets/stylesheets/store/checkout.css +1 -0
- data/app/assets/stylesheets/store/spree_wallet.css +3 -0
- data/app/controllers/spree/admin/store_credits_controller.rb +56 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +57 -0
- data/app/controllers/spree/payments_controller_decorator.rb +34 -0
- data/app/models/spree/credit.rb +13 -0
- data/app/models/spree/debit.rb +13 -0
- data/app/models/spree/order_decorator.rb +53 -0
- data/app/models/spree/payment_decorator.rb +39 -0
- data/app/models/spree/payment_method/wallet.rb +19 -0
- data/app/models/spree/store_credit.rb +30 -0
- data/app/models/spree/user_decorator.rb +3 -0
- data/app/overrides/add_store_credits_tab_in_configuration_menu.rb +8 -0
- data/app/views/spree/admin/payments/source_forms/_wallet.html.erb +0 -0
- data/app/views/spree/admin/payments/source_views/_wallet.html.erb +0 -0
- data/app/views/spree/admin/store_credits/index.html.erb +97 -0
- data/app/views/spree/admin/store_credits/new.html.erb +27 -0
- data/app/views/spree/admin/users/index.html.erb +59 -0
- data/app/views/spree/checkout/_payment.html.erb +45 -0
- data/app/views/spree/checkout/payment/_wallet.html.erb +0 -0
- data/config/locales/en.yml +21 -0
- data/config/routes.rb +11 -0
- data/db/migrate/20130712094651_create_spree_store_credits.rb +15 -0
- data/db/migrate/20130715130434_add_store_credits_to_spree_users.rb +5 -0
- data/db/migrate/20130719124429_add_indexes_on_spree_store_credits_fields_type_and_user_id.rb +6 -0
- data/db/migrate/20130729071647_add_lock_version_to_spree_users.rb +5 -0
- data/db/migrate/20130729140933_add_unique_index_on_transaction_id_to_spree_store_credits.rb +5 -0
- data/db/migrate/20130801135105_add_transactioner_id_to_spree_store_credits.rb +6 -0
- data/lib/generators/spree_wallet/install/install_generator.rb +25 -0
- data/lib/spree/disable_negative_payment_mode_and_set_balance_ability.rb +18 -0
- data/lib/spree_wallet/engine.rb +26 -0
- data/lib/spree_wallet/factories.rb +6 -0
- data/lib/spree_wallet.rb +2 -0
- metadata +38 -3
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2013 [name of plugin creator]
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
SpreeWallet
|
2
|
+
===========
|
3
|
+
|
4
|
+
Installation
|
5
|
+
------------
|
6
|
+
|
7
|
+
Add spree_wallet to your Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
|
11
|
+
gem 'spree_wallet', :git => 'git://github.com/vinsol/spree_wallet.git'
|
12
|
+
OR
|
13
|
+
gem 'spree_wallet', '~> 2.0.6'
|
14
|
+
```
|
15
|
+
|
16
|
+
Bundle your dependencies and run the installation generator:
|
17
|
+
|
18
|
+
```shell
|
19
|
+
bundle
|
20
|
+
bundle exec rails g spree_wallet:install
|
21
|
+
bundle exec rake db:migrate
|
22
|
+
```
|
23
|
+
|
24
|
+
Usage
|
25
|
+
-----
|
26
|
+
|
27
|
+
From Admin end, create a payment method of Wallet type. From User end, user can only select or unselect wallet payment type. Spree Wallet will deduce minimum of order total and spree wallet balance of that user. If there's any remaining amount in the order it will be deducted from other payment method choosen by the user.
|
28
|
+
|
29
|
+
While from admin end, Admin can select any amount from wallet, but it should be less than amount present in user's balance.
|
30
|
+
|
31
|
+
## Contribution
|
32
|
+
|
33
|
+
You need to do a quick one-time creation of a test application and then you can use it to run the tests.
|
34
|
+
|
35
|
+
bundle exec rake test_app
|
36
|
+
|
37
|
+
Then run the rspec tests with mysql.
|
38
|
+
|
39
|
+
bundle exec rspec .
|
@@ -0,0 +1 @@
|
|
1
|
+
.hidden { display: none; }
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class StoreCreditsController < ResourceController
|
4
|
+
helper_method :store_credit_class
|
5
|
+
skip_before_filter :load_resource, :only => [:index]
|
6
|
+
before_filter :disable_negative_payment_mode, :add_transactioner_to_store_credit, :only => :create
|
7
|
+
|
8
|
+
def index
|
9
|
+
@search = association_or_class.order_created_at_desc.ransack(params[:q])
|
10
|
+
@store_credits = @search.result.page(params[:page]).includes(required_includes_arguements)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def disable_negative_payment_mode
|
16
|
+
@store_credit.disable_negative_payment_mode = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_transactioner_to_store_credit
|
20
|
+
@store_credit.transactioner = spree_current_user
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parent_data
|
24
|
+
{ :model_class => Spree.user_class, :find_by => :id, :model_name => 'spree/user' }
|
25
|
+
end
|
26
|
+
|
27
|
+
def association_or_class
|
28
|
+
parent ? parent.store_credits : Spree::StoreCredit
|
29
|
+
end
|
30
|
+
|
31
|
+
def required_includes_arguements
|
32
|
+
parent ? :transactioner : [:transactioner, :user]
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_resource
|
36
|
+
if parent_data.present?
|
37
|
+
store_credit_class.new{ |store_credit| store_credit.user = parent }
|
38
|
+
else
|
39
|
+
store_credit_class.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_resource
|
44
|
+
if parent_data.present?
|
45
|
+
store_credit_class.where(:id => params[:id], :user_id => parent.id).first
|
46
|
+
else
|
47
|
+
store_credit_class.where(:id => params[:id]).first
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def store_credit_class
|
52
|
+
params[:type] ? "spree/#{params[:type]}".classify.constantize : model_class
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
Spree::CheckoutController.class_eval do
|
2
|
+
before_filter :validate_payments, :only => :update, :if => lambda { @order && @order.has_checkout_step?("payment") && @order.payment? && @order.available_wallet_payment_method }
|
3
|
+
|
4
|
+
private
|
5
|
+
def object_params
|
6
|
+
if @order.has_checkout_step?("payment") && @order.payment?
|
7
|
+
if params[:payment_source].present?
|
8
|
+
source_params = params.delete(:payment_source)[non_wallet_payment_method]
|
9
|
+
|
10
|
+
if source_params
|
11
|
+
non_wallet_payment_attributes(params[:order][:payments_attributes]).first[:source_attributes] = source_params
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if (params[:order][:payments_attributes])
|
16
|
+
# This method is overrided because spree add all order total in first payment, now after wallet we can have multiple payments.
|
17
|
+
if spree_current_user && @order.available_wallet_payment_method
|
18
|
+
wallet_payments = wallet_payment_attributes(params[:order][:payments_attributes])
|
19
|
+
wallet_payments.first[:amount] = [@order.remaining_total, spree_current_user.store_credits_total].min if wallet_payments.present?
|
20
|
+
params[:order][:payments_attributes] = wallet_payments if remaining_order_total_after_wallet(@order, wallet_payments) <= 0
|
21
|
+
non_wallet_payment_attributes(params[:order][:payments_attributes]).first[:amount] = remaining_order_total_after_wallet(@order, wallet_payments) if non_wallet_payment_attributes(params[:order][:payments_attributes]).present?
|
22
|
+
else
|
23
|
+
params[:order][:payments_attributes].first[:amount] = @order.remaining_total
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
params[:order]
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate_payments
|
31
|
+
payments_attributes = params[:order][:payments_attributes]
|
32
|
+
wallet_payment = wallet_payment_attributes(payments_attributes)
|
33
|
+
if !spree_current_user && wallet_payment.present?
|
34
|
+
flash[:error] = Spree.t(:cannot_select_wallet_while_guest_checkout)
|
35
|
+
redirect_to checkout_state_path(@order.state)
|
36
|
+
elsif wallet_payment.present? && non_wallet_payment_attributes(payments_attributes).empty? && @order.remaining_total >= spree_current_user.store_credits_total
|
37
|
+
flash[:error] = Spree.t(:not_sufficient_amount_in_wallet)
|
38
|
+
redirect_to checkout_state_path(@order.state)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def non_wallet_payment_method
|
43
|
+
non_wallet_payment_attributes(params[:order][:payments_attributes]).first[:payment_method_id] if non_wallet_payment_attributes(params[:order][:payments_attributes]).first
|
44
|
+
end
|
45
|
+
|
46
|
+
def remaining_order_total_after_wallet(order, wallet_payments)
|
47
|
+
wallet_payments.present? ? order.remaining_total - wallet_payments.first[:amount] : order.remaining_total
|
48
|
+
end
|
49
|
+
|
50
|
+
def wallet_payment_attributes(payment_attributes)
|
51
|
+
payment_attributes.select { |payment| payment["payment_method_id"] == Spree::PaymentMethod::Wallet.first.id.to_s }
|
52
|
+
end
|
53
|
+
|
54
|
+
def non_wallet_payment_attributes(payment_attributes)
|
55
|
+
@non_wallet_payment ||= payment_attributes - wallet_payment_attributes(payment_attributes)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
Spree::Admin::PaymentsController.class_eval do
|
2
|
+
def create
|
3
|
+
@payment = @order.payments.build(object_params)
|
4
|
+
if @payment.payment_method.is_a?(Spree::Gateway) && @payment.payment_method.payment_profiles_supported? && params[:card].present? and params[:card] != 'new'
|
5
|
+
@payment.source = Spree::CreditCard.find_by_id(params[:card])
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
unless @payment.save
|
10
|
+
# In spree, if payment is not able to save. It will redirect to index page, rather than it should render new with errors.
|
11
|
+
render :new
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
if @order.completed?
|
16
|
+
@payment.process!
|
17
|
+
flash[:success] = flash_message_for(@payment, :successfully_created)
|
18
|
+
|
19
|
+
redirect_to admin_order_payments_path(@order)
|
20
|
+
else
|
21
|
+
#This is the first payment (admin created order)
|
22
|
+
until @order.completed?
|
23
|
+
@order.next!
|
24
|
+
end
|
25
|
+
flash[:success] = Spree.t(:new_order_completed)
|
26
|
+
redirect_to edit_admin_order_url(@order)
|
27
|
+
end
|
28
|
+
|
29
|
+
rescue Spree::Core::GatewayError => e
|
30
|
+
flash[:error] = "#{e.message}"
|
31
|
+
redirect_to new_admin_order_payment_path(@order)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Spree
|
2
|
+
class Credit < StoreCredit
|
3
|
+
# Negative Payment Mode cannot be set manually. They are reserved for some particular task internally.
|
4
|
+
PAYMENT_MODE = { 'Payment Refund' => -1, 'Refund' => 0, 'Bank' => 1 }
|
5
|
+
|
6
|
+
include Spree::DisableNegativePaymentModeAndSetBalanceAbility
|
7
|
+
|
8
|
+
private
|
9
|
+
def effective_amount(amount = amount)
|
10
|
+
amount
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Spree
|
2
|
+
class Debit < StoreCredit
|
3
|
+
# Negative Payment Mode cannot be set manually. They are reserved for some particular task internally.
|
4
|
+
PAYMENT_MODE = { 'Order Purchase' => -1, 'Deduce' => 0 }
|
5
|
+
|
6
|
+
include Spree::DisableNegativePaymentModeAndSetBalanceAbility
|
7
|
+
|
8
|
+
private
|
9
|
+
def effective_amount(amount = amount)
|
10
|
+
-(amount)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
Spree::Order.class_eval do
|
2
|
+
fsm = self.state_machines[:state]
|
3
|
+
fsm.after_transition :to => [:canceled], :do => :make_wallet_payments_void
|
4
|
+
|
5
|
+
def user_or_by_email
|
6
|
+
user ? user : Spree::User.where(:email => email).first
|
7
|
+
end
|
8
|
+
|
9
|
+
def make_wallet_payments_void
|
10
|
+
wallet_payments.each { |p| p.void! if p.can_void? }
|
11
|
+
end
|
12
|
+
|
13
|
+
def has_unprocessed_payments?
|
14
|
+
payments.with_state('checkout').reload.exists? || (available_wallet_payment_method.present? && (wallet_payment = payments.where(:payment_method_id => available_wallet_payment_method.id).last).present? && wallet_payment.amount <= remaining_total)
|
15
|
+
end
|
16
|
+
|
17
|
+
def remaining_total
|
18
|
+
total - payment_total
|
19
|
+
end
|
20
|
+
|
21
|
+
def available_payment_methods_without_wallet
|
22
|
+
available_payment_methods.reject { |p| p.is_a? Spree::PaymentMethod::Wallet }
|
23
|
+
end
|
24
|
+
|
25
|
+
def available_wallet_payment_method
|
26
|
+
@wallet_payment_method ||= available_payment_methods.select { |p| p.is_a? Spree::PaymentMethod::Wallet }.first
|
27
|
+
end
|
28
|
+
|
29
|
+
def other_than_wallet_payment_required?
|
30
|
+
remaining_total > user.store_credits_total
|
31
|
+
end
|
32
|
+
|
33
|
+
def available_wallet_payment_amount
|
34
|
+
[remaining_total, user_or_by_email.store_credits_total].min
|
35
|
+
end
|
36
|
+
|
37
|
+
def display_available_wallet_payment_amount
|
38
|
+
Spree::Money.new(available_wallet_payment_amount)
|
39
|
+
end
|
40
|
+
|
41
|
+
def remaining_total_after_wallet
|
42
|
+
remaining_total - available_wallet_payment_amount
|
43
|
+
end
|
44
|
+
|
45
|
+
def display_remaining_total_after_wallet
|
46
|
+
Spree::Money.new(remaining_total_after_wallet)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def wallet_payments
|
51
|
+
payments.where(:payment_method_id => Spree::PaymentMethod::Wallet.pluck(:id))
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Spree::Payment.class_eval do
|
2
|
+
validates :amount, :numericality => { :less_than_or_equal_to => lambda { |payment| [payment.order_user_or_by_email.store_credits_total, payment.order_remaining_total].min }, :greater_than_or_equal_to => 0 }, :if => lambda { |payment| payment.order_user_or_by_email && payment.wallet? && payment.amount_changed? }, :allow_blank => true
|
3
|
+
validates :amount, :numericality => { :less_than_or_equal_to => lambda { |payment| payment.order_remaining_total }}, :unless => :wallet?, :if => :amount_changed?, :allow_blank => true
|
4
|
+
validate :restrict_wallet_when_no_user
|
5
|
+
|
6
|
+
after_create :complete!, :if => :wallet?
|
7
|
+
|
8
|
+
delegate :remaining_total, :user_or_by_email, :to => :order, :prefix => true, :allow_nil => true
|
9
|
+
|
10
|
+
fsm = self.state_machines[:state]
|
11
|
+
fsm.after_transition :from => fsm.states.map(&:name) - ['completed'], :to => ['completed'], :do => :consume_user_credits, :if => :wallet?
|
12
|
+
fsm.after_transition :from => ['completed'], :to => fsm.states.map(&:name) - ['completed'] , :do => :release_user_credits, :if => :wallet?
|
13
|
+
|
14
|
+
def wallet?
|
15
|
+
payment_method.is_a? Spree::PaymentMethod::Wallet
|
16
|
+
end
|
17
|
+
|
18
|
+
def invalidate_old_payments
|
19
|
+
order.payments.with_state('checkout').where("id != ?", self.id).each do |payment|
|
20
|
+
payment.invalidate!
|
21
|
+
end unless wallet?
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def restrict_wallet_when_no_user
|
27
|
+
if wallet? && !order_user_or_by_email
|
28
|
+
self.errors[:base] = Spree.t(:wallet_not_linked_to_user)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def consume_user_credits
|
33
|
+
Spree::Debit.create!(:amount => amount, :payment_mode => Spree::Debit::PAYMENT_MODE['Order Purchase'], :reason => "Payment consumed of order #{order.number}") { |debit| debit.user = order_user_or_by_email }
|
34
|
+
end
|
35
|
+
|
36
|
+
def release_user_credits
|
37
|
+
Spree::Credit.create!(:amount => amount, :payment_mode => Spree::Credit::PAYMENT_MODE['Payment Refund'], :reason => "Payment released of order #{order.number}") { |credit| credit.user = order_user_or_by_email }
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Spree
|
2
|
+
class PaymentMethod::Wallet < PaymentMethod
|
3
|
+
def actions
|
4
|
+
%w{void}
|
5
|
+
end
|
6
|
+
|
7
|
+
def can_void?(payment)
|
8
|
+
payment.state != 'void'
|
9
|
+
end
|
10
|
+
|
11
|
+
def void(*args)
|
12
|
+
ActiveMerchant::Billing::Response.new(true, "", {}, {})
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_required?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Spree
|
2
|
+
class StoreCredit < ActiveRecord::Base
|
3
|
+
attr_accessible :amount, :reason, :payment_mode
|
4
|
+
attr_accessor :disable_negative_payment_mode
|
5
|
+
|
6
|
+
belongs_to :transactioner, :class_name => Spree.user_class
|
7
|
+
|
8
|
+
validates :amount, :user_id, :reason, :type, :balance, :transaction_id, :presence => true
|
9
|
+
validates :amount, :balance, :numericality => { :greater_than_or_equal_to => 0 }, :allow_blank => true
|
10
|
+
validates :transaction_id, :uniqueness => true, :allow_blank => true
|
11
|
+
|
12
|
+
belongs_to :user, :class_name => Spree.user_class
|
13
|
+
|
14
|
+
before_validation :generate_transaction_id, :on => :create
|
15
|
+
before_create :update_user_wallet
|
16
|
+
|
17
|
+
scope :order_created_at_desc, order('created_at desc')
|
18
|
+
|
19
|
+
private
|
20
|
+
def update_user_wallet
|
21
|
+
user.update_attribute(:store_credits_total, balance)
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate_transaction_id
|
25
|
+
begin
|
26
|
+
self.transaction_id = (Time.now.strftime("%s") + rand(999999).to_s).to(15)
|
27
|
+
end while Spree::StoreCredit.where(:transaction_id => transaction_id).present?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Deface::Override.new(
|
2
|
+
:virtual_path => 'spree/admin/shared/_configuration_menu',
|
3
|
+
:name => 'add_store_credits_to_admin_configuration_sidebar',
|
4
|
+
:insert_bottom => "[data-hook='admin_configurations_sidebar_menu']",
|
5
|
+
:text => %q{
|
6
|
+
<%= configurations_sidebar_menu_item Spree.t(:store_credits), admin_store_credits_path %>
|
7
|
+
}
|
8
|
+
)
|
File without changes
|
File without changes
|
@@ -0,0 +1,97 @@
|
|
1
|
+
<%= render :partial => 'spree/admin/shared/configuration_menu' %>
|
2
|
+
|
3
|
+
<% content_for :table_filter do %>
|
4
|
+
<div data-hook="admin_store_credits_sidebar">
|
5
|
+
|
6
|
+
<%= search_form_for [:admin, @search] do |f| %>
|
7
|
+
<div data-hook="admin_store_credits_index_search">
|
8
|
+
<div class="alpha nine columns">
|
9
|
+
<div class="field">
|
10
|
+
<%= f.label :transaction_id_eq, Spree.t(:transaction_id) %>
|
11
|
+
<%= f.text_field :transaction_id_eq %>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="field">
|
15
|
+
<%= f.label :transactioner_email_cont, Spree.t(:transactioner_email) %>
|
16
|
+
<%= f.email_field :transactioner_email_cont %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<% unless @user %>
|
20
|
+
<div class="field">
|
21
|
+
<%= f.label :user_email_cont, Spree.t(:user_email) %>
|
22
|
+
<%= f.email_field :user_email_cont %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<div class="clear"></div>
|
29
|
+
|
30
|
+
<div class="form-buttons actions filter-actions" data-hook="admin_products_index_search_buttons">
|
31
|
+
<%= button Spree.t(:search), 'icon-search' %>
|
32
|
+
</div>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<% content_for :page_title do %>
|
38
|
+
<% if @user %>
|
39
|
+
<%= Spree.t(:store_credits_for_user_email, user_email: @user.email) %> (<%= Spree.t(:current_balance_for_user, total: @user.store_credits_total) %>)
|
40
|
+
<% else %>
|
41
|
+
<%= Spree.t(:listing_store_credits) %>
|
42
|
+
<% end %>
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
<% if @user %>
|
46
|
+
<% content_for :page_actions do %>
|
47
|
+
<li>
|
48
|
+
<%= button_link_to Spree.t(:new_credit), new_admin_user_credit_path(:user_id => @user) %>
|
49
|
+
<%= button_link_to Spree.t(:new_debit), new_admin_user_debit_path(:user_id => @user) %>
|
50
|
+
</li>
|
51
|
+
<% end %>
|
52
|
+
<% end %>
|
53
|
+
|
54
|
+
<%= paginate @store_credits %>
|
55
|
+
|
56
|
+
<table class="index">
|
57
|
+
<thead>
|
58
|
+
<tr>
|
59
|
+
<th><%= sort_link @search, :transaction_id, Spree.t(:transaction_number) %></th>
|
60
|
+
<% unless @user %>
|
61
|
+
<th><%= sort_link @search, :user_email, Spree.t(:user) %></th>
|
62
|
+
<% end %>
|
63
|
+
<th><%= sort_link @search, :transactioner_email, Spree.t(:transactioner_email) %></th>
|
64
|
+
<th><%= sort_link @search, :amount, Spree.t(:amount) %></th>
|
65
|
+
<th><%= sort_link @search, :balance, Spree.t(:balance) %></th>
|
66
|
+
<% if @user %>
|
67
|
+
<th><%= Spree.t(:reason) %></th>
|
68
|
+
<th><%= Spree.t(:payment_mode) %></th>
|
69
|
+
<% end %>
|
70
|
+
<th><%= sort_link @search, :type, Spree.t(:type) %></th>
|
71
|
+
<% unless @user %>
|
72
|
+
<th><%= Spree.t(:action) %></th>
|
73
|
+
<% end %>
|
74
|
+
</tr>
|
75
|
+
</thead>
|
76
|
+
<tbody>
|
77
|
+
<% @store_credits.each do |store_credit|%>
|
78
|
+
<tr id="<%= cycle('odd', 'even') %>">
|
79
|
+
<td class="align-center"><%= store_credit.transaction_id %></td>
|
80
|
+
<% unless @user %>
|
81
|
+
<td class="align-center"><%= link_to store_credit.user.email, admin_user_path(store_credit.user) %></td>
|
82
|
+
<% end %>
|
83
|
+
<td class="align-center"><%= store_credit.transactioner.try(:email) %></td>
|
84
|
+
<td class="align-center"><%= number_to_currency store_credit.amount %></td>
|
85
|
+
<td class="align-center"><%= number_to_currency store_credit.balance %></td>
|
86
|
+
<% if @user %>
|
87
|
+
<td class="align-center"><%= store_credit.reason %></td>
|
88
|
+
<td class="align-center"><%= store_credit.class::PAYMENT_MODE.key(store_credit.payment_mode) %>
|
89
|
+
<% end %>
|
90
|
+
<td class="align-center"><%= store_credit.type.demodulize %></td>
|
91
|
+
<% unless @user %>
|
92
|
+
<td><%= link_to Spree.t(:credit), new_admin_user_credit_path(:user_id => store_credit.user) %> | <%= link_to Spree.t(:debit), new_admin_user_debit_path(:user_id => store_credit.user) %> | <%= link_to Spree.t(:view), admin_user_store_credits_path(:user_id => store_credit.user) %></td>
|
93
|
+
<% end %>
|
94
|
+
</tr>
|
95
|
+
<% end %>
|
96
|
+
</tbody>
|
97
|
+
</table>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<%= render :partial => 'spree/admin/shared/configuration_menu' %>
|
2
|
+
|
3
|
+
<h1><%= Spree.t("new_store_#{@store_credit.type.demodulize.downcase}")%></h1>
|
4
|
+
|
5
|
+
<%= render 'spree/shared/error_messages', :target => @store_credit %>
|
6
|
+
|
7
|
+
<h3 data-hook='user-email'>User Email: <%= @store_credit.user.email %></h3>
|
8
|
+
<h4 data-hook='user-email'>Current Balance: <%= @store_credit.user.store_credits_total %></h4>
|
9
|
+
|
10
|
+
<%= form_for [:admin, @user, @store_credit], :as => :store_credit do |f| %>
|
11
|
+
<%= f.field_container :amount do %>
|
12
|
+
<%= f.label :amount %><br />
|
13
|
+
<%= f.text_field :amount, :id => "debit_credit_amount" %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%= f.field_container :payment_mode do %>
|
17
|
+
<%= f.label :payment_mode, 'Payment Mode' %><br />
|
18
|
+
<%= f.select :payment_mode, store_credit_class::PAYMENT_MODE.select { |key, value| value >= 0 }, { :prompt => 'Select' } %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<%= f.field_container :reason do %>
|
22
|
+
<%= f.label :reason %><br />
|
23
|
+
<%= f.text_field :reason %>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<%= f.submit :commit, :value => @store_credit.type.demodulize, :class => 'button', :id => 'debit_credit' %>
|
27
|
+
<% end %>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= Spree.t(:listing_users) %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for :page_actions do %>
|
6
|
+
<li>
|
7
|
+
<%= button_link_to Spree.t(:new_user), new_object_url, :icon => 'icon-plus', :id => 'admin_new_user_link' %>
|
8
|
+
</li>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<table class="index" id="listing_users" data-hook>
|
12
|
+
<colgroup>
|
13
|
+
<col style="width: 40%">
|
14
|
+
<col style="width: 20%">
|
15
|
+
<col style="width: 25%">
|
16
|
+
<col style="width: 15%">
|
17
|
+
</colgroup>
|
18
|
+
<thead>
|
19
|
+
<tr data-hook="admin_users_index_headers">
|
20
|
+
<th><%= sort_link @search,:email, Spree.t(:user), {}, {:title => 'users_email_title'} %></th>
|
21
|
+
<th><%= Spree.t(:store_credits_total) %></th>
|
22
|
+
<th><%= Spree.t(:store_credits_action) %></th>
|
23
|
+
<th data-hook="admin_users_index_header_actions" class="actions"></th>
|
24
|
+
</tr>
|
25
|
+
</thead>
|
26
|
+
<tbody>
|
27
|
+
<% @users.each do |user|%>
|
28
|
+
<tr id="<%= spree_dom_id user %>" data-hook="admin_users_index_rows" class="<%= cycle('odd', 'even')%>">
|
29
|
+
<td class='user_email'><%=link_to user.email, object_url(user) %></td>
|
30
|
+
<td><%= user.store_credits_total %></td>
|
31
|
+
<td><%= link_to Spree.t(:credit), new_admin_user_credit_path(:user_id => user) %> | <%= link_to Spree.t(:debit), new_admin_user_debit_path(:user_id => user) %> | <%= link_to Spree.t(:view), admin_user_store_credits_path(:user_id => user) %></td>
|
32
|
+
<td data-hook="admin_users_index_row_actions" class="actions">
|
33
|
+
<%= link_to_edit user, :no_text => true %>
|
34
|
+
<%= link_to_delete user, :no_text => true %>
|
35
|
+
</td>
|
36
|
+
</tr>
|
37
|
+
<% end %>
|
38
|
+
</tbody>
|
39
|
+
</table>
|
40
|
+
|
41
|
+
<%= paginate @users %>
|
42
|
+
|
43
|
+
<% content_for :sidebar_title do %>
|
44
|
+
<%= Spree.t(:search) %>
|
45
|
+
<% end %>
|
46
|
+
|
47
|
+
<% content_for :sidebar do %>
|
48
|
+
<div class="box align-center" data-hook="admin_users_index_search">
|
49
|
+
<%= search_form_for [:admin, @search] do |f| %>
|
50
|
+
<div class="field">
|
51
|
+
<%= f.label Spree.t(:email) %> <br>
|
52
|
+
<%= f.text_field :email_cont, :class => 'fullwidth' %>
|
53
|
+
</div>
|
54
|
+
<div data-hook="admin_users_index_search_buttons">
|
55
|
+
<%= button Spree.t(:search), 'icon-search' %>
|
56
|
+
</div>
|
57
|
+
<% end %>
|
58
|
+
</div>
|
59
|
+
<% end %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
<fieldset id="payment" data-hook>
|
2
|
+
<legend align="center"><%= Spree.t(:payment_information) %></legend>
|
3
|
+
<div data-hook="checkout_payment_step">
|
4
|
+
|
5
|
+
|
6
|
+
<% if spree_current_user && @order.available_wallet_payment_method && !spree_current_user.store_credits_total.to_f.zero? %>
|
7
|
+
<%= check_box_tag "order[payments_attributes][][payment_method_id]", @order.available_wallet_payment_method.id %>
|
8
|
+
<%= Spree.t(@order.available_wallet_payment_method.name, :scope => :payment_methods, :default => @order.available_wallet_payment_method.name) %>( <%= spree_current_user.store_credits_total %> )
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<% @order.available_payment_methods_without_wallet.each do |method| %>
|
12
|
+
<p>
|
13
|
+
<label>
|
14
|
+
<%= radio_button_tag "order[payments_attributes][][payment_method_id]", method.id %>
|
15
|
+
<%= Spree.t(method.name, :scope => :payment_methods, :default => method.name) %>
|
16
|
+
</label>
|
17
|
+
</p>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<ul id="payment-methods" data-hook>
|
21
|
+
<% @order.available_payment_methods_without_wallet.each do |method| %>
|
22
|
+
<!-- hidden class is added to hide the partial initially -->
|
23
|
+
<li id="payment_method_<%= method.id %>" class="hidden <%= 'last' if method == @order.available_payment_methods_without_wallet.last %>" data-hook>
|
24
|
+
<fieldset>
|
25
|
+
<%= render :partial => "spree/checkout/payment/#{method.method_type}", :locals => { :payment_method => method } %>
|
26
|
+
</fieldset>
|
27
|
+
</li>
|
28
|
+
<% end %>
|
29
|
+
</ul>
|
30
|
+
<br style="clear:both;" />
|
31
|
+
<% if Spree::Promotion.with_code.count > 0 %>
|
32
|
+
<p class='field' data-hook='coupon_code'>
|
33
|
+
<%= form.label :coupon_code %><br />
|
34
|
+
<%= form.text_field :coupon_code %>
|
35
|
+
</p>
|
36
|
+
<% end %>
|
37
|
+
</div>
|
38
|
+
</fieldset>
|
39
|
+
|
40
|
+
<br class="space" />
|
41
|
+
|
42
|
+
<div class="form-buttons" data-hook="buttons">
|
43
|
+
<%= submit_tag Spree.t(:save_and_continue), :class => 'continue button primary' %>
|
44
|
+
<script>Spree.disableSaveOnClick();</script>
|
45
|
+
</div>
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Sample localization file for English. Add more files in this directory for other locales.
|
2
|
+
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
|
3
|
+
|
4
|
+
en:
|
5
|
+
spree:
|
6
|
+
store_credits_action: "Store Credits Action"
|
7
|
+
listing_store_credits: "Listing Store Credits"
|
8
|
+
store_credits: "Store Credits"
|
9
|
+
new_credit: "New Credit"
|
10
|
+
new_debit: "New Debit"
|
11
|
+
credit: "Credit"
|
12
|
+
debit: "Debit"
|
13
|
+
view: "View"
|
14
|
+
store_credits_for_user_email: "Store Credits For %{user_email}"
|
15
|
+
not_sufficient_amount_in_wallet: "Payment could not be processed. Because you don't have sufficient amount in your wallet. Please choose another payment method with it."
|
16
|
+
new_store_credit: "New Store Credit"
|
17
|
+
new_store_debit: "New Store Debit"
|
18
|
+
cannot_select_wallet_while_guest_checkout: "Payment Method Wallet can't be selected while guest checkout."
|
19
|
+
wallet_not_linked_to_user: "There is no wallet linked to the user of this order"
|
20
|
+
current_balance_for_user: "Current Balance: %{total}"
|
21
|
+
store_credits_total: "Store Credits Total"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Spree::Core::Engine.routes.draw do
|
2
|
+
namespace :admin do
|
3
|
+
resources :users, :only => :none do
|
4
|
+
resources :store_credits, :only => [:index]
|
5
|
+
resources :credits, :only => [:new, :create, :show], :controller => :store_credits, :type => 'credits'
|
6
|
+
resources :debits, :only => [:new, :create, :show], :controller => :store_credits, :type => 'debits'
|
7
|
+
end
|
8
|
+
|
9
|
+
resources :store_credits, :only => [:index]
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateSpreeStoreCredits < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :spree_store_credits do |t|
|
4
|
+
t.string :reason
|
5
|
+
t.string :type
|
6
|
+
t.string :transaction_id
|
7
|
+
t.decimal :amount, :precision => 10, :scale => 2
|
8
|
+
t.decimal :balance, :precision => 10, :scale => 2
|
9
|
+
t.integer :payment_mode
|
10
|
+
t.references :user
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
class AddIndexesOnSpreeStoreCreditsFieldsTypeAndUserId < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
add_index :spree_store_credits, :type, :name => "index_type_on_spree_store_credits"
|
4
|
+
add_index :spree_store_credits, :user_id, :name => "index_user_id_on_spree_store_credits"
|
5
|
+
end
|
6
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SpreeWallet
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
class_option :auto_run_migrations, :type => :boolean, :default => false
|
6
|
+
|
7
|
+
def add_stylesheets
|
8
|
+
inject_into_file 'app/assets/stylesheets/store/all.css', " *= require store/spree_wallet\n", :before => /\*\//, :verbose => true
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_migrations
|
12
|
+
run 'bundle exec rake railties:install:migrations FROM=spree_wallet'
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_migrations
|
16
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask 'Would you like to run the migrations now? [Y/n]')
|
17
|
+
if run_migrations
|
18
|
+
run 'bundle exec rake db:migrate'
|
19
|
+
else
|
20
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Spree
|
2
|
+
module DisableNegativePaymentModeAndSetBalanceAbility
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
attr_accessor :disable_negative_payment_mode
|
6
|
+
|
7
|
+
validates :payment_mode, :inclusion => { :in => klass::PAYMENT_MODE.values }, :unless => :disable_negative_payment_mode
|
8
|
+
validates :payment_mode, :inclusion => { :in => klass::PAYMENT_MODE.values.select { |value| value >= 0 } }, :if => :disable_negative_payment_mode
|
9
|
+
|
10
|
+
before_validation :set_balance, :on => :create
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_balance
|
15
|
+
self.balance = user.store_credits_total + effective_amount if user && amount
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SpreeWallet
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
require 'spree/core'
|
4
|
+
isolate_namespace Spree
|
5
|
+
engine_name 'spree_wallet'
|
6
|
+
|
7
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
8
|
+
|
9
|
+
# use rspec for tests
|
10
|
+
config.generators do |g|
|
11
|
+
g.test_framework :rspec
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.activate
|
15
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
16
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
initializer "spree.register.payment_methods" do |app|
|
21
|
+
app.config.spree.payment_methods << Spree::PaymentMethod::Wallet
|
22
|
+
end
|
23
|
+
|
24
|
+
config.to_prepare &method(:activate).to_proc
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
# Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
|
3
|
+
#
|
4
|
+
# Example adding this to your spec_helper will load these Factories for use:
|
5
|
+
# require 'spree_wallet/factories'
|
6
|
+
end
|
data/lib/spree_wallet.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_wallet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-01-
|
12
|
+
date: 2014-01-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: spree_core
|
@@ -32,7 +32,42 @@ email: info@vinsol.com
|
|
32
32
|
executables: []
|
33
33
|
extensions: []
|
34
34
|
extra_rdoc_files: []
|
35
|
-
files:
|
35
|
+
files:
|
36
|
+
- LICENSE
|
37
|
+
- README.md
|
38
|
+
- app/assets/stylesheets/store/checkout.css
|
39
|
+
- app/assets/stylesheets/store/spree_wallet.css
|
40
|
+
- app/overrides/add_store_credits_tab_in_configuration_menu.rb
|
41
|
+
- app/models/spree/user_decorator.rb
|
42
|
+
- app/models/spree/payment_method/wallet.rb
|
43
|
+
- app/models/spree/payment_decorator.rb
|
44
|
+
- app/models/spree/store_credit.rb
|
45
|
+
- app/models/spree/debit.rb
|
46
|
+
- app/models/spree/credit.rb
|
47
|
+
- app/models/spree/order_decorator.rb
|
48
|
+
- app/controllers/spree/checkout_controller_decorator.rb
|
49
|
+
- app/controllers/spree/admin/store_credits_controller.rb
|
50
|
+
- app/controllers/spree/payments_controller_decorator.rb
|
51
|
+
- app/views/spree/checkout/payment/_wallet.html.erb
|
52
|
+
- app/views/spree/checkout/_payment.html.erb
|
53
|
+
- app/views/spree/admin/users/index.html.erb
|
54
|
+
- app/views/spree/admin/store_credits/new.html.erb
|
55
|
+
- app/views/spree/admin/store_credits/index.html.erb
|
56
|
+
- app/views/spree/admin/payments/source_views/_wallet.html.erb
|
57
|
+
- app/views/spree/admin/payments/source_forms/_wallet.html.erb
|
58
|
+
- config/routes.rb
|
59
|
+
- config/locales/en.yml
|
60
|
+
- lib/generators/spree_wallet/install/install_generator.rb
|
61
|
+
- lib/spree/disable_negative_payment_mode_and_set_balance_ability.rb
|
62
|
+
- lib/spree_wallet.rb
|
63
|
+
- lib/spree_wallet/engine.rb
|
64
|
+
- lib/spree_wallet/factories.rb
|
65
|
+
- db/migrate/20130729071647_add_lock_version_to_spree_users.rb
|
66
|
+
- db/migrate/20130719124429_add_indexes_on_spree_store_credits_fields_type_and_user_id.rb
|
67
|
+
- db/migrate/20130712094651_create_spree_store_credits.rb
|
68
|
+
- db/migrate/20130729140933_add_unique_index_on_transaction_id_to_spree_store_credits.rb
|
69
|
+
- db/migrate/20130715130434_add_store_credits_to_spree_users.rb
|
70
|
+
- db/migrate/20130801135105_add_transactioner_id_to_spree_store_credits.rb
|
36
71
|
homepage: http://vinsol.com
|
37
72
|
licenses:
|
38
73
|
- MIT
|