Enforce parent device hierarchy: slots/size unset, battery summary, sub-component toggle
This commit is contained in:
@@ -98,7 +98,7 @@ def create_app(config_object="config"):
|
||||
.distinct().order_by(Battery.storage_location).all()
|
||||
]
|
||||
devices = db.query(Device).order_by(Device.name).all()
|
||||
devices_with_slots = [d for d in devices if d.installed_count() < d.battery_slots]
|
||||
devices_with_slots = [d for d in devices if d.installed_count() < d.battery_slots and not d.has_children()]
|
||||
today = date.today()
|
||||
one_year_ago = (today - timedelta(days=365)).isoformat()
|
||||
total_charges = db.query(func.count(ChargeLog.id)).scalar() or 0
|
||||
@@ -397,7 +397,7 @@ def create_app(config_object="config"):
|
||||
return redirect(url_for("battery_detail", battery_id=battery_id))
|
||||
|
||||
devices = db.query(Device).order_by(Device.name).all()
|
||||
devices_with_slots = [d for d in devices if d.installed_count() < d.battery_slots]
|
||||
devices_with_slots = [d for d in devices if d.installed_count() < d.battery_slots and not d.has_children()]
|
||||
|
||||
if request.method == "POST":
|
||||
device_id = request.form.get("device_id", type=int)
|
||||
@@ -406,6 +406,10 @@ def create_app(config_object="config"):
|
||||
flash("Device not found.", "error")
|
||||
return render_template("assign.html", battery=battery, devices=devices_with_slots)
|
||||
|
||||
if device.has_children():
|
||||
flash(f"{device.name} has sub-components; assign batteries to its sub-components instead.", "error")
|
||||
return render_template("assign.html", battery=battery, devices=devices_with_slots)
|
||||
|
||||
if device.installed_count() >= device.battery_slots:
|
||||
flash(
|
||||
f"{device.name} is already full "
|
||||
@@ -556,6 +560,10 @@ def create_app(config_object="config"):
|
||||
flash("Device not found.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
if device.has_children():
|
||||
flash(f"{device.name} has sub-components; install batteries into those instead.", "error")
|
||||
return redirect(url_for("dashboard"))
|
||||
|
||||
already_here = [b for b in batteries if b.device_id == device.id]
|
||||
retired_sel = [b for b in batteries if b.is_retired()]
|
||||
to_process = [b for b in batteries
|
||||
@@ -692,6 +700,16 @@ def create_app(config_object="config"):
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes), 400
|
||||
if parent_device.battery_slots != 0 or parent_device.battery_size:
|
||||
flash(
|
||||
f"'{parent_device.name}' must have battery slots set to 0 "
|
||||
f"and battery size cleared before sub-components can be added.",
|
||||
"error",
|
||||
)
|
||||
return render_template("device_add.html",
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes), 400
|
||||
|
||||
if not name:
|
||||
flash("Device name is required.", "error")
|
||||
@@ -701,22 +719,12 @@ def create_app(config_object="config"):
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
prefill_parent=parent_device), 400
|
||||
|
||||
if not battery_size:
|
||||
flash("Battery size is required.", "error")
|
||||
return render_template("device_add.html",
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
form_name=name, form_notes=notes or "",
|
||||
form_device_type=request.form.get("device_type", ""),
|
||||
prefill_parent=parent_device), 400
|
||||
|
||||
try:
|
||||
slots = int(slots_raw)
|
||||
if slots < 1:
|
||||
if slots < 0:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
flash("Battery slots must be a positive integer.", "error")
|
||||
flash("Battery slots must be a non-negative integer.", "error")
|
||||
return render_template("device_add.html",
|
||||
device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
@@ -750,7 +758,9 @@ def create_app(config_object="config"):
|
||||
return render_template("device_add.html", device_types=device_types,
|
||||
device_locations=device_locations,
|
||||
device_battery_sizes=device_battery_sizes,
|
||||
prefill_parent=prefill_parent)
|
||||
prefill_parent=prefill_parent,
|
||||
form_device_type=prefill_parent.device_type if prefill_parent else None,
|
||||
form_location=prefill_parent.location if prefill_parent else None)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# Devices — detail
|
||||
@@ -823,7 +833,9 @@ def create_app(config_object="config"):
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
try:
|
||||
slots = int(slots_raw)
|
||||
if slots < 1:
|
||||
if slots < 0:
|
||||
raise ValueError
|
||||
if slots < 1 and not device.has_children():
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
flash("Battery slots must be a positive integer.", "error")
|
||||
@@ -846,17 +858,28 @@ def create_app(config_object="config"):
|
||||
if new_parent.is_subcomponent():
|
||||
flash("Cannot nest sub-components more than one level deep.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
if new_parent.battery_slots != 0 or new_parent.battery_size:
|
||||
flash(
|
||||
f"'{new_parent.name}' must have battery slots set to 0 "
|
||||
f"and battery size cleared before sub-components can be added.",
|
||||
"error",
|
||||
)
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
device.parent_id = new_parent.id
|
||||
else:
|
||||
device.parent_id = None
|
||||
|
||||
device.name = name
|
||||
device.battery_slots = slots
|
||||
device.notes = notes
|
||||
device.device_type = device_type
|
||||
new_battery_size = request.form.get("battery_size", "").strip() or None
|
||||
if new_battery_size is not None:
|
||||
device.battery_size = new_battery_size
|
||||
if device.has_children():
|
||||
device.battery_slots = 0
|
||||
device.battery_size = None
|
||||
else:
|
||||
device.battery_slots = slots
|
||||
new_battery_size = request.form.get("battery_size", "").strip() or None
|
||||
if new_battery_size is not None:
|
||||
device.battery_size = new_battery_size
|
||||
device.location = request.form.get("location", "").strip() or None
|
||||
device.ha_entity_id = request.form.get("ha_entity_id", "").strip() or None
|
||||
db.commit()
|
||||
@@ -873,6 +896,10 @@ def create_app(config_object="config"):
|
||||
if device is None:
|
||||
abort(404)
|
||||
|
||||
if device.has_children():
|
||||
flash(f"{device.name} has sub-components; install batteries into those instead.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
|
||||
brands = request.form.getlist("brand[]")
|
||||
qtys_raw = request.form.getlist("qty[]")
|
||||
|
||||
@@ -945,6 +972,9 @@ def create_app(config_object="config"):
|
||||
device = db.get(Device, device_id)
|
||||
if device is None:
|
||||
abort(404)
|
||||
if device.has_children():
|
||||
flash(f"{device.name} has sub-components; install batteries into those instead.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
battery_id = request.form.get("battery_id", type=int)
|
||||
battery = db.get(Battery, battery_id)
|
||||
if battery is None or not battery.is_available():
|
||||
@@ -1034,6 +1064,9 @@ def create_app(config_object="config"):
|
||||
device = db.get(Device, device_id)
|
||||
if device is None:
|
||||
abort(404)
|
||||
if device.has_children():
|
||||
flash(f"{device.name} has sub-components; install batteries into those instead.", "error")
|
||||
return redirect(url_for("device_detail", device_id=device_id))
|
||||
battery_ids = request.form.getlist("battery_ids")
|
||||
free = device.battery_slots - device.installed_count()
|
||||
if not battery_ids:
|
||||
|
||||
Reference in New Issue
Block a user