13
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Solidusで決済手数料をさくっと導入する

Last updated at Posted at 2016-04-08

Ruby on Rails製のECシステムであるSolidusは非常に拡張性に富んだ設計がされているものの、デフォルトのままだと文字通り必要最低限の機能しかないうえに、海外の商習慣に基いて作られているため日本国内で使う場合には多くの箇所を自力でカスタマイズするしかありません。

この記事でテーマとしている決済手数料も、日本国内では未だ少なくないECサイトが「代金引換決済の場合324円発生します」とかしているにも関わらず標準のSolidusではそれを実現することができません。

エクステンションを用いて実現することも可能ですが古いバージョンのまま更新が止まってしまっていたり、複数通貨にも対応していて多機能過ぎたりします。もっとシンプルに実装したい場合には今回紹介する方法を用いると良いかもしれません。

最初にコードを記します。

  • 動作環境 Solidus 2.3系
app/models/spree/payment_method_decorator.rb
Spree::PaymentMethod.class_eval do
  preference :payment_method_fee, :integer
end
app/controllers/spree/checkout_controller_decorator.rb
Spree::CheckoutController.class_eval do
  before_action :update_payment_method_fee, only: :update

  private
  def update_payment_method_fee
    return unless params['state'] == "payment"

    if params[:order][:wallet_payment_source_id].present?
      # solidusはparams[:wallet_payment_source_id]の有無でwalletの使用/不使用を判定している
      # カードの場合0円にしてます。適時書き換えてください。
      payment_method_fee_is = 0
    else
      payment_method_fee_is = Spree::PaymentMethod.find(params['order']['payments_attributes'][0]['payment_method_id']).preferred_payment_method_fee
    end
    payment_method_fee_was = @order.adjustments.eligible.where(label: Spree.t(:payment_method_fee)).sum(:amount).to_i

    if payment_method_fee_is != payment_method_fee_was
      @order.adjustments.eligible.where(label: Spree.t(:payment_method_fee)).update_all(eligible: false)
      Spree::Adjustment.create(label: Spree.t(:payment_method_fee), adjustable: @order, order: @order, amount: payment_method_fee_is) if payment_method_fee_is != 0
      @order.adjustments.reload
      @order.updater.update # @order.totalや@order.adjustment_totalを再計算する
    end
  end
end

これら2つのファイルをプロジェクトに追加するだけで実現できてしまいます。簡単ですよね。

仕組み

PREFERENCE

決済手数料の金額は、SolidusのPreferenceを使用して保存しています。Preferenceについて詳しくは下記の記事をご覧いただければと思いますが、簡単に説明するとDBにカラムを追加せずに任意のキーの変数をActiveRecordインスタンスやアプリケーション全体に対して保存できる仕組みのことです。

[日本語訳] PREFERENCES - DEVELOPER GUIDE | SPREE COMMERCE

なおSpree::PaymentMethodクラスはデフォルトでPreferenceを使用できる設計になっています。新しくPreferenceを定義すると自動でadmin/payment_methods/:id/editに型に応じたフォームが現れるのでビューをいじる必要もなく任意の変数を保存することができます。あとはこのフォームから金額を設定してあげるだけですね。

あとはcheckout_controller_decorator.rbが決済方法に応じた手数料を注文に付与してくれます。解説についてはコード内にコメントで書いた通りです。

ちなみにSpree::Paymentのコールバックとかで決済手数料を計算しようともしてみたんですがうまく行きませんでした。adjustmentを作るだけと思いきや、order.totalやpayment.amount辺りも値を更新する必要があるのでタイミングが結構シビアです。色々試した結果checkout_controllerで計算するのが一番という結論に至りました。

ついでに

Solidusを使ってECサイトを作る場合、コアとなるようなメソッドに手を加えてしまうとSolidus本体のアップデートの際にシステムが壊れてしまったり、コードの見通しが悪くなったりとあまり良いことがありません。

カスタマイズする場合は、今回みたいにコントローラのbefore_actionやコールバック等を活用してSolidusのコアと疎結合になるよう組み立ててゆきましょう。

13
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?