v1.1 - Import/Export CSV, 17 dépenses restaurées
This commit is contained in:
79
app.py
79
app.py
@@ -1,8 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
from flask import Flask, request, jsonify, redirect
|
||||
from flask import Flask, request, jsonify, redirect, send_file
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
import csv
|
||||
import io
|
||||
|
||||
app = Flask(__name__)
|
||||
CONFIG_FILE = '/home/h3r7/depenses_trello/config.json'
|
||||
@@ -73,6 +75,73 @@ def clear_depenses():
|
||||
save_config(config)
|
||||
return jsonify({'success': True})
|
||||
|
||||
# Export CSV
|
||||
@app.route('/api/export')
|
||||
def export_csv():
|
||||
config = load_config()
|
||||
depenses = config.get('depenses', [])
|
||||
|
||||
output = io.StringIO()
|
||||
writer = csv.writer(output)
|
||||
writer.writerow(['prenom', 'date', 'libelle', 'montant', 'status'])
|
||||
|
||||
for d in depenses:
|
||||
writer.writerow([
|
||||
d.get('prenom', ''),
|
||||
d.get('date', ''),
|
||||
d.get('libelle', ''),
|
||||
d.get('montant', 0),
|
||||
d.get('status', '')
|
||||
])
|
||||
|
||||
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) # Skip header
|
||||
|
||||
config = load_config()
|
||||
if 'depenses' not in config:
|
||||
config['depenses'] = []
|
||||
|
||||
max_id = max([d.get('id', 0) for d in config.get('depenses', [])], default=0)
|
||||
|
||||
imported = 0
|
||||
for row in reader:
|
||||
if len(row) >= 4:
|
||||
max_id += 1
|
||||
config['depenses'].append({
|
||||
'id': max_id,
|
||||
'prenom': row[0].strip(),
|
||||
'date': row[1].strip(),
|
||||
'libelle': row[2].strip(),
|
||||
'montant': float(row[3]) if row[3] else 0,
|
||||
'status': row[4].strip() if len(row) > 4 else 'En attente'
|
||||
})
|
||||
imported += 1
|
||||
|
||||
save_config(config)
|
||||
return jsonify({'success': True, 'imported': imported})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 400
|
||||
|
||||
# Generate text for ONE expense
|
||||
@app.route('/api/generate_one/<int:id>', methods=['GET'])
|
||||
def generate_one(id):
|
||||
@@ -104,7 +173,6 @@ def send_one(id):
|
||||
if not t.get('api_key') or not t.get('token') or not t.get('list_id'):
|
||||
return jsonify({'error': 'Config Trello manquante'}), 400
|
||||
|
||||
# Find the expense
|
||||
d = None
|
||||
for exp in config.get('depenses', []):
|
||||
if exp.get('id') == id:
|
||||
@@ -114,11 +182,9 @@ def send_one(id):
|
||||
if not d:
|
||||
return jsonify({'error': 'Dépense non trouvée'}), 404
|
||||
|
||||
# Skip if already sent
|
||||
if d.get('status') == 'Envoyé ✅':
|
||||
return jsonify({'error': 'Déjà envoyé'}), 400
|
||||
|
||||
# Generate text
|
||||
template = config.get('format', '{prenom} - {date} - {libelle} - {montant}€')
|
||||
line = template
|
||||
ddate = d.get('date', '') or ''
|
||||
@@ -129,7 +195,6 @@ def send_one(id):
|
||||
line = line.replace('{libelle}', d.get('libelle', ''))
|
||||
line = line.replace('{montant}', str(d.get('montant', 0)))
|
||||
|
||||
# Send to Trello
|
||||
url = 'https://api.trello.com/1/cards'
|
||||
params = {
|
||||
'key': t.get('api_key'),
|
||||
@@ -141,7 +206,6 @@ def send_one(id):
|
||||
try:
|
||||
r = requests.post(url, params=params)
|
||||
if r.status_code == 200:
|
||||
# Mark as sent
|
||||
for exp in config.get('depenses', []):
|
||||
if exp.get('id') == id:
|
||||
exp['status'] = 'Envoyé ✅'
|
||||
@@ -159,11 +223,9 @@ def send_trello():
|
||||
if not t.get('api_key') or not t.get('token') or not t.get('list_id'):
|
||||
return jsonify({'error': 'Config Trello manquante'}), 400
|
||||
|
||||
# Send only pending expenses
|
||||
sent_count = 0
|
||||
for d in config.get('depenses', []):
|
||||
if d.get('status') == 'En attente':
|
||||
# Generate text
|
||||
template = config.get('format', '{prenom} - {date} - {libelle} - {montant}€')
|
||||
line = template
|
||||
ddate = d.get('date', '') or ''
|
||||
@@ -174,7 +236,6 @@ def send_trello():
|
||||
line = line.replace('{libelle}', d.get('libelle', ''))
|
||||
line = line.replace('{montant}', str(d.get('montant', 0)))
|
||||
|
||||
# Send to Trello
|
||||
url = 'https://api.trello.com/1/cards'
|
||||
params = {
|
||||
'key': t.get('api_key'),
|
||||
|
||||
Reference in New Issue
Block a user