', methods=['GET', 'PUT', 'DELETE'])
@login_required
@@ -829,6 +869,15 @@ def service_record_operations(vehicle_id, record_id):
return jsonify({'message': 'Service record updated successfully'})
elif request.method == 'DELETE':
+ # Clean up attachment if it exists
+ if record.document_path:
+ try:
+ full_path = os.path.join('/app/uploads', record.document_path)
+ if os.path.exists(full_path):
+ os.remove(full_path)
+ except Exception as e:
+ print(f"Failed to delete attachment: {e}")
+
db.session.delete(record)
db.session.commit()
return jsonify({'message': 'Service record deleted successfully'})
@@ -847,7 +896,8 @@ def fuel_record_operations(vehicle_id, record_id):
'odometer': record.odometer,
'fuel_amount': record.fuel_amount,
'cost': record.cost,
- 'notes': record.notes or ''
+ 'notes': record.notes or '',
+ 'document_path': record.document_path or ''
})
elif request.method == 'PUT':
@@ -857,10 +907,20 @@ def fuel_record_operations(vehicle_id, record_id):
record.fuel_amount = data.get('fuel_amount', record.fuel_amount)
record.cost = data.get('cost', record.cost)
record.notes = data.get('notes', record.notes)
+ record.document_path = data.get('document_path', record.document_path)
db.session.commit()
return jsonify({'message': 'Fuel record updated successfully'})
elif request.method == 'DELETE':
+ # Clean up attachment if it exists
+ if record.document_path:
+ try:
+ full_path = os.path.join('/app/uploads', record.document_path)
+ if os.path.exists(full_path):
+ os.remove(full_path)
+ except Exception as e:
+ print(f"Failed to delete attachment: {e}")
+
db.session.delete(record)
db.session.commit()
return jsonify({'message': 'Fuel record deleted successfully'})
@@ -897,3 +957,8 @@ def reminder_operations(vehicle_id, reminder_id):
db.session.delete(reminder)
db.session.commit()
return jsonify({'message': 'Reminder deleted successfully'})
+
+if __name__ == '__main__':
+ with app.app_context():
+ db.create_all()
+ app.run(host='0.0.0.0', port=5000, debug=False)
diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh
index 75115e3..eecbf25 100755
--- a/backend/entrypoint.sh
+++ b/backend/entrypoint.sh
@@ -14,6 +14,10 @@ echo "Initializing database..."
cd /app/backend
python init_db.py
+# Run migrations
+echo "Running database migrations..."
+python migrate_attachments.py
+
# Set database file permissions
if [ -f /app/data/masina_dock.db ]; then
chmod 666 /app/data/masina_dock.db
diff --git a/backend/migrate_attachments.py b/backend/migrate_attachments.py
new file mode 100644
index 0000000..a7fa0ef
--- /dev/null
+++ b/backend/migrate_attachments.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+"""
+Database migration script to add document_path columns to FuelRecord and RecurringExpense tables.
+This migration adds support for file attachments to fuel and tax (recurring expense) entries.
+"""
+import sqlite3
+import os
+import sys
+
+def migrate_database():
+ """Add document_path columns to FuelRecord and RecurringExpense tables."""
+ # Support both Docker and local paths
+ db_paths = [
+ '/app/data/masina_dock.db',
+ './data/masina_dock.db',
+ '../data/masina_dock.db'
+ ]
+
+ db_path = None
+ for path in db_paths:
+ if os.path.exists(path):
+ db_path = path
+ break
+
+ if not db_path:
+ print("Database does not exist yet. Migration will be applied on first run.")
+ return True
+
+ print(f"Migrating database at: {db_path}")
+
+ try:
+ conn = sqlite3.connect(db_path)
+ cursor = conn.cursor()
+
+ # Check FuelRecord table
+ cursor.execute("PRAGMA table_info(fuel_record)")
+ fuel_columns = [column[1] for column in cursor.fetchall()]
+
+ if 'document_path' not in fuel_columns:
+ print("Adding document_path column to fuel_record table...")
+ cursor.execute("ALTER TABLE fuel_record ADD COLUMN document_path VARCHAR(255)")
+ print("✓ Added document_path to fuel_record")
+ else:
+ print("✓ fuel_record.document_path already exists")
+
+ # Check RecurringExpense table
+ cursor.execute("PRAGMA table_info(recurring_expense)")
+ expense_columns = [column[1] for column in cursor.fetchall()]
+
+ if 'document_path' not in expense_columns:
+ print("Adding document_path column to recurring_expense table...")
+ cursor.execute("ALTER TABLE recurring_expense ADD COLUMN document_path VARCHAR(255)")
+ print("✓ Added document_path to recurring_expense")
+ else:
+ print("✓ recurring_expense.document_path already exists")
+
+ conn.commit()
+ print("\n✓ Database migration completed successfully!")
+ return True
+
+ except sqlite3.Error as e:
+ print(f"✗ Migration error: {e}", file=sys.stderr)
+ if conn:
+ conn.rollback()
+ return False
+ except Exception as e:
+ print(f"✗ Unexpected error: {e}", file=sys.stderr)
+ return False
+ finally:
+ if conn:
+ conn.close()
+
+if __name__ == '__main__':
+ success = migrate_database()
+ sys.exit(0 if success else 1)
diff --git a/backend/models.py b/backend/models.py
index a9967e0..c65932b 100644
--- a/backend/models.py
+++ b/backend/models.py
@@ -111,6 +111,7 @@ class FuelRecord(db.Model):
fuel_economy = db.Column(db.Float)
unit = db.Column(db.String(20), default='MPG')
notes = db.Column(db.Text)
+ document_path = db.Column(db.String(255))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
class Reminder(db.Model):
@@ -151,3 +152,4 @@ class RecurringExpense(db.Model):
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
notes = db.Column(db.Text)
+ document_path = db.Column(db.String(255))
diff --git a/frontend/static/js/app.js b/frontend/static/js/app.js
index d7afa1c..d59c1dc 100644
--- a/frontend/static/js/app.js
+++ b/frontend/static/js/app.js
@@ -254,7 +254,7 @@ function displayFuelRecords(records) {
| ${formatCurrency(r.cost, settings.currency)} |
${r.distance || 'N/A'} |
${r.fuel_economy ? r.fuel_economy.toFixed(2) : 'N/A'} ${r.unit} |
- ${r.notes && r.notes.startsWith('attachment:') ? `Download` : 'None'} |
+ ${r.document_path ? `Download` : 'None'} |
diff --git a/frontend/templates/fuel.html b/frontend/templates/fuel.html
index 9897f57..60742e7 100644
--- a/frontend/templates/fuel.html
+++ b/frontend/templates/fuel.html
@@ -100,7 +100,7 @@
-
+
Supported: PDF, Images, Text
diff --git a/frontend/templates/service_records.html b/frontend/templates/service_records.html
index db89fcc..e6b9d28 100644
--- a/frontend/templates/service_records.html
+++ b/frontend/templates/service_records.html
@@ -90,7 +90,7 @@
-
+
Suportat: PDF, Imagini, Text, Word, Excel
diff --git a/frontend/templates/taxes.html b/frontend/templates/taxes.html
index eac0f4b..230662e 100644
--- a/frontend/templates/taxes.html
+++ b/frontend/templates/taxes.html
@@ -99,7 +99,7 @@
-
+
Supported: PDF, Images, Text, Word
@@ -193,6 +193,7 @@
Frequency: ${e.frequency}
Next Due: ${formatDate(e.next_due_date)}
${e.notes || ''}
+ ${e.document_path ? ` Attachment: Download ` : ''}
@@ -291,7 +292,8 @@
amount: parseFloat(document.getElementById('tax-amount').value),
frequency: document.getElementById('tax-frequency').value,
start_date: document.getElementById('tax-date').value,
- notes: document.getElementById('tax-notes').value || null
+ notes: document.getElementById('tax-notes').value || null,
+ document_path: attachmentPath
};
try {
|