Add size, chemistry, capacity, purchase date to bulk add form
Shared metadata fields settable at creation time apply to all batteries in the batch, avoiding per-battery detail page visits.
This commit is contained in:
@@ -37,10 +37,11 @@ def create_app(config_object="config"):
|
|||||||
@app.route("/battery/add", methods=["GET", "POST"])
|
@app.route("/battery/add", methods=["GET", "POST"])
|
||||||
def battery_add():
|
def battery_add():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
brand = request.form.get("brand", "").strip()
|
f = request.form
|
||||||
notes = request.form.get("notes", "").strip() or None
|
brand = f.get("brand", "").strip()
|
||||||
|
notes = f.get("notes", "").strip() or None
|
||||||
try:
|
try:
|
||||||
count = max(1, min(50, int(request.form.get("count", 1) or 1)))
|
count = max(1, min(50, int(f.get("count", 1) or 1)))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
count = 1
|
count = 1
|
||||||
|
|
||||||
@@ -51,10 +52,24 @@ def create_app(config_object="config"):
|
|||||||
form_brand="", form_count=1, form_notes=notes or "",
|
form_brand="", form_count=1, form_notes=notes or "",
|
||||||
brands=brands), 400
|
brands=brands), 400
|
||||||
|
|
||||||
|
def _int(key):
|
||||||
|
v = f.get(key, "").strip()
|
||||||
|
try:
|
||||||
|
return int(v) if v else None
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
size = f.get("size", "").strip() or None
|
||||||
|
chemistry = f.get("chemistry", "").strip() or None
|
||||||
|
capacity_mah = _int("capacity_mah")
|
||||||
|
purchase_date = f.get("purchase_date", "").strip() or None
|
||||||
|
|
||||||
existing = db.query(func.count(Battery.id)).filter_by(brand=brand).scalar()
|
existing = db.query(func.count(Battery.id)).filter_by(brand=brand).scalar()
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
label = f"{brand} {existing + i + 1:03d}"
|
label = f"{brand} {existing + i + 1:03d}"
|
||||||
db.add(Battery(label=label, brand=brand, status="available", notes=notes))
|
db.add(Battery(label=label, brand=brand, status="available", notes=notes,
|
||||||
|
size=size, chemistry=chemistry,
|
||||||
|
capacity_mah=capacity_mah, purchase_date=purchase_date))
|
||||||
db.commit()
|
db.commit()
|
||||||
flash(f"Added {count} {brand} batter{'y' if count == 1 else 'ies'}.", "success")
|
flash(f"Added {count} {brand} batter{'y' if count == 1 else 'ies'}.", "success")
|
||||||
return redirect(url_for("dashboard"))
|
return redirect(url_for("dashboard"))
|
||||||
|
|||||||
+64
-21
@@ -6,29 +6,72 @@
|
|||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<form method="post" action="{{ url_for('battery_add') }}">
|
<form method="post" action="{{ url_for('battery_add') }}">
|
||||||
<div class="form-group">
|
|
||||||
<label for="brand-select">Brand <span class="text-danger">*</span></label>
|
|
||||||
<select id="brand-select" onchange="brandSelectChanged(this, 'brand')">
|
|
||||||
<option value="">— select a brand —</option>
|
|
||||||
{% for b in brands|default([]) %}
|
|
||||||
<option value="{{ b }}">{{ b }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
<option value="__new__">➕ New brand…</option>
|
|
||||||
</select>
|
|
||||||
<input type="text" id="brand" name="brand" value="{{ form_brand|default('') }}"
|
|
||||||
placeholder="Type new brand name" required
|
|
||||||
style="display:none;margin-top:0.4rem;">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0 1rem;">
|
||||||
<label for="count">Quantity</label>
|
|
||||||
<input type="number" id="count" name="count" value="{{ form_count|default(1) }}" min="1" max="50">
|
<div class="form-group" style="grid-column:1/-1;">
|
||||||
<small class="text-muted">Labels are auto-generated (e.g. Eneloop 001, Eneloop 002)</small>
|
<label for="brand-select">Brand <span class="text-danger">*</span></label>
|
||||||
|
<select id="brand-select" onchange="metaSelectChanged(this, 'brand')">
|
||||||
|
<option value="">— select a brand —</option>
|
||||||
|
{% for b in brands|default([]) %}
|
||||||
|
<option value="{{ b }}">{{ b }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
<option value="__new__">➕ New brand…</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" id="brand" name="brand" value="{{ form_brand|default('') }}"
|
||||||
|
placeholder="Type new brand name" required
|
||||||
|
style="display:none;margin-top:0.4rem;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="count">Quantity</label>
|
||||||
|
<input type="number" id="count" name="count" value="{{ form_count|default(1) }}" min="1" max="50">
|
||||||
|
<small class="text-muted">Labels are auto-generated (e.g. Eneloop 001, Eneloop 002)</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="capacity_mah">Capacity (mAh)</label>
|
||||||
|
<input type="number" id="capacity_mah" name="capacity_mah" min="0"
|
||||||
|
value="" placeholder="e.g. 2000 — optional">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Size</label>
|
||||||
|
<select id="size-select" onchange="metaSelectChanged(this,'size')">
|
||||||
|
<option value="">— none —</option>
|
||||||
|
{% for opt in ['AA','AAA','C','D','9V','18650','21700','14500','26650','CR2032','CR123A'] %}
|
||||||
|
<option value="{{ opt }}">{{ opt }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
<option value="__new__">Other…</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" id="size" name="size" value=""
|
||||||
|
placeholder="Enter size" style="display:none;margin-top:0.4rem;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Chemistry</label>
|
||||||
|
<select id="chemistry-select" onchange="metaSelectChanged(this,'chemistry')">
|
||||||
|
<option value="">— none —</option>
|
||||||
|
{% for opt in ['NiMH','Alkaline','Li-ion','LiFePO4','NiCd','Zinc-Carbon','Li-MnO2'] %}
|
||||||
|
<option value="{{ opt }}">{{ opt }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
<option value="__new__">Other…</option>
|
||||||
|
</select>
|
||||||
|
<input type="text" id="chemistry" name="chemistry" value=""
|
||||||
|
placeholder="Enter chemistry" style="display:none;margin-top:0.4rem;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="purchase_date">Purchase Date</label>
|
||||||
|
<input type="date" id="purchase_date" name="purchase_date" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="notes">Notes</label>
|
<label for="notes">Notes</label>
|
||||||
<textarea id="notes" name="notes" placeholder="Optional notes applied to all batteries…">{{ form_notes|default('') }}</textarea>
|
<textarea id="notes" name="notes"
|
||||||
|
placeholder="Optional notes applied to all batteries…">{{ form_notes|default('') }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
@@ -39,9 +82,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function brandSelectChanged(sel, inputId) {
|
function metaSelectChanged(sel, inputId) {
|
||||||
var input = document.getElementById(inputId);
|
var input = document.getElementById(inputId);
|
||||||
if (sel.value === '__new__' || sel.value === '') {
|
if (sel.value === '__new__') {
|
||||||
input.style.display = '';
|
input.style.display = '';
|
||||||
input.value = '';
|
input.value = '';
|
||||||
input.focus();
|
input.focus();
|
||||||
@@ -51,7 +94,7 @@ function brandSelectChanged(sel, inputId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore state on error re-render (form_brand set)
|
// Restore brand state on error re-render
|
||||||
(function () {
|
(function () {
|
||||||
var input = document.getElementById('brand');
|
var input = document.getElementById('brand');
|
||||||
var sel = document.getElementById('brand-select');
|
var sel = document.getElementById('brand-select');
|
||||||
|
|||||||
Reference in New Issue
Block a user