diff --git a/app/routes/api_v1.py b/app/routes/api_v1.py index d0852a4a..8aa03e97 100644 --- a/app/routes/api_v1.py +++ b/app/routes/api_v1.py @@ -1536,7 +1536,7 @@ def update_invoice(invoice_id): current_app.logger.warning(f"Invalid tax_rate value in invoice update: {data.get('tax_rate')} - {e}") if "amount_paid" in data: try: - from decimal import Decimal + from decimal import Decimal, InvalidOperation update_kwargs["amount_paid"] = Decimal(str(data["amount_paid"])) except (ValueError, TypeError, InvalidOperation) as e: diff --git a/app/routes/custom_reports.py b/app/routes/custom_reports.py index 7e3a3d42..9f46317c 100644 --- a/app/routes/custom_reports.py +++ b/app/routes/custom_reports.py @@ -2,7 +2,7 @@ Routes for custom report builder. """ -from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify +from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, current_app from flask_babel import gettext as _ from flask_login import login_required, current_user from app import db diff --git a/app/routes/integrations.py b/app/routes/integrations.py index 9683ae37..c55361bd 100644 --- a/app/routes/integrations.py +++ b/app/routes/integrations.py @@ -317,6 +317,8 @@ def manage_integration(provider): # Per-user integration integration = Integration.query.filter_by(provider=provider, user_id=current_user.id, is_global=False).first() + user_integration = None if is_global else integration + # Handle POST (OAuth credential updates - admin only for global integrations) if request.method == "POST": if is_global and not current_user.is_admin: diff --git a/app/routes/invoice_approvals.py b/app/routes/invoice_approvals.py index 070d9cd6..42caa1c4 100644 --- a/app/routes/invoice_approvals.py +++ b/app/routes/invoice_approvals.py @@ -2,7 +2,7 @@ Routes for invoice approval workflow. """ -from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify +from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, current_app from flask_babel import gettext as _ from flask_login import login_required, current_user from app.models import Invoice, InvoiceApproval, User diff --git a/app/routes/invoices.py b/app/routes/invoices.py index fa4896c7..61db731f 100644 --- a/app/routes/invoices.py +++ b/app/routes/invoices.py @@ -1073,8 +1073,8 @@ def export_invoice_ubl(invoice_id): svc = PeppolService() sender = svc._get_sender_party() - recipient_party, _, _ = svc._get_recipient_party(invoice) - ubl_xml, _ = build_peppol_ubl_invoice_xml(invoice=invoice, supplier=sender, customer=recipient_party) + recipient_party, _ign, _ign = svc._get_recipient_party(invoice) + ubl_xml, _ign = build_peppol_ubl_invoice_xml(invoice=invoice, supplier=sender, customer=recipient_party) fn = f"invoice_{invoice.invoice_number}.xml" return Response(ubl_xml, mimetype="application/xml", headers={"Content-Disposition": f"attachment; filename={fn}"}) except ValueError as e: diff --git a/app/routes/reports.py b/app/routes/reports.py index bb17fbec..c7b872f5 100644 --- a/app/routes/reports.py +++ b/app/routes/reports.py @@ -1,4 +1,4 @@ -from flask import Blueprint, render_template, request, redirect, url_for, flash, send_file, jsonify +from flask import Blueprint, render_template, request, redirect, url_for, flash, send_file, jsonify, current_app from flask_login import login_required, current_user from flask_babel import _ from app import db, log_event, track_event diff --git a/app/routes/scheduled_reports.py b/app/routes/scheduled_reports.py index 80264a57..7e76c103 100644 --- a/app/routes/scheduled_reports.py +++ b/app/routes/scheduled_reports.py @@ -2,7 +2,7 @@ Routes for scheduled reports management. """ -from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify +from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, current_app from flask_babel import gettext as _ from flask_login import login_required, current_user from app.models import SavedReportView, ReportEmailSchedule diff --git a/app/routes/tasks.py b/app/routes/tasks.py index 614b4c04..fb124741 100644 --- a/app/routes/tasks.py +++ b/app/routes/tasks.py @@ -1,6 +1,6 @@ import re -from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, make_response, Response +from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, make_response, Response, current_app from flask_babel import gettext as _ from flask_login import login_required, current_user import app as app_module diff --git a/app/utils/data_import.py b/app/utils/data_import.py index e00c48ba..648c75e8 100644 --- a/app/utils/data_import.py +++ b/app/utils/data_import.py @@ -4,6 +4,7 @@ Data import utilities for importing time tracking data from various sources import json import csv +import logging import requests from datetime import datetime, timedelta from io import StringIO @@ -12,6 +13,8 @@ from app import db from app.models import User, Project, TimeEntry, Task, Client, Expense, ExpenseCategory, Contact from app.utils.db import safe_commit +logger = logging.getLogger(__name__) + class ImportError(Exception): """Custom exception for import errors""" diff --git a/app/utils/excel_export.py b/app/utils/excel_export.py index 87c5fbff..7ca4ade8 100644 --- a/app/utils/excel_export.py +++ b/app/utils/excel_export.py @@ -1,12 +1,15 @@ """Excel export utilities for reports and data export""" import io +import logging from datetime import datetime from openpyxl import Workbook from openpyxl.styles import Font, Alignment, PatternFill, Border, Side from openpyxl.utils import get_column_letter from app.utils.timezone import convert_app_datetime_to_user +logger = logging.getLogger(__name__) + def create_time_entries_excel(entries, filename_prefix="timetracker_export"): """Create Excel file from time entries diff --git a/migrations/versions/116_merge_three_heads.py b/migrations/versions/116_merge_three_heads.py new file mode 100644 index 00000000..e2b1e42b --- /dev/null +++ b/migrations/versions/116_merge_three_heads.py @@ -0,0 +1,29 @@ +"""Merge three migration heads into one + +Revision ID: 116_merge_three_heads +Revises: 090_add_push_subscriptions, 100_gantt_colors_modules, 115_add_exclude_weekends +Create Date: 2026-01-25 + +Merge revision to resolve multiple heads: +- 090_add_push_subscriptions +- 100_gantt_colors_modules +- 115_add_exclude_weekends +""" +from alembic import op + + +# revision identifiers, used by Alembic. +revision = '116_merge_three_heads' +down_revision = ('090_add_push_subscriptions', '100_gantt_colors_modules', '115_add_exclude_weekends') +branch_labels = None +depends_on = None + + +def upgrade(): + """No schema changes - merge only.""" + pass + + +def downgrade(): + """No schema changes - merge only.""" + pass