diff --git a/CHANGELOG.md b/CHANGELOG.md index 56e3eba5..9edf9edb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ - Add "Cannery" to page titles - Don't show true/false column for ammo types if all values are false - Fix ammo type firing type display - +- Show original count, current value, and percentage remaining for ammo groups +- Show shot history for an ammo group # 0.1.0 - Initial release! diff --git a/lib/cannery/ammo.ex b/lib/cannery/ammo.ex index 01b4e130..6800c59a 100644 --- a/lib/cannery/ammo.ex +++ b/lib/cannery/ammo.ex @@ -162,10 +162,12 @@ defmodule Cannery.Ammo do @spec list_ammo_groups_for_type(AmmoType.t(), User.t()) :: [AmmoGroup.t()] def list_ammo_groups_for_type(%AmmoType{id: ammo_type_id, user_id: user_id}, %User{id: user_id}) do Repo.all( - from am in AmmoGroup, - where: am.ammo_type_id == ^ammo_type_id, - where: am.user_id == ^user_id, - order_by: am.id + from ag in AmmoGroup, + left_join: sg in assoc(ag, :shot_groups), + where: ag.ammo_type_id == ^ammo_type_id, + where: ag.user_id == ^user_id, + preload: [shot_groups: sg], + order_by: ag.id ) end @@ -182,12 +184,18 @@ defmodule Cannery.Ammo do @spec list_ammo_groups(User.t(), include_empty :: boolean()) :: [AmmoGroup.t()] def list_ammo_groups(%User{id: user_id}, include_empty \\ false) do if include_empty do - from am in AmmoGroup, where: am.user_id == ^user_id, order_by: am.id + from ag in AmmoGroup, + left_join: sg in assoc(ag, :shot_groups), + where: ag.user_id == ^user_id, + preload: [shot_groups: sg], + order_by: ag.id else - from am in AmmoGroup, - where: am.user_id == ^user_id, - where: not (am.count == 0), - order_by: am.id + from ag in AmmoGroup, + left_join: sg in assoc(ag, :shot_groups), + where: ag.user_id == ^user_id, + where: not (ag.count == 0), + preload: [shot_groups: sg], + order_by: ag.id end |> Repo.all() end @@ -204,10 +212,12 @@ defmodule Cannery.Ammo do @spec list_staged_ammo_groups(User.t()) :: [AmmoGroup.t()] def list_staged_ammo_groups(%User{id: user_id}) do Repo.all( - from am in AmmoGroup, - where: am.user_id == ^user_id, - where: am.staged == true, - order_by: am.id + from ag in AmmoGroup, + left_join: sg in assoc(ag, :shot_groups), + where: ag.user_id == ^user_id, + where: ag.staged == true, + preload: [shot_groups: sg], + order_by: ag.id ) end @@ -226,8 +236,42 @@ defmodule Cannery.Ammo do """ @spec get_ammo_group!(AmmoGroup.id(), User.t()) :: AmmoGroup.t() - def get_ammo_group!(id, %User{id: user_id}), - do: Repo.one!(from am in AmmoGroup, where: am.id == ^id and am.user_id == ^user_id) + def get_ammo_group!(id, %User{id: user_id}) do + Repo.one!( + from ag in AmmoGroup, + left_join: sg in assoc(ag, :shot_groups), + where: ag.id == ^id, + where: ag.user_id == ^user_id, + preload: [shot_groups: sg] + ) + end + + @doc """ + Returns the number of shot rounds for an ammo group + """ + @spec get_used_count(AmmoGroup.t()) :: non_neg_integer() + def get_used_count(%AmmoGroup{} = ammo_group) do + ammo_group + |> Repo.preload(:shot_groups) + |> Map.get(:shot_groups) + |> Enum.map(fn %{count: count} -> count end) + |> Enum.sum() + end + + @doc """ + Calculates the percentage remaining of an ammo group out of 100 + """ + @spec get_percentage_remaining(AmmoGroup.t()) :: non_neg_integer() + def get_percentage_remaining(%AmmoGroup{count: 0}), do: 0 + + def get_percentage_remaining(%AmmoGroup{count: count} = ammo_group) do + ammo_group = ammo_group |> Repo.preload(:shot_groups) + + shot_group_sum = + ammo_group.shot_groups |> Enum.map(fn %{count: count} -> count end) |> Enum.sum() + + round(count / (count + shot_group_sum) * 100) + end @doc """ Creates a ammo_group. diff --git a/lib/cannery_web/live/ammo_group_live/index.html.heex b/lib/cannery_web/live/ammo_group_live/index.html.heex index 3377f6cc..c2fab220 100644 --- a/lib/cannery_web/live/ammo_group_live/index.html.heex +++ b/lib/cannery_web/live/ammo_group_live/index.html.heex @@ -33,7 +33,7 @@ <%= gettext("Price paid") %> - <%= gettext("Notes") %> + <%= gettext("% left") %> <%= gettext("Range") %> @@ -68,7 +68,7 @@ - <%= ammo_group.notes %> + <%= "#{ammo_group |> Ammo.get_percentage_remaining()}%" %> diff --git a/lib/cannery_web/live/ammo_group_live/show.html.heex b/lib/cannery_web/live/ammo_group_live/show.html.heex index c20e836f..119e6932 100644 --- a/lib/cannery_web/live/ammo_group_live/show.html.heex +++ b/lib/cannery_web/live/ammo_group_live/show.html.heex @@ -9,6 +9,16 @@ <%= @ammo_group.count %> + + <%= gettext("Original count:") %> + <%= @ammo_group.count + Ammo.get_used_count(@ammo_group) %> + + + + <%= gettext("Percentage left:") %> + <%= "#{@ammo_group |> Ammo.get_percentage_remaining()}%" %> + + <%= if @ammo_group.notes do %> <%= gettext("Notes:") %> @@ -18,11 +28,20 @@ <%= if @ammo_group.price_paid do %> - <%= gettext("Price paid:") %> + <%= gettext("Original cost:") %> <%= gettext("$%{amount}", amount: @ammo_group.price_paid |> :erlang.float_to_binary(decimals: 2) ) %> + + + <%= gettext("Current value:") %> + <%= gettext("$%{amount}", + amount: + (@ammo_group.price_paid * Ammo.get_percentage_remaining(@ammo_group) / 100) + |> :erlang.float_to_binary(decimals: 2) + ) %> + <% end %> @@ -84,6 +103,47 @@ <%= gettext("This ammo group is not in a container") %> <% end %> + + <%= unless @ammo_group.shot_groups |> Enum.empty?() do %> +
+ +

+ <%= gettext("Rounds used") %> +

+ +
+ + + + + + + + + + <%= for shot_group <- @ammo_group.shot_groups do %> + + + + + + <% end %> + +
+ <%= gettext("Rounds shot") %> + + <%= gettext("Notes") %> + + <%= gettext("Date") %> +
+ <%= shot_group.count %> + + <%= shot_group.notes %> + + <%= shot_group.date |> display_date() %> +
+
+ <% end %> <%= case @live_action do %> diff --git a/priv/gettext/actions.pot b/priv/gettext/actions.pot index fb98e755..ae84f44e 100644 --- a/priv/gettext/actions.pot +++ b/priv/gettext/actions.pot @@ -161,13 +161,13 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_group_live/index.html.heex:85 -#: lib/cannery_web/live/ammo_group_live/show.html.heex:67 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:86 #: lib/cannery_web/live/range_live/index.html.heex:36 msgid "Record shots" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.html.heex:31 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:50 msgid "Ammo Details" msgstr "" @@ -177,7 +177,7 @@ msgid "Add another container!" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.html.heex:61 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:80 msgid "Move containers" msgstr "" diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 61885faa..bbe52eb1 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -358,7 +358,7 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/add_shot_group_component.html.heex:30 #: lib/cannery_web/live/ammo_group_live/form_component.html.heex:41 -#: lib/cannery_web/live/ammo_group_live/index.html.heex:36 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:122 #: lib/cannery_web/live/range_live/form_component.html.heex:29 #: lib/cannery_web/live/range_live/index.html.heex:67 msgid "Notes" @@ -366,7 +366,7 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/ammo_group_card.ex:35 -#: lib/cannery_web/live/ammo_group_live/show.html.heex:14 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:24 msgid "Notes:" msgstr "" @@ -390,7 +390,6 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/ammo_group_card.ex:42 -#: lib/cannery_web/live/ammo_group_live/show.html.heex:21 msgid "Price paid:" msgstr "" @@ -447,7 +446,7 @@ msgid "Steel" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.html.heex:79 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:98 msgid "Stored in" msgstr "" @@ -473,7 +472,7 @@ msgid "The self-hosted firearm tracker website" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.html.heex:84 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:103 msgid "This ammo group is not in a container" msgstr "" @@ -538,6 +537,7 @@ msgid "Range day" msgstr "" #, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:125 #: lib/cannery_web/live/range_live/index.html.heex:70 msgid "Date" msgstr "" @@ -553,13 +553,13 @@ msgid "No ammo staged" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.html.heex:58 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:77 #: lib/cannery_web/live/range_live/index.html.heex:33 msgid "Stage for range" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.html.heex:57 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:76 #: lib/cannery_web/live/range_live/index.html.heex:32 msgid "Unstage from range" msgstr "" @@ -613,6 +613,7 @@ msgid "Rounds left" msgstr "" #, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:119 #: lib/cannery_web/live/range_live/index.html.heex:64 msgid "Rounds shot" msgstr "" @@ -646,7 +647,8 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/ammo_group_card.ex:43 #: lib/cannery_web/live/ammo_group_live/index.html.heex:64 -#: lib/cannery_web/live/ammo_group_live/show.html.heex:22 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:32 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:39 #: lib/cannery_web/live/ammo_type_live/show.html.heex:82 msgid "$%{amount}" msgstr "" @@ -760,3 +762,33 @@ msgstr "" #: lib/cannery_web/live/ammo_type_live/show.html.heex:88 msgid "No cost information" msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/index.html.heex:36 +msgid "% left" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:38 +msgid "Current value:" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:31 +msgid "Original cost:" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:13 +msgid "Original count:" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:18 +msgid "Percentage left:" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/live/ammo_group_live/show.html.heex:111 +msgid "Rounds used" +msgstr "" diff --git a/priv/gettext/prompts.pot b/priv/gettext/prompts.pot index 4713a48a..1ffdbd15 100644 --- a/priv/gettext/prompts.pot +++ b/priv/gettext/prompts.pot @@ -98,7 +98,7 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_group_live/index.html.heex:120 -#: lib/cannery_web/live/ammo_group_live/show.html.heex:47 +#: lib/cannery_web/live/ammo_group_live/show.html.heex:66 #: lib/cannery_web/live/ammo_type_live/index.html.heex:68 msgid "Are you sure you want to delete this ammo?" msgstr ""