Files
openfoodnetwork/spec/requests/spree/admin/payments_spec.rb
Gaetan Craig-Riou bc23423521 Remove the link between enterprise and internal payment method
Enterprise have access to the internal payment method by default.
The access is handled at the application level so we don't have to
manage database links.
2026-03-10 16:07:43 +11:00

415 lines
14 KiB
Ruby

# frozen_string_literal: true
RSpec.describe Spree::Admin::PaymentsController do
let(:user) { order.user }
let(:order) { create(:completed_order_with_fees) }
before do
sign_in create(:admin_user)
end
describe "POST /admin/orders/:order_number/payments.json" do
let(:params) do
{
payment: {
payment_method_id: payment_method.id, amount: order.total
}
}
end
let(:payment_method) do
create(:payment_method, distributors: [order.distributor])
end
it "creates a payment" do
expect {
post("/admin/orders/#{order.number}/payments.json", params:)
}.to change { order.payments.count }.by(1)
end
it "redirect to payments page" do
post("/admin/orders/#{order.number}/payments.json", params:)
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:success]).to eq "Payment has been successfully created!"
end
context "when failing to create payment" do
it "redirects to payments page" do
payment_mock = instance_double(Spree::Payment)
allow(order.payments).to receive(:build).and_return(payment_mock)
allow(payment_mock).to receive(:save).and_return(false)
post("/admin/orders/#{order.number}/payments.json", params:)
expect(response).to redirect_to(spree.admin_order_payments_path(order))
end
end
context "when a gateway error happens" do
let(:payment_method) do
create(:stripe_sca_payment_method, distributors: [order.distributor])
end
it "redirect to payments page" do
allow(Spree::Order).to receive(:find_by!).and_return(order)
stripe_sca_payment_authorize =
instance_double(OrderManagement::Order::StripeScaPaymentAuthorize)
allow(OrderManagement::Order::StripeScaPaymentAuthorize).to receive(:new)
.and_return(stripe_sca_payment_authorize)
# Simulate an error
allow(stripe_sca_payment_authorize).to receive(:call!) do
order.errors.add(:base, "authorization_failure")
end
post("/admin/orders/#{order.number}/payments.json", params:)
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:error]).to eq("Authorization Failure")
end
end
context "with a VINE voucher", feature: :connected_apps do
let(:vine_voucher) {
create(:vine_voucher, code: 'some_code', enterprise: order.distributor, amount: 6)
}
let(:vine_voucher_redeemer) { instance_double(Vine::VoucherRedeemerService) }
before do
add_voucher_to_order(vine_voucher, order)
allow(Vine::VoucherRedeemerService).to receive(:new).and_return(vine_voucher_redeemer)
end
it "completes the order and redirects to payment page" do
expect(vine_voucher_redeemer).to receive(:redeem).and_return(true)
post("/admin/orders/#{order.number}/payments.json", params:)
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:success]).to eq "Payment has been successfully created!"
expect(order.reload.state).to eq "complete"
end
context "when redeeming the voucher fails" do
it "redirect to payments page" do
allow(vine_voucher_redeemer).to receive(:redeem).and_return(false)
allow(vine_voucher_redeemer).to receive(:errors).and_return(
{ redeeming_failed: "Redeeming the voucher failed" }
)
post("/admin/orders/#{order.number}/payments.json", params:)
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:error]).to match "Redeeming the voucher failed"
end
end
context "when an other error happens" do
it "redirect to payments page" do
allow(vine_voucher_redeemer).to receive(:redeem).and_return(false)
allow(vine_voucher_redeemer).to receive(:errors).and_return(
{ vine_api: "There was an error communicating with the API" }
)
post("/admin/orders/#{order.number}/payments.json", params:)
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:error]).to match "There was an error while trying to redeem your voucher"
end
end
end
end
describe "PUT /admin/orders/:order_number/payments/:id/fire" do
let(:payment) do
create(
:payment,
payment_method: stripe_payment_method,
order:,
response_code: "pi_123",
amount: order.total,
state: "completed"
)
end
let(:stripe_payment_method) do
create(:stripe_sca_payment_method, distributors: [order.distributor])
end
let(:headers) { { HTTP_REFERER: spree.admin_order_payments_url(order) } }
before do
order.update(payments: [])
order.payments << payment
end
context "with no event parameter" do
it "redirect to payments page" do
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
end
end
context "with no payment source" do
it "redirect to payments page" do
allow(payment).to receive(:payment_source).and_return(nil)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire?e=void",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
end
end
# TODO with internal_void event
context "with 'void' event" do
before do
allow(Spree::Payment).to receive(:find).and_return(payment)
end
it "calls void_transaction! on payment" do
expect(payment).to receive(:void_transaction!)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire?e=void",
params: {},
headers:
)
end
it "redirect to payments page" do
allow(payment).to receive(:void_transaction!).and_return(true)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire?e=void",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:success]).to eq "Payment Updated"
end
context "when void_transaction! fails" do
it "set an error flash message" do
allow(payment).to receive(:void_transaction!).and_return(false)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire?e=void",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:error]).to eq "Could not update the payment"
end
end
end
context "with 'capture_and_complete_order' event" do
before do
allow(Spree::Payment).to receive(:find).and_return(payment)
end
it "calls capture_and_complete_order! on payment" do
expect(payment).to receive(:capture_and_complete_order!)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/" \
"fire?e=capture_and_complete_order",
params: {},
headers:
)
end
it "redirect to payments page" do
allow(payment).to receive(:capture_and_complete_order!).and_return(true)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/" \
"fire?e=capture_and_complete_order",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:success]).to eq "Payment Updated"
end
context "when capture_and_complete_order! fails" do
it "set an error flash message" do
allow(payment).to receive(:capture_and_complete_order!).and_return(false)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/" \
"fire?e=capture_and_complete_order",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:error]).to eq "Could not update the payment"
end
end
context "with a VINE voucher", feature: :connected_apps do
let(:vine_voucher) {
create(:vine_voucher, code: 'some_code', enterprise: order.distributor, amount: 6)
}
let(:vine_voucher_redeemer) { instance_double(Vine::VoucherRedeemerService) }
before do
add_voucher_to_order(vine_voucher, order)
allow(Vine::VoucherRedeemerService).to receive(:new).and_return(vine_voucher_redeemer)
end
it "completes the order and redirects to payment page" do
expect(vine_voucher_redeemer).to receive(:redeem).and_return(true)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/" \
"fire?e=capture_and_complete_order",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:success]).to eq "Payment Updated"
expect(order.reload.state).to eq "complete"
end
context "when redeeming the voucher fails" do
it "redirect to payments page" do
allow(vine_voucher_redeemer).to receive(:redeem).and_return(false)
allow(vine_voucher_redeemer).to receive(:errors).and_return(
{ redeeming_failed: "Redeeming the voucher failed" }
)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/" \
"fire?e=capture_and_complete_order",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:error]).to match "Redeeming the voucher failed"
end
end
context "when an other error happens" do
it "redirect to payments page" do
allow(vine_voucher_redeemer).to receive(:redeem).and_return(false)
allow(vine_voucher_redeemer).to receive(:errors).and_return(
{ vine_api: "There was an error communicating with the API" }
)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/" \
"fire?e=capture_and_complete_order",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
expect(flash[:error]).to match "There was an error while trying to redeem your voucher"
end
end
end
end
context "when something unexpected happen" do
before do
allow(Spree::Payment).to receive(:find).and_return(payment)
allow(payment).to receive(:void_transaction!).and_raise(StandardError, "Unexpected !")
end
it "log the error message" do
# The redirect_do also calls Rails.logger.error
expect(Rails.logger).to receive(:error).with("Unexpected !").ordered
expect(Rails.logger).to receive(:error).with(/Redirected/).ordered
expect(Bugsnag).to receive(:notify).with(StandardError)
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire?e=void",
params: {},
headers: { HTTP_REFERER: spree.admin_order_payments_url(order) }
)
expect(flash[:error]).to eq "Unexpected !"
end
it "redirect to payments page" do
put(
"/admin/orders/#{order.number}/payments/#{order.payments.first.id}/fire?e=void",
params: {},
headers:
)
expect(response).to redirect_to(spree.admin_order_payments_url(order))
end
end
end
describe "POST /admin/orders/:order_number/payments/credit_customer" do
let(:success_response) {
Orders::CustomerCreditService::Response.new(success: true, message: "Refund successful!")
}
let(:customer_credit_service_mock) { instance_double(Orders::CustomerCreditService) }
before do
allow(customer_credit_service_mock).to receive(:apply)
# order setup will call Orders::CustomerCreditService once
expect(Orders::CustomerCreditService).to receive(:new).and_call_original
expect(Orders::CustomerCreditService).to receive(:new).and_return(
customer_credit_service_mock
)
end
it "creates a customer credit payment" do
expect(customer_credit_service_mock).to receive(:refund).and_return(success_response)
post("/admin/orders/#{order.number}/payments/credit_customer")
end
it "redirect to payments page" do
expect(customer_credit_service_mock).to receive(:refund).and_return(success_response)
post("/admin/orders/#{order.number}/payments/credit_customer")
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:success]).to eq "Customer has been successfully credited!"
end
context "when failing to create payment" do
let(:failure_response) {
Orders::CustomerCreditService::Response.new(success: false, message: "Some error")
}
it "redirects to payments page" do
expect(customer_credit_service_mock).to receive(:refund).and_return(failure_response)
post("/admin/orders/#{order.number}/payments/credit_customer")
expect(response).to redirect_to(spree.admin_order_payments_path(order))
expect(flash[:error]).to eq "Some error"
end
end
end
def add_voucher_to_order(voucher, order)
voucher.create_adjustment(voucher.code, order)
OrderManagement::Order::Updater.new(order).update_voucher
end
end