diff --git a/README.md b/README.md
index 0f05aef..14e8532 100644
--- a/README.md
+++ b/README.md
@@ -345,6 +345,11 @@ else
end
```
+### Epsilon Link Payment Void Transaction
+```ruby
+gateway.void('order_number')
+```
+
### Error handling
If epsilon server returns status excepted 200, `#purchase` method raise `ActiveMerchant::ResponseError`.
diff --git a/lib/active_merchant/billing/gateways/epsilon_link_payment.rb b/lib/active_merchant/billing/gateways/epsilon_link_payment.rb
index 013b352..d58a266 100644
--- a/lib/active_merchant/billing/gateways/epsilon_link_payment.rb
+++ b/lib/active_merchant/billing/gateways/epsilon_link_payment.rb
@@ -37,6 +37,15 @@ def purchase(amount, detail = {})
commit('receive_order3.cgi', params, RESPONSE_KEYS)
end
+
+ def void(order_number)
+ params = {
+ contract_code: self.contract_code,
+ order_number: order_number
+ }
+
+ commit('cancel_payment.cgi', params)
+ end
end
end
end
diff --git a/test/fixtures/vcr_cassettes/epsilon_link_type_purchase_fail.yml b/test/fixtures/vcr_cassettes/epsilon_link_type_purchase_fail.yml
new file mode 100644
index 0000000..712d5c2
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/epsilon_link_type_purchase_fail.yml
@@ -0,0 +1,43 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://beta.epsilon.jp/cgi-bin/order/receive_order3.cgi
+ body:
+ encoding: UTF-8
+ string: contract_code=[CONTRACT_CODE]&user_id=U1594794779&user_name=%E5%B1%B1%E7%94%B0+%E5%A4%AA%E9%83%8E&user_mail_add=yamada-taro%40example.com&item_code=ITEM001&item_name=Greate+Product&order_number=O59578602&st_code=invalid_id&mission_code=1&item_price=10000&process_code=1&xml=1&delivery_code=99&consignee_postal=1000001&consignee_name=%E3%82%A4%E3%83%97%E3%82%B7%E3%83%AD%E3%83%B3%E3%82%BF%E3%83%AD%E3%82%A6&consignee_address=%E6%9D%B1%E4%BA%AC%E9%83%BD%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E5%8D%83%E4%BB%A3%E7%94%B01%E7%95%AA1%E5%8F%B7&consignee_tel=0312345678&orderer_postal=1000001&orderer_name=YAMADA+Taro&orderer_address=%E6%9D%B1%E4%BA%AC%E9%83%BD%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E5%8D%83%E4%BB%A3%E7%94%B01%E7%95%AA1%E5%8F%B7&orderer_tel=0312345678&memo1=memo1&memo2=memo2
+ headers:
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Connection:
+ - close
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Wed, 15 Jul 2020 06:32:59 GMT
+ Server:
+ - Apache
+ Connection:
+ - close
+ Transfer-Encoding:
+ - chunked
+ Content-Type:
+ - text/xml
+ body:
+ encoding: UTF-8
+ string: "\r\n \r\n
+ \ \r\n \r\n \r\n \r\n \r\n
+ \ \r\n"
+ recorded_at: Wed, 15 Jul 2020 06:33:00 GMT
+recorded_with: VCR 6.0.0
diff --git a/test/fixtures/vcr_cassettes/epsilon_link_type_purchase_successfull.yml b/test/fixtures/vcr_cassettes/epsilon_link_type_purchase_successfull.yml
new file mode 100644
index 0000000..310e7f4
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/epsilon_link_type_purchase_successfull.yml
@@ -0,0 +1,44 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://beta.epsilon.jp/cgi-bin/order/receive_order3.cgi
+ body:
+ encoding: UTF-8
+ string: contract_code=[CONTRACT_CODE]&user_id=U1594794223&user_name=%E5%B1%B1%E7%94%B0+%E5%A4%AA%E9%83%8E&user_mail_add=yamada-taro%40example.com&item_code=ITEM001&item_name=Greate+Product&order_number=O43585140&st_code=00000-0000-01000-00000-00000-00000-00000&mission_code=1&item_price=10000&process_code=1&xml=1&delivery_code=99&consignee_postal=1000001&consignee_name=%E3%82%A4%E3%83%97%E3%82%B7%E3%83%AD%E3%83%B3%E3%82%BF%E3%83%AD%E3%82%A6&consignee_address=%E6%9D%B1%E4%BA%AC%E9%83%BD%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E5%8D%83%E4%BB%A3%E7%94%B01%E7%95%AA1%E5%8F%B7&consignee_tel=0312345678&orderer_postal=1000001&orderer_name=YAMADA+Taro&orderer_address=%E6%9D%B1%E4%BA%AC%E9%83%BD%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E5%8D%83%E4%BB%A3%E7%94%B01%E7%95%AA1%E5%8F%B7&orderer_tel=0312345678&memo1=memo1&memo2=memo2
+ headers:
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Connection:
+ - close
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Wed, 15 Jul 2020 06:23:43 GMT
+ Server:
+ - Apache
+ Connection:
+ - close
+ Transfer-Encoding:
+ - chunked
+ Content-Type:
+ - text/xml
+ body:
+ encoding: UTF-8
+ string: |
+
+
+
+
+
+ recorded_at: Wed, 15 Jul 2020 06:23:44 GMT
+recorded_with: VCR 6.0.0
diff --git a/test/fixtures/vcr_cassettes/epsilon_link_type_void_fail.yml b/test/fixtures/vcr_cassettes/epsilon_link_type_void_fail.yml
new file mode 100644
index 0000000..09357c1
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/epsilon_link_type_void_fail.yml
@@ -0,0 +1,45 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://beta.epsilon.jp/cgi-bin/order/cancel_payment.cgi
+ body:
+ encoding: UTF-8
+ string: contract_code=&order_number=invalid_order_number
+ headers:
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Connection:
+ - close
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Mon, 20 Jul 2020 02:48:28 GMT
+ Server:
+ - Apache
+ Connection:
+ - close
+ Transfer-Encoding:
+ - chunked
+ Content-Type:
+ - text/xml; charset=CP932
+ body:
+ encoding: UTF-8
+ string: |-
+
+
+
+
+
+
+ recorded_at: Mon, 20 Jul 2020 02:48:29 GMT
+recorded_with: VCR 6.0.0
diff --git a/test/fixtures/vcr_cassettes/epsilon_link_type_void_successfull.yml b/test/fixtures/vcr_cassettes/epsilon_link_type_void_successfull.yml
new file mode 100644
index 0000000..e29e23c
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/epsilon_link_type_void_successfull.yml
@@ -0,0 +1,45 @@
+---
+http_interactions:
+- request:
+ method: post
+ uri: https://beta.epsilon.jp/cgi-bin/order/cancel_payment.cgi
+ body:
+ encoding: UTF-8
+ string: contract_code=[CONTRACT_CODE]&order_number=595213151
+ headers:
+ Content-Type:
+ - application/x-www-form-urlencoded
+ Connection:
+ - close
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Mon, 20 Jul 2020 02:56:42 GMT
+ Server:
+ - Apache
+ Connection:
+ - close
+ Transfer-Encoding:
+ - chunked
+ Content-Type:
+ - text/xml; charset=CP932
+ body:
+ encoding: UTF-8
+ string: |-
+
+
+
+
+
+
+ recorded_at: Mon, 20 Jul 2020 02:56:43 GMT
+recorded_with: VCR 6.0.0
diff --git a/test/remote/gateways/remote_epsilon_link_payment_test.rb b/test/remote/gateways/remote_epsilon_link_payment_test.rb
new file mode 100644
index 0000000..510da15
--- /dev/null
+++ b/test/remote/gateways/remote_epsilon_link_payment_test.rb
@@ -0,0 +1,46 @@
+require 'test_helper'
+class RemoteEpsilonLinkPaymentTest < MiniTest::Test
+ include SamplePaymentMethods
+
+ def gateway
+ @gateway ||= ActiveMerchant::Billing::EpsilonLinkPaymentGateway.new
+ end
+
+ def test_epsilon_link_type_purchase_successfull
+ VCR.use_cassette(:epsilon_link_type_purchase_successfull) do
+ response = gateway.purchase(10000, valid_epsilon_link_type_purchase_detail)
+
+ assert_equal true, response.success?
+ assert_equal true, !response.params['redirect'].empty?
+ end
+ end
+
+ def test_epsilon_link_type_purchase_fail
+ VCR.use_cassette(:epsilon_link_type_purchase_fail) do
+ response = gateway.purchase(10000, invalid_epsilon_link_type_purchase_detail)
+
+ assert_equal false, response.success?
+ assert_equal true, response.params["error_detail"].valid_encoding?
+ end
+ end
+
+ def test_epsilon_link_type_void_successfull
+ VCR.use_cassette(:epsilon_link_type_void_successfull) do
+ # あらかじめ課金済ステータスの受注がイプシロン側にないと取り消しができないため、課金済の受注をイプシロン側で作成しておいた。
+ # ここでは void の引数として作成済の受注のorder_numberを渡している。
+ # VCRのキャッシュを作成し直す場合は変更しないとエラーとなる。
+ response = gateway.void('595213151')
+
+ assert_equal true, response.success?
+ end
+ end
+
+ def test_epsilon_link_type_void_fail
+ VCR.use_cassette(:epsilon_link_type_void_fail) do
+ response = gateway.void('invalid_order_number')
+
+ assert_equal false, response.success?
+ assert_equal true, response.params["error_detail"].valid_encoding?
+ end
+ end
+end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index c2445fd..405fb4a 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -230,6 +230,52 @@ def gmo_after_purchase_detail
}
end
+ def valid_epsilon_link_type_purchase_detail
+ now = Time.now
+ {
+ user_id: "U#{Time.now.to_i}",
+ user_name: '山田 太郎',
+ user_email: 'yamada-taro@example.com',
+ item_code: 'ITEM001',
+ item_name: 'Greate Product',
+ order_number: "O#{now.sec}#{now.usec}",
+ st_code: '00000-0000-01000-00000-00000-00000-00000',
+ memo1: 'memo1',
+ memo2: 'memo2',
+ consignee_postal: '1000001',
+ consignee_name: 'イプシロンタロウ',
+ consignee_address: '東京都千代田区千代田1番1号',
+ consignee_tel: '0312345678',
+ orderer_postal: '1000001',
+ orderer_name: 'YAMADA Taro',
+ orderer_address: '東京都千代田区千代田1番1号',
+ orderer_tel: '0312345678',
+ }
+ end
+
+ def invalid_epsilon_link_type_purchase_detail
+ now = Time.now
+ {
+ user_id: "U#{Time.now.to_i}",
+ user_name: '山田 太郎',
+ user_email: 'yamada-taro@example.com',
+ item_code: 'ITEM001',
+ item_name: 'Greate Product',
+ order_number: "O#{now.sec}#{now.usec}",
+ st_code: 'invalid_id',
+ memo1: 'memo1',
+ memo2: 'memo2',
+ consignee_postal: '1000001',
+ consignee_name: 'イプシロンタロウ',
+ consignee_address: '東京都千代田区千代田1番1号',
+ consignee_tel: '0312345678',
+ orderer_postal: '1000001',
+ orderer_name: 'YAMADA Taro',
+ orderer_address: '東京都千代田区千代田1番1号',
+ orderer_tel: '0312345678',
+ }
+ end
+
def fixture_xml(filename, parse: true)
xml = File.read("test/fixtures/#{filename}")
parse ? Nokogiri.parse(xml.sub('x-sjis-cp932', 'CP932')) : xml