Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mercadopago] Implemented refund #155

Closed
wants to merge 60 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
961dfcb
Added project logo
pkrawat1 Dec 29, 2017
90e8b3e
Added version for inch_ex
oyeb Jan 2, 2018
907723b
test case added for network failure
jyotigautam Jan 2, 2018
609a92c
[ci skip] Get more Open Source Helpers
schneems Jan 2, 2018
41f1de5
Codeclimate fixes (#68)
sivagollapalli Jan 3, 2018
2680289
FIX# code style for large numbers (#67)
sivagollapalli Jan 3, 2018
6e402e9
Stripe gateway minor fixes and docs update (#75)
chandradot99 Jan 4, 2018
ea11367
Using Address and Credit Card struct (#74)
jyotigautam Jan 4, 2018
df44753
Cams : Added error response handling (#65)
gopalshimpi Jan 4, 2018
afdd12e
test authorize net
arjun289 Dec 25, 2017
d5fda24
Introducing the Money protocol (#71)
oyeb Jan 10, 2018
6fafa1d
Update README.md
pkrawat1 Jan 10, 2018
9a4c89b
Adds a super useful mix task: gringotts.new
oyeb Jan 9, 2018
365c3f1
[money-protocol] Expansion: `to_string` and `to_integer` (#86)
oyeb Jan 19, 2018
6d1828f
add mix task for tests, mocks and integration
arjun289 Jan 17, 2018
a135692
[monei] Implements optional/extra params (#79)
oyeb Jan 21, 2018
ce7c6bd
Money integration with ANet and Anet test modification (#82)
arjun289 Jan 21, 2018
db9190b
[ANet] Corrected use of money protocol and examples (#92)
oyeb Jan 25, 2018
5e748e7
[trexle] Adds Money protocol (#84)
jyotigautam Jan 25, 2018
f3c0d58
[CAMS] Adds money protocol (#89)
gopalshimpi Jan 25, 2018
f2796b4
Fix doc example typos, and mock tests (#93)
oyeb Jan 25, 2018
fa1cd11
[mix-task] Fixed arg order in capture (#94)
oyeb Jan 25, 2018
5b15d30
Global Collect payment gateway integration. (#95)
jyotigautam Jan 25, 2018
99850ab
Introduces `Response.t` with docs (#119)
oyeb Feb 6, 2018
1920ced
Removes payment worker.
oyeb Feb 5, 2018
8622ded
Removed offending (now useless) test case
oyeb Feb 5, 2018
6aa6a86
Removed GenServer import. Fixes #8.
oyeb Feb 15, 2018
3768649
Refactored ResponseHandler, for new Response.t
oyeb Feb 9, 2018
e16fe72
Refactored `commit` and corrected avs, cvc result
oyeb Feb 9, 2018
6eef8ef
Correct a few doc examples
oyeb Feb 9, 2018
e3c86ce
Adds changelog, contributing guide and improves mix task (#117)
oyeb Mar 15, 2018
71a5bc3
[monei] Test fixes (#116)
oyeb Mar 15, 2018
cf39d54
Fix gringotts.new Option.parse call. (#125)
oyeb Mar 19, 2018
a9b76db
Adapts Stripe with the money protocol
oyeb Jan 29, 2018
f99f258
Adapted Trexle for new `Response.t`
oyeb Feb 9, 2018
a91deec
[CAMS] Adapt for new Response.t (#120)
oyeb Mar 21, 2018
7bf1857
Format project and migrate to CodeCov (#135)
oyeb Mar 22, 2018
a4082cb
[global-collect] Layout, docs improvements and code refactors (#111)
jyotigautam Mar 30, 2018
a444179
Initial Commit \n Implemented Authorize
subpal Mar 20, 2018
ea9c912
Implemented authorize
subpal Mar 20, 2018
2127fe9
Refined authorize function
subpal Mar 21, 2018
d7d74b9
Implemented authorize
subpal Mar 21, 2018
b776dc9
jgkg
subpal Mar 26, 2018
4a99128
Modification in authorize/3, and implemented capture
subpal Mar 26, 2018
a6b4298
Modification in authorize/3, and implemented capture
subpal Mar 26, 2018
94f5b1c
Modification in authorize/3, and implemented capture
subpal Mar 26, 2018
1d46184
Modification in authorize/3, and implemented capture
subpal Mar 26, 2018
5956d5b
Updated authorize/3
subpal Mar 27, 2018
fd135db
Updated authorize/3
subpal Mar 27, 2018
e7349da
Updated authorize/3
subpal Mar 28, 2018
5eabe34
Updated authorize/3
subpal Mar 31, 2018
b51e7f1
Authorize integration test cases created
subpal Mar 31, 2018
d0277b2
Authorize integration test cases created
subpal Mar 31, 2018
0e159ab
Authorize integration test cases created
subpal Mar 31, 2018
d0bda62
Applied elixer formatter.
subpal Apr 17, 2018
1357aa8
Capture and test cases
subpal Apr 17, 2018
699876f
Added test cases for capture
subpal Apr 17, 2018
3254c54
Implemented purchase
subpal Apr 17, 2018
9d52afa
Implemented void
subpal Apr 17, 2018
96f729c
Implemented Refund
subpal Apr 17, 2018
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
Prev Previous commit
Next Next commit
Adds a super useful mix task: gringotts.new
* Generates a barebones implementation
* Also generates docs dynamically,
  - If no required_keys are supplied when the task is run, the docs do
not contain an empty table.
  - Otherwise, the table and config examples include the keys.
  • Loading branch information
oyeb authored and pkrawat1 committed Jan 12, 2018
commit 9a4c89bbf66e3276e8b22bbe087b3a945acd56b4
97 changes: 97 additions & 0 deletions lib/mix/new.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
defmodule Mix.Tasks.Gringotts.New do
@shortdoc """
Generates a barebones implementation for a gateway.
"""

@moduledoc """
Generates a barebones implementation for a gateway.

It expects the (brand) name of the gateway as argument. This will not
necessarily be the module name, but we recommend the name be capitalized.

mix gringotts.new NAME [-m, --module MODULE] [--url URL]

A barebones implementation of the gateway will be created along with skeleton
mock and integration tests in `lib/gringotts/gateways/`. The command will
prompt for the module name, and other metadata.

## Options

> ***Tip!***
> You can supply the extra arguments to `gringotts.new` to skip (some of) the
> prompts.

* `-m` `--module` - The module name for the Gateway.
* `--url` - The homepage of the gateway.

## Examples

mix gringotts.new foobar

The prompts for this will be:
MODULE = `Foobar`
URL = `https://www.foobar.com`
REQUIRED_KEYS = []
"""

use Mix.Task
import Mix.Generator

@long_msg ~s{
Comma separated list of required configuration keys:
(This can be skipped by hitting `Enter`)
> }

def run(args) do
{key_list, [name], []} =
OptionParser.parse(
args,
switches: [module: :string, url: :string],
aliases: [m: :module]
)

Mix.Shell.IO.info("Generating barebones implementation for #{name}.")
Mix.Shell.IO.info("Hit enter to select the suggestion.")

module_name =
case Keyword.fetch(key_list, :module) do
:error -> prompt_with_suggestion("\nModule name", String.capitalize(name))
{:ok, mod_name} -> mod_name
end

url =
case Keyword.fetch(key_list, :url) do
:error -> prompt_with_suggestion("\nHomepage URL", "https://www.#{String.Casing.downcase(name)}.com")
{:ok, url} -> url
end

required_keys =
case Mix.Shell.IO.prompt(@long_msg) |> String.trim do
"" -> []
keys -> String.split(keys, ",") |> Enum.map(&(String.trim(&1))) |> Enum.map(&(String.to_atom(&1)))
end

bindings = [
gateway: name,
gateway_module: module_name,
gateway_underscore: Macro.underscore(name),
required_config_keys: required_keys,
gateway_url: url
]

if (Mix.Shell.IO.yes? "\nDoes this look good?\n#{inspect(bindings, pretty: true)}\n>") do
gateway = EEx.eval_file("templates/gateway.eex", bindings)
# mock = ""
# integration = ""
create_file("lib/gringotts/gateways/#{bindings[:gateway_underscore]}.ex", gateway)
else
Mix.Shell.IO.info("Doing nothing, bye!")
end
end

defp prompt_with_suggestion(message, suggestion) do
decorated_message = "#{message} [#{suggestion}]"
response = Mix.Shell.IO.prompt(decorated_message) |> String.trim
if response == "", do: suggestion, else: response
end
end
275 changes: 275 additions & 0 deletions templates/gateway.eex
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
defmodule Gringotts.Gateways.<%= gateway_module %> do
@moduledoc """
[<%= gateway %>][home] gateway implementation.

## Instructions!

***This is an example `moduledoc`, and suggests some items that should be
documented in here.***

The quotation boxes like the one below will guide you in writing excellent
documentation for your gateway. All our gateways are documented in this manner
and we aim to keep our docs as consistent with each other as possible.
**Please read them and do as they suggest**. Feel free to add or skip sections
though.

If you'd like to make edits to the template docs, they exist at
`templates/gateway.eex`. We encourage you to make corrections and open a PR
and tag it with the label `template`.

***Actual docs begin below this line!***

--------------------------------------------------------------------------------

> List features that have been implemented, and what "actions" they map to as
> per the <%= gateway %> gateway docs.
> A table suits really well for this.

## Optional or extra parameters

Most `Gringotts` API calls accept an optional `Keyword` list `opts` to supply
optional arguments for transactions with the gateway.

> List all available (ie, those that will be supported by this module) keys, a
> description of their function/role and whether they have been implemented
> and tested.
> A table suits really well for this.

## Registering your <%= gateway %> account at `Gringotts`

Explain how to make an account with the gateway and show how to put the
`required_keys` (like authentication info) to the configuration.
<%= if required_config_keys != [] do %>
> Here's how the secrets map to the required configuration parameters for <%= gateway %>:
>
> | Config parameter | <%= gateway %> secret |
> | ------- | ---- |
<%= for key <- required_config_keys do %>> | `<%= inspect(key) %>` | **<%= Macro.camelize("#{key}") %>** |
<% end %><% end %>
> Your Application config<%= if required_config_keys != [] do %> **must include the `<%= inspect(required_config_keys) %>` field(s)** and<% end %> would look
> something like this:
>
> config :gringotts, Gringotts.Gateways.<%= gateway_module %>,
> adapter: Gringotts.Gateways.<%= gateway_module %><%= if required_config_keys != [] do %>,<% end %>
<%= for key <- required_config_keys do %>> <%= "#{key}" %>: "your_secret_<%= "#{key}" %>"
<% end %>

## Scope of this module

> It's unlikely that your first iteration will support all features of the
> gateway, so list down those items that are missing.

## Supported currencies and countries

> It's enough if you just add a link to the gateway's docs or FAQ that provide
> info about this.

## Following the examples

1. First, set up a sample application and configure it to work with MONEI.
- You could do that from scratch by following our [Getting Started][gs] guide.
- To save you time, we recommend [cloning our example
repo][example] that gives you a pre-configured sample app ready-to-go.
+ You could use the same config or update it the with your "secrets"
as described [above](#module-registering-your-monei-account-at-<%=
gateway %>).

2. Run an `iex` session with `iex -S mix` and add some variable bindings and
aliases to it (to save some time):
```
iex> alias Gringotts.{Response, CreditCard, Gateways.<%= gateway_module %>}
iex> card = %CreditCard{first_name: "Jo",
last_name: "Doe",
number: "4200000000000000",
year: 2099, month: 12,
verification_code: "123", brand: "VISA"}
```

> Add any other frequently used bindings up here.

We'll be using these in the examples below.

[gs]: https://github.com/aviabird/gringotts/wiki/
[home]: <%= gateway_url %>
[example]: https://github.com/aviabird/gringotts_example
"""

# The Base module has the (abstract) public API, and some utility
# implementations.
use Gringotts.Gateways.Base

# The Adapter module provides the `validate_config/1`
# Add the keys that must be present in the Application config in the
# `required_config` list
use Gringotts.Adapter, required_config: <%= inspect(required_config_keys) %>

import Poison, only: [decode: 1]

alias Gringotts.{Money,
CreditCard,
Response}

@doc """
Performs a (pre) Authorize operation.

The authorization validates the `card` details with the banking network,
places a hold on the transaction `amount` in the customer’s issuing bank.

> ** You could perhaps:**
> 1. describe what are the important fields in the Response struct
> 2. mention what a merchant can do with these important fields (ex:
> `capture/3`, etc.)

## Note

> If there's anything noteworthy about this operation, it comes here.

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec authorize(Money.t(), CreditCard.t(), keyword) :: {:ok | :error, Response}
def authorize(amount, card = %CreditCard{}, opts) do
# commit(args, ...)
end

@doc """
Captures a pre-authorized `amount`.

`amount` is transferred to the merchant account by <%= gateway %> used in the
pre-authorization referenced by `payment_id`.

## Note

> If there's anything noteworthy about this operation, it comes here.
> For example, does the gateway support partial, multiple captures?

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec capture(Money.t, String.t(), keyword) :: {:ok | :error, Response}
def capture(amount, payment_id, opts) do
# commit(args, ...)
end

@doc """
Transfers `amount` from the customer to the merchant.

<%= gateway %> attempts to process a purchase on behalf of the customer, by
debiting `amount` from the customer's account by charging the customer's
`card`.

## Note

> If there's anything noteworthy about this operation, it comes here.

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec purchase(Money.t, CreditCard.t(), keyword) :: {:ok | :error, Response}
def purchase(amount, card = %CreditCard{}, opts) do
# commit(args, ...)
end

@doc """
Voids the referenced payment.

This method attempts a reversal of a previous transaction referenced by
`payment_id`.

> As a consequence, the customer will never see any booking on his statement.

## Note

> Which transactions can be voided?
> Is there a limited time window within which a void can be perfomed?

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec void(String.t(), keyword) :: {:ok | :error, Response}
def void(payment_id, opts) do
# commit(args, ...)
end

@doc """
Refunds the `amount` to the customer's account with reference to a prior transfer.

> Refunds are allowed on which kinds of "prior" transactions?

## Note

> The end customer will usually see two bookings/records on his statement. Is
> that true for <%= gateway %>?
> Is there a limited time window within which a void can be perfomed?

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec refund(Money.t, String.t(), keyword) :: {:ok | :error, Response}
def refund(amount, <<payment_id::bytes-size(32)>>, opts) do
# commit(args, ...)
end

@doc """
Stores the payment-source data for later use.

> This usually enable "One Click" and/or "Recurring Payments"

## Note

> If there's anything noteworthy about this operation, it comes here.

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec store(CreditCard.t(), keyword) :: {:ok | :error, Response}
def store(%CreditCard{} = card, opts) do
# commit(args, ...)
end

@doc """
Removes card or payment info that was previously `store/2`d

Deletes previously stored payment-source data.

## Note

> If there's anything noteworthy about this operation, it comes here.

## Example

> A barebones example using the bindings you've suggested in the `moduledoc`.
"""
@spec unstore(String.t(), keyword) :: {:ok | :error, Response}
def unstore(<<registrationId::bytes-size(32)>>, opts) do
# commit(args, ...)
end

###############################################################################
# PRIVATE METHODS #
###############################################################################

# Makes the request to <%= gateway %>'s network.
# For consistency with other gateway implementations, make your (final)
# network request in here, and parse it using another private method called
# `respond`.
@spec commit(_) :: {:ok | :error, Response}
defp commit(_) do
# resp = HTTPoison.request(args, ...)
# respond(resp, ...)
end

# Parses <%= gateway %>'s response and returns a `Gringotts.Response` struct
# in a `:ok`, `:error` tuple.
@spec respond(term) :: {:ok | :error, Response}
defp respond(<%= gateway_underscore %>_response)
defp respond({:ok, %{status_code: 200, body: body}}), do: "something"
defp respond({:ok, %{status_code: status_code, body: body}}), do: "something"
defp respond({:error, %HTTPoison.Error{} = error}), do: "something"
end