lib/circlex/api/core/bank_accounts.ex

defmodule Circlex.Api.Core.BankAccounts do
  @moduledoc """
  API Client to the Core Bank Accounts API.

  Reference: https://developers.circle.com/reference/createbusinessaccountwirebankaccount
  """

  import Circlex.Api.Tooling

  alias Circlex.Struct.BankAccount
  alias Circlex.Struct.WireInstructions

  @doc ~S"""
  Create a bank account (wires).

  Reference: https://developers.circle.com/reference/payments-bank-accounts-wires-create

  ## Examples

      iex> host = Circlex.Test.start_server()
      iex> billing_details = %{city: "Toronto", country: "CA", district: "ON", line1: "100 Money St", name: "Satoshi Nakamoto", postalCode: "ON M5J 1S9"}
      iex> bank_address = %{bankName: "HSBC Canada", city: "Toronto", country: "CA"}
      iex> Circlex.Api.Core.BankAccounts.create("1000000001", "999999999", billing_details, bank_address, host: host)
      {
        :ok,
        %Circlex.Struct.BankAccount{
          description: "HSBC Canada 0001",
          bank_address: %{"bankName" => "HSBC Canada", "city" => "Toronto", "country" => "CA"},
          billing_details: %{"city" => "Toronto", "country" => "CA", "district" => "ON", "line1" => "100 Money St", "name" => "Satoshi Nakamoto", "postalCode" => "ON M5J 1S9"},
          create_date: "2022-07-17T08:59:41.344582Z",
          fingerprint: "b09eb536-05ae-11ed-aaa8-6a1733211c01",
          id: "a033a6d8-05ae-11ed-9e62-6a1733211c00",
          status: "pending",
          tracking_ref: "CIR3KXZZ00",
          update_date: "2022-07-17T08:59:41.344582Z",
          virtual_account_number: "547425368404"
        }
      }
  """
  def create(account_number, routing_number, billing_details, bank_address, opts \\ []) do
    idempotency_key = Keyword.get(opts, :idempotency_key, UUID.uuid1())

    with {:ok, bank_account} <-
           api_post(
             "/v1/businessAccount/banks/wires",
             %{
               idempotencyKey: idempotency_key,
               accountNumber: account_number,
               routingNumber: routing_number,
               billingDetails: billing_details,
               bankAddress: bank_address
             },
             opts
           ) do
      {:ok, BankAccount.deserialize(bank_account)}
    end
  end

  @doc ~S"""
  Get a list of bank accounts (wires).

  Reference: https://developers.circle.com/reference/getbusinessaccountwirebankaccount

  ## Examples

      iex> host = Circlex.Test.start_server()
      iex> Circlex.Api.Core.BankAccounts.list_bank_accounts(host: host)
      {
        :ok,
        [
          %Circlex.Struct.BankAccount{
            description: "HSBC Canada ****4444",
            bank_address: %{"bankName" => "HSBC Canada", "city" => "Toronto", "country" => "CA"},
            billing_details: %{"city" => "Toronto", "country" => "CA", "district" => "ON", "line1" => "100 Money St", "name" => "Satoshi Nakamoto", "postalCode" => "ON M5J 1S9"},
            create_date: "2022-02-14T22:29:32.779Z",
            fingerprint: "b296029f-8ec2-49bf-9b11-22ba09973c49",
            id: "fce6d303-2923-43cf-a66a-1e4690e08d1b",
            status: "complete",
            tracking_ref: "CIR3KX3L99",
            update_date: "2022-02-14T22:29:33.516Z",
            virtual_account_number: "547425368404"
          }
        ]
      }
  """
  def list_bank_accounts(opts \\ []) do
    with {:ok, bank_accounts} <- api_get("/v1/businessAccount/banks/wires", opts) do
      {:ok, Enum.map(bank_accounts, &BankAccount.deserialize/1)}
    end
  end

  @doc ~S"""
  Get a bank account (wires)

  Reference: https://developers.circle.com/reference/getbusinessaccountwirebankaccounts

  ## Examples

      iex> host = Circlex.Test.start_server()
      iex> Circlex.Api.Core.BankAccounts.get_bank_account("fce6d303-2923-43cf-a66a-1e4690e08d1b", host: host)
      {
        :ok,
        %Circlex.Struct.BankAccount{
          description: "HSBC Canada ****4444",
          bank_address: %{"bankName" => "HSBC Canada", "city" => "Toronto", "country" => "CA"},
          billing_details: %{"city" => "Toronto", "country" => "CA", "district" => "ON", "line1" => "100 Money St", "name" => "Satoshi Nakamoto", "postalCode" => "ON M5J 1S9"},
          create_date: "2022-02-14T22:29:32.779Z",
          fingerprint: "b296029f-8ec2-49bf-9b11-22ba09973c49",
          id: "fce6d303-2923-43cf-a66a-1e4690e08d1b",
          status: "complete",
          tracking_ref: "CIR3KX3L99",
          update_date: "2022-02-14T22:29:33.516Z",
          virtual_account_number: "547425368404"
        }
      }
  """
  def get_bank_account(id, opts \\ []) do
    with {:ok, bank_account} <-
           api_get(Path.join("/v1/businessAccount/banks/wires", to_string(id)), opts) do
      {:ok, BankAccount.deserialize(bank_account)}
    end
  end

  @doc ~S"""
  Get wire instructions for a bank account (wires)

  Reference: https://developers.circle.com/reference/payments-bank-accounts-wires-get-id-instructions

  ## Examples

      iex> host = Circlex.Test.start_server()
      iex> Circlex.Api.Core.BankAccounts.get_wire_instructions("fce6d303-2923-43cf-a66a-1e4690e08d1b", host: host)
      {
        :ok,
        %Circlex.Struct.WireInstructions{
          beneficiary: %{
            "address1" => "1 MAIN STREET",
            "address2" => "SUITE 1",
            "name" => "CIRCLE INTERNET FINANCIAL INC"
          },
          beneficiary_bank: %Circlex.Struct.BeneficiaryBank{
            account_number: "547425368404",
            address: "1 MONEY STREET",
            city: "NEW YORK",
            country: "US",
            currency: "USD",
            name: "CRYPTO BANK",
            postal_code: "1001",
            routing_number: "999999999",
            swift_code: "CRYPTO99"
          },
          tracking_ref: "CIR3KX3L99",
          virtual_account_enabled: true
        }
      }
  """
  def get_wire_instructions(id, opts \\ []) do
    with {:ok, wire_instructions} <-
           api_get(Path.join(["/v1/banks/wires", to_string(id), "instructions"]), opts) do
      {:ok, WireInstructions.deserialize(wire_instructions)}
    end
  end
end