Class: PaymentMethod::GmoPg
- Inherits:
-
Gateway
- Object
- Gateway
- PaymentMethod::GmoPg
- Includes:
- Spree::PaymentMethod::AutoCaptureDigitalConcern
- Defined in:
- app/models/spree/payment_method/gmo_pg.rb
Constant Summary collapse
- GMO_PG_CARD_NOT_FOUND_ERRORS =
GMO-PGでカードが既に削除済みの場合のエラーパターン
/not found|404|E01390007/i
Class Method Summary collapse
-
.persist_3ds_redirect_data(payment, gmo_pg_data) ⇒ Object
3DS認証情報を payment に保存し、コールバック後に unprocessed_payments で 再処理できるよう checkout 状態に戻す。 process_payment_with_3ds は process_payments! の with_lock トランザクション内で実行され、 そこで保存しても PaymentRedirectRequired の伝播でロールバックされる。そのため保存は トランザクション外(CheckoutController の rescue)からこのメソッドを呼んで行う。.
Instance Method Summary collapse
-
#authorize(money, source, gateway_options) ⇒ Object
オーソリ(仮売上)を実行 登録済みカードの場合は "member_id|card_seq" 形式に変換してから実行 3DS2.0対応: 1回目はEntryTran+ExecTran、2回目はSecureTran2を実行.
- #can_capture?(payment) ⇒ Boolean
-
#cancel(response_code, payment = nil) ⇒ ActiveMerchant::Billing::Response
支払いをキャンセルします 注文キャンセル時に Order#after_cancel から自動的に呼び出されます.
- #create_profile(payment) ⇒ Object
-
#credit(money, source, authorization, options = {}) ⇒ ActiveMerchant::Billing::Response
返金を実行します payment_profiles_supported? が true のため、Spreeは4つの引数で呼び出します.
- #custom_form_fields_partial_name ⇒ Object
- #disable_customer_profile(source) ⇒ Object
- #method_type ⇒ Object
- #options ⇒ Object
- #payment_profiles_supported? ⇒ Boolean
- #payment_source_class ⇒ Object
- #provider_class ⇒ Object
-
#purchase(money, source, gateway_options) ⇒ Object
即時売上を実行 登録済みカードの場合は "member_id|card_seq" 形式に変換してから実行 3DS2.0対応: 1回目はEntryTran+ExecTran、2回目はSecureTran2を実行.
- #supports?(source) ⇒ Boolean
-
#void(response_code, source = nil, options = {}) ⇒ ActiveMerchant::Billing::Response
支払いを無効化します(手動void用) 管理画面から手動でvoidする際に Payment#void_transaction! から呼び出されます payment_profiles_supported? が true のため、Spreeは3つの引数で呼び出します.
Class Method Details
.persist_3ds_redirect_data(payment, gmo_pg_data) ⇒ Object
3DS認証情報を payment に保存し、コールバック後に unprocessed_payments で 再処理できるよう checkout 状態に戻す。 process_payment_with_3ds は process_payments! の with_lock トランザクション内で実行され、 そこで保存しても PaymentRedirectRequired の伝播でロールバックされる。そのため保存は トランザクション外(CheckoutController の rescue)からこのメソッドを呼んで行う。
21 22 23 24 25 26 27 28 29 30 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 21 def self.persist_3ds_redirect_data(payment, gmo_pg_data) return if payment.blank? || gmo_pg_data.blank? # ロールバック後の DB の値に合わせてから保存する payment.reload payment.[:gmo_pg] = gmo_pg_data payment.save! # update_column で state_machine の検証をバイパスして checkout に戻す payment.update_column(:state, 'checkout') unless payment.checkout? end |
Instance Method Details
#authorize(money, source, gateway_options) ⇒ Object
オーソリ(仮売上)を実行 登録済みカードの場合は "member_id|card_seq" 形式に変換してから実行 3DS2.0対応: 1回目はEntryTran+ExecTran、2回目はSecureTran2を実行
73 74 75 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 73 def (money, source, ) process_payment_with_3ds(:authorize, money, source, ) end |
#can_capture?(payment) ⇒ Boolean
52 53 54 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 52 def can_capture?(payment) payment.pending? || payment.checkout? end |
#cancel(response_code, payment = nil) ⇒ ActiveMerchant::Billing::Response
支払いをキャンセルします 注文キャンセル時に Order#after_cancel から自動的に呼び出されます
211 212 213 214 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 211 def cancel(response_code, payment = nil) # ActiveMerchantのvoidメソッドを呼び出してGMO-PGのオーソリをキャンセル provider.void(response_code, payment&. || {}) end |
#create_profile(payment) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 84 def create_profile(payment) return unless payment.source.gateway_payment_profile_id.present? source = payment.source token = source.gateway_payment_profile_id # すでに登録済みカード(member_id + CardSeq両方ある)の場合はスキップ if source.gateway_customer_profile_id.present? && source.gateway_payment_profile_id.present? Rails.logger.info "Using existing registered card (member_id: #{source.gateway_customer_profile_id}, CardSeq: #{source.gateway_payment_profile_id})" return end # ゲスト購入の場合は、トークンをそのまま保存して終了 # SaveMember/SaveCard APIは呼ばない if payment.order.user.blank? Rails.logger.info "Guest checkout: Token saved without card registration (token: #{token[0..10]}...)" return # トークンは既にgateway_payment_profile_idに入っているので何もしない end # ログイン済みユーザーの場合は既存の処理(#692の実装) # トークンから会員登録とカード登録を実行 member_id = payment.order.user_id.to_s Rails.logger.info "Logged-in user checkout: Registering card with GMO-PG (member_id: #{member_id})" # ActiveMerchantのstore メソッドを呼び出し # store(payment, options = {}) # paymentにはトークンを渡す response = provider.store( token, { member_id: member_id, order_id: payment.order.number } ) if response.success? # response.authorizationから member_id と CardSeq を取得 # authorization は "member_id|card_seq" の形式 member_id_from_response, card_seq = response..split('|') # GatewayCustomerを作成または取得 self.gateway_customers.find_or_create_by( user: payment.order.user ) do |gc| gc.profile_id = member_id end # GMOから返却されたcard_seqが既に他のレコードに存在するかチェック existing_card = payment.order.user.credit_cards.where( payment_method_id: self.id, gateway_customer_profile_id: member_id, gateway_payment_profile_id: card_seq ).where.not(id: source.id).first if existing_card # 既存カードがある場合 = GMOで更新が行われた = 情報を統合 Rails.logger.info "GMO updated existing card (CardSeq: #{card_seq}), merging records..." # 既存カードの情報を更新(有効期限、名義など) # defaultフラグは変更しない(ユーザーが既に選択している可能性があるため) existing_card.update!( month: source.month, year: source.year, name: source.name # last_digits, cc_type は変わらないはず(同じカード番号なので) # default は変更しない ) # 新規作成したsourceレコードは不要なので削除 source.destroy # paymentのsource_idを既存カードに変更 # update_columnsを使ってafter_saveコールバックをスキップ(無限ループ防止) payment.update_columns(source_id: existing_card.id, source_type: existing_card.class.name) Rails.logger.info "Updated existing card record (id: #{existing_card.id})" else # 既存カードがない場合 = 新規登録 source.update!( gateway_payment_profile_id: card_seq, gateway_customer_profile_id: member_id ) Rails.logger.info "Card registered successfully (CardSeq: #{card_seq})" end else # エラーの場合は例外を発生させる raise Spree::Core::GatewayError.new(response.) end rescue ActiveMerchant::ConnectionError => e raise Spree::Core::GatewayError.new(e.) end |
#credit(money, source, authorization, options = {}) ⇒ ActiveMerchant::Billing::Response
返金を実行します payment_profiles_supported? が true のため、Spreeは4つの引数で呼び出します
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 245 def credit(money, source, , = {}) # 返金元の情報を取得 originator = [:originator] unless originator&.respond_to?(:payment) raise Spree::Core::GatewayError, 'Refund originator is required' end payment = originator.payment # 現在の残額を計算 # money, payment.captured_amount, refunds.sum(:amount)はすべてamount_in_centsの結果で同じ単位 # JPYの場合でも、修正後のamount_in_centsは正しい値を返すので×100は不要 captured_cents = payment.captured_amount.to_i # transaction_idが存在する返金のみをカウント(完了済みの返金) refunded_cents = payment.refunds.where.not(transaction_id: nil).sum(:amount).to_i remaining_cents = captured_cents - refunded_cents # 今回の返金後の残額 new_remaining_cents = remaining_cents - money # 全額返金かどうか if new_remaining_cents <= 0 # 全額返金 → void(キャンセル) Rails.logger.info "[GMO-PG Refund] Full refund: money=#{money}, remaining=#{remaining_cents}, authorization=#{}" provider.void(, ) else # 部分返金 → update_amount(減額) job_cd = payment.completed? ? 'CAPTURE' : 'AUTH' Rails.logger.info "[GMO-PG Refund] Partial refund: money=#{money}, new_remaining=#{new_remaining_cents}, job_cd=#{job_cd}, authorization=#{}" provider.update_amount(new_remaining_cents, , .merge(job_cd: job_cd)) end end |
#custom_form_fields_partial_name ⇒ Object
56 57 58 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 56 def custom_form_fields_partial_name 'gmo_pg_form_fields' end |
#disable_customer_profile(source) ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 177 def disable_customer_profile(source) return unless source.is_a?(Spree::CreditCard) # gateway_payment_profile_idが無い場合(登録未完了)はDB側のみ削除 if source.gateway_payment_profile_id.blank? source.destroy Rails.logger.info "Local credit card deleted (not registered with GMO-PG): #{source.id}" return end # GMO-PG側から削除 # unstore の第1引数は "member_id|card_seq" の形式 identification = "#{source.gateway_customer_profile_id}|#{source.gateway_payment_profile_id}" result = provider.unstore(identification) # GMO-PG側で既に削除済み(404)や成功の場合、DB側を削除 if result.success? || result..to_s.match?(GMO_PG_CARD_NOT_FOUND_ERRORS) source.destroy Rails.logger.info "GMO-PG card deleted: #{source.gateway_payment_profile_id}" else # 削除失敗時はエラーを投げる Rails.logger.error "GMO-PG card deletion failed: #{result.}" raise Spree::Core::GatewayError, result. end rescue ActiveMerchant::ConnectionError => e raise Spree::Core::GatewayError.new(e.) end |
#method_type ⇒ Object
40 41 42 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 40 def method_type 'gmo_pg' end |
#options ⇒ Object
60 61 62 63 64 65 66 67 68 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 60 def { shop_id: preferred_shop_id, shop_pass: preferred_shop_pass, site_id: preferred_site_id, site_pass: preferred_site_pass, test: preferred_test_mode } end |
#payment_profiles_supported? ⇒ Boolean
44 45 46 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 44 def payment_profiles_supported? true end |
#payment_source_class ⇒ Object
36 37 38 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 36 def payment_source_class Spree::CreditCard end |
#provider_class ⇒ Object
32 33 34 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 32 def provider_class ActiveMerchant::Billing::GmoPgGateway end |
#purchase(money, source, gateway_options) ⇒ Object
即時売上を実行 登録済みカードの場合は "member_id|card_seq" 形式に変換してから実行 3DS2.0対応: 1回目はEntryTran+ExecTran、2回目はSecureTran2を実行
80 81 82 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 80 def purchase(money, source, ) process_payment_with_3ds(:purchase, money, source, ) end |
#supports?(source) ⇒ Boolean
48 49 50 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 48 def supports?(source) source.is_a?(Spree::CreditCard) end |
#void(response_code, source = nil, options = {}) ⇒ ActiveMerchant::Billing::Response
支払いを無効化します(手動void用) 管理画面から手動でvoidする際に Payment#void_transaction! から呼び出されます payment_profiles_supported? が true のため、Spreeは3つの引数で呼び出します
224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'app/models/spree/payment_method/gmo_pg.rb', line 224 def void(response_code, source = nil, = {}) # 2引数呼び出し(古いSpreeバージョンや直接呼び出し)の互換性対応 # source が Hash の場合、それが実際の options if source.is_a?(Hash) = source source = nil end # GMO-PG の void は authorization と options のみを使用 # source (CreditCard) は不要なので無視 provider.void(response_code, ) end |