Skip to content

Commit

Permalink
Merge pull request solidusio#6034 from MadelineCollier/admin-user-sto…
Browse files Browse the repository at this point in the history
…re-credit-invalidate

[Admin][Users] Add new admin store credits invalidate flow
  • Loading branch information
MadelineCollier authored Dec 16, 2024
2 parents 596adae + c734f99 commit 77f8302
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%= turbo_frame_tag :edit_validity_modal do %>
<%= render component("ui/modal").new(title: t(".title")) do |modal| %>
<%= form_for @store_credit, url: solidus_admin.invalidate_user_store_credit_path(@user, @store_credit), method: :put, html: { id: form_id } do |f| %>
<div class="flex flex-col gap-6 pb-4">
<%= render component("ui/forms/field").select(
f,
:store_credit_reason_id,
store_credit_reasons_select_options.html_safe,
include_blank: t('spree.choose_reason'),
html: { required: true }
) %>
</div>
<% modal.with_actions do %>
<form method="dialog">
<%= render component("ui/button").new(scheme: :secondary, text: t('.cancel')) %>
</form>
<%= render component("ui/button").new(form: form_id, scheme: :danger, type: :submit, text: t('.submit')) %>
<% end %>
<% end %>
<% end %>
<% end %>
<%= render component("users/store_credits/show").new(user: @user, store_credit: @store_credit, events: @store_credit_events) %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class SolidusAdmin::Users::StoreCredits::EditValidity::Component < SolidusAdmin::BaseComponent
def initialize(user:, store_credit:, events:, reasons:)
@user = user
@store_credit = store_credit
@store_credit_events = events
@store_credit_reasons = reasons
end

def form_id
dom_id(@store_credit, "#{stimulus_id}_edit_validity_form")
end

def store_credit_reasons_select_options
# Placeholder + Store Credit Reasons
"<option value>#{t('.choose_reason')}</option>" + options_from_collection_for_select(@store_credit_reasons, :id, :name)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
en:
title: Invalidate Store Credit
cancel: Cancel
submit: Invalidate
choose_reason: Choose Reason For Invalidating
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@
<% if @store_credit.invalidateable? %>
<%= render component("ui/button").new(
scheme: :danger,
tag: :a,
"data-action": "click->#{stimulus_id}#actionButtonClicked",
"data-#{stimulus_id}-url-param": solidus_admin.edit_validity_user_store_credit_path(@user, @store_credit, _turbo_frame: :edit_validity_modal),
text: t(".invalidate"),
href: spree.edit_validity_admin_user_store_credit_path(@user, @store_credit)
)%>
<% end %>

<%= render component("ui/button").new(
"data-action": "click->#{stimulus_id}#actionButtonClicked",
"data-#{stimulus_id}-url-param": solidus_admin.edit_memo_user_store_credit_path(@user, @store_credit, _turbo_frame: :edit_memo_modal),
text: t(".edit_memo"),
)%>

<% if @store_credit.editable? %>
<%= render component("ui/button").new(
"data-action": "click->#{stimulus_id}#actionButtonClicked",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def turbo_frames
%w[
edit_amount_modal
edit_memo_modal
edit_validity_modal
]
end

Expand Down
61 changes: 53 additions & 8 deletions admin/app/controllers/solidus_admin/store_credits_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
module SolidusAdmin
class StoreCreditsController < SolidusAdmin::BaseController
before_action :set_user
before_action :set_store_credit, only: [:show, :edit_amount, :update_amount, :edit_memo, :update_memo]
before_action :set_store_credit_reasons, only: [:edit_amount, :update_amount]
before_action :set_store_credit, only: [:show, :edit_amount, :update_amount, :edit_memo, :update_memo, :edit_validity, :invalidate]
before_action :set_store_credit_reasons, only: [:edit_amount, :update_amount, :edit_validity, :invalidate]

def index
@store_credits = Spree::StoreCredit.where(user_id: @user.id).order(id: :desc)
Expand Down Expand Up @@ -54,7 +54,7 @@ def update_amount
end
end
else
render_edit_amount_with_errors and return
render_edit_with_errors and return
end
end

Expand Down Expand Up @@ -91,6 +91,45 @@ def update_memo
end
end

def edit_validity
@store_credit_events = @store_credit.store_credit_events.chronological

respond_to do |format|
format.html {
render component("users/store_credits/edit_validity").new(
user: @user,
store_credit: @store_credit,
events: @store_credit_events,
reasons: @store_credit_reasons
)
}
end
end

def invalidate
return unless ensure_store_credit_reason

if @store_credit.invalidate(@store_credit_reason, spree_current_user)
flash[:notice] = t('.success')
else
# Ensure store_credit_reason handles invalid param/form submissions and modal re-rendering.
# This is just a fallback error state in case anything goes wrong with StoreCredit#invalidate.
flash[:error] = t('.failure')
end

respond_to do |format|
flash[:notice] = t('.success')

format.html do
redirect_to solidus_admin.user_store_credit_path(@user, @store_credit), status: :see_other
end

format.turbo_stream do
render turbo_stream: '<turbo-stream action="refresh" />'
end
end
end

private

def set_store_credit
Expand All @@ -107,17 +146,23 @@ def set_store_credit_reasons

def permitted_store_credit_params
permitted_params = [:amount, :currency, :category_id, :memo]
permitted_params << :store_credit_reason_id if action_name.to_sym == :update_amount
permitted_params << :store_credit_reason_id if [:update_amount, :invalidate].include?(action_name.to_sym)

params.require(:store_credit).permit(permitted_params).merge(created_by: spree_current_user)
end

def render_edit_amount_with_errors
def render_edit_with_errors
@store_credit_events = @store_credit.store_credit_events.chronological

template = if action_name.to_sym == :invalidate
"edit_validity"
else
"edit_amount"
end

respond_to do |format|
format.html do
render component("users/store_credits/edit_amount").new(
render component("users/store_credits/#{template}").new(
user: @user,
store_credit: @store_credit,
events: @store_credit_events,
Expand All @@ -131,7 +176,7 @@ def render_edit_amount_with_errors
def ensure_amount
if permitted_store_credit_params[:amount].blank?
@store_credit.errors.add(:amount, :greater_than, count: 0, value: permitted_store_credit_params[:amount])
render_edit_amount_with_errors
render_edit_with_errors
return false
end
true
Expand All @@ -142,7 +187,7 @@ def ensure_store_credit_reason

if @store_credit_reason.blank?
@store_credit.errors.add(:store_credit_reason_id, "Store Credit reason must be provided")
render_edit_amount_with_errors
render_edit_with_errors
return false
end
true
Expand Down
3 changes: 3 additions & 0 deletions admin/config/locales/store_credits.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ en:
update_memo:
success: "Store credit was successfully updated."
failure: "Something went wrong. Store credit could not be updated."
invalidate:
success: "Store credit was successfully invalidated."
failure: "Something went wrong. Store credit could not be invalidated."
2 changes: 2 additions & 0 deletions admin/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
put :update_amount
get :edit_memo
put :update_memo
get :edit_validity
put :invalidate
end
end
end
Expand Down
46 changes: 34 additions & 12 deletions admin/spec/features/store_credits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,6 @@
expect(page).to have_content("Added")
end

it "allows invalidating of the store credit" do
click_on "Invalidate"
select "credit given in error", from: "store_credit_reason_id"
click_on "Invalidate"
expect(page).to have_content("Store Credit History")
expect(page).to have_content("Action")
expect(page).to have_content("Added")
expect(page).to have_content("Invalidated")
expect(page).to have_content("Reason for updating")
expect(page).to have_content("credit given in error")
end

context "when editing the store credit amount" do
context "with invalid amount" do
it "shows the appropriate error message" do
Expand Down Expand Up @@ -137,6 +125,40 @@
end
end

context "when invalidating" do
context "without a valid reason" do
it "shows the appropriate error message" do
click_on "Invalidate"
expect(page).to have_selector("dialog", wait: 5)
expect(page).to have_content("Invalidate Store Credit")

within("dialog") do
click_on "Invalidate"
expect(page).to have_content("Store Credit reason must be provided")
click_on "Cancel"
end
end
end

context "with a valid reason" do
it "invalidates the store credit" do
click_on "Invalidate"
expect(page).to have_selector("dialog", wait: 5)
expect(page).to have_content("Invalidate Store Credit")

within("dialog") do
select "credit given in error", from: "store_credit[store_credit_reason_id]"
click_on "Invalidate"
end

expect(page).to have_content("Store credit was successfully invalidated.")
expect(page).to have_content("Invalidated")
expect(page).to have_content("credit given in error")
expect(page).not_to have_content("Edit Amount")
end
end
end

context "when editing the store credit memo" do
it "allows editing of the store credit memo" do
click_on "Edit Memo"
Expand Down
75 changes: 75 additions & 0 deletions admin/spec/requests/solidus_admin/store_credits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
let(:valid_params) { { amount: 100, store_credit_reason_id: create(:store_credit_reason).id } }
let(:invalid_params) { { amount: nil } }
let(:valid_memo_params) { { memo: "Updated memo text" } }
let(:invalid_reason_params) { { store_credit_reason_id: nil } }

before do
allow_any_instance_of(SolidusAdmin::BaseController).to receive(:spree_current_user).and_return(admin_user)
Expand Down Expand Up @@ -91,6 +92,80 @@
end
end

describe "GET /edit_validity" do
it "renders the edit_validity template with a 200 OK status" do
get solidus_admin.edit_validity_user_store_credit_path(user, store_credit)
expect(response).to have_http_status(:ok)
expect(response.body).to include(store_credit.amount.to_s)
end
end

describe "PUT /invalidate" do
context "with valid parameters" do
let(:store_credit_reason) { create(:store_credit_reason) }

it "invalidates the store credit" do
expect {
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: { store_credit_reason_id: store_credit_reason.id } }
}.to change { store_credit.reload.invalidated? }.from(false).to(true)
end

it "redirects to the store credit show page with a 303 See Other status" do
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: { store_credit_reason_id: store_credit_reason.id } }
expect(response).to redirect_to(solidus_admin.user_store_credit_path(user, store_credit))
expect(response).to have_http_status(:see_other)
end

it "displays a success flash message" do
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: { store_credit_reason_id: store_credit_reason.id } }
follow_redirect!
expect(response.body).to include("Store credit was successfully invalidated.")
end
end

context "with invalid parameters" do
it "does not invalidate the store credit" do
expect {
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: invalid_reason_params }
}.not_to change { store_credit.reload.invalidated? }
end

it "renders the edit_validity template with unprocessable_entity status" do
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: invalid_reason_params }
expect(response).to have_http_status(:unprocessable_entity)
end

it "displays error messages in the response" do
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: invalid_reason_params }
expect(response.body).to include("Store Credit reason must be provided")
end
end

context "when the database update fails" do
before do
allow_any_instance_of(Spree::StoreCredit).to receive(:invalidate).and_return(false)
end

it "does not invalidate the store credit" do
expect {
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: valid_params }
}.not_to change { store_credit.reload.invalidated? }
end

it "redirects to the store credit show page with a 303 See Other status" do
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: valid_params }
expect(response).to redirect_to(solidus_admin.user_store_credit_path(user, store_credit))
expect(response).to have_http_status(:see_other)
end

it "displays a failure flash message" do
put solidus_admin.invalidate_user_store_credit_path(user, store_credit), params: { store_credit: valid_params }
follow_redirect!
expect(response.body).to include("Something went wrong. Store credit could not be invalidated.")
end
end
end

describe "GET /edit_memo" do
it "renders the edit_memo template with a 200 OK status" do
get solidus_admin.edit_memo_user_store_credit_path(user, store_credit)
Expand Down

0 comments on commit 77f8302

Please sign in to comment.