refactor(elixir): remove unused is_active field
from storage location
This commit is contained in:
@@ -15,14 +15,16 @@ defmodule ComponentsElixir.Inventory do
|
||||
"""
|
||||
def list_storage_locations do
|
||||
# Get all locations with preloaded parents in a single query
|
||||
locations = StorageLocation
|
||||
|> order_by([sl], [asc: sl.name])
|
||||
|> preload(:parent)
|
||||
|> Repo.all()
|
||||
locations =
|
||||
StorageLocation
|
||||
|> order_by([sl], asc: sl.name)
|
||||
|> preload(:parent)
|
||||
|> Repo.all()
|
||||
|
||||
# Compute hierarchy fields for all locations efficiently
|
||||
processed_locations = compute_hierarchy_fields_batch(locations)
|
||||
|> Enum.sort_by(&{&1.level, &1.name})
|
||||
processed_locations =
|
||||
compute_hierarchy_fields_batch(locations)
|
||||
|> Enum.sort_by(&{&1.level, &1.name})
|
||||
|
||||
# Ensure AprilTag SVGs exist for all locations
|
||||
spawn(fn ->
|
||||
@@ -46,24 +48,35 @@ defmodule ComponentsElixir.Inventory do
|
||||
end
|
||||
|
||||
defp compute_level_efficient(%{parent_id: nil}, _location_map, _depth), do: 0
|
||||
|
||||
defp compute_level_efficient(%{parent_id: parent_id}, location_map, depth) when depth < 10 do
|
||||
case Map.get(location_map, parent_id) do
|
||||
nil -> 0 # Orphaned record
|
||||
# Orphaned record
|
||||
nil -> 0
|
||||
parent -> 1 + compute_level_efficient(parent, location_map, depth + 1)
|
||||
end
|
||||
end
|
||||
defp compute_level_efficient(_location, _location_map, _depth), do: 0 # Prevent infinite recursion
|
||||
|
||||
# Prevent infinite recursion
|
||||
defp compute_level_efficient(_location, _location_map, _depth), do: 0
|
||||
|
||||
defp compute_path_efficient(%{parent_id: nil, name: name}, _location_map, _depth), do: name
|
||||
defp compute_path_efficient(%{parent_id: parent_id, name: name}, location_map, depth) when depth < 10 do
|
||||
|
||||
defp compute_path_efficient(%{parent_id: parent_id, name: name}, location_map, depth)
|
||||
when depth < 10 do
|
||||
case Map.get(location_map, parent_id) do
|
||||
nil -> name # Orphaned record
|
||||
# Orphaned record
|
||||
nil ->
|
||||
name
|
||||
|
||||
parent ->
|
||||
parent_path = compute_path_efficient(parent, location_map, depth + 1)
|
||||
"#{parent_path}/#{name}"
|
||||
end
|
||||
end
|
||||
defp compute_path_efficient(%{name: name}, _location_map, _depth), do: name # Prevent infinite recursion
|
||||
|
||||
# Prevent infinite recursion
|
||||
defp compute_path_efficient(%{name: name}, _location_map, _depth), do: name
|
||||
|
||||
@doc """
|
||||
Returns the list of root storage locations (no parent).
|
||||
@@ -71,7 +84,7 @@ defmodule ComponentsElixir.Inventory do
|
||||
def list_root_storage_locations do
|
||||
StorageLocation
|
||||
|> where([sl], is_nil(sl.parent_id))
|
||||
|> order_by([sl], [asc: sl.name])
|
||||
|> order_by([sl], asc: sl.name)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@@ -79,9 +92,10 @@ defmodule ComponentsElixir.Inventory do
|
||||
Gets a single storage location with computed hierarchy fields.
|
||||
"""
|
||||
def get_storage_location!(id) do
|
||||
location = StorageLocation
|
||||
|> preload(:parent)
|
||||
|> Repo.get!(id)
|
||||
location =
|
||||
StorageLocation
|
||||
|> preload(:parent)
|
||||
|> Repo.get!(id)
|
||||
|
||||
# Compute hierarchy fields
|
||||
level = compute_level_for_single(location)
|
||||
@@ -91,6 +105,7 @@ defmodule ComponentsElixir.Inventory do
|
||||
|
||||
# Simple computation for single location (allows DB queries)
|
||||
defp compute_level_for_single(%{parent_id: nil}), do: 0
|
||||
|
||||
defp compute_level_for_single(%{parent_id: parent_id}) do
|
||||
case Repo.get(StorageLocation, parent_id) do
|
||||
nil -> 0
|
||||
@@ -99,6 +114,7 @@ defmodule ComponentsElixir.Inventory do
|
||||
end
|
||||
|
||||
defp compute_path_for_single(%{parent_id: nil, name: name}), do: name
|
||||
|
||||
defp compute_path_for_single(%{parent_id: parent_id, name: name}) do
|
||||
case Repo.get(StorageLocation, parent_id) do
|
||||
nil -> name
|
||||
@@ -115,7 +131,9 @@ defmodule ComponentsElixir.Inventory do
|
||||
|> preload(:parent)
|
||||
|> Repo.one()
|
||||
|> case do
|
||||
nil -> nil
|
||||
nil ->
|
||||
nil
|
||||
|
||||
location ->
|
||||
level = compute_level_for_single(location)
|
||||
path = compute_path_for_single(location)
|
||||
@@ -130,13 +148,15 @@ defmodule ComponentsElixir.Inventory do
|
||||
# Convert string keys to atoms to maintain consistency
|
||||
attrs = normalize_string_keys(attrs)
|
||||
|
||||
result = %StorageLocation{}
|
||||
|> StorageLocation.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
result =
|
||||
%StorageLocation{}
|
||||
|> StorageLocation.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
|
||||
case result do
|
||||
{:ok, location} ->
|
||||
{:ok, location}
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
@@ -149,13 +169,15 @@ defmodule ComponentsElixir.Inventory do
|
||||
# Convert string keys to atoms to maintain consistency
|
||||
attrs = normalize_string_keys(attrs)
|
||||
|
||||
result = storage_location
|
||||
|> StorageLocation.changeset(attrs)
|
||||
|> Repo.update()
|
||||
result =
|
||||
storage_location
|
||||
|> StorageLocation.changeset(attrs)
|
||||
|> Repo.update()
|
||||
|
||||
case result do
|
||||
{:ok, updated_location} ->
|
||||
{:ok, updated_location}
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
@@ -182,12 +204,14 @@ defmodule ComponentsElixir.Inventory do
|
||||
case get_storage_location_by_apriltag_id(apriltag_id) do
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
|
||||
location ->
|
||||
{:ok, %{
|
||||
type: :storage_location,
|
||||
location: location,
|
||||
apriltag_id: apriltag_id
|
||||
}}
|
||||
{:ok,
|
||||
%{
|
||||
type: :storage_location,
|
||||
location: location,
|
||||
apriltag_id: apriltag_id
|
||||
}}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -195,6 +219,7 @@ defmodule ComponentsElixir.Inventory do
|
||||
Computes the path for a storage location (for display purposes).
|
||||
"""
|
||||
def compute_storage_location_path(nil), do: nil
|
||||
|
||||
def compute_storage_location_path(%StorageLocation{} = location) do
|
||||
compute_path_for_single(location)
|
||||
end
|
||||
@@ -205,6 +230,7 @@ defmodule ComponentsElixir.Inventory do
|
||||
{key, value}, acc when is_binary(key) ->
|
||||
atom_key = String.to_atom(key)
|
||||
Map.put(acc, atom_key, value)
|
||||
|
||||
{key, value}, acc ->
|
||||
Map.put(acc, key, value)
|
||||
end)
|
||||
@@ -281,28 +307,33 @@ defmodule ComponentsElixir.Inventory do
|
||||
|
||||
{:search, search_term}, query when is_binary(search_term) and search_term != "" ->
|
||||
search_pattern = "%#{search_term}%"
|
||||
where(query, [c],
|
||||
|
||||
where(
|
||||
query,
|
||||
[c],
|
||||
ilike(c.name, ^search_pattern) or
|
||||
ilike(c.description, ^search_pattern) or
|
||||
ilike(c.keywords, ^search_pattern) or
|
||||
ilike(c.position, ^search_pattern)
|
||||
ilike(c.description, ^search_pattern) or
|
||||
ilike(c.keywords, ^search_pattern) or
|
||||
ilike(c.position, ^search_pattern)
|
||||
)
|
||||
|
||||
_, query -> query
|
||||
_, query ->
|
||||
query
|
||||
end)
|
||||
end
|
||||
|
||||
defp apply_component_sorting(query, opts) do
|
||||
case Keyword.get(opts, :sort_criteria, "name_asc") do
|
||||
"name_asc" -> order_by(query, [c], [asc: c.name])
|
||||
"name_desc" -> order_by(query, [c], [desc: c.name])
|
||||
"inserted_at_asc" -> order_by(query, [c], [asc: c.inserted_at])
|
||||
"inserted_at_desc" -> order_by(query, [c], [desc: c.inserted_at])
|
||||
"updated_at_asc" -> order_by(query, [c], [asc: c.updated_at])
|
||||
"updated_at_desc" -> order_by(query, [c], [desc: c.updated_at])
|
||||
"count_asc" -> order_by(query, [c], [asc: c.count])
|
||||
"count_desc" -> order_by(query, [c], [desc: c.count])
|
||||
_ -> order_by(query, [c], [asc: c.name]) # Default fallback
|
||||
"name_asc" -> order_by(query, [c], asc: c.name)
|
||||
"name_desc" -> order_by(query, [c], desc: c.name)
|
||||
"inserted_at_asc" -> order_by(query, [c], asc: c.inserted_at)
|
||||
"inserted_at_desc" -> order_by(query, [c], desc: c.inserted_at)
|
||||
"updated_at_asc" -> order_by(query, [c], asc: c.updated_at)
|
||||
"updated_at_desc" -> order_by(query, [c], desc: c.updated_at)
|
||||
"count_asc" -> order_by(query, [c], asc: c.count)
|
||||
"count_desc" -> order_by(query, [c], desc: c.count)
|
||||
# Default fallback
|
||||
_ -> order_by(query, [c], asc: c.name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -353,10 +384,12 @@ defmodule ComponentsElixir.Inventory do
|
||||
def get_inventory_stats do
|
||||
total_components = Repo.aggregate(Component, :count, :id)
|
||||
|
||||
total_stock = Component
|
||||
total_stock =
|
||||
Component
|
||||
|> Repo.aggregate(:sum, :count)
|
||||
|
||||
categories_with_components = Component
|
||||
categories_with_components =
|
||||
Component
|
||||
|> distinct([c], c.category_id)
|
||||
|> Repo.aggregate(:count, :category_id)
|
||||
|
||||
@@ -406,6 +439,7 @@ defmodule ComponentsElixir.Inventory do
|
||||
"""
|
||||
def decrement_component_count(%Component{} = component) do
|
||||
new_count = max(0, component.count - 1)
|
||||
|
||||
component
|
||||
|> Component.changeset(%{count: new_count})
|
||||
|> Repo.update()
|
||||
|
||||
Reference in New Issue
Block a user