#!/usr/bin/env python3 from flask import Flask, request, jsonify, redirect, send_file import sqlite3 import os import requests import csv import io app = Flask(__name__) DB_FILE = '/home/h3r7/depenses_trello/depenses.db' def init_db(): conn = sqlite3.connect(DB_FILE) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS depenses ( id INTEGER PRIMARY KEY AUTOINCREMENT, prenom TEXT, date TEXT, libelle TEXT, montant REAL, status TEXT DEFAULT 'En attente', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') c.execute('''CREATE TABLE IF NOT EXISTS config ( key TEXT PRIMARY KEY, value TEXT )''') c.execute('''CREATE TABLE IF NOT EXISTS prenoms ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE )''') conn.commit() conn.close() def get_db(): conn = sqlite3.connect(DB_FILE) conn.row_factory = sqlite3.Row return conn init_db() def parse_date(d): if not d: return "" if "/" in d: parts = d.split("/") if len(parts) == 3: return f"{parts[2]}-{parts[1]}-{parts[0]}" return d @app.route('/') def index(): with open('/home/h3r7/depenses_trello/templates/index.html', 'r') as f: return f.read() @app.route('/dashboard') def dashboard(): with open('/home/h3r7/depenses_trello/templates/dashboard.html', 'r') as f: return f.read() # API Config @app.route('/api/config') def get_config(): conn = get_db() c = conn.cursor() # Get prenoms c.execute('SELECT name FROM prenoms') prenoms = [row[0] for row in c.fetchall()] # Get format c.execute("SELECT value FROM config WHERE key='format'") format_row = c.fetchone() format_val = format_row[0] if format_row else '{prenom} - {date} - {libelle} - {montant}€' # Get trello config c.execute("SELECT value FROM config WHERE key='trello'") trello_row = c.fetchone() trello = {} if trello_row: import json trello = json.loads(trello_row[0]) # Get categories c.execute("SELECT value FROM config WHERE key='categories'") cat_row = c.fetchone() categories = cat_row[0].split(',') if cat_row else ['Courses', 'Essence', 'Loisirs', 'Maison', 'Santé', 'Transport', 'Autre'] conn.close() return jsonify({ 'format': format_val, 'prenoms': prenoms, 'categories': categories, 'trello': trello }) # Add depense @app.route('/api/add', methods=['POST']) def add_depense(): conn = get_db() c = conn.cursor() c.execute('INSERT INTO depenses (prenom, date, libelle, montant, status, category) VALUES (?, ?, ?, ?, ?, ?)', (request.form.get('prenom'), parse_date(request.form.get('date', '')), request.form.get('libelle'), float(request.form.get('montant', 0)), 'En attente', request.form.get('category', 'Autre'))) conn.commit() conn.close() return redirect('/?page=saisie') # Get depenses @app.route('/api/depenses') def get_depenses(): conn = get_db() c = conn.cursor() c.execute('SELECT id, prenom, date, libelle, montant, status, category FROM depenses ORDER BY date DESC') rows = c.fetchall() conn.close() return jsonify([dict(row) for row in rows]) # Delete depense @app.route('/api/del/') def delete_depense(id): conn = get_db() c = conn.cursor() c.execute('DELETE FROM depenses WHERE id=?', (id,)) conn.commit() conn.close() return redirect('/?page=saisie') # Clear all @app.route('/api/clear', methods=['POST']) def clear_depenses(): conn = get_db() c = conn.cursor() c.execute('DELETE FROM depenses') conn.commit() conn.close() return jsonify({'success': True}) # Export CSV @app.route('/api/export') def export_csv(): conn = get_db() c = conn.cursor() c.execute('SELECT prenom, date, libelle, montant, status FROM depenses ORDER BY date DESC') rows = c.fetchall() conn.close() output = io.StringIO() writer = csv.writer(output) writer.writerow(['prenom', 'date', 'libelle', 'montant', 'status']) for row in rows: writer.writerow(row) output.seek(0) return send_file( io.BytesIO(output.getvalue().encode('utf-8')), mimetype='text/csv', as_attachment=True, download_name='depenses_2026.csv' ) # Import CSV @app.route('/api/import', methods=['POST']) def import_csv(): if 'file' not in request.files: return jsonify({'error': 'Aucun fichier'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': 'Fichier vide'}), 400 try: content = file.read().decode('utf-8') reader = csv.reader(content.splitlines()) next(reader) conn = get_db() c = conn.cursor() imported = 0 for row in reader: if len(row) >= 4: c.execute('INSERT INTO depenses (prenom, date, libelle, montant, status) VALUES (?, ?, ?, ?, ?)', (row[0].strip(), row[1].strip(), row[2].strip(), float(row[3]) if row[3] else 0, row[4].strip() if len(row) > 4 else 'En attente')) imported += 1 conn.commit() conn.close() return jsonify({'success': True, 'imported': imported}) except Exception as e: return jsonify({'error': str(e)}), 400 # Send ONE to Trello @app.route('/api/trello/send_one/', methods=['POST']) def send_one(id): conn = get_db() c = conn.cursor() c.execute("SELECT value FROM config WHERE key='trello'") trello_row = c.fetchone() if not trello_row: conn.close() return jsonify({'error': 'Config Trello manquante'}), 400 import json t = json.loads(trello_row[0]) if not t.get('api_key') or not t.get('token') or not t.get('list_id'): conn.close() return jsonify({'error': 'Config Trello incomplète'}), 400 c.execute('SELECT * FROM depenses WHERE id=?', (id,)) d = c.fetchone() if not d: conn.close() return jsonify({'error': 'Dépense non trouvée'}), 404 if d['status'] == 'Envoyé ✅': conn.close() return jsonify({'error': 'Déjà envoyé'}), 400 # Generate text c.execute("SELECT value FROM config WHERE key='format'") format_row = c.fetchone() template = format_row[0] if format_row else '{prenom} - {date} - {libelle} - {montant}€' ddate = d['date'] or '' if ddate: ddate = '/'.join(ddate.split('-')[::-1]) line = template line = line.replace('{prenom}', d['prenom'] or '') line = line.replace('{date}', ddate) line = line.replace('{libelle}', d['libelle'] or '') line = line.replace('{montant}', str(d['montant'])) # Send to Trello url = 'https://api.trello.com/1/cards' params = { 'key': t.get('api_key'), 'token': t.get('token'), 'idList': t.get('list_id'), 'name': line, 'desc': line } try: r = requests.post(url, params=params) if r.status_code == 200: c.execute('UPDATE depenses SET status=? WHERE id=?', ('Envoyé ✅', id)) conn.commit() conn.close() return jsonify({'success': True}) conn.close() return jsonify({'error': r.text}), r.status_code except Exception as e: conn.close() return jsonify({'error': str(e)}), 500 # Generate text (all) @app.route('/api/generate', methods=['POST']) def generate_text(): conn = get_db() c = conn.cursor() c.execute("SELECT value FROM config WHERE key='format'") format_row = c.fetchone() template = format_row[0] if format_row else '{prenom} - {date} - {libelle} - {montant}€' conn.close() data = request.json lines = [] for d in data.get('depenses', []): line = template ddate = d.get('date', '') or '' if ddate: ddate = '/'.join(ddate.split('-')[::-1]) line = line.replace('{prenom}', d.get('prenom', '')) line = line.replace('{date}', ddate) line = line.replace('{libelle}', d.get('libelle', '')) line = line.replace('{montant}', str(d.get('montant', 0))) lines.append(line) return jsonify({'text': '\n'.join(lines)}) # Add prenom @app.route('/api/prenom/add', methods=['POST']) def add_prenom(): conn = get_db() c = conn.cursor() prenom = request.form.get('prenom', '').strip() if prenom: try: c.execute('INSERT INTO prenoms (name) VALUES (?)', (prenom,)) conn.commit() except: pass conn.close() return redirect('/?page=config') # Del prenom @app.route('/api/prenom/del/') def del_prenom(idx): conn = get_db() c = conn.cursor() c.execute('DELETE FROM prenoms WHERE id=?', (idx+1,)) conn.commit() conn.close() return redirect('/?page=config') # Save format @app.route('/api/format', methods=['POST']) def save_format(): conn = get_db() c = conn.cursor() format_val = request.form.get('format', '{prenom} - {date} - {libelle} - {montant}€') c.execute('INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)', ('format', format_val)) conn.commit() conn.close() return redirect('/?page=config') # Save trello config @app.route('/api/trello/save', methods=['POST']) def save_trello(): import json conn = get_db() c = conn.cursor() t = json.dumps({ 'api_key': request.form.get('api_key', ''), 'token': request.form.get('token', ''), 'list_id': request.form.get('list_id', '') }) c.execute('INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)', ('trello', t)) conn.commit() conn.close() return redirect('/?page=config') if __name__ == '__main__': app.run(host='0.0.0.0', port=8769, debug=False)