diff --git a/README.md b/README.md index ffafdc7..a7b484e 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ config :shippex, currency: :usd, # :usd, :can, :mxn, :eur carriers: [ ups: [ - module: Shippex.Carrier.UPS, + module: Shippex.Carrier.UPS, # optional username: "MyUsername", password: "MyPassword", secret_key: "123123", diff --git a/lib/shippex/carrier.ex b/lib/shippex/carrier.ex index a023d15..f7a3bf4 100644 --- a/lib/shippex/carrier.ex +++ b/lib/shippex/carrier.ex @@ -4,7 +4,7 @@ defmodule Shippex.Carrier do function for fetching the Carrier module. """ - alias Shippex.{Shipment, Service, Rate, Transaction} + alias Shippex.{Shipment, Service, Rate, Transaction, Util} @callback fetch_rates(Shipment.t()) :: [{atom, Rate.t()}] @callback fetch_rate(Shipment.t(), Service.t()) :: [{atom, Rate.t()}] | {atom, Rate.t()} @@ -15,6 +15,7 @@ defmodule Shippex.Carrier do @callback validate_address(Address.t()) :: {:ok, [Address.t()]} | {:error, any()} @callback track_packages(String.t() | [String.t()]) :: {:ok | :error, any()} @callback services_country?(ISO.country_code()) :: boolean() + @callback carrier() :: atom @type t() :: atom() @@ -31,13 +32,22 @@ defmodule Shippex.Carrier do @spec module(atom | String.t()) :: module() def module(carrier) when is_atom(carrier) do # NOTE, this might be a good place to use a protocol? + default_modules = Util.get_modules() carriers = Application.get_env(:shippex, :carriers, []) - |> Enum.with_index(fn(c, i) -> - module = List.first(c).module - {i, module} + |> Enum.with_index(fn c, i -> + module = Keyword.get(c, :module) + + case module do + nil -> + Enum.filter(default_modules, fn {_module, module_carrier} -> module_carrier == i end) + + module -> + {i, module} + end end) + |> Enum.reject(fn x -> x == nil end) module = case Enum.filter(carriers, fn {x, _} -> x == carrier end) do diff --git a/lib/shippex/carrier/dummy.ex b/lib/shippex/carrier/dummy.ex index 1a14779..c5339a7 100644 --- a/lib/shippex/carrier/dummy.ex +++ b/lib/shippex/carrier/dummy.ex @@ -47,10 +47,11 @@ defmodule Shippex.Carrier.Dummy do end defp rate() do + {carrier, _} = carrier() %Shippex.Rate{ service: %Shippex.Service{ id: :dummy, - carrier: carrier(), + carrier: carrier, description: "Dummy Shipping Service" }, price: 1000, @@ -61,7 +62,9 @@ defmodule Shippex.Carrier.Dummy do defp shipment() do end - defp carrier() do + @impl true + def carrier() do :dummy end + end diff --git a/lib/shippex/carrier/ups.ex b/lib/shippex/carrier/ups.ex index dc51069..30fcd88 100644 --- a/lib/shippex/carrier/ups.ex +++ b/lib/shippex/carrier/ups.ex @@ -445,4 +445,9 @@ defmodule Shippex.Carrier.UPS do raise InvalidConfigError, message: "USPS config is either invalid or not found." end end + + @impl true + def carrier() do + :ups + end end diff --git a/lib/shippex/carrier/usps.ex b/lib/shippex/carrier/usps.ex index 971c8f3..7f2a151 100644 --- a/lib/shippex/carrier/usps.ex +++ b/lib/shippex/carrier/usps.ex @@ -519,4 +519,9 @@ defmodule Shippex.Carrier.USPS do raise InvalidConfigError, message: "UPS config is either invalid or not found." end end + + @impl true + def carrier() do + :usps + end end diff --git a/lib/shippex/util.ex b/lib/shippex/util.ex index 2e27872..6d57af3 100644 --- a/lib/shippex/util.ex +++ b/lib/shippex/util.ex @@ -180,4 +180,30 @@ defmodule Shippex.Util do {key, val} end end + + @doc """ + Returns the mane and module tuple. + + iex> Util.get_modules() + {%{}, :module_name} + """ + def get_modules() do + {:ok, modules} = :application.get_key(:shippex, :modules) + + modules + |> Stream.map(&Module.split/1) + |> Stream.filter(fn module -> + case module do + ["Shippex", "Carrier", _] -> true + ["Shippex", "Carrier", "_", "Client"] -> false + _ -> false + end + end) + # concat + |> Stream.map(&Module.concat/1) + |> Stream.map(&{&1, apply(&1, :carrier, [])}) + |> Enum.map(fn output -> + output + end) + end end