from __future__ import annotations from datetime import date from decimal import Decimal from flask import Blueprint, abort, jsonify, request from ..extensions import db from ..models import AppSetting, Category, Expense, User from ..services.audit import log_action api_bp = Blueprint('api', __name__, url_prefix='/api') def _require_webhook_token() -> None: token = (request.headers.get('X-Webhook-Token') or '').strip() expected = AppSetting.get('webhook_api_token', '') or '' if not expected or token != expected: abort(403) @api_bp.route('/webhooks/expenses', methods=['POST']) def webhook_expenses(): _require_webhook_token() payload = request.get_json(silent=True) or {} if not payload: abort(400) email = (payload.get('user_email') or '').strip().lower() user = User.query.filter_by(email=email, is_active_user=True).first() if not user: abort(404) category = None if payload.get('category_key'): category = Category.query.filter_by(key=str(payload['category_key']).strip().lower(), is_active=True).first() amount = Decimal(str(payload.get('amount', '0'))) expense = Expense( user_id=user.id, title=(payload.get('title') or payload.get('vendor') or 'Webhook expense')[:255], vendor=(payload.get('vendor') or '')[:255], description=(payload.get('description') or '')[:2000], amount=amount, currency=(payload.get('currency') or user.default_currency or 'PLN')[:10], purchase_date=date.fromisoformat(payload.get('purchase_date') or date.today().isoformat()), payment_method=(payload.get('payment_method') or 'card')[:20], tags=(payload.get('tags') or '')[:255], recurring_period=(payload.get('recurring_period') or 'none')[:20], status=(payload.get('status') or 'confirmed')[:20], is_business=bool(payload.get('is_business')), is_refund=bool(payload.get('is_refund')), category_id=category.id if category else None, ocr_status='webhook', ) db.session.add(expense) db.session.commit() log_action('expense_webhook_created', 'expense', expense.id, user_email=user.email) db.session.commit() return jsonify({'status': 'ok', 'expense_id': expense.id})