From ff6b364d7444ff62dbbb73b7f1bc25d91797e3ca Mon Sep 17 00:00:00 2001 From: Nino Date: Wed, 28 Mar 2018 17:34:14 +0530 Subject: [PATCH 1/6] Implemented `capture/3` Captures a pre-authorized transcation from the customer. Successful request returns a charge object that was captured. It takes payment_id, amount and opts as arguments. --- lib/gringotts/gateways/securion_pay.ex | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/gringotts/gateways/securion_pay.ex b/lib/gringotts/gateways/securion_pay.ex index 1aab1ea4..d29a8fca 100644 --- a/lib/gringotts/gateways/securion_pay.ex +++ b/lib/gringotts/gateways/securion_pay.ex @@ -94,6 +94,30 @@ defmodule Gringotts.Gateways.SecurionPay do commit(params, "charges", opts) end + @doc """ + Captures a pre-authorized transcation from the customer. + + The amount present in the pre-authorization referenced by `payment_id` is transferred to the + merchant account by SecurionPay. + + + Successful request returns a charge object that was captured. + + ## Note + > SecurionPay does not support partial captures. So there is no need of amount in capture. + + ## Example + iex> opts = [config: [secret_key: "c2tfdGVzdF82cGZBYTI3aDhvOUUxanRJZWhaQkE3dkE6"]] + iex> amount = 100 + iex> payment_id = "char_WCglhaf1Gn9slpXWYBkZqbGK" + iex> result = Gringotts.Gateways.SecurionPay.capture(payment_id, amount, opts) + + """ + @spec capture(String.t(), Money.t(), keyword) :: {:ok | :error, Response} + def capture(payment_id, _amount, opts) do + commit([], "charges/#{payment_id}/capture", opts) + end + ########################################################################## # PRIVATE METHODS # ########################################################################## From 3729e2bfba27a0460e74188cf762db59c9b058b1 Mon Sep 17 00:00:00 2001 From: Nino Date: Wed, 28 Mar 2018 18:07:14 +0530 Subject: [PATCH 2/6] Added integration tests for `capture/3` It has been tested for two test cases *With valid authorizaton id *With invalid payment id --- .../gateways/securion_pay_test.exs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/integration/gateways/securion_pay_test.exs b/test/integration/gateways/securion_pay_test.exs index 239caffa..aa8cd808 100644 --- a/test/integration/gateways/securion_pay_test.exs +++ b/test/integration/gateways/securion_pay_test.exs @@ -40,6 +40,7 @@ defmodule Gringotts.Integration.Gateways.SecurionPayTest do @bad_opts [config: [secret_key: "pr_test_tXHm9qV9qV9bjIRHcQr9PLPa"]] @card_id "card_wVuO1a5BGM12UV10FwpkK9YW" + @bad_charge_id "char_wVuO1a5BGM12UV10FwpkK9YW" describe "[authorize]" do test "with CreditCard" do @@ -77,4 +78,25 @@ defmodule Gringotts.Integration.Gateways.SecurionPayTest do end end end + + describe "[capture]" do + test "with_authorized_payment_id" do + use_cassette "securion_pay/capture_after_authorization" do + {:ok, auth_response} = Gateway.authorize(@amount, @good_card, @opts) + assert {:ok, capt_response} = Gateway.capture(auth_response.id, @amount, @opts) + assert capt_response.success == true + assert capt_response.status_code == 200 + end + end + + test "with_invalid_payment_id" do + use_cassette "securion_pay/capture_with_invalid_payment_id" do + assert {:error, response} = Gateway.capture(@bad_charge_id, @amount, @opts) + assert response.success == false + refute response.status_code == 200 + assert response.message == "invalid_request" + assert response.reason == "Charge '#{@bad_charge_id}' does not exist" + end + end + end end From 21f37f2ff7ad58bcb23ff34a807660bbd4a4b398 Mon Sep 17 00:00:00 2001 From: Nino Date: Thu, 29 Mar 2018 01:57:14 +0530 Subject: [PATCH 3/6] Minor changes in docs --- lib/gringotts/gateways/securion_pay.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gringotts/gateways/securion_pay.ex b/lib/gringotts/gateways/securion_pay.ex index d29a8fca..6ce8c963 100644 --- a/lib/gringotts/gateways/securion_pay.ex +++ b/lib/gringotts/gateways/securion_pay.ex @@ -104,7 +104,7 @@ defmodule Gringotts.Gateways.SecurionPay do Successful request returns a charge object that was captured. ## Note - > SecurionPay does not support partial captures. So there is no need of amount in capture. + SecurionPay does not support partial captures. So there is no need of amount in capture. ## Example iex> opts = [config: [secret_key: "c2tfdGVzdF82cGZBYTI3aDhvOUUxanRJZWhaQkE3dkE6"]] From b3ee48c787647976d95ba01657eb484236425184 Mon Sep 17 00:00:00 2001 From: Nino Date: Thu, 29 Mar 2018 18:29:13 +0530 Subject: [PATCH 4/6] Added dummy charge ID Removed the secret key Imroved docs and added nil in amount --- lib/gringotts/gateways/securion_pay.ex | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/gringotts/gateways/securion_pay.ex b/lib/gringotts/gateways/securion_pay.ex index 6ce8c963..04e6d38f 100644 --- a/lib/gringotts/gateways/securion_pay.ex +++ b/lib/gringotts/gateways/securion_pay.ex @@ -78,7 +78,7 @@ defmodule Gringotts.Gateways.SecurionPay do ### With a `card_token` and `customer_token` iex> amount = Money.new(20, :USD) iex> opts = [customer_id: "cust_9999999999999999999999999"] - iex> card = "card_LqTT5tC10BQzDbwWJhFWXDoP" + iex> card = "card_999999999999999" iex> result = Gringotts.Gateways.SecurionPay.authorize(amount, card, opts) """ @@ -97,19 +97,17 @@ defmodule Gringotts.Gateways.SecurionPay do @doc """ Captures a pre-authorized transcation from the customer. - The amount present in the pre-authorization referenced by `payment_id` is transferred to the - merchant account by SecurionPay. - + The complete amount present in the pre-authorization referenced by `payment_id` is transferred + to the merchant account by SecurionPay. The `amount` argument is ignored. Successful request returns a charge object that was captured. ## Note - SecurionPay does not support partial captures. So there is no need of amount in capture. + Because SecurionPay **does not support partial captures**, please pass `nil` in `amount` ## Example - iex> opts = [config: [secret_key: "c2tfdGVzdF82cGZBYTI3aDhvOUUxanRJZWhaQkE3dkE6"]] - iex> amount = 100 - iex> payment_id = "char_WCglhaf1Gn9slpXWYBkZqbGK" + iex> amount = nil + iex> payment_id = "char_9999999999999999" iex> result = Gringotts.Gateways.SecurionPay.capture(payment_id, amount, opts) """ From 8b440c4c7650a6f3c1f3449ee28855dfe3d51235 Mon Sep 17 00:00:00 2001 From: Nino Date: Wed, 25 Apr 2018 17:00:38 +0530 Subject: [PATCH 5/6] Implemented store/2 and its test cases. --- lib/gringotts/gateways/securion_pay.ex | 81 ++++++++++++++++++- .../gateways/securion_pay_test.exs | 35 +++++++- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/lib/gringotts/gateways/securion_pay.ex b/lib/gringotts/gateways/securion_pay.ex index 04e6d38f..d89b21f4 100644 --- a/lib/gringotts/gateways/securion_pay.ex +++ b/lib/gringotts/gateways/securion_pay.ex @@ -116,9 +116,84 @@ defmodule Gringotts.Gateways.SecurionPay do commit([], "charges/#{payment_id}/capture", opts) end - ########################################################################## - # PRIVATE METHODS # - ########################################################################## + @doc """ + Stores the customer's card details for later use. + + SecurionPay can store the payment-source details, for example card details + which can be used to effectively process _One-Click_ payments, and returns a + card id which can be used for `purchase/3`, `authorize/3` and `unstore/2`. + + The card id is available in the `Response.id` field. + + It is **mandatory** to pass either `:email` or `:customer_id` in the opts field. + + Here `store/2` is implemented in two ways: + * `:customer_id` is available in the opts field + * `:email` is available in the opts field(`:customer_id` not available) + + ## Example + ### With the `:customer_id` available in the opts field + iex> opts = [config: [secret_key: "c2tfdGVzdF9GZjJKcHE1OXNTV1Q3cW1JOWF0aWk1elI6"], customer_id: "cust_zpYEBK396q3rvIBZYc3PIDwT"] + iex> card = %CreditCard{ + first_name: "Harry", + last_name: "Potter", + number: "4200000000000000", + year: 2027, + month: 12, + verification_code: "123", + brand: "VISA" + } + iex> result = Gringotts.Gateways.SecurionPay.store(card, opts) + ## Example + ### With `:email` in the opts field + iex> opts = [config: [secret_key: "c2tfdGVzdF9GZjJKcHE1OXNTV1Q3cW1JOWF0aWk1elI6"], email: "customer@example.com"] + iex> card = %CreditCard{ + first_name: "Harry", + last_name: "Potter", + number: "4200000000000000", + year: 2027, + month: 12, + verification_code: "123", + brand: "VISA" + } + iex> result = Gringotts.Gateways.SecurionPay.store(card, opts) + + """ + @spec store(CreditCard.t(), Keyword.t()) :: {:ok | :error, Response.t()} + def store(card, opts) do + if Keyword.has_key?(opts, :customer_id) do + card |> create_card(opts) + else + card |> create_customer(opts) + end + end + + ############################################################################### + # PRIVATE METHODS # + ############################################################################### + + # Creates the parameters for authorise function when + # card_id and customerId is provided. + + # @spec create_card() + defp create_card(card, opts) do + [ + {"number", card.number}, + {"expMonth", card.month}, + {"expYear", card.year}, + {"cvc", card.verification_code} + ] + |> commit("customers/#{opts[:customer_id]}/cards", opts) + end + + # @spec create_customer() + defp create_customer(card, opts) do + {_, res} = + [{"email", opts[:email]}] + |> commit("customers", opts) + + create_card(card, opts ++ [customer_id: res.id]) + end # Creates the common parameters for authorize function @spec common_params(String.t(), String.t()) :: keyword diff --git a/test/integration/gateways/securion_pay_test.exs b/test/integration/gateways/securion_pay_test.exs index aa8cd808..f4a9bc73 100644 --- a/test/integration/gateways/securion_pay_test.exs +++ b/test/integration/gateways/securion_pay_test.exs @@ -8,7 +8,7 @@ defmodule Gringotts.Integration.Gateways.SecurionPayTest do alias Gringotts.Gateways.SecurionPay, as: Gateway - @moduletag integration: true + @moduletag integration: false @amount Money.new(42, :EUR) @@ -37,6 +37,11 @@ defmodule Gringotts.Integration.Gateways.SecurionPayTest do customer_id: "cust_NxPh6PUq9KWUW8tZKkUnV2Nt" ] + @email_opts [ + config: [secret_key: "pr_test_tXHm9qV9qV9bjIRHcQr9PLPa"], + email: "customer@example.com" + ] + @bad_opts [config: [secret_key: "pr_test_tXHm9qV9qV9bjIRHcQr9PLPa"]] @card_id "card_wVuO1a5BGM12UV10FwpkK9YW" @@ -99,4 +104,32 @@ defmodule Gringotts.Integration.Gateways.SecurionPayTest do end end end + + describe "[store]" do + test "with_customer_id" do + use_cassette "securion_pay/with_customer_id" do + {:ok, response} = Gateway.store(@good_card, @opts) + assert response.success == true + assert response.status_code == 200 + end + end + + test "with expired CreditCard" do + use_cassette "securion_pay/store_with_expired_card" do + assert {:error, response} = Gateway.store(@bad_card, @opts) + assert response.success == false + refute response.status_code == 200 + assert response.message == "card_error" + assert response.reason == "The card has expired." + end + end + + test "without_customer_id" do + use_cassette "securion_pay/without_customer_id" do + {:ok, response} = Gateway.store(@good_card, @email_opts) + assert response.success == true + assert response.status_code == 200 + end + end + end end From fdd705e3f85669f56656c1abaaf82b89ad9ce36c Mon Sep 17 00:00:00 2001 From: Nino Date: Wed, 25 Apr 2018 17:08:18 +0530 Subject: [PATCH 6/6] Implemented store/2 with test cases . Changed integration : false to true --- test/integration/gateways/securion_pay_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/gateways/securion_pay_test.exs b/test/integration/gateways/securion_pay_test.exs index f4a9bc73..9b1a560b 100644 --- a/test/integration/gateways/securion_pay_test.exs +++ b/test/integration/gateways/securion_pay_test.exs @@ -8,7 +8,7 @@ defmodule Gringotts.Integration.Gateways.SecurionPayTest do alias Gringotts.Gateways.SecurionPay, as: Gateway - @moduletag integration: false + @moduletag integration: true @amount Money.new(42, :EUR)