Skip to content

Commit

Permalink
Merge pull request #2183 from jordan-brough/store-credit-currency-fix
Browse files Browse the repository at this point in the history
Fix StoreCredit with multiple currencies
  • Loading branch information
jordan-brough authored Aug 28, 2017
2 parents 795d978 + 8fc7e56 commit 8e17226
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 102 deletions.
103 changes: 53 additions & 50 deletions backend/app/views/spree/admin/store_credits/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,61 +12,64 @@
<% end %>

<% if @store_credits.any? %>
<fieldset id='sc-current-balance'>
<legend>
<%= Spree.t("admin.store_credits.current_balance") %>
<%= @user.display_total_available_store_credit %>
</legend>
<% @store_credits.group_by(&:currency).each do |currency, credits| %>
<fieldset class="sc-current-balance">
<legend>
<%= currency %> <%= Spree.t("admin.store_credits.current_balance") %>
<% total = credits.sum(&:amount_remaining) %>
<%= Spree::Money.new(total, currency: currency) %>
</legend>

<table id="sc-table">
<thead>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:amount_credited) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:amount_used) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:amount_authorized) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:category_id) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:created_by_id) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:created_at) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:invalidated_at) %></th>
<th data-hook="admin_store_credits_index_header_actions" class="actions"></th>
<thead>
<tbody>
<% @store_credits.each do |store_credit| %>
<tr>
<td>
<span><%= store_credit.display_amount.to_html %></span>
</td>
<td>
<span><%= store_credit.display_amount_used.to_html %></span>
</td>
<td>
<span><%= store_credit.display_amount_authorized.to_html %></span>
</td>
<td>
<span><%= store_credit.category_name %></span>
</td>
<td>
<span><%= store_credit.created_by_email %></span>
</td>
<td>
<span><%= l store_credit.created_at.to_date %></span>
</td>
<td>
<span><%= store_credit.invalidated? %></span>
</td>
<td class="actions" data-hook="admin_store_credits_index_row_actions">
<% if can?(:show, store_credit) %>
<%= link_to_edit_url admin_user_store_credit_path(@user, store_credit), { no_text: true, class: 'edit' } %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<table class="sc-table">
<thead>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:amount_credited) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:amount_used) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:amount_authorized) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:category_id) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:created_by_id) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:created_at) %></th>
<th class="wrap-text"><%= Spree::StoreCredit.human_attribute_name(:invalidated_at) %></th>
<th data-hook="admin_store_credits_index_header_actions" class="actions"></th>
<thead>
<tbody>
<% credits.each do |store_credit| %>
<tr>
<td>
<span><%= store_credit.display_amount.to_html %></span>
</td>
<td>
<span><%= store_credit.display_amount_used.to_html %></span>
</td>
<td>
<span><%= store_credit.display_amount_authorized.to_html %></span>
</td>
<td>
<span><%= store_credit.category_name %></span>
</td>
<td>
<span><%= store_credit.created_by_email %></span>
</td>
<td>
<span><%= l store_credit.created_at.to_date %></span>
</td>
<td>
<span><%= store_credit.invalidated? %></span>
</td>
<td class="actions" data-hook="admin_store_credits_index_row_actions">
<% if can?(:show, store_credit) %>
<%= link_to_edit_url admin_user_store_credit_path(@user, store_credit), { no_text: true, class: 'edit' } %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</fieldset>
<% end %>
<% else %>
<div class="col-9 no-objects-found">
<%= render 'spree/admin/shared/no_objects_found',
resource: Spree::StoreCredit,
new_resource_url: new_object_url %>
</div>
<% end %>
</fieldset>
6 changes: 3 additions & 3 deletions backend/spec/features/admin/store_credits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
click_link "Store Credit"
expect(page.current_path).to eq spree.admin_user_store_credits_path(store_credit.user)

store_credit_table = page.find("#sc-table")
store_credit_table = page.find(".sc-table")
expect(store_credit_table).to have_css('tr', count: 1)
expect(store_credit_table).to have_content(Spree::Money.new(store_credit.amount).to_s)
expect(store_credit_table).to have_content(Spree::Money.new(store_credit.amount_used).to_s)
Expand All @@ -48,7 +48,7 @@
click_button "Create"

expect(page.current_path).to eq spree.admin_user_store_credits_path(store_credit.user)
store_credit_table = page.find("#sc-table")
store_credit_table = page.find(".sc-table")
expect(store_credit_table).to have_css('tr', count: 2)
expect(Spree::StoreCredit.count).to eq 2
end
Expand All @@ -67,7 +67,7 @@
end

it "updates the store credit's amount" do
page.find("#sc-table td.actions a.fa-edit").click
page.find(".sc-table td.actions a.fa-edit").click
expect(page).to have_content 'Store credit history'
click_link "Change amount"
expect(page).to have_content 'Editing store credit amount'
Expand Down
16 changes: 16 additions & 0 deletions core/app/models/concerns/spree/user_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ module UserMethods

has_many :store_credits, -> { includes(:credit_type) }, foreign_key: "user_id", class_name: "Spree::StoreCredit"
has_many :store_credit_events, through: :store_credits

money_methods :total_available_store_credit
deprecate display_total_available_store_credit: :display_available_store_credit_total, deprecator: Spree::Deprecation

has_many :credit_cards, class_name: "Spree::CreditCard", foreign_key: :user_id
has_many :wallet_payment_sources, foreign_key: 'user_id', class_name: 'Spree::WalletPaymentSource', inverse_of: :user
Expand Down Expand Up @@ -66,5 +68,19 @@ def last_incomplete_spree_order(store: nil, only_frontend_viewable: true)
def total_available_store_credit
store_credits.reload.to_a.sum(&:amount_remaining)
end
deprecate total_available_store_credit: :available_store_credit_total, deprecator: Spree::Deprecation

def available_store_credit_total(currency:)
store_credits.reload.to_a.
select { |c| c.currency == currency }.
sum(&:amount_remaining)
end

def display_available_store_credit_total(currency:)
Spree::Money.new(
available_store_credit_total(currency: currency),
currency: currency,
)
end
end
end
14 changes: 8 additions & 6 deletions core/app/models/spree/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ def tax_total

def add_store_credit_payments
return if user.nil?
return if payments.store_credits.checkout.empty? && user.total_available_store_credit.zero?
return if payments.store_credits.checkout.empty? && user.available_store_credit_total(currency: currency).zero?

payments.store_credits.checkout.each(&:invalidate!)

Expand All @@ -631,10 +631,12 @@ def add_store_credit_payments

remaining_total = outstanding_balance - authorized_total

if user.store_credits.any?
matching_store_credits = user.store_credits.where(currency: currency)

if matching_store_credits.any?
payment_method = Spree::PaymentMethod::StoreCredit.first

user.store_credits.order_by_priority.each do |credit|
matching_store_credits.order_by_priority.each do |credit|
break if remaining_total.zero?
next if credit.amount_remaining.zero?

Expand Down Expand Up @@ -664,13 +666,13 @@ def add_store_credit_payments

def covered_by_store_credit?
return false unless user
user.total_available_store_credit >= total
user.available_store_credit_total(currency: currency) >= total
end
alias_method :covered_by_store_credit, :covered_by_store_credit?

def total_available_store_credit
return 0.0 unless user
user.total_available_store_credit
user.available_store_credit_total(currency: currency)
end

def order_total_after_store_credit
Expand All @@ -681,7 +683,7 @@ def total_applicable_store_credit
if can_complete? || complete?
payments.store_credits.valid.sum(:amount)
else
[total, (user.try(:total_available_store_credit) || 0.0)].min
[total, (user.try(:available_store_credit_total, currency: currency) || 0.0)].min
end
end

Expand Down
2 changes: 1 addition & 1 deletion core/app/models/spree/store_credit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def store_event
event.update_attributes!({
amount: action_amount || amount,
authorization_code: action_authorization_code || event.authorization_code || generate_authorization_code,
user_total_amount: user.total_available_store_credit,
user_total_amount: user.available_store_credit_total(currency: currency),
originator: action_originator,
update_reason: update_reason
})
Expand Down
59 changes: 59 additions & 0 deletions core/spec/models/spree/concerns/user_methods_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,63 @@
end
end
end

describe '#available_store_credit_total' do
subject do
test_user.available_store_credit_total(currency: 'USD')
end

context 'when the user does not have any credit' do
it { is_expected.to eq(0) }
end

context 'when the user has credits' do
let!(:credit_1) { create(:store_credit, user: test_user, amount: 100) }
let!(:credit_2) { create(:store_credit, user: test_user, amount: 200) }

it { is_expected.to eq(100 + 200) }

context 'when some has been used' do
before { credit_1.update_attributes!(amount_used: 35) }

it { is_expected.to eq(100 + 200 - 35) }

context 'when some has been authorized' do
before { credit_1.update_attributes!(amount_authorized: 10) }

it { is_expected.to eq(100 + 200 - 35 - 10) }
end
end

context 'when some has been authorized' do
before { credit_1.update_attributes!(amount_authorized: 10) }

it { is_expected.to eq(100 + 200 - 10) }
end

context 'with credits of multiple currencies' do
let!(:credit_3) { create(:store_credit, user: test_user, amount: 400, currency: 'GBP') }

it 'separates the currencies' do
expect(test_user.available_store_credit_total(currency: 'USD')).to eq(100 + 200)
expect(test_user.available_store_credit_total(currency: 'GBP')).to eq(400)
end
end
end
end

describe '#display_available_store_credit_total' do
subject do
test_user.display_available_store_credit_total(currency: 'USD')
end

context 'without credit' do
it { is_expected.to eq(Spree::Money.new(0)) }
end

context 'with credit' do
let!(:credit) { create(:store_credit, user: test_user, amount: 100) }
it { is_expected.to eq(Spree::Money.new(100)) }
end
end
end
Loading

0 comments on commit 8e17226

Please sign in to comment.