Infrastructure: Implement master/dev/vX branching, save git path, and fix username casing

This commit is contained in:
Daniel Bedeleanu
2026-04-10 21:51:22 +03:00
parent 93edcc261b
commit 8a3783c7e9
3397 changed files with 57402 additions and 98 deletions

View File

@@ -1,4 +1,5 @@
from fastapi import APIRouter, Depends, HTTPException, status
from typing import List
from sqlalchemy.orm import Session
from .. import models, schemas
from ..database import get_db
@@ -76,12 +77,13 @@ def trash_item(op: schemas.TrashOperationCreate, db: Session = Depends(get_db)):
# Update quantity
item.quantity -= op.quantity
# Create Mandatory Audit Log with TRASH action and reason
# Create Mandatory Audit Log with TRASH action and reason in details
audit = models.AuditLog(
user_id=op.user_id,
action=f"TRASH: {op.reason}",
action="TRASH",
target_item_id=item.id,
quantity_change=-op.quantity
quantity_change=-op.quantity,
details=op.reason
)
db.add(audit)
@@ -122,3 +124,81 @@ def bulk_check_out(bulk_op: schemas.BulkOperationCreate, db: Session = Depends(g
db.commit()
return results
@router.post("/bulk-sync")
def bulk_sync(payload: schemas.SyncPayload, db: Session = Depends(get_db)):
results = {"success": [], "errors": []}
for op in payload.operations:
try:
# DEDUPLICATION CHECK: If this UUID already exists, skip it
if op.uuid:
existing = db.query(models.AuditLog).filter(models.AuditLog.uuid == op.uuid).first()
if existing:
results["success"].append({"barcode": op.barcode, "type": op.type, "note": "Already synced"})
continue
item = db.query(models.Item).filter(models.Item.barcode == op.barcode).first()
if not item:
results["errors"].append({"barcode": op.barcode, "error": "Item not found"})
continue
if op.type == "CHECK_IN":
item.quantity += op.quantity
change = op.quantity
elif op.type == "CHECK_OUT" or op.type == "TRASH":
if item.quantity < op.quantity:
results["errors"].append({"barcode": op.barcode, "error": f"Insufficient stock (Available: {item.quantity})"})
continue
item.quantity -= op.quantity
change = -op.quantity
else:
results["errors"].append({"barcode": op.barcode, "error": f"Invalid operation type: {op.type}"})
continue
# Log audit with original offline timestamp and UUID
audit = models.AuditLog(
user_id=payload.user_id,
action=op.type,
target_item_id=item.id,
quantity_change=change,
timestamp=op.timestamp,
uuid=op.uuid,
details="Offline Synchronization"
)
db.add(audit)
results["success"].append({"barcode": op.barcode, "type": op.type})
except Exception as e:
results["errors"].append({"barcode": op.barcode, "error": str(e)})
db.commit()
return results
@router.get("/logs", response_model=List[schemas.AuditLogResponse])
def get_logs(limit: int = 50, db: Session = Depends(get_db)):
# Join with User to get the username directly
logs_with_users = db.query(
models.AuditLog.id,
models.AuditLog.timestamp,
models.AuditLog.user_id,
models.User.username,
models.AuditLog.action,
models.AuditLog.target_item_id,
models.AuditLog.quantity_change,
models.AuditLog.details
).join(models.User, models.AuditLog.user_id == models.User.id).order_by(models.AuditLog.timestamp.desc()).limit(limit).all()
# Mapper to dictionary for Pydantic
return [
{
"id": l.id,
"timestamp": l.timestamp,
"user_id": l.user_id,
"username": l.username,
"action": l.action,
"target_item_id": l.target_item_id,
"quantity_change": l.quantity_change,
"details": l.details
} for l in logs_with_users
]