Add examples to inventory
This commit is contained in:
@@ -14,7 +14,6 @@ app = Flask(__name__)
|
||||
DATABASE_PATH = os.environ.get("DATABASE_PATH", str(Path(__file__).with_name("inventory.db")))
|
||||
UPLOAD_FOLDER = Path(os.environ.get("UPLOAD_FOLDER", str(Path(DATABASE_PATH).parent / "uploads")))
|
||||
ALLOWED_IMAGE_EXTENSIONS = {"jpg", "jpeg", "png", "gif", "webp"}
|
||||
ALLOWED_STATUSES = {"Available", "Trashed", "Sold"}
|
||||
app.config["MAX_CONTENT_LENGTH"] = 250 * 1024 * 1024
|
||||
|
||||
|
||||
@@ -42,7 +41,7 @@ def initialize_db():
|
||||
status TEXT NOT NULL DEFAULT 'Available',
|
||||
location TEXT,
|
||||
destination TEXT,
|
||||
price REAL,
|
||||
checkout_date TEXT,
|
||||
purchase_date TEXT,
|
||||
notes TEXT,
|
||||
cpu TEXT,
|
||||
@@ -68,12 +67,18 @@ def initialize_db():
|
||||
"""
|
||||
)
|
||||
columns = {row[1] for row in connection.execute("PRAGMA table_info(inventory_items)")}
|
||||
if "image_filename" not in columns:
|
||||
connection.execute("ALTER TABLE inventory_items ADD COLUMN image_filename TEXT")
|
||||
if "price" not in columns:
|
||||
connection.execute("ALTER TABLE inventory_items ADD COLUMN price REAL")
|
||||
if "destination" not in columns:
|
||||
connection.execute("ALTER TABLE inventory_items ADD COLUMN destination TEXT")
|
||||
migrations = {
|
||||
"image_filename": "ALTER TABLE inventory_items ADD COLUMN image_filename TEXT",
|
||||
"destination": "ALTER TABLE inventory_items ADD COLUMN destination TEXT",
|
||||
"checkout_date": "ALTER TABLE inventory_items ADD COLUMN checkout_date TEXT",
|
||||
}
|
||||
for column, statement in migrations.items():
|
||||
if column not in columns:
|
||||
try:
|
||||
connection.execute(statement)
|
||||
except sqlite3.OperationalError as error:
|
||||
if "duplicate column name" not in str(error):
|
||||
raise
|
||||
connection.execute(
|
||||
"""INSERT INTO inventory_images (item_id, filename, original_name, created_at)
|
||||
SELECT id, image_filename, image_filename, COALESCE(updated_at, datetime('now'))
|
||||
@@ -88,19 +93,6 @@ def clean(value):
|
||||
|
||||
|
||||
def item_payload(data):
|
||||
price_value = clean(data.get("price"))
|
||||
if price_value:
|
||||
try:
|
||||
price = round(float(price_value), 2)
|
||||
except ValueError:
|
||||
raise ValueError("Price must be a valid number.")
|
||||
if price < 0:
|
||||
raise ValueError("Price cannot be negative.")
|
||||
else:
|
||||
price = None
|
||||
status = clean(data.get("status")) or "Available"
|
||||
if status not in ALLOWED_STATUSES:
|
||||
raise ValueError("Status must be Available, Trashed, or Sold.")
|
||||
return {
|
||||
"name": clean(data.get("name")),
|
||||
"item_type": clean(data.get("item_type")),
|
||||
@@ -108,10 +100,10 @@ def item_payload(data):
|
||||
"model": clean(data.get("model")),
|
||||
"serial_number": clean(data.get("serial_number")) or None,
|
||||
"asset_tag": clean(data.get("asset_tag")) or None,
|
||||
"status": status,
|
||||
"status": clean(data.get("status")) or "Available",
|
||||
"location": clean(data.get("location")),
|
||||
"destination": clean(data.get("destination")),
|
||||
"price": price,
|
||||
"checkout_date": clean(data.get("checkout_date")) or None,
|
||||
"purchase_date": clean(data.get("purchase_date")) or None,
|
||||
"notes": clean(data.get("notes")),
|
||||
"cpu": clean(data.get("cpu")),
|
||||
@@ -253,9 +245,9 @@ def summary():
|
||||
with get_db() as connection:
|
||||
total = connection.execute("SELECT COUNT(*) FROM inventory_items").fetchone()[0]
|
||||
available = connection.execute("SELECT COUNT(*) FROM inventory_items WHERE status = 'Available'").fetchone()[0]
|
||||
trashed = connection.execute("SELECT COUNT(*) FROM inventory_items WHERE status = 'Trashed'").fetchone()[0]
|
||||
sold = connection.execute("SELECT COUNT(*) FROM inventory_items WHERE status = 'Sold'").fetchone()[0]
|
||||
return jsonify({"total": total, "available": available, "trashed": trashed, "sold": sold})
|
||||
checked_out = connection.execute("SELECT COUNT(*) FROM inventory_items WHERE status = 'Checked out'").fetchone()[0]
|
||||
maintenance = connection.execute("SELECT COUNT(*) FROM inventory_items WHERE status = 'Maintenance'").fetchone()[0]
|
||||
return jsonify({"total": total, "available": available, "checked_out": checked_out, "maintenance": maintenance})
|
||||
|
||||
|
||||
@app.get("/api/backup")
|
||||
@@ -292,10 +284,7 @@ def restore():
|
||||
|
||||
@app.post("/api/items")
|
||||
def create_item():
|
||||
try:
|
||||
data = item_payload(request_data())
|
||||
except ValueError as error:
|
||||
return jsonify({"error": str(error)}), 400
|
||||
data = item_payload(request_data())
|
||||
if not data["name"] or not data["item_type"]:
|
||||
return jsonify({"error": "Name and type are required."}), 400
|
||||
selected_files = [image for image in files_from_request() if image and image.filename]
|
||||
@@ -310,7 +299,7 @@ def create_item():
|
||||
with get_db() as connection:
|
||||
cursor = connection.execute(
|
||||
"""INSERT INTO inventory_items
|
||||
(name, item_type, brand, model, serial_number, asset_tag, status, location, destination, price, purchase_date, notes, cpu, ram, gpu, storage, media_format, created_at, updated_at)
|
||||
(name, item_type, brand, model, serial_number, asset_tag, status, location, destination, checkout_date, purchase_date, notes, cpu, ram, gpu, storage, media_format, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(*data.values(), now, now),
|
||||
)
|
||||
@@ -327,10 +316,7 @@ def create_item():
|
||||
|
||||
@app.put("/api/items/<int:item_id>")
|
||||
def update_item(item_id):
|
||||
try:
|
||||
data = item_payload(request_data())
|
||||
except ValueError as error:
|
||||
return jsonify({"error": str(error)}), 400
|
||||
data = item_payload(request_data())
|
||||
if not data["name"] or not data["item_type"]:
|
||||
return jsonify({"error": "Name and type are required."}), 400
|
||||
data["updated_at"] = datetime.now(timezone.utc).isoformat()
|
||||
@@ -346,7 +332,7 @@ def update_item(item_id):
|
||||
return jsonify({"error": "Each inventory item can have up to 5 pictures."}), 400
|
||||
saved_images = save_images(new_images)
|
||||
result = connection.execute(
|
||||
"""UPDATE inventory_items SET name=?, item_type=?, brand=?, model=?, serial_number=?, asset_tag=?, status=?, location=?, destination=?, price=?, purchase_date=?, notes=?, cpu=?, ram=?, gpu=?, storage=?, media_format=?, updated_at=? WHERE id=?""",
|
||||
"""UPDATE inventory_items SET name=?, item_type=?, brand=?, model=?, serial_number=?, asset_tag=?, status=?, location=?, destination=?, checkout_date=?, purchase_date=?, notes=?, cpu=?, ram=?, gpu=?, storage=?, media_format=?, updated_at=? WHERE id=?""",
|
||||
(*data.values(), item_id),
|
||||
)
|
||||
for filename, original_name in saved_images:
|
||||
|
||||
Reference in New Issue
Block a user