import datetime from flask import Blueprint, request, jsonify from flask_jwt_extended import jwt_required, get_jwt_identity from .database import db, ConsumptionRecord, MilkBatch, User from .utils import convert_volume consumption_bp = Blueprint('consumption', __name__, url_prefix='/api/consumption') @consumption_bp.route('', methods=['POST']) @jwt_required() def record_consumption(): current_user_id = get_jwt_identity() data = request.get_json() if not data: return jsonify({"error": "Request must be JSON"}), 400 batch_id = data.get('milkBatchId') amount_str = data.get('amountConsumed') unit = data.get('unitConsumed') # 'ml', 'L', 'items' consumed_at_str = data.get('dateConsumed', datetime.datetime.utcnow().isoformat()) # --- Validation --- if not batch_id or amount_str is None or not unit: return jsonify({"error": "Missing fields: milkBatchId, amountConsumed, unitConsumed"}), 400 if unit not in ['ml', 'L', 'items']: return jsonify({"error": "Invalid unitConsumed."}), 400 try: amount = float(amount_str) if amount <= 0: raise ValueError("Amount must be positive.") except (ValueError, TypeError): return jsonify({"error": "Invalid number format for amountConsumed."}), 400 try: # Attempt to parse date, fallback to now if invalid format consumed_time = datetime.datetime.fromisoformat(consumed_at_str.replace('Z', '+00:00')) except ValueError: consumed_time = datetime.datetime.utcnow() # --- Find Batch & Check Status --- batch = MilkBatch.query.filter_by(id=batch_id, user_id=current_user_id, is_deleted=False).first() if not batch: return jsonify({"error": "Milk batch not found or invalid."}), 404 if batch.remaining_volume < 0.001: return jsonify({"error": "Selected milk batch is empty."}), 400 if batch.expiry_date < datetime.date.today(): # Optionally warn or prevent consuming expired? For now, allow but maybe log. print(f"Warning: Consuming from expired batch {batch_id}") # --- Calculate Consumed Volume in Batch's Unit --- try: consumed_volume_in_batch_unit = 0 if unit == 'items': consumed_volume_in_batch_unit = amount * batch.volume_per_item elif unit == batch.volume_unit: consumed_volume_in_batch_unit = amount else: # Convert (e.g., L consumed from ml batch) consumed_volume_in_batch_unit = convert_volume(amount, unit, batch.volume_unit) # --- Check Availability & Update --- # Use tolerance for float comparison if consumed_volume_in_batch_unit > (batch.remaining_volume + 0.001): return jsonify({"error": f"Not enough milk. Only {batch.remaining_volume:.2f} {batch.volume_unit} left."}), 400 batch.remaining_volume -= consumed_volume_in_batch_unit batch.remaining_volume = max(0, batch.remaining_volume) # Prevent going negative # --- Record Consumption --- new_record = ConsumptionRecord( user_id=current_user_id, milk_batch_id=batch_id, amount_consumed=amount, # Log the originally entered amount/unit unit_consumed=unit, consumed_at=consumed_time ) db.session.add(new_record) db.session.commit() # Return updated batch state return jsonify(batch.to_dict()), 201 except (ValueError, TypeError) as e: db.session.rollback() return jsonify({"error": f"Invalid input or calculation error: {e}"}), 400 except Exception as e: db.session.rollback() print(f"Error recording consumption: {e}") return jsonify({"error": "Database error occurred."}), 500 @consumption_bp.route('', methods=['GET']) @jwt_required() def get_consumption_history(): current_user_id = get_jwt_identity() # Add pagination later if needed limit = request.args.get('limit', 50, type=int) offset = request.args.get('offset', 0, type=int) records = ConsumptionRecord.query.filter_by(user_id=current_user_id)\ .order_by(ConsumptionRecord.consumed_at.desc())\ .limit(limit).offset(offset).all() return jsonify([record.to_dict() for record in records]), 200