Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Admin][Users] Add new admin store credits invalidate flow #6034

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
@@ -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",
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ def turbo_frames
%w[
edit_amount_modal
edit_memo_modal
edit_validity_modal
]
end

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
@@ -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)
@@ -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

@@ -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
@@ -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,
@@ -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
@@ -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
3 changes: 3 additions & 0 deletions admin/config/locales/store_credits.en.yml
Original file line number Diff line number Diff line change
@@ -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
@@ -59,6 +59,8 @@
put :update_amount
get :edit_memo
put :update_memo
get :edit_validity
put :invalidate
end
end
end
46 changes: 34 additions & 12 deletions admin/spec/features/store_credits_spec.rb
Original file line number Diff line number Diff line change
@@ -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
@@ -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"
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
@@ -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)
@@ -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)