add multiple ammo groups at one time
continuous-integration/drone/push Build is passing Details

This commit is contained in:
shibao 2022-02-24 00:16:23 -05:00
parent d79d0fa179
commit a6b2c6181e
13 changed files with 257 additions and 54 deletions

View File

@ -3,6 +3,7 @@
- Add prompt to create first container before first ammo group - Add prompt to create first container before first ammo group
- Edit and delete shot groups from ammo group show page - Edit and delete shot groups from ammo group show page
- Use today's date when adding new shot groups - Use today's date when adding new shot groups
- Create multiple ammo groups at one time
# v0.2.3 # v0.2.3
- Fix modals with overflowing forms - Fix modals with overflowing forms

View File

@ -6,7 +6,9 @@ defmodule Cannery.Ammo do
import Ecto.Query, warn: false import Ecto.Query, warn: false
alias Cannery.{Accounts.User, Containers, Repo} alias Cannery.{Accounts.User, Containers, Repo}
alias Cannery.Ammo.{AmmoGroup, AmmoType} alias Cannery.Ammo.{AmmoGroup, AmmoType}
alias Ecto.Changeset alias Ecto.{Changeset, Multi}
@ammo_group_create_limit 10_000
@doc """ @doc """
Returns the list of ammo_types. Returns the list of ammo_types.
@ -327,36 +329,63 @@ defmodule Cannery.Ammo do
end end
@doc """ @doc """
Creates a ammo_group. Creates multiple ammo_groups at once.
## Examples ## Examples
iex> create_ammo_group(%{field: value}, %User{id: 123}) iex> create_ammo_groups(%{field: value}, 3, %User{id: 123})
{:ok, %AmmoGroup{}} {:ok, {3, [%AmmoGroup{}]}}
iex> create_ammo_group(%{field: bad_value}, %User{id: 123}) iex> create_ammo_groups(%{field: bad_value}, 3, %User{id: 123})
{:error, %Changeset{}} {:error, %Changeset{}}
""" """
@spec create_ammo_group(attrs :: map(), User.t()) :: @spec create_ammo_groups(attrs :: map(), multiplier :: non_neg_integer(), User.t()) ::
{:ok, AmmoGroup.t()} | {:error, Changeset.t(AmmoGroup.new_ammo_group())} {:ok, {count :: non_neg_integer(), [AmmoGroup.t()] | nil}}
def create_ammo_group( | {:error, Changeset.t(AmmoGroup.new_ammo_group()) | nil}
def create_ammo_groups(
%{"ammo_type_id" => ammo_type_id, "container_id" => container_id} = attrs, %{"ammo_type_id" => ammo_type_id, "container_id" => container_id} = attrs,
multiplier,
%User{id: user_id} = user %User{id: user_id} = user
) do )
when multiplier >= 1 and multiplier <= @ammo_group_create_limit do
# validate ammo type and container ids belong to user # validate ammo type and container ids belong to user
_valid_ammo_type = get_ammo_type!(ammo_type_id, user) _valid_ammo_type = get_ammo_type!(ammo_type_id, user)
_valid_container = Containers.get_container!(container_id, user) _valid_container = Containers.get_container!(container_id, user)
%AmmoGroup{} now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
|> AmmoGroup.create_changeset(attrs |> Map.put("user_id", user_id))
|> Repo.insert() changesets =
Enum.map(1..multiplier, fn _count ->
%AmmoGroup{} |> AmmoGroup.create_changeset(attrs |> Map.put("user_id", user_id))
end)
if changesets |> Enum.all?(fn %{valid?: valid} -> valid end) do
Multi.new()
|> Multi.insert_all(
:create_ammo_groups,
AmmoGroup,
changesets
|> Enum.map(fn changeset ->
changeset
|> Map.get(:changes)
|> Map.merge(%{inserted_at: now, updated_at: now})
end),
returning: true
)
|> Repo.transaction()
|> case do
{:ok, %{create_ammo_groups: {count, ammo_groups}}} -> {:ok, {count, ammo_groups}}
{:error, :create_ammo_groups, changeset, _changes_so_far} -> {:error, changeset}
{:error, _other_transaction, _value, _changes_so_far} -> {:error, nil}
end
else
{:error, changesets |> List.first()}
end
end end
def create_ammo_group(invalid_attrs, _user) do def create_ammo_groups(invalid_attrs, _multiplier, _user) do
%AmmoGroup{} {:error, %AmmoGroup{} |> AmmoGroup.create_changeset(invalid_attrs)}
|> AmmoGroup.create_changeset(invalid_attrs |> Map.put("user_id", "-1"))
|> Repo.insert()
end end
@doc """ @doc """

View File

@ -9,6 +9,8 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
alias Ecto.Changeset alias Ecto.Changeset
alias Phoenix.LiveView.Socket alias Phoenix.LiveView.Socket
@ammo_group_create_limit 10_000
@impl true @impl true
@spec update( @spec update(
%{:ammo_group => AmmoGroup.t(), :current_user => User.t(), optional(any) => any}, %{:ammo_group => AmmoGroup.t(), :current_user => User.t(), optional(any) => any},
@ -22,6 +24,7 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
def update(%{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket) do def update(%{assigns: %{ammo_group: ammo_group, current_user: current_user}} = socket) do
socket = socket =
socket socket
|> assign(:ammo_group_create_limit, @ammo_group_create_limit)
|> assign(:changeset, Ammo.change_ammo_group(ammo_group)) |> assign(:changeset, Ammo.change_ammo_group(ammo_group))
|> assign(:ammo_types, Ammo.list_ammo_types(current_user)) |> assign(:ammo_types, Ammo.list_ammo_types(current_user))
|> assign_new(:containers, fn -> Containers.list_containers(current_user) end) |> assign_new(:containers, fn -> Containers.list_containers(current_user) end)
@ -80,20 +83,68 @@ defmodule CanneryWeb.AmmoGroupLive.FormComponent do
end end
defp save_ammo_group( defp save_ammo_group(
%{assigns: %{current_user: current_user, return_to: return_to}} = socket, %{assigns: %{changeset: changeset}} = socket,
:new, :new,
ammo_group_params %{"multiplier" => multiplier_str} = ammo_group_params
) do ) do
socket = socket =
case Ammo.create_ammo_group(ammo_group_params, current_user) do case multiplier_str |> Integer.parse() do
{:ok, _ammo_group} -> {multiplier, _remainder}
prompt = dgettext("prompts", "Ammo group created successfully") when multiplier >= 1 and multiplier <= @ammo_group_create_limit ->
socket |> put_flash(:info, prompt) |> push_redirect(to: return_to) socket |> create_multiple(ammo_group_params, multiplier)
{:error, %Changeset{} = changeset} -> {multiplier, _remainder} ->
socket |> assign(changeset: changeset) error_msg =
dgettext(
"errors",
"Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
max: @ammo_group_create_limit,
multiplier: multiplier
)
{:error, changeset} =
changeset
|> Changeset.add_error(:multiplier, error_msg)
|> Changeset.apply_action(:insert)
socket |> assign(:changeset, changeset)
:error ->
error_msg = dgettext("errors", "Could not parse number of copies")
{:error, changeset} =
changeset
|> Changeset.add_error(:multiplier, error_msg)
|> Changeset.apply_action(:insert)
socket |> assign(:changeset, changeset)
end end
{:noreply, socket} {:noreply, socket}
end end
defp create_multiple(
%{assigns: %{current_user: current_user, return_to: return_to}} = socket,
ammo_group_params,
multiplier
) do
case Ammo.create_ammo_groups(ammo_group_params, multiplier, current_user) do
{:ok, {count, _ammo_groups}} ->
prompt =
dngettext(
"prompts",
"Ammo group created successfully",
"Ammo groups created successfully",
count
)
socket |> put_flash(:info, prompt) |> push_redirect(to: return_to)
{:error, %Changeset{} = changeset} ->
socket |> assign(changeset: changeset)
{:error, nil} ->
socket
end
end
end end

View File

@ -33,7 +33,7 @@
<%= label(f, :price_paid, gettext("Price paid"), class: "title text-lg text-primary-600") %> <%= label(f, :price_paid, gettext("Price paid"), class: "title text-lg text-primary-600") %>
<%= number_input(f, :price_paid, <%= number_input(f, :price_paid,
step: "0.01", step: 0.01,
class: "text-center col-span-2 input input-primary" class: "text-center col-span-2 input input-primary"
) %> ) %>
<%= error_tag(f, :price_paid, "col-span-3 text-center") %> <%= error_tag(f, :price_paid, "col-span-3 text-center") %>
@ -51,9 +51,29 @@
) %> ) %>
<%= error_tag(f, :container_id, "col-span-3 text-center") %> <%= error_tag(f, :container_id, "col-span-3 text-center") %>
<%= submit(dgettext("actions", "Save"), <%= case @action do %>
phx_disable_with: dgettext("prompts", "Saving..."), <% :new -> %>
class: "mx-auto col-span-3 btn btn-primary" <hr class="hr col-span-3" />
) %>
<%= label(f, :multiplier, gettext("Copies"), class: "title text-lg text-primary-600") %>
<%= number_input(f, :multiplier,
max: @ammo_group_create_limit,
class: "text-center input input-primary",
value: 1,
phx_update: "ignore"
) %>
<%= submit(dgettext("actions", "Create"),
phx_disable_with: dgettext("prompts", "Creating..."),
class: "mx-auto btn btn-primary"
) %>
<%= error_tag(f, :multiplier, "col-span-3 text-center") %>
<% :edit -> %>
<%= submit(dgettext("actions", "Save"),
phx_disable_with: dgettext("prompts", "Saving..."),
class: "mx-auto col-span-3 btn btn-primary"
) %>
<% end %>
</.form> </.form>
</div> </div>

View File

@ -125,7 +125,7 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:46 #: lib/cannery_web/components/add_shot_group_component.html.heex:46
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:54 #: lib/cannery_web/live/ammo_group_live/form_component.html.heex:73
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:156 #: lib/cannery_web/live/ammo_type_live/form_component.html.heex:156
#: lib/cannery_web/live/container_live/form_component.html.heex:50 #: lib/cannery_web/live/container_live/form_component.html.heex:50
#: lib/cannery_web/live/invite_live/form_component.html.heex:28 #: lib/cannery_web/live/invite_live/form_component.html.heex:28
@ -196,3 +196,8 @@ msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:36 #: lib/cannery_web/live/ammo_group_live/index.html.heex:36
msgid "add a container first" msgid "add a container first"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:66
msgid "Create"
msgstr ""

View File

@ -834,3 +834,8 @@ msgstr ""
#: lib/cannery_web/live/range_live/index.ex:28 #: lib/cannery_web/live/range_live/index.ex:28
msgid "Record Shots" msgid "Record Shots"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:58
msgid "Copies"
msgstr ""

View File

@ -157,3 +157,13 @@ msgstr ""
#: lib/cannery_web/live/container_live/edit_tags_component.ex:52 #: lib/cannery_web/live/container_live/edit_tags_component.ex:52
msgid "Tag could not be removed" msgid "Tag could not be removed"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:113
msgid "Could not parse number of copies"
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:98
msgid "Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}"
msgstr ""

View File

@ -61,11 +61,6 @@ msgstr ""
msgid "A link to confirm your email change has been sent to the new address." msgid "A link to confirm your email change has been sent to the new address."
msgstr "" msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:90
msgid "Ammo group created successfully"
msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/index.ex:56 #: lib/cannery_web/live/ammo_group_live/index.ex:56
#: lib/cannery_web/live/ammo_group_live/show.ex:52 #: lib/cannery_web/live/ammo_group_live/show.ex:52
@ -73,7 +68,7 @@ msgid "Ammo group deleted succesfully"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:72 #: lib/cannery_web/live/ammo_group_live/form_component.ex:75
msgid "Ammo group updated successfully" msgid "Ammo group updated successfully"
msgstr "" msgstr ""
@ -160,7 +155,7 @@ msgstr ""
#, elixir-autogen, elixir-format #, elixir-autogen, elixir-format
#: lib/cannery_web/components/add_shot_group_component.html.heex:48 #: lib/cannery_web/components/add_shot_group_component.html.heex:48
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:55 #: lib/cannery_web/live/ammo_group_live/form_component.html.heex:74
#: lib/cannery_web/live/ammo_type_live/form_component.html.heex:157 #: lib/cannery_web/live/ammo_type_live/form_component.html.heex:157
#: lib/cannery_web/live/container_live/form_component.html.heex:52 #: lib/cannery_web/live/container_live/form_component.html.heex:52
#: lib/cannery_web/live/invite_live/form_component.html.heex:30 #: lib/cannery_web/live/invite_live/form_component.html.heex:30
@ -251,3 +246,15 @@ msgstr ""
#: lib/cannery_web/live/ammo_group_live/index.html.heex:33 #: lib/cannery_web/live/ammo_group_live/index.html.heex:33
msgid "You'll need to" msgid "You'll need to"
msgstr "" msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.html.heex:67
msgid "Creating..."
msgstr ""
#, elixir-autogen, elixir-format
#: lib/cannery_web/live/ammo_group_live/form_component.ex:134
msgid "Ammo group created successfully"
msgid_plural "Ammo groups created successfully"
msgstr[0] ""
msgstr[1] ""

View File

@ -20,8 +20,8 @@ defmodule Cannery.ActivityLogTest do
container = container_fixture(current_user) container = container_fixture(current_user)
ammo_type = ammo_type_fixture(current_user) ammo_type = ammo_type_fixture(current_user)
%{id: ammo_group_id} = {1, [%{id: ammo_group_id} = ammo_group]} =
ammo_group = ammo_group_fixture(%{"count" => 25}, ammo_type, container, current_user) ammo_group_fixture(%{"count" => 25}, ammo_type, container, current_user)
shot_group = shot_group =
%{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"} %{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}

View File

@ -108,7 +108,7 @@ defmodule Cannery.AmmoTest do
current_user = user_fixture() current_user = user_fixture()
ammo_type = ammo_type_fixture(current_user) ammo_type = ammo_type_fixture(current_user)
container = container_fixture(current_user) container = container_fixture(current_user)
ammo_group = ammo_group_fixture(ammo_type, container, current_user) {1, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
[ [
ammo_type: ammo_type, ammo_type: ammo_type,
@ -129,28 +129,28 @@ defmodule Cannery.AmmoTest do
ammo_group |> Repo.preload(:shot_groups) ammo_group |> Repo.preload(:shot_groups)
end end
test "create_ammo_group/1 with valid data creates a ammo_group", test "create_ammo_groups/3 with valid data creates a ammo_group",
%{ %{
ammo_type: ammo_type, ammo_type: ammo_type,
container: container, container: container,
current_user: current_user current_user: current_user
} do } do
assert {:ok, %AmmoGroup{} = ammo_group} = assert {:ok, {1, [%AmmoGroup{} = ammo_group]}} =
@valid_attrs @valid_attrs
|> Map.merge(%{"ammo_type_id" => ammo_type.id, "container_id" => container.id}) |> Map.merge(%{"ammo_type_id" => ammo_type.id, "container_id" => container.id})
|> Ammo.create_ammo_group(current_user) |> Ammo.create_ammo_groups(1, current_user)
assert ammo_group.count == 42 assert ammo_group.count == 42
assert ammo_group.notes == "some notes" assert ammo_group.notes == "some notes"
assert ammo_group.price_paid == 120.5 assert ammo_group.price_paid == 120.5
end end
test "create_ammo_group/1 with invalid data returns error changeset", test "create_ammo_groups/3 with invalid data returns error changeset",
%{ammo_type: ammo_type, container: container, current_user: current_user} do %{ammo_type: ammo_type, container: container, current_user: current_user} do
assert {:error, %Changeset{}} = assert {:error, %Changeset{}} =
@invalid_attrs @invalid_attrs
|> Map.merge(%{"ammo_type_id" => ammo_type.id, "container_id" => container.id}) |> Map.merge(%{"ammo_type_id" => ammo_type.id, "container_id" => container.id})
|> Ammo.create_ammo_group(current_user) |> Ammo.create_ammo_groups(1, current_user)
end end
test "update_ammo_group/2 with valid data updates the ammo_group", test "update_ammo_group/2 with valid data updates the ammo_group",

View File

@ -6,19 +6,20 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
use CanneryWeb.ConnCase use CanneryWeb.ConnCase
import Phoenix.LiveViewTest import Phoenix.LiveViewTest
import CanneryWeb.Gettext import CanneryWeb.Gettext
alias Cannery.Repo alias Cannery.{Ammo, Repo}
@moduletag :ammo_group_live_test @moduletag :ammo_group_live_test
@shot_group_create_attrs %{"ammo_left" => 5, "notes" => "some notes"} @shot_group_create_attrs %{"ammo_left" => 5, "notes" => "some notes"}
@shot_group_update_attrs %{"count" => 5, "notes" => "some updated notes"} @shot_group_update_attrs %{"count" => 5, "notes" => "some updated notes"}
@create_attrs %{count: 42, notes: "some notes", price_paid: 120.5} @create_attrs %{"count" => 42, "notes" => "some notes", "price_paid" => 120.5}
@update_attrs %{count: 43, notes: "some updated notes", price_paid: 456.7} @update_attrs %{"count" => 43, "notes" => "some updated notes", "price_paid" => 456.7}
@ammo_group_create_limit 10_000
# @invalid_attrs %{count: -1, notes: nil, price_paid: nil} # @invalid_attrs %{count: -1, notes: nil, price_paid: nil}
defp create_ammo_group(%{current_user: current_user}) do defp create_ammo_group(%{current_user: current_user}) do
ammo_type = ammo_type_fixture(current_user) ammo_type = ammo_type_fixture(current_user)
container = container_fixture(current_user) container = container_fixture(current_user)
ammo_group = ammo_group_fixture(ammo_type, container, current_user) {1, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
shot_group = shot_group =
%{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"} %{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}
@ -38,7 +39,7 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
assert html =~ ammo_group.ammo_type.name assert html =~ ammo_group.ammo_type.name
end end
test "saves new ammo_group", %{conn: conn} do test "saves a single new ammo_group", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "New Ammo group")) |> render_click() =~ assert index_live |> element("a", dgettext("actions", "New Ammo group")) |> render_click() =~
@ -60,6 +61,68 @@ defmodule CanneryWeb.AmmoGroupLiveTest do
assert html =~ "42" assert html =~ "42"
end end
test "saves multiple new ammo_groups", %{conn: conn, current_user: current_user} do
multiplier = 25
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "New Ammo group")) |> render_click() =~
gettext("New Ammo group")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :new))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
{:ok, _, html} =
index_live
|> form("#ammo_group-form",
ammo_group: @create_attrs |> Map.put("multiplier", to_string(multiplier))
)
|> render_submit()
|> follow_redirect(conn, Routes.ammo_group_index_path(conn, :index))
assert html =~ dgettext("prompts", "Ammo groups created successfully")
assert Ammo.list_ammo_groups(current_user) |> Enum.count() == multiplier + 1
end
test "does not save invalid number of new ammo_groups", %{conn: conn} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))
assert index_live |> element("a", dgettext("actions", "New Ammo group")) |> render_click() =~
gettext("New Ammo group")
assert_patch(index_live, Routes.ammo_group_index_path(conn, :new))
# assert index_live
# |> form("#ammo_group-form", ammo_group: @invalid_attrs)
# |> render_change() =~ dgettext("errors", "can't be blank")
assert index_live
|> form("#ammo_group-form", ammo_group: @create_attrs |> Map.put("multiplier", "0"))
|> render_submit() =~
dgettext(
"errors",
"Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
multiplier: 0,
max: @ammo_group_create_limit
)
assert index_live
|> form("#ammo_group-form",
ammo_group:
@create_attrs |> Map.put("multiplier", to_string(@ammo_group_create_limit + 1))
)
|> render_submit() =~
dgettext(
"errors",
"Invalid number of copies, must be between 1 and %{max}. Was %{multiplier}",
multiplier: @ammo_group_create_limit + 1,
max: @ammo_group_create_limit
)
end
test "saves new shot_group", %{conn: conn, ammo_group: ammo_group} do test "saves new shot_group", %{conn: conn, ammo_group: ammo_group} do
{:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index)) {:ok, index_live, _html} = live(conn, Routes.ammo_group_index_path(conn, :index))

View File

@ -16,7 +16,9 @@ defmodule CanneryWeb.RangeLiveTest do
defp create_shot_group(%{current_user: current_user}) do defp create_shot_group(%{current_user: current_user}) do
container = container_fixture(%{"staged" => true}, current_user) container = container_fixture(%{"staged" => true}, current_user)
ammo_type = ammo_type_fixture(current_user) ammo_type = ammo_type_fixture(current_user)
ammo_group = ammo_group_fixture(%{"staged" => true}, ammo_type, container, current_user)
{1, [ammo_group]} =
ammo_group_fixture(%{"staged" => true}, ammo_type, container, current_user)
shot_group = shot_group =
%{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"} %{"count" => 5, "date" => ~N[2022-02-13 03:17:00], "notes" => "some notes"}

View File

@ -111,10 +111,20 @@ defmodule Cannery.Fixtures do
@doc """ @doc """
Generate a AmmoGroup Generate a AmmoGroup
""" """
@spec ammo_group_fixture(AmmoType.t(), Container.t(), User.t()) :: AmmoGroup.t() @spec ammo_group_fixture(AmmoType.t(), Container.t(), User.t()) ::
@spec ammo_group_fixture(attrs :: map(), AmmoType.t(), Container.t(), User.t()) :: AmmoGroup.t() {count :: non_neg_integer(), [AmmoGroup.t()]}
@spec ammo_group_fixture(attrs :: map(), AmmoType.t(), Container.t(), User.t()) ::
{count :: non_neg_integer(), [AmmoGroup.t()]}
@spec ammo_group_fixture(
attrs :: map(),
multiplier :: non_neg_integer(),
AmmoType.t(),
Container.t(),
User.t()
) :: {count :: non_neg_integer(), [AmmoGroup.t()]}
def ammo_group_fixture( def ammo_group_fixture(
attrs \\ %{}, attrs \\ %{},
multiplier \\ 1,
%AmmoType{id: ammo_type_id}, %AmmoType{id: ammo_type_id},
%Container{id: container_id}, %Container{id: container_id},
%User{} = user %User{} = user
@ -125,7 +135,7 @@ defmodule Cannery.Fixtures do
"container_id" => container_id, "container_id" => container_id,
"count" => 20 "count" => 20
}) })
|> Ammo.create_ammo_group(user) |> Ammo.create_ammo_groups(multiplier, user)
|> unwrap_ok_tuple() |> unwrap_ok_tuple()
end end