Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
http_interactions:
- request:
method: post
uri: https://<HOST>/payment/ExecTran.idPass
body:
encoding: UTF-8
string: AccessID=<ACCESS_ID>&AccessPass=<ACCESS_PASS>&OrderID=<ORDER_ID>&Method=1&PayTimes=&MemberID=<MEMBER_ID>&CardSeq=0&TdsType=2&Tds2Type=2&CallBackUrl=https%3A%2F%2Fexample.com%2Fcallback&Tds2RetUrl=https%3A%2F%2Fexample.com%2F3ds%2Freturn
headers:
Accept:
- "*/*"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Content-Type:
- text/plain; charset=shift_jis
Date:
- Thu, 24 Jul 2025 23:15:18 GMT
Server:
- Apache
body:
encoding: UTF-8
string: OrderID=<ORDER_ID>&Forward=<FORWARD>&Method=1&PayTimes=&Approve=&TranID=<TRAN_ID>&TranDate=<TRAN_DATE>&CheckString=<CHECK_STRING>&Tds2TransResult=C&Tds2TransResultReason=01&Tds2ChallengeUrl=https://<HOST>/payment/Tds2Challenge?tds2TransID=<TDS2_TRANS_ID>&Tds2TransID=<TDS2_TRANS_ID>
recorded_at: Thu, 24 Jul 2025 23:15:18 GMT
recorded_with: VCR 6.3.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
http_interactions:
- request:
method: post
uri: https://<HOST>/payment/SecureTran2.idPass
body:
encoding: UTF-8
string: AccessID=<ACCESS_ID>&AccessPass=<ACCESS_PASS>
headers:
Accept:
- "*/*"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Content-Type:
- text/plain; charset=shift_jis
Date:
- Thu, 24 Jul 2025 23:15:18 GMT
Server:
- Apache
body:
encoding: UTF-8
string: OrderID=<ORDER_ID>&Forward=<FORWARD>&Method=1&PayTimes=&Approve=<APPROVE>&TranID=<TRAN_ID>&TranDate=<TRAN_DATE>&CheckString=<CHECK_STRING>
recorded_at: Thu, 24 Jul 2025 23:15:18 GMT
recorded_with: VCR 6.3.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
http_interactions:
- request:
method: post
uri: https://<HOST>/payment/Tds2Auth.idPass
body:
encoding: UTF-8
string: AccessID=<ACCESS_ID>&AccessPass=<ACCESS_PASS>&Tds2Param=<TDS2_PARAM>&ShopID=<SHOP_ID>&ShopPass=<SHOP_PASS>
headers:
Accept:
- "*/*"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Content-Type:
- text/plain; charset=shift_jis
Date:
- Thu, 24 Jul 2025 23:15:18 GMT
Server:
- Apache
body:
encoding: UTF-8
string: OrderID=<ORDER_ID>&Forward=<FORWARD>&Method=1&PayTimes=&Approve=&TranID=<TRAN_ID>&TranDate=<TRAN_DATE>&CheckString=<CHECK_STRING>&Tds2TransResult=Y&Tds2TransResultReason=&Tds2ChallengeUrl=https://<HOST>/payment/Tds2Challenge?tds2TransID=<TDS2_TRANS_ID>
recorded_at: Thu, 24 Jul 2025 23:15:18 GMT
recorded_with: VCR 6.3.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
http_interactions:
- request:
method: post
uri: https://<HOST>/payment/Tds2Result.idPass
body:
encoding: UTF-8
string: AccessID=<ACCESS_ID>&AccessPass=<ACCESS_PASS>&ShopID=<SHOP_ID>&ShopPass=<SHOP_PASS>
headers:
Accept:
- "*/*"
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Content-Type:
- application/x-www-form-urlencoded
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Content-Type:
- text/plain; charset=shift_jis
Date:
- Thu, 24 Jul 2025 23:15:18 GMT
Server:
- Apache
body:
encoding: UTF-8
string: OrderID=<ORDER_ID>&Forward=<FORWARD>&Method=1&PayTimes=&Approve=&TranID=<TRAN_ID>&TranDate=<TRAN_DATE>&CheckString=<CHECK_STRING>&Tds2TransResult=Y&Tds2TransResultReason=
recorded_at: Thu, 24 Jul 2025 23:15:18 GMT
recorded_with: VCR 6.3.1
7 changes: 7 additions & 0 deletions lib/gmo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ def api(path, args = {}, verb = "post", options = {}, &error_checking_block)
key_values = result.body.to_s.split('&').map { |str| str.split('=', 2) }.flatten
response = Hash[*key_values]
end
# Transform the redirect_url
# "ACS=2&RedirectUrl=https://manage.tds2gw.gmopg.jp/api/v2/brw/callback?transId=6e48e31f-2940-48e1-a702-ebba2f3373ee&t=dccc8a7ed85372c9accff576bff59b3a"
# => { "ACS" => "2", RedirectUrl => "https://manage.tds2gw.gmopg.jp/api/v2/brw/callback?transId=6e48e31f-2940-48e1-a702- ebba2f3373ee&t=dccc8a7ed85372c9accff576bff59b3a" }
if response['RedirectUrl'] && response['RedirectUrl'] != '' && response['t'] && response['t'] != '' && response.keys.index('RedirectUrl') + 1 == response.keys.index('t')
response['RedirectUrl'] = response['RedirectUrl'] + '&t=' + response['t']
response.delete('t')
end
# converting to UTF-8
body = response = Hash[response.map { |k,v| [k, NKF.nkf('-S -w',v)] }]
# Check for errors if provided a error_checking_block
Expand Down
50 changes: 50 additions & 0 deletions lib/gmo/const.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ module Const
:auth_code_2 => "Auth_Code2",
:auth_code_3 => "Auth_Code3",
:amount => "Amount",
:app_mode => "AppMode",
:bank_code => "Bank_Code",
:bank_id => "Bank_ID",
:branch_code => "Branch_Code",
:branch_code_jp => "Branch_Code_Jpbank",
:call_back_url => "Call_Back_Url",
:callback_type => "CallbackType",
:cancel_amount => "CancelAmount",
:cancel_tax => "CancelTax",
:card_name => "CardName",
Expand Down Expand Up @@ -156,7 +158,55 @@ module Const
:suica_add_info_4 => "SuicaAddInfo4",
:tax => "Tax",
:td_flag => "TdFlag",
:tds2_type => "Tds2Type",
:td_required => "TdRequired",
:td_tenant_name => "TdTenantName",
:tds2_ch_acc_change => "Tds2ChAccChange",
:tds2_ch_acc_date => "Tds2ChAccDate",
:tds2_ch_acc_pw_change => "Tds2ChAccPwChange",
:tds2_nb_purchase_account => "Tds2NbPurchaseAccount",
:tds2_param => "Tds2Param",
:tds2_payment_acc_age => "Tds2PaymentAccAge",
:tds2_provision_attempts_day => "Tds2ProvisionAttemptsDay",
:tds2_ship_address_usage => "Tds2ShipAddressUsage",
:tds2_ship_name_ind => "Tds2ShipNameInd",
:tds2_suspicious_acc_activity => "Tds2SuspiciousAccActivity",
:tds2_txn_activity_day => "Tds2TxnActivityDay",
:tds2_txn_activity_year => "Tds2TxnActivityYear",
:tds2_3ds_req_auth_data => "Tds2ThreeDSReqAuthData",
:tds2_3ds_req_auth_method => "Tds2ThreeDSReqAuthMethod",
:tds2_3ds_req_auth_timestamp => "Tds2ThreeDSReqAuthTimestamp",
:tds2_addr_match => "Tds2AddrMatch",
:tds2_bill_addr_city => "Tds2BillAddrCity",
:tds2_bill_addr_country => "Tds2BillAddrCountry",
:tds2_bill_addr_line1 => "Tds2BillAddrLine1",
:tds2_bill_addr_line2 => "Tds2BillAddrLine2",
:tds2_bill_addr_line3 => "Tds2BillAddrLine3",
:tds2_bill_addr_post_code => "Tds2BillAddrPostCode",
:tds2_bill_addr_state => "Tds2BillAddrState",
:tds2_email => "Tds2Email",
:tds2_home_phone_cc => "Tds2HomePhoneCC",
:tds2_home_phone_subscriber => "Tds2HomePhoneSubscriber",
:tds2_mobile_phone_cc => "Tds2MobilePhoneCC",
:tds2_mobile_phone_subscriber => "Tds2MobilePhoneSubscriber",
:tds2_work_phone_cc => "Tds2WorkPhoneCC",
:tds2_work_phone_subscriber => "Tds2WorkPhoneSubscriber",
:tds2_ship_addr_city => "Tds2ShipAddrCity",
:tds2_ship_addr_country => "Tds2ShipAddrCountry",
:tds2_ship_addr_line1 => "Tds2ShipAddrLine1",
:tds2_ship_addr_line2 => "Tds2ShipAddrLine2",
:tds2_ship_addr_line3 => "Tds2ShipAddrLine3",
:tds2_ship_addr_post_code => "Tds2ShipAddrPostCode",
:tds2_ship_addr_state => "Tds2ShipAddrState",
:tds2_delivery_email_address => "Tds2DeliveryEmailAddress",
:tds2_delivery_time_frame => "Tds2DeliveryTimeframe",
:tds2_gift_card_amount => "Tds2GiftCardAmount",
:tds2_gift_card_count => "Tds2GiftCardCount",
:tds2_gift_card_curr => "Tds2GiftCardCurr",
:tds2_pre_order_date => "Tds2PreOrderDate",
:tds2_pre_order_purchase_ind => "Tds2PreOrderPurchaseInd",
:tds2_reorder_items_ind => "Tds2ReorderItemsInd",
:tds2_ship_ind => "Tds2ShipInd",
:tel_no => "TelNo",
:token => "Token",
:token_seq => "TokenSeq",
Expand Down
33 changes: 33 additions & 0 deletions lib/gmo/shop_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,39 @@ def search_trade_multi(options = {})
post_request name, options
end

###################################################
# 3DS2.0 対応
###################################################

# 4.3.1.7 3DS2.0認証実行(Tds2Auth)
# DS2.0認証を実行します。
# 3DS2.0認証初期化URL(RedirectUrl)のコールバックを受けたタイミングで本処理を実行してください。
def tds2_auth(options = {})
name = "Tds2Auth.idPass"
required = [:access_id, :access_pass, :tds2_param]
assert_required_options(required, options)
post_request name, options
end

# 4.3.1.8 3DS2.0認証結果取得(Tds2Result)
# 3DS2.0認証の最終的な認証結果を取得します。
# 3DS2.0認証チャレンジURL(ChallengeUrl)のコールバックを受けたタイミングで本処理を実行してください。
def tds2_result(options = {})
name = "Tds2Result.idPass"
required = [:access_id, :access_pass]
assert_required_options(required, options)
post_request name, options
end

# 4.3.1.12 3DS2.0認証後決済実行(SecureTran2)
# 3DS2.0サービスの結果を解析し、その情報を使用してカード会社と通信を行い決済を実施して結果を返します。
def secure_tran_2(options = {})
name = "SecureTran2.idPass"
required = [:access_id, :access_pass]
assert_required_options(required, options)
post_request name, options
end

private

def api_call(name, args = {}, verb = "post", options = {})
Expand Down
90 changes: 90 additions & 0 deletions spec/gmo/shop_api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1192,4 +1192,94 @@
end
end

describe "#exec_tran with 3DS2.0" do
it "returns 3DS2.0 challenge flow response", :vcr do
result = @service.exec_tran({
:access_id => "test_access_7ed782e0e10604b31258e0d69ee3e887",
:access_pass => "test_pass_7be5e8786e2e959d7b48ad708634dc7e",
:order_id => "TEST_3DS_20250724231518",
:method => 1,
:pay_times => "",
:card_no => "4111111111111111",
:expire => "2512",
:member_id => "TEST_MEMBER_5df458bc",
:card_seq => 0,
:tds_type => 2,
:tds2_type => 2,
:call_back_url => "https://example.com/callback",
:tds2_ret_url => "https://example.com/3ds/return"
})

result["OrderID"].should == "<ORDER_ID>"
result["Forward"].should == "<FORWARD>"
result["Method"].should == "1"
result["TranID"].should == "<TRAN_ID>"
result["TranDate"].should == "<TRAN_DATE>"
result["Tds2TransResult"].should == "C"
result["Tds2TransResultReason"].should == "01"
result["Tds2ChallengeUrl"].should include("/payment/Tds2Challenge")
result["Tds2TransID"].should == "<TDS2_TRANS_ID>"
end
end

describe "#tds2_auth" do
it "executes 3DS2.0 authentication", :vcr do
result = @service.tds2_auth({
:access_id => "test_access_7ed782e0e10604b31258e0d69ee3e887",
:access_pass => "test_pass_7be5e8786e2e959d7b48ad708634dc7e",
:tds2_param => "dummy_tds2_param"
})

result["OrderID"].should == "<ORDER_ID>"
result["Forward"].should == "<FORWARD>"
result["Method"].should == "1"
result["PayTimes"].should == ""
result["Approve"].should == ""
result["TranID"].should == "<TRAN_ID>"
result["TranDate"].should == "<TRAN_DATE>"
result["CheckString"].should == "<CHECK_STRING>"
result["Tds2TransResult"].should == "Y" # Authentication successful
result["Tds2TransResultReason"].should == ""
result["Tds2ChallengeUrl"].should_not be_nil
result["Tds2ChallengeUrl"].should include("/payment/Tds2Challenge")
end
end

describe "#tds2_result" do
it "gets 3DS2.0 authentication result", :vcr do
result = @service.tds2_result({
:access_id => "test_access_7ed782e0e10604b31258e0d69ee3e887",
:access_pass => "test_pass_7be5e8786e2e959d7b48ad708634dc7e"
})

result["OrderID"].should == "<ORDER_ID>"
result["Forward"].should == "<FORWARD>"
result["Method"].should == "1"
result["PayTimes"].should == ""
result["Approve"].should == ""
result["TranID"].should == "<TRAN_ID>"
result["TranDate"].should == "<TRAN_DATE>"
result["CheckString"].should == "<CHECK_STRING>"
result["Tds2TransResult"].should == "Y" # Authentication successful
result["Tds2TransResultReason"].should == ""
end
end

describe "#secure_tran_2" do
it "completes payment after 3DS2.0 challenge verification", :vcr do
result = @service.secure_tran_2({
:access_id => "test_access_7ed782e0e10604b31258e0d69ee3e887",
:access_pass => "test_pass_7be5e8786e2e959d7b48ad708634dc7e"
})

result["OrderID"].should == "<ORDER_ID>"
result["Forward"].should == "<FORWARD>"
result["Method"].should == "1"
result["PayTimes"].should == ""
result["Approve"].should == "<APPROVE>"
result["TranID"].should == "<TRAN_ID>"
result["TranDate"].should == "<TRAN_DATE>"
result["CheckString"].should == "<CHECK_STRING>"
end
end
end