show original count, current value, percentage remaining and shot history for ammo groups

This commit is contained in:
shibao 2022-02-19 00:05:22 -05:00
parent 91ff0c14e4
commit dba53106fb
7 changed files with 168 additions and 31 deletions

View File

@ -4,7 +4,8 @@
- Add "Cannery" to page titles - Add "Cannery" to page titles
- Don't show true/false column for ammo types if all values are false - Don't show true/false column for ammo types if all values are false
- Fix ammo type firing type display - 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 # 0.1.0
- Initial release! - Initial release!

View File

@ -162,10 +162,12 @@ defmodule Cannery.Ammo do
@spec list_ammo_groups_for_type(AmmoType.t(), User.t()) :: [AmmoGroup.t()] @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 def list_ammo_groups_for_type(%AmmoType{id: ammo_type_id, user_id: user_id}, %User{id: user_id}) do
Repo.all( Repo.all(
from am in AmmoGroup, from ag in AmmoGroup,
where: am.ammo_type_id == ^ammo_type_id, left_join: sg in assoc(ag, :shot_groups),
where: am.user_id == ^user_id, where: ag.ammo_type_id == ^ammo_type_id,
order_by: am.id where: ag.user_id == ^user_id,
preload: [shot_groups: sg],
order_by: ag.id
) )
end end
@ -182,12 +184,18 @@ defmodule Cannery.Ammo do
@spec list_ammo_groups(User.t(), include_empty :: boolean()) :: [AmmoGroup.t()] @spec list_ammo_groups(User.t(), include_empty :: boolean()) :: [AmmoGroup.t()]
def list_ammo_groups(%User{id: user_id}, include_empty \\ false) do def list_ammo_groups(%User{id: user_id}, include_empty \\ false) do
if include_empty 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 else
from am in AmmoGroup, from ag in AmmoGroup,
where: am.user_id == ^user_id, left_join: sg in assoc(ag, :shot_groups),
where: not (am.count == 0), where: ag.user_id == ^user_id,
order_by: am.id where: not (ag.count == 0),
preload: [shot_groups: sg],
order_by: ag.id
end end
|> Repo.all() |> Repo.all()
end end
@ -204,10 +212,12 @@ defmodule Cannery.Ammo do
@spec list_staged_ammo_groups(User.t()) :: [AmmoGroup.t()] @spec list_staged_ammo_groups(User.t()) :: [AmmoGroup.t()]
def list_staged_ammo_groups(%User{id: user_id}) do def list_staged_ammo_groups(%User{id: user_id}) do
Repo.all( Repo.all(
from am in AmmoGroup, from ag in AmmoGroup,
where: am.user_id == ^user_id, left_join: sg in assoc(ag, :shot_groups),
where: am.staged == true, where: ag.user_id == ^user_id,
order_by: am.id where: ag.staged == true,
preload: [shot_groups: sg],
order_by: ag.id
) )
end end
@ -226,8 +236,42 @@ defmodule Cannery.Ammo do
""" """
@spec get_ammo_group!(AmmoGroup.id(), User.t()) :: AmmoGroup.t() @spec get_ammo_group!(AmmoGroup.id(), User.t()) :: AmmoGroup.t()
def get_ammo_group!(id, %User{id: user_id}), def get_ammo_group!(id, %User{id: user_id}) do
do: Repo.one!(from am in AmmoGroup, where: am.id == ^id and am.user_id == ^user_id) 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 """ @doc """
Creates a ammo_group. Creates a ammo_group.

View File

@ -33,7 +33,7 @@
<%= gettext("Price paid") %> <%= gettext("Price paid") %>
</th> </th>
<th class="p-2"> <th class="p-2">
<%= gettext("Notes") %> <%= gettext("% left") %>
</th> </th>
<th class="p-2"> <th class="p-2">
<%= gettext("Range") %> <%= gettext("Range") %>
@ -68,7 +68,7 @@
</td> </td>
<td class="p-2"> <td class="p-2">
<%= ammo_group.notes %> <%= "#{ammo_group |> Ammo.get_percentage_remaining()}%" %>
</td> </td>
<td class="p-2"> <td class="p-2">

View File

@ -9,6 +9,16 @@
<%= @ammo_group.count %> <%= @ammo_group.count %>
</span> </span>
<span class="rounded-lg title text-lg">
<%= gettext("Original count:") %>
<%= @ammo_group.count + Ammo.get_used_count(@ammo_group) %>
</span>
<span class="rounded-lg title text-lg">
<%= gettext("Percentage left:") %>
<%= "#{@ammo_group |> Ammo.get_percentage_remaining()}%" %>
</span>
<%= if @ammo_group.notes do %> <%= if @ammo_group.notes do %>
<span class="rounded-lg title text-lg"> <span class="rounded-lg title text-lg">
<%= gettext("Notes:") %> <%= gettext("Notes:") %>
@ -18,11 +28,20 @@
<%= if @ammo_group.price_paid do %> <%= if @ammo_group.price_paid do %>
<span class="rounded-lg title text-lg"> <span class="rounded-lg title text-lg">
<%= gettext("Price paid:") %> <%= gettext("Original cost:") %>
<%= gettext("$%{amount}", <%= gettext("$%{amount}",
amount: @ammo_group.price_paid |> :erlang.float_to_binary(decimals: 2) amount: @ammo_group.price_paid |> :erlang.float_to_binary(decimals: 2)
) %> ) %>
</span> </span>
<span class="rounded-lg title text-lg">
<%= gettext("Current value:") %>
<%= gettext("$%{amount}",
amount:
(@ammo_group.price_paid * Ammo.get_percentage_remaining(@ammo_group) / 100)
|> :erlang.float_to_binary(decimals: 2)
) %>
</span>
<% end %> <% end %>
</div> </div>
@ -84,6 +103,47 @@
<%= gettext("This ammo group is not in a container") %> <%= gettext("This ammo group is not in a container") %>
<% end %> <% end %>
</div> </div>
<%= unless @ammo_group.shot_groups |> Enum.empty?() do %>
<hr class="mb-4 w-full" />
<h1 class="mb-4 px-4 py-2 text-center rounded-lg title text-xl">
<%= gettext("Rounds used") %>
</h1>
<div class="w-full overflow-x-auto border border-gray-600 rounded-lg shadow-lg bg-black">
<table class="min-w-full table-auto text-center bg-white">
<thead class="border-b border-primary-600">
<tr>
<th class="p-2">
<%= gettext("Rounds shot") %>
</th>
<th class="p-2">
<%= gettext("Notes") %>
</th>
<th class="p-2">
<%= gettext("Date") %>
</th>
</tr>
</thead>
<tbody id="shot_groups">
<%= for shot_group <- @ammo_group.shot_groups do %>
<tr id={"shot_group-#{shot_group.id}"}>
<td class="p-2">
<%= shot_group.count %>
</td>
<td class="p-2">
<%= shot_group.notes %>
</td>
<td class="p-2">
<%= shot_group.date |> display_date() %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
</div> </div>
<%= case @live_action do %> <%= case @live_action do %>

View File

@ -161,13 +161,13 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:85 #: 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 #: lib/cannery_web/live/range_live/index.html.heex:36
msgid "Record shots" msgid "Record shots"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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" msgid "Ammo Details"
msgstr "" msgstr ""
@ -177,7 +177,7 @@ msgid "Add another container!"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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" msgid "Move containers"
msgstr "" msgstr ""

View File

@ -358,7 +358,7 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:30 #: 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/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/form_component.html.heex:29
#: lib/cannery_web/live/range_live/index.html.heex:67 #: lib/cannery_web/live/range_live/index.html.heex:67
msgid "Notes" msgid "Notes"
@ -366,7 +366,7 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/components/ammo_group_card.ex:35 #: 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:" msgid "Notes:"
msgstr "" msgstr ""
@ -390,7 +390,6 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/components/ammo_group_card.ex:42 #: lib/cannery_web/components/ammo_group_card.ex:42
#: lib/cannery_web/live/ammo_group_live/show.html.heex:21
msgid "Price paid:" msgid "Price paid:"
msgstr "" msgstr ""
@ -447,7 +446,7 @@ msgid "Steel"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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" msgid "Stored in"
msgstr "" msgstr ""
@ -473,7 +472,7 @@ msgid "The self-hosted firearm tracker website"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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" msgid "This ammo group is not in a container"
msgstr "" msgstr ""
@ -538,6 +537,7 @@ msgid "Range day"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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 #: lib/cannery_web/live/range_live/index.html.heex:70
msgid "Date" msgid "Date"
msgstr "" msgstr ""
@ -553,13 +553,13 @@ msgid "No ammo staged"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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 #: lib/cannery_web/live/range_live/index.html.heex:33
msgid "Stage for range" msgid "Stage for range"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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 #: lib/cannery_web/live/range_live/index.html.heex:32
msgid "Unstage from range" msgid "Unstage from range"
msgstr "" msgstr ""
@ -613,6 +613,7 @@ msgid "Rounds left"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, 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 #: lib/cannery_web/live/range_live/index.html.heex:64
msgid "Rounds shot" msgid "Rounds shot"
msgstr "" msgstr ""
@ -646,7 +647,8 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/components/ammo_group_card.ex:43 #: 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/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 #: lib/cannery_web/live/ammo_type_live/show.html.heex:82
msgid "$%{amount}" msgid "$%{amount}"
msgstr "" msgstr ""
@ -760,3 +762,33 @@ msgstr ""
#: lib/cannery_web/live/ammo_type_live/show.html.heex:88 #: lib/cannery_web/live/ammo_type_live/show.html.heex:88
msgid "No cost information" msgid "No cost information"
msgstr "" 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 ""

View File

@ -98,7 +98,7 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.html.heex:120 #: 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 #: lib/cannery_web/live/ammo_type_live/index.html.heex:68
msgid "Are you sure you want to delete this ammo?" msgid "Are you sure you want to delete this ammo?"
msgstr "" msgstr ""