Skip to content

Commit

Permalink
General CRUD
Browse files Browse the repository at this point in the history
- Add basic CRUD.
  • Loading branch information
thelastinuit committed Sep 23, 2021
1 parent b7d8757 commit 570838e
Show file tree
Hide file tree
Showing 30 changed files with 448 additions and 66 deletions.
5 changes: 2 additions & 3 deletions .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
excluded: [
~r"/_build/",
~r"/deps/",
~r"/node_modules/",
~r"/node_modules/"
]
},
#
Expand Down Expand Up @@ -87,8 +87,7 @@
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength,
[priority: :low, max_length: 120]},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, false},
{Credo.Check.Readability.ModuleNames, []},
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
elixir: [1.11]
otp: [23.2]
elixir: [1.12]
otp: [24]
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.6.0
Expand Down Expand Up @@ -60,8 +60,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
elixir: [1.11]
otp: [23.2]
elixir: [1.12]
otp: [24]
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.6.0
Expand Down Expand Up @@ -100,8 +100,8 @@ jobs:
strategy:
fail-fast: false
matrix:
elixir: [1.11]
otp: [23.2]
elixir: [1.12]
otp: [24]
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.6.0
Expand Down Expand Up @@ -133,4 +133,8 @@ jobs:
- name: Run test
env:
MIX_ENV: test
FACTURAPI_USER_KEY: fakeuserkey
FACTURAPI_VENTUP_ORGANIZATION_API_LIVE_KEY: fakeapilivekey
FACTURAPI_VENTUP_ORGANIZATION_API_TEST_KEY: faketestkey
FACTURAPI_VENTUP_ORGANIZATION_ID: fakeorganizationid
run: mix test --trace --slowest 10
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ clean:
format:
mix format

force-format:
find test -name '*.ex' -o -name '*.exs' | mix format --check-formatted || mix format
find lib -name '*.ex' -o -name '*.exs' | mix format --check-formatted || mix format

precommit:
pre-commit run --all-files

gcdeps:
mix deps.get && mix deps.compile

test:
MIX_ENV=test mix test --trace --max-failures 1
t:
MIX_ENV=test mix test --trace --max-failures 1 --cover

test-watcher:
MIX_ENV=test mix test.watch
Expand Down
49 changes: 42 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# ExFacturapi

**TODO: Add description**
ExFacturAPI is a library to access to the FacturAPI API.

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `ex_facturapi` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
Expand All @@ -15,7 +12,45 @@ def deps do
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/ex_facturapi](https://hexdocs.pm/ex_facturapi).
## Usage Examples

```elixir

## List all organizations

iex> ExFacturapi.Organizations.list()

## Retrieve an organization

iex> ExFacturapi.Organizations.retrieve("organization-id")

## Create an organization

iex> ExFacturapi.Organizations.create(%{name: "skynet"})

## Get Organization API keys

iex> ExFacturapi.Organizations.api_keys("organization-id")

## Update Organization fiscal information

iex> ExFacturapi.Organizations.legal("organization-id",
%{
name: "SkyNet",
legal_name: "Skynet Inc.",
tax_system: "601",
website: "https://sky.net",
phone: "555-5555",
address: %{
exterior: "10-b",
interior: "200A",
zip: "12224",
street: "Bearoso st",
neighborhood: "Palm Spring",
city: "Los Angeles",
municipality: "L.A.",
state: "CA",
country: "USA"
}
})
```
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use Mix.Config
21 changes: 0 additions & 21 deletions coveralls.json

This file was deleted.

124 changes: 114 additions & 10 deletions lib/ex_facturapi.ex
Original file line number Diff line number Diff line change
@@ -1,18 +1,122 @@
defmodule ExFacturapi do
@moduledoc """
Documentation for `ExFacturapi`.
@default_api_endpoint "https://www.facturapi.io/v1/"
@default_http_client HTTPoison
@client_version Mix.Project.config()[:version]

alias ExFacturapi.{
APIConnectionError,
APIError,
AuthenticationError,
InvalidRequestError,
RateLimitError
}

@missing_secret_key_error_message """
Missing Keys, please set them up
"""

@doc """
Hello world.
@spec version() :: String.t()
def version do
@client_version
end

## Examples
@spec request(atom(), String.t(), map()) :: map()
def request(action, endpoint, data) when action in [:get, :post, :put, :delete] do
action
|> http_client().request(request_url(endpoint, data), "", create_headers())
|> handle_response
end

iex> ExFacturapi.hello()
:world
defp http_client do
Application.get_env(:facturapi, :http_client) ||
@default_http_client
end

"""
def hello do
:world
defp get_api_endpoint do
System.get_env("FACTURAPI_ENDPOINT") ||
Application.get_env(:facturapi, :endpoint) ||
@default_api_endpoint
end

defp request_url(endpoint) do
Path.join(get_api_endpoint(), endpoint)
end

defp request_url(endpoint, []) do
Path.join(get_api_endpoint(), endpoint)
end

defp request_url(endpoint, data) do
base_url = request_url(endpoint)
query_params = ExFacturapi.Utils.encode_data(data)
"#{base_url}?#{query_params}"
end

defp create_headers do
[
{"Authorization", "Basic #{Base.encode64(get_api_key() <> ":")}"},
{"Content-Type", "application/json"}
]
end

defp get_api_key do
System.get_env("FACTURAPI_USER_KEY") ||
Application.get_env(:facturapi, :user_key) ||
raise AuthenticationError, message: @missing_secret_key_error_message
end

defp get_api_live_key do
System.get_env("FACTURAPI_LIVE_KEY") ||
Application.get_env(:facturapi, :live_key) ||
raise AuthenticationError, message: @missing_secret_key_error_message
end

defp get_api_test_key do
System.get_env("FACTURAPI_TEST_KEY") ||
Application.get_env(:facturapi, :test_key) ||
raise AuthenticationError, message: @missing_secret_key_error_message
end

defp get_organization_id do
System.get_env("FACTURAPI_ORGANIZATION_ID") ||
Application.get_env(:facturapi, :organization_id) ||
raise AuthenticationError, message: @missing_secret_key_error_message
end

defp handle_response({:ok, %{body: body, status_code: 200}}) do
{:ok, process_response_body(body)}
end

defp handle_response({:ok, %{body: body, status_code: code}}) do
%{"message" => message} =
error =
body
|> process_response_body
|> Map.fetch!("error")

error_struct =
case code do
code when code in [400, 404] ->
%InvalidRequestError{message: message, param: error["param"]}

401 ->
%AuthenticationError{message: message}

429 ->
%RateLimitError{message: message}

_ ->
%APIError{message: message}
end

{:error, error_struct}
end

defp handle_response({:error, %HTTPoison.Error{reason: reason}}) do
%APIConnectionError{message: "Network Error: #{reason}"}
end

defp process_response_body(body) do
Poison.decode!(body)
end
end
43 changes: 43 additions & 0 deletions lib/ex_facturapi/api.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
defmodule ExFacturapi.API do
defmacro __using__(opts) do
quote do
if :create in unquote(opts) do
@spec create(map()) :: map()
def create(data) do
ExFacturapi.request(:post, endpoint(), data)
end
end

if :retrieve in unquote(opts) do
@spec retrieve(binary()) :: map()
def retrieve(id) when is_bitstring(id) do
resource_url = Path.join(endpoint(), id)
ExFacturapi.request(:get, resource_url, [])
end
end

if :update in unquote(opts) do
@spec update(binary(), map()) :: map()
def update(id, data) when is_bitstring(id) do
resource_url = Path.join(endpoint(), id)
ExFacturapi.request(:put, resource_url, data)
end
end

if :list in unquote(opts) do
@spec list(list()) :: map()
def list(pagination_opts \\ []) when is_list(pagination_opts) do
ExFacturapi.request(:get, endpoint(), pagination_opts)
end
end

if :delete in unquote(opts) do
@spec delete(binary(), map()) :: map()
def delete(id, data \\ []) when is_bitstring(id) do
resource_url = Path.join(endpoint(), id)
ExFacturapi.request(:delete, resource_url, data)
end
end
end
end
end
8 changes: 8 additions & 0 deletions lib/ex_facturapi/catalogs.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule ExFacturapi.Catalogs do
use ExFacturapi.API, [:retrieve, :update, :create, :list, :delete]

@spec endpoint() :: String.t()
def endpoint do
"/catalogs"
end
end
8 changes: 8 additions & 0 deletions lib/ex_facturapi/clients.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule ExFacturapi.Clients do
use ExFacturapi.API, [:retrieve, :update, :create, :list, :delete]

@spec endpoint() :: String.t()
def endpoint do
"/clients"
end
end
3 changes: 3 additions & 0 deletions lib/ex_facturapi/errors/api_connection_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ExFacturapi.APIConnectionError do
defexception type: "api_connection_error", message: nil
end
3 changes: 3 additions & 0 deletions lib/ex_facturapi/errors/api_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ExFacturapi.APIError do
defexception type: "api_error", message: nil
end
3 changes: 3 additions & 0 deletions lib/ex_facturapi/errors/authentication_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ExFacturapi.AuthenticationError do
defexception type: "authentication_error", message: nil
end
3 changes: 3 additions & 0 deletions lib/ex_facturapi/errors/invalid_request_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ExFacturapi.InvalidRequestError do
defexception type: "invalid_request_error", message: nil, param: nil
end
3 changes: 3 additions & 0 deletions lib/ex_facturapi/errors/rate_limit_error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule ExFacturapi.RateLimitError do
defexception type: "rate_limit_error", message: nil
end
8 changes: 8 additions & 0 deletions lib/ex_facturapi/invoices.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule ExFacturapi.Invoices do
use ExFacturapi.API, [:retrieve, :update, :create, :list, :delete]

@spec endpoint() :: String.t()
def endpoint do
"/invoices"
end
end
Loading

0 comments on commit 570838e

Please sign in to comment.