Add void action to Taler for refunds

This commit is contained in:
Maikel Linke
2026-02-05 13:58:45 +11:00
parent ed701b00dc
commit de873ae42c
6 changed files with 103 additions and 0 deletions

View File

@@ -26,4 +26,17 @@ class PaymentMailer < ApplicationMailer
reply_to: @order.email)
end
end
def refund_available(payment, taler_order_status_url)
@order = payment.order
@taler_order_status_url = taler_order_status_url
subject = I18n.t("spree.payment_mailer.refund_available.subject",
order: @order)
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject:,
reply_to: @order.email)
end
end
end

View File

@@ -21,6 +21,14 @@ module Spree
preference :backend_url, :string
preference :api_key, :password
def actions
%w{void}
end
def can_void?(payment)
payment.state == "completed"
end
# Name of the view to display during checkout
def method_type
"check" # empty view
@@ -60,6 +68,25 @@ module Spree
ActiveMerchant::Billing::Response.new(success, message)
end
def void(response_code, gateway_options)
payment = gateway_options[:payment]
taler_order = taler_order(id: response_code)
status = taler_order.fetch("order_status")
if status == "claimed"
return ActiveMerchant::Billing::Response.new(true, "Already expired")
end
raise "Unsupported action" if status != "paid"
amount = taler_order.fetch("contract_terms")["amount"]
taler_order.refund(refund: amount, reason: "void")
PaymentMailer.refund_available(payment, taler_order.status_url).deliver_later
ActiveMerchant::Billing::Response.new(true, "Refund initiated")
end
private
def load_payment(order)

View File

@@ -0,0 +1,2 @@
%p= t("spree.payment_mailer.refund_available.message", order_number: @order.number)
%p= link_to @taler_order_status_url, @taler_order_status_url

View File

@@ -4930,6 +4930,9 @@ en:
authorization_required:
subject: "A payment requires authorization from the customer"
message: "A payment for order %{order_number} requires additional authorization from the customer. The customer has been notified via email and the payment will appear as pending until it is authorized."
refund_available:
subject: "Refund available"
message: "Your payment for order %{order_number} is being refunded. Claim your refund following the link below."
shipment_mailer:
shipped_email:
dear_customer: "Dear Customer,"

View File

@@ -40,4 +40,16 @@ RSpec.describe PaymentMailer do
end
end
end
describe "#refund_available" do
it "tells the user to accept a refund" do
payment = create(:payment)
link = "https://taler.example.com/order/1"
mail = PaymentMailer.refund_available(payment, link)
expect(mail.subject).to eq "Refund available"
expect(mail.body).to match "Claim your refund following the link below."
expect(mail.body).to match link
end
end
end

View File

@@ -49,4 +49,50 @@ RSpec.describe Spree::PaymentMethod::Taler do
expect(response.message).to eq "The payment request expired. Please try again."
end
end
describe "#void" do
let(:order_endpoint) { "#{backend_url}/private/orders/taler-order-8" }
let(:refund_endpoint) { "#{order_endpoint}/refund" }
let(:taler_refund_uri) {
"taler://refund/backend.demo.taler.net/instances/sandbox/taler-order-8/"
}
it "starts the refund process" do
order_status = {
order_status: "paid",
contract_terms: {
amount: "KUDOS:2",
}
}
stub_request(:get, order_endpoint).to_return(body: order_status.to_json)
stub_request(:post, refund_endpoint).to_return(body: { taler_refund_uri: }.to_json)
order = create(:completed_order_with_totals)
order.payments.create(
amount: order.total, state: :completed,
payment_method: taler,
response_code: "taler-order-8",
)
expect {
response = taler.void("taler-order-8", { payment: order.payments[0] })
expect(response.success?).to eq true
}.to enqueue_mail(PaymentMailer, :refund_available)
end
it "returns early if payment already void" do
order_status = {
order_status: "claimed",
}
stub_request(:get, order_endpoint).to_return(body: order_status.to_json)
order = create(:completed_order_with_totals)
order.payments.create(
amount: order.total, state: :completed,
payment_method: taler,
response_code: "taler-order-8",
)
expect {
response = taler.void("taler-order-8", { payment: order.payments[0] })
expect(response.success?).to eq true
}.not_to enqueue_mail
end
end
end