diff --git a/lib/gringotts/gateways/securion_pay.ex b/lib/gringotts/gateways/securion_pay.ex index 1aab1ea4..d89b21f4 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) """ @@ -94,9 +94,106 @@ defmodule Gringotts.Gateways.SecurionPay do commit(params, "charges", opts) end - ########################################################################## - # PRIVATE METHODS # - ########################################################################## + @doc """ + Captures a pre-authorized transcation from the customer. + + 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 + Because SecurionPay **does not support partial captures**, please pass `nil` in `amount` + + ## Example + iex> amount = nil + iex> payment_id = "char_9999999999999999" + 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 + + @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 239caffa..9b1a560b 100644 --- a/test/integration/gateways/securion_pay_test.exs +++ b/test/integration/gateways/securion_pay_test.exs @@ -37,9 +37,15 @@ 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" + @bad_charge_id "char_wVuO1a5BGM12UV10FwpkK9YW" describe "[authorize]" do test "with CreditCard" do @@ -77,4 +83,53 @@ 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 + + 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