defmodule Plausible.Billing.Plan do @moduledoc false use Ecto.Schema import Ecto.Changeset @type t() :: %__MODULE__{} embedded_schema do # Due to grandfathering, we sometimes need to check the "generation" (e.g. # v1, v2, etc...) of a user's subscription plan. For instance, on prod, the # users subscribed to a v2 plan are only supposed to see v2 plans when they # go to the upgrade page. # # In the `dev` environment though, "sandbox" plans are used, which unlike # production plans, contain multiple generations of plans in the same file # for testing purposes. field :generation, :integer field :kind, Ecto.Enum, values: [:starter, :growth, :business] field :features, {:array, Plausible.Billing.Ecto.Feature} field :monthly_pageview_limit, :integer field :site_limit, :integer field :team_member_limit, Plausible.Billing.Ecto.Limit field :volume, :string field :data_retention_in_years, :integer field :monthly_cost field :monthly_product_id, :string field :yearly_cost field :yearly_product_id, :string end @required_fields ~w(generation kind features monthly_pageview_limit site_limit team_member_limit volume)a @optional_fields ~w(monthly_cost yearly_cost monthly_product_id yearly_product_id data_retention_in_years)a @fields @required_fields ++ @optional_fields def changeset(plan, attrs) do plan |> cast(attrs, @fields) |> put_volume() |> validate_required_either([:monthly_product_id, :yearly_product_id]) |> validate_required(@required_fields) end defp put_volume(changeset) do if volume = get_field(changeset, :monthly_pageview_limit) do put_change(changeset, :volume, PlausibleWeb.StatsView.large_number_format(volume)) else changeset end end def validate_required_either(changeset, fields) do if Enum.any?(fields, &get_field(changeset, &1)) do changeset else add_error(changeset, hd(fields), "one of these fields must be present #{inspect(fields)}") end end end