Add internal to payment method

It's used to hide the payment method used for paying with credit. These
payment method are for internal use only.
This commit is contained in:
Gaetan Craig-Riou
2026-02-24 13:17:38 +11:00
parent 3e2e7f1799
commit d95aac333b
12 changed files with 84 additions and 20 deletions

View File

@@ -8,7 +8,9 @@ class CustomerAccountTransaction < ApplicationRecord
localize_number :amount
belongs_to :customer
belongs_to :payment_method, class_name: "Spree::PaymentMethod"
belongs_to :payment_method, -> {
internal
}, class_name: "Spree::PaymentMethod", inverse_of: :customer_account_transactions
belongs_to :payment, class_name: "Spree::Payment", optional: true
validates :amount, presence: true
@@ -41,7 +43,7 @@ class CustomerAccountTransaction < ApplicationRecord
# Creates the first transaction with a 0 amount
def create_initial_transaction
api_payment_method = Spree::PaymentMethod.find_by!(
api_payment_method = customer.enterprise.payment_methods.internal.find_by!(
name: Rails.application.config.api_payment_method[:name]
)
CustomerAccountTransaction.create!(

View File

@@ -18,7 +18,9 @@ module Spree
belongs_to :order, class_name: 'Spree::Order'
belongs_to :source, polymorphic: true
belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
belongs_to :payment_method, -> {
unscope(where: :internal)
}, class_name: "Spree::PaymentMethod", inverse_of: :payments
has_many :offsets, -> { where("source_type = 'Spree::Payment' AND amount < 0").completed },
class_name: "Spree::Payment", foreign_key: :source_id,

View File

@@ -11,9 +11,11 @@ module Spree
acts_as_paranoid
DISPLAY = [:both, :back_end].freeze
default_scope -> { where(deleted_at: nil) }
default_scope -> { where(deleted_at: nil, internal: false) }
has_many :credit_cards, class_name: "Spree::CreditCard", dependent: :destroy
has_many :customer_account_transactions, dependent: :restrict_with_error
has_many :payments, class_name: "Spree::Payment", dependent: :restrict_with_error
validates :name, presence: true
validate :distributor_validation
@@ -52,8 +54,12 @@ module Spree
.where(environment: [Rails.env, "", nil])
}
scope :internal, -> { unscoped.where(internal: true, deleted_at: nil) }
# It's meant to be use to get the customer credit payment method for a given enterprise ie:
# `enterprise.payment_methods.customer_credit`
def self.customer_credit
find_by(name: Rails.application.config.credit_payment_method[:name])
internal.find_by(name: Rails.application.config.credit_payment_method[:name])
end
def configured?

View File

@@ -89,10 +89,6 @@ module Spree
false
end
def internal?
true
end
private
def payment_method

View File

@@ -29,7 +29,9 @@ module CreditPaymentMethod
private
def api_payment_method
Spree::PaymentMethod.find_by(name: Rails.application.config.api_payment_method[:name])
Spree::PaymentMethod.internal.find_by(
name: Rails.application.config.api_payment_method[:name]
)
end
def create_api_payment_method
@@ -39,7 +41,8 @@ module CreditPaymentMethod
description: configured[:description],
display_on: "back_end",
environment: Rails.env,
distributor_ids: [enterprise.id]
distributor_ids: [enterprise.id],
internal: true
)
end
@@ -54,7 +57,8 @@ module CreditPaymentMethod
description: configured[:description],
display_on: "both",
environment: Rails.env,
distributor_ids: [enterprise.id]
distributor_ids: [enterprise.id],
internal: true
)
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddInternalToSpreePaymentMethods < ActiveRecord::Migration[7.1]
def change
add_column :spree_payment_methods, :internal, :boolean, null: false, default: false
end
end

View File

@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2026_02_06_054509) do
ActiveRecord::Schema[7.1].define(version: 2026_02_23_040231) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
enable_extension "plpgsql"
@@ -651,6 +651,7 @@ ActiveRecord::Schema[7.1].define(version: 2026_02_06_054509) do
t.datetime "updated_at", precision: nil, null: false
t.datetime "deleted_at", precision: nil
t.string "display_on", limit: 255
t.boolean "internal", default: false, null: false
end
create_table "spree_payments", id: :serial, force: :cascade do |t|

View File

@@ -6,7 +6,8 @@ FactoryBot.define do
amount { 10.00 }
currency { "AUD" }
payment_method {
build(:payment_method, name: Rails.application.config.api_payment_method[:name])
build(:payment_method, name: Rails.application.config.api_payment_method[:name],
internal: true)
}
end
end

View File

@@ -34,7 +34,7 @@ FactoryBot.define do
name { Rails.application.config.credit_payment_method[:name] }
description { Rails.application.config.credit_payment_method[:description] }
environment { 'test' }
internal { true }
distributors { [Enterprise.is_distributor.first || FactoryBot.create(:distributor_enterprise)] }
end
end

View File

@@ -4,6 +4,13 @@ class Spree::Gateway::Test < Spree::Gateway
end
RSpec.describe Spree::PaymentMethod do
describe "validations" do
subject { build(:payment_method) }
it { is_expected.to have_many(:customer_account_transactions) }
it { is_expected.to have_many(:payments) }
end
describe ".managed_by scope" do
subject! { create(:payment_method) }
let(:owner) { subject.distributors.first.owner }
@@ -55,6 +62,28 @@ RSpec.describe Spree::PaymentMethod do
end
end
describe "#internal" do
it "returns only internal payment method" do
external = create(:payment_method)
internal = create(:payment_method, internal: true)
payment_methods = described_class.internal
expect(payment_methods).to include(internal)
expect(payment_methods).not_to include(external)
end
end
describe "#customer_credit" do
it "returns customer credit payment method" do
# Creating an enterprise will create the needed internal payment method if needed
enterprise = create(:enterprise)
payment_method = Spree::PaymentMethod.unscoped.find_by(
name: Rails.application.config.credit_payment_method[:name], internal: true
)
expect(enterprise.payment_methods.customer_credit).to eq(payment_method)
end
end
describe "#configured?" do
context "non-Stripe payment method" do
let(:payment_method) { build(:payment_method) }

View File

@@ -15,21 +15,24 @@ RSpec.describe CreditPaymentMethod::LinkerService do
describe ".link" do
it "links the given enterprise to customer credit related payment method" do
api_payment_method = create(:payment_method,
name: Rails.application.config.api_payment_method[:name])
api_payment_method = create(
:payment_method,
name: Rails.application.config.api_payment_method[:name],
internal: true
)
credit_payment_method = create(:customer_credit_payment_method)
described_class.link(enterprise:)
expect(enterprise.payment_methods).to include(api_payment_method)
expect(enterprise.payment_methods).to include(credit_payment_method)
expect(enterprise.payment_methods.unscoped).to include(api_payment_method)
expect(enterprise.payment_methods.unscoped).to include(credit_payment_method)
end
context "when payment method don't exist" do
it "creates customer credit related payment method" do
described_class.link(enterprise:)
api_payment_method = Spree::PaymentMethod.find_by(
api_payment_method = Spree::PaymentMethod.internal.find_by(
name: Rails.application.config.api_payment_method[:name]
)
expect(api_payment_method).not_to be_nil

View File

@@ -38,6 +38,19 @@ RSpec.describe Orders::AvailablePaymentMethodsService do
expect(available_payment_methods).to eq [frontend_payment_method]
end
it "does not return payment methods which are internal" do
distributor = create(:distributor_enterprise)
frontend_payment_method = create(:payment_method, distributors: [distributor])
internal_payment_method = Spree::PaymentMethod.customer_credit
order_cycle = create(:sells_own_order_cycle)
order = build(:order, distributor:, order_cycle:)
available_payment_methods = Orders::AvailablePaymentMethodsService.new(order).to_a
expect(available_payment_methods).to eq [frontend_payment_method]
end
context "when no tag rules are in effect" do
context "sells own order cycle i.e. simple" do
it "only returns the payment methods which are available on the order cycle