Add bulk install-in-device from dashboard and unretire action

- Dashboard bulk toolbar: select batteries, pick a device, click 'Install
  in device'; confirms before moving already-installed batteries; enforces
  slot capacity and warns on brand mix
- Battery detail: 'Unretire Battery' button replaces 'Retire Battery' when
  battery is retired, restoring it to available status
- Tests: 3 new bulk-install-device tests (capacity block, move, success);
  42 total passing
This commit is contained in:
2026-04-12 21:08:48 -05:00
parent 81e87d2fe2
commit 0869ef3d5e
4 changed files with 137 additions and 0 deletions
+39
View File
@@ -294,6 +294,45 @@ def test_device_install_over_capacity(client):
assert b"slot" in resp.data.lower()
def test_bulk_install_device(client):
"""Select multiple available batteries and install them into a device."""
client.post("/device/add", data={"name": "Box", "battery_slots": "3"})
client.post("/battery/add", data={"brand": "Eneloop", "count": "2"})
resp = client.post("/battery/bulk-action",
data={"battery_ids": ["1", "2"], "action": "install_device",
"device_id": "1"},
follow_redirects=True)
assert resp.status_code == 200
assert b"Installed 2" in resp.data
def test_bulk_install_device_over_capacity(client):
"""Bulk install is blocked when device lacks free slots."""
client.post("/device/add", data={"name": "Box", "battery_slots": "1"})
client.post("/battery/add", data={"brand": "Eneloop", "count": "2"})
resp = client.post("/battery/bulk-action",
data={"battery_ids": ["1", "2"], "action": "install_device",
"device_id": "1"},
follow_redirects=True)
assert resp.status_code == 200
assert b"slot" in resp.data.lower()
def test_bulk_install_device_moves_installed_battery(client):
"""Bulk install moves a battery already installed in another device."""
client.post("/device/add", data={"name": "Box A", "battery_slots": "2"})
client.post("/device/add", data={"name": "Box B", "battery_slots": "2"})
client.post("/battery/add", data={"brand": "Eneloop", "count": "1"})
client.post("/battery/1/assign", data={"device_id": "1"})
resp = client.post("/battery/bulk-action",
data={"battery_ids": ["1"], "action": "install_device",
"device_id": "2"},
follow_redirects=True)
assert resp.status_code == 200
assert b"Installed 1" in resp.data
assert b"Box B" in client.get("/battery/1").data
# ------------------------------------------------------------------ #
# Dashboard — quick-assign
# ------------------------------------------------------------------ #