# frozen_string_literal: true module Spree class PaymentMethod < ApplicationRecord # rubocop:disable Metrics/ClassLength include CalculatedAdjustments include PaymentMethodDistributors self.belongs_to_required_by_default = false acts_as_taggable acts_as_paranoid DISPLAY = [:both, :back_end].freeze INTERNAL = %w{Spree::PaymentMethod::CustomerCredit Spree::PaymentMethod::ApiCustomerCredit}.freeze default_scope -> { where(deleted_at: nil).where.not(type: INTERNAL) } has_many :credit_cards, class_name: "Spree::CreditCard", dependent: :destroy has_many :payments, class_name: "Spree::Payment", dependent: :restrict_with_error validates :name, presence: true validate :distributor_validation validates_associated :calculator after_initialize :init scope :inactive_or_backend, -> { where("active = false OR display_on = 'back_end'") } scope :production, -> { where(environment: 'production') } scope :managed_by, lambda { |user| return where(nil) if user.admin? joins(:distributors). where(distributors_payment_methods: { distributor_id: user.enterprises.select(&:id) }). select('DISTINCT spree_payment_methods.*') } scope :for_distributors, ->(distributors) { non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors }) where(id: non_unique_matches.map(&:id)) } scope :for_distributor, ->(distributor) { joins(:distributors).where(enterprises: { id: distributor }) } scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) } scope :by_name, -> { order('spree_payment_methods.name ASC') } scope :available, lambda { |display_on = 'both'| where(active: true) .where(display_on: [display_on, "", nil]) .where(environment: [Rails.env, "", nil]) } scope :internal, -> { unscoped.where(deleted_at: nil, type: INTERNAL) } # These two method are used to get the two internal payment method. They are accessible to all # enterprise, but the accessibility is managed by the code, as opposed to using the database. def self.customer_credit unscoped.find_by(type: "Spree::PaymentMethod::CustomerCredit", deleted_at: nil) end def self.api_customer_credit unscoped.find_by(type: "Spree::PaymentMethod::ApiCustomerCredit", deleted_at: nil) end def configured? !stripe? || stripe_configured? end def provider_class raise 'You must implement provider_class method for this gateway.' end # Does the PaymentMethod require redirecting to an external gateway? def external_gateway? false end # Inheriting PaymentMethods can implement this method if needed def external_payment_url(_options) nil end def frontend? active? && display_on != "back_end" end # The class that will process payments for this payment type, used for @payment.source # e.g. CreditCard in the case of a the Gateway payment type # nil means the payment method doesn't require a source e.g. check def payment_source_class raise 'You must implement payment_source_class method for this gateway.' end def self.active? where(type: to_s, environment: Rails.env, active: true).count.positive? end def method_type type.demodulize.downcase end def self.find_with_destroyed(*) unscoped { find(*) } end def source_required? true end def supports?(_source) true end def init self.calculator ||= ::Calculator::None.new end def has_distributor?(distributor) distributors.include?(distributor) end def display_name try_translating(name) end def display_description try_translating(description) end def internal? type.in?(INTERNAL) end private def distributor_validation return true if type.in?(INTERNAL) validates_with DistributorsValidator end def stripe? type.ends_with?("StripeSCA") end def stripe_configured? Spree::Config.stripe_connect_enabled && Stripe.publishable_key && preferred_enterprise_id.present? && preferred_enterprise_id > 0 && stripe_account_id.present? end def try_translating(value) return value if value.blank? I18n.t(value, default: value) end end end