defmodule BasicECommerce do @moduledoc """ Main module for this library. To use it, it needs to be used on your own application and it should configure an adapter by specifying the used `otp_app` and correctly configuring the adapter for this OTP app. ## Example # config/config.exs config :my_app, MyApp.BasicECommerce, adapter: BasicECommerce.DataSource.JsonAdapter, json_file_path: '/data/pricing_data.json` # my_app/basic_ecommerce.ex defmodule MyApp.BasicECommerce do use BasicECommerce, otp_app: :my_app end """ defmacro __using__(opts) do quote bind_quoted: [opts: opts] do @otp_app Keyword.fetch!(opts, :otp_app) @config Application.get_env(@otp_app, __MODULE__, []) @adapter Keyword.fetch!(@config, :adapter) @doc """ Returns the list of all products in the data source. """ @spec list_products() :: [BasicECommerce.Product.t()] def list_products do @adapter.list_products(@config) end @doc """ Gets a single product by its SKU. """ @spec get_product(sku :: atom()) :: {:ok, BasicECommerce.Product.t()} | {:error, String.t()} def get_product(sku) do @adapter.get_product(sku, @config) end @doc """ Returns the applicable special offers for a given SKU. """ @spec applicable_special_offers(sku :: atom()) :: [BasicECommerce.SpecialOffer.t()] def applicable_special_offers(sku) do @adapter.applicable_special_offers(sku, @config) end @doc """ Compute and return the total price of an order """ @spec compute_total(order :: BasicECommerce.Order.t()) :: integer() def compute_total(order) do BasicECommerce.Order.total!(order, &get_product/1, &applicable_special_offers/1) end @on_load :validate_config @doc false def validate_config do @adapter.validate_config(@config) end end end end