diff --git a/Dockerfile b/Dockerfile
index 7bb4b07..e6bf857 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,10 +4,10 @@
#
# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
# - https://hub.docker.com/_/debian/tags?name=trixie-20251229-slim - for the release image
-# - Ex: docker.io/hexpm/elixir:1.19.5-erlang-28.3-debian-trixie-20251229-slim
+# - Ex: docker.io/hexpm/elixir:1.19.5-erlang-28.5-debian-trixie-20251229-slim
#
ARG ELIXIR_VERSION=1.19.5
-ARG OTP_VERSION=28.3
+ARG OTP_VERSION=28.5
ARG DEBIAN_VERSION=trixie-20251229-slim
ARG BUILDER_IMAGE="docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
diff --git a/lib/ammoprices/prices.ex b/lib/ammoprices/prices.ex
index 653a997..ad54563 100644
--- a/lib/ammoprices/prices.ex
+++ b/lib/ammoprices/prices.ex
@@ -83,6 +83,7 @@ defmodule Ammoprices.Prices do
join: p in assoc(ps, :product),
where: p.caliber_id == ^caliber_id,
where: ps.recorded_at >= ^since,
+ where: ps.in_stock == true,
group_by: fragment("date_trunc('day', ?)", ps.recorded_at),
order_by: [asc: fragment("date_trunc('day', ?)", ps.recorded_at)],
select: %{
@@ -145,12 +146,15 @@ defmodule Ammoprices.Prices do
from(ps in PriceSnapshot,
join: p in assoc(ps, :product),
where: p.caliber_id == ^caliber_id,
- where: ps.in_stock == true,
distinct: ps.product_id,
order_by: [asc: ps.product_id, desc: ps.recorded_at],
- select: ps.price_per_round_cents
+ select: %{
+ price_per_round_cents: ps.price_per_round_cents,
+ in_stock: ps.in_stock
+ }
)
|> subquery()
+ |> where([s], s.in_stock == true)
|> select([s], min(s.price_per_round_cents))
|> Repo.one()
@@ -170,19 +174,20 @@ defmodule Ammoprices.Prices do
latest =
from(ps in PriceSnapshot,
join: p in assoc(ps, :product),
- where: ps.in_stock == true,
- where: p.in_stock == true,
distinct: ps.product_id,
order_by: [asc: ps.product_id, desc: ps.recorded_at],
select: %{
product_id: ps.product_id,
caliber_id: p.caliber_id,
- price_per_round_cents: ps.price_per_round_cents
+ price_per_round_cents: ps.price_per_round_cents,
+ in_stock: ps.in_stock,
+ product_in_stock: p.in_stock
}
)
Repo.all(
from(s in subquery(latest),
+ where: s.in_stock == true and s.product_in_stock == true,
group_by: s.caliber_id,
select: %{caliber_id: s.caliber_id, min_ppr: min(s.price_per_round_cents)}
)
diff --git a/lib/ammoprices/scraping/retailers/natchez.ex b/lib/ammoprices/scraping/retailers/natchez.ex
index 8d883d8..54f19a2 100644
--- a/lib/ammoprices/scraping/retailers/natchez.ex
+++ b/lib/ammoprices/scraping/retailers/natchez.ex
@@ -123,15 +123,25 @@ defmodule Ammoprices.Scraping.Retailers.Natchez do
end
defp extract_price(%{"price_range" => %{"minimum_price" => %{"final_price" => %{"value" => value}}}}) do
- {:ok,
- value
- |> String.to_float()
- |> Kernel.*(100)
- |> round()}
+ case parse_price(value) do
+ nil -> :error
+ price_cents -> {:ok, price_cents}
+ end
end
defp extract_price(_), do: :error
+ defp parse_price(value) when is_number(value), do: round(value * 100)
+
+ defp parse_price(value) when is_binary(value) do
+ case Float.parse(value) do
+ {amount, ""} -> round(amount * 100)
+ _ -> nil
+ end
+ end
+
+ defp parse_price(_), do: nil
+
defp parse_integer(nil), do: nil
defp parse_integer(str) when is_binary(str) do
diff --git a/lib/ammoprices_web/controllers/page_html/home.html.heex b/lib/ammoprices_web/controllers/page_html/home.html.heex
index b107fd0..7c49a7d 100644
--- a/lib/ammoprices_web/controllers/page_html/home.html.heex
+++ b/lib/ammoprices_web/controllers/page_html/home.html.heex
@@ -69,8 +69,7 @@
href="https://hexdocs.pm/phoenix/overview.html"
class="group relative rounded-box px-6 py-4 text-sm font-semibold leading-6 sm:py-6"
>
-
-
+