forked from shibao/cannery
show original count, current value, percentage remaining and shot history for ammo groups
This commit is contained in:
parent
91ff0c14e4
commit
dba53106fb
@ -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!
|
||||||
|
@ -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.
|
||||||
|
@ -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">
|
||||||
|
@ -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 %>
|
||||||
|
@ -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 ""
|
||||||
|
|
||||||
|
@ -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 ""
|
||||||
|
@ -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 ""
|
||||||
|
Loading…
Reference in New Issue
Block a user