Commit Graph

259 Commits

Author SHA1 Message Date
Dries Peeters 9d4be6feec fix(admin): prefer form template_json for invoice PDF preview
When the layout editor posts template_json with the preview request,
use it instead of loading only the saved database template. Preview
then matches unsaved canvas edits and avoids stale layouts.

Normalize page width/height from the selected page size when parsing
form JSON; fall back to the stored template if the body is missing
or invalid.

Add a regression test ensuring form JSON overrides DB content.
2026-04-30 06:17:21 +02:00
Dries Peeters 887c93f00c fix(quotes): align list/detail scope with quote edit permissions
Ensure quote list/detail access uses shared quote scope resolution so users with quote-management permissions can view records they can edit, including post-edit redirects in web and API flows. Add regression coverage for non-admin edit_quotes behavior and document the scope-alignment requirement in advanced permissions docs.
2026-04-29 10:27:00 +02:00
Dries Peeters eb7b1be05f feat(i18n): add Portuguese (pt) locale and translation scaffold
Register Português in LANGUAGES and normalize pt-BR/pt-PT (and similar)
to pt in _normalize_locale so Accept-Language and stored preferences resolve
to translations/pt/.

Add translations/pt/LC_MESSAGES/messages.po seeded from English msgids;
translators can fill msgstr incrementally.

Extend i18n tests for pt presence and catalog file. Update translation
docs (TRANSLATION_SYSTEM, CONTRIBUTING_TRANSLATIONS, implementation note).
2026-04-29 06:53:24 +02:00
Dries Peeters 5d4e693a2b Add LDAP setup wizard on Integrations and admin routes
Introduce a guided LDAP configuration wizard mirroring the OIDC flow:
five-step UI with server/TLS, bind, directory layout, groups and
AUTH_METHOD, then optional connection test and .env / Docker Compose
generation for copy-paste deployment.

- Refactor LDAPService.test_connection to accept an optional config
  mapping so the wizard can test draft values without merging live env
  secrets; keep POST /admin/ldap/test on current_app.config.
- Add GET /admin/ldap/setup-wizard plus POST endpoints for test,
  validate, and generate-config (manage_settings, rate limited).
- Surface an LDAP card with status badge and wizard link on the
  integrations list for admins and manage_settings users.
- Add tests for validate, generate, and wizard test delegation.
2026-04-27 20:21:34 +02:00
Dries Peeters 6c8e86cd01 fix(timer): respect Settings.single_active_timer at runtime
Timer starts always blocked a second running entry and never read the\nadmin-controlled Settings flag.\n\n- Add TimeTrackingService.can_start_timer() using Settings.get_settings()\n  and wire it into start_timer, web timer routes, kiosk start, and\n  legacy POST /api/timer/resume.\n- POST /api/v1/timer/start returns 409 with error_code\n  timer_already_running when single-active mode is on and a timer\n  is already running.\n- Deduplicate start_timer template handling in the service.\n\nTests: tests/test_single_active_timer_setting.py.\nDocs: REST_API (responses), GETTING_STARTED, REQUIREMENTS, Docker env\nnotes, TESTING_STRATEGY, env.example comment; CHANGELOG entry.
2026-04-27 19:16:25 +02:00
Dries Peeters e34a668ddc feat(auth): add LDAP directory authentication
Introduce AUTH_METHOD values ldap and all, with LDAP_* environment settings, ldap3-based LDAPService (search, optional groupOfNames checks, user bind, DB sync), and users.auth_provider (local|oidc|ldap) via migration 153_add_user_auth_provider.

Login supports LDAP-only and combined all (local then LDAP where appropriate); OIDC callback sets auth_provider. Forgot/reset/change password flows skip LDAP-managed accounts. Admin System Settings gains a read-only LDAP summary and POST /admin/ldap/test. Production env validation requires core LDAP variables when LDAP is enabled; OIDC registration and docs recognize all.

Documentation: new docs/admin/configuration/LDAP_SETUP.md; updates to OIDC_SETUP, GETTING_STARTED, Docker guides, Render deploy notes, docs README, and CHANGELOG. Tests: tests/test_ldap_auth.py; test_oidc_logout allows auth_method all.
2026-04-27 19:08:08 +02:00
Dries Peeters 8fc823c252 feat(pwa): static manifest, root-scoped worker, offline fallback
Add app/static/manifest.json (TimeTracker / Tracker, indigo theme) and PNG install icons via scripts/generate_pwa_icons.py.

Replace inline Flask service worker with app/static/js/sw.js served at /service-worker.js for full-site scope. Cache name timetracker-v1: cache-first for /static, network-first for HTML and non-v1 /api, no interception of /api/v1/* (preserves Authorization).

Add public GET /offline and offline.html for SW navigation fallback; redirect /manifest.webmanifest to the static manifest.

Wire base.html (manifest link, theme-color #4F46E5, SW registration) and pwa-enhancements.js (ready/update/push without duplicate registration). Remove legacy app/static/service-worker.js and manifest.webmanifest.

Tests: service worker and offline routes, manifest redirect, TestPWA expectations; drop duplicate test_enhanced_ui app/client fixtures in favor of conftest.

Docs: ASSETS.md, BUILD_CONFIGURATION.md, implementation notes, and incomplete-features analysis updated for new paths.
2026-04-27 18:43:14 +02:00
Dries Peeters f2e81dfaef feat(billing): invoice all unbilled time for a client from API and UI
Add POST /api/v1/clients/{client_id}/invoice-unbilled to build one draft
invoice from completed billable time not yet on any invoice line, grouped
by project with RateOverride-based rates. Supports API tokens
(write:invoices) or a logged-in user with create_invoices; enforces client
and module access.

InvoiceService gains shared preview/state helpers and
create_client_unbilled_invoice with safe_commit and invoice webhook.

Client detail page adds a confirmation flow and redirect to the new
invoice. Document read:invoices / write:invoices and the new route in
docs/api/API_TOKEN_SCOPES.md; expose the path on the v1 discovery payload.

Tests: two-project client creates two line items; second call returns
no_unbilled_entries.
2026-04-27 18:15:24 +02:00
Dries Peeters ea913c6c4b feat(ai,security): add web AI helper, secret encryption, and 2FA
Introduce a web-first AI helper with admin-configurable providers (Ollama or hosted OpenAI-compatible), server-side context building, and confirmed write actions. Expose the feature via session /api/ai/* endpoints and scoped /api/v1/ai/* endpoints.

Harden security by requiring a strong SECRET_KEY for Docker Compose, adding optional settings encryption-at-rest (Fernet), and introducing TOTP-based 2FA plus password reset flows. Update admin UI, API docs, and install documentation.
2026-04-26 07:55:47 +02:00
Dries Peeters 89623682c8 fix(security): sandbox Jinja2 for database-backed PDF and email templates
Add render_sandboxed_string() using SandboxedEnvironment so stored invoice and
quote HTML, ReportLab text templates, admin PDF previews, and invoice email
HTML are not evaluated with Flask's full template globals (mitigating SSTI).

Add regression tests for sandbox behavior and demo user permissions.
2026-04-24 21:13:29 +02:00
Dries Peeters 568933c3b9 fix(auth): scope client portal users to their assigned client
Client-portal-enabled users (main app login, typically viewer) were not
included in get_allowed_client_ids(), so ProjectService and other callers
saw scope_client_ids=None and listed every project.

- Return [client_id] for is_client_portal_user in User.get_allowed_client_ids
- Derive get_allowed_project_ids from allowed client IDs for all non-admins
- Apply client/project scope and access checks from allowed IDs, not only
  subcontractor is_scope_restricted (fixes user_can_access_* for portal)

Fixes DRYTRIX/TimeTracker#592.

Tests: extend test_scope_filter with client_portal_scoped_user and API
isolation for GET /api/v1/projects.
2026-04-24 16:15:24 +02:00
Dries Peeters eb2f5c6afa fix(apps): harden desktop and mobile server connectivity
Desktop (Electron):
- Add two-step first-run wizard: test TimeTracker via GET /api/v1/info, then log in with API token
- Replace bogus token check with validateSession (users/me, fallback to timer/status for narrow scopes)
- Normalize base URLs; classify TLS/DNS/timeout errors; periodic 401 forces re-login
- Settings save/test use public + authenticated checks; prebuild/prestart and npm test

Server:
- Exempt /api/v1/info, /api/v1/health, and POST /api/v1/auth/login from HTML setup redirect
- Include setup_required on GET /api/v1/info for unfinished installs

Mobile (Flutter):
- Validate saved token against new server URL before persisting settings change
- Remove unused lib/core/config.dart; point BUILD_CONFIGURATION at app_config.dart

Docs: DESKTOP_SETTINGS, desktop README, mobile-desktop-apps README, REST_API /info
2026-04-16 19:59:20 +02:00
Dries Peeters 999f5c6319 feat(api): clarify /api vs /api/v1 and reduce duplication
Document the dual HTTP surface everywhere integrators look: OpenAPI intro and servers, ARCHITECTURE, REST_API, API_VERSIONING (deprecated vs internal routes, shared modules), and CONTRIBUTING (v1-first rule).

Session JSON routes in app/routes/api.py that overlap REST v1 now return X-API-Deprecated and a Link header with rel successor-version, implemented via app/utils/api_deprecation.py.

Extract shared global search into app/services/global_search_service.py for both GET /api/search and GET /api/v1/search while preserving legacy short-query 200 empty responses and v1 400 validation.

Refactor legacy POST /api/timer/start, /api/timer/stop, and the start path of /api/timer/resume to use TimeTrackingService; keep existing socketio emits for the web UI.

Add tests/test_api_deprecation_headers.py and adjust search partial-failure tests to patch Project.query on the service module.
2026-04-16 15:36:01 +02:00
Dries Peeters 7aeef629db docs(api): document value dashboard; fix project tasks API test
Document session-auth GET /api/stats/value-dashboard in REST_API.md
(response shape, last_7_days, estimated value fields, 10-minute Redis
cache). Link dashboard session JSON routes from docs/API.md and note
that /api/v1 scopes do not apply to those legacy paths.

Update the comprehensive API test so GET /api/projects/<id>/tasks is
expected to return every task status, including done and cancelled,
which matches the time-entry UI.

Changelog: record the documentation update and the test correction.
2026-04-16 15:09:03 +02:00
Dries Peeters ef9b66f5e7 fix(api): align client search, OpenAPI version, and Client construction
Global search referenced Client.company, which is not a column on Client, so client matches failed at runtime. Legacy and v1 search, plus search_clients(), now filter on name, email, description, and contact_person; result descriptions use the same fields. Legacy /api/search returns count: 0 for queries shorter than two characters so responses stay consistent.

OpenAPI info.version is taken from get_version_from_setup(), with a config fallback when the resolved version is unknown. get_version_from_setup() also honors TIMETRACKER_VERSION and APP_VERSION for CI and container builds.

Client.__init__ accepts custom_fields. ClientService no longer passes status= into Client(), which the initializer does not support.

Tests add HTTP route contract checks and OpenAPI version alignment, fix subcontractor search fixtures (Client/Task construction and v1 client fixture naming), and update related API integration tests.
2026-04-15 12:57:01 +02:00
Dries Peeters 89a8c773d6 test(api): assert legacy search respects client scope for subcontractors
Adds out_of_scope_entities fixture and a session-authenticated search test so projects, tasks, and clients from unassigned clients are excluded alongside the API v1 search scope refactor.
2026-04-15 12:15:32 +02:00
Dries Peeters 91127bf188 feat: smart in-app notifications, value dashboard stats, and search scope helpers
Smart notifications (opt-in under user settings): NotificationService builds candidates from the user's local day and active timers; GET /api/notifications and POST /api/notifications/dismiss; migration 150 adds user columns and user_smart_notification_dismissals. /api/summary/today uses the same local-day totals. Client polls from smart-notifications.js; toastManager.show gains onDismiss for server dismiss sync. Config and env.example document SMART_NOTIFY_* variables.

Value dashboard: StatsService with Redis-backed caching, GET /api/stats/value-dashboard, dashboard template and dashboard-enhancements polling alongside existing widgets.

API v1 token search now uses apply_project_scope and apply_client_scope on queries; scope_filter adds apply_project_scope; tests extended for the new helper.
2026-04-15 12:15:23 +02:00
Dries Peeters b0dde80ba9 feat(web): high-visibility support modal, prompts, and supporter UX
Add a support modal with usage stats, tier and license links, share control, and offline-safe outbound CTAs. Surface support from the header, sidebar, user menu, dashboard card, and settings "Support & Community" section without hiding entry points when a supporter license is active.

Introduce UsageStatsService and a persisted users.support_stats_reports_generated counter incremented on key report exports and custom report views. Add SupportPromptService for session-scoped soft toasts (after export, dashboard milestones, long session via POST /donate/request-soft-prompt).

Wire consent-aware track_event names support.* and mirror funnel rows in DonationInteraction; fix has_recent_donation_click to treat link_clicked as a recent click. Document events and SUPPORT_* / migration notes in docs.

Tests: tests/test_support_services.py for prompt and usage stats behavior.
2026-04-15 10:55:37 +02:00
Dries Peeters 96955aee62 feat(admin): GitHub-based version update notification for admins
Add VersionService to fetch and cache the latest GitHub release, compare it to the installed semver (APP_VERSION when valid, else setup.py), and expose admin-only GET /api/version/check and POST /api/version/dismiss on the legacy /api blueprint (session or Bearer token).

Persist per-user dismissal in users.dismissed_release_version (Alembic 148) and show a non-blocking update card in base.html for administrators. Add packaging for semver parsing and tests for comparison, service, and routes.

Document configuration in docs/admin/deployment/VERSION_MANAGEMENT.md and endpoints in docs/api/REST_API.md and docs/API.md.
2026-04-15 09:39:32 +02:00
Dries Peeters 15ddabdffb feat(quotes): reorder form rows and improve quote view i18n docs
Add Move up / Move down controls and an Order column for quote line items, Costs, and Extra goods on create and edit pages (Issue #584). DOM row order matches POST field order so existing QuoteItem.position handling stays correct.

Fix the quote detail Valid until row by using quote.is_expired instead of an undefined Jinja now() (Issue #583). Submit a past valid_until in the web regression test so the view path is exercised.

Document translation contributions without Git: add docs/CONTRIBUTING_TRANSLATIONS.md, a Translation improvement issue template, links from CONTRIBUTING.md and TRANSLATION_SYSTEM.md, and a Translations subsection in docs/development/CONTRIBUTING.md. Refresh CHANGELOG [Unreleased] for these items.
2026-04-15 07:57:10 +02:00
Dries Peeters 974f5cdd50 feat(quotes): invoice-style line items, costs, and extra goods (#585)
Add quote_items.line_kind (item | expense | good) plus display_name,
category, line_date, and sku so one table still drives totals, PDFs,
and acceptance stock logic.

- Migration 147: new columns with backfill line_kind=item
- Quote create/edit: three sections; stock and warehouse only when a
  line item is sourced from inventory; shared JS partial
- POST parsing, positions, and duplicate-quote copying for all fields
- API v1 quote items accept the new fields with defaults for old clients
- View, client portal, and PDF/fallback rendering use display_name and
  line metadata where relevant
- Integration tests: stock POST shape; expense and good line creation

Docs: extend INVENTORY_MANAGEMENT_PLAN QuoteItem and migration notes.
2026-04-12 14:00:12 +02:00
Dries Peeters c134e07e2a feat(quotes): reorder line items on create/edit (#584)
Add Move up / Move down controls and a 13-column desktop grid on quote
item rows so users can change line order without deleting entries. Order
matches persisted quote_items.position (migration 146) for PDFs and views.

Update CHANGELOG [Unreleased] with Issue #584. Fix inventory integration
test to read quote.items[0] (relationship returns a list, not a query).
2026-04-12 13:40:47 +02:00
Dries Peeters 70510a6622 fix: quote create 500, line order, and Factur-X PDF parity
Quotes (#583):
- Add requires_approval, approval_level, and can_be_sent; wire create form
- Migrations 145 (approval columns) and 146 (quote_items.position)
- Order Quote.items by position; set positions on create/edit/duplicate/API
- Fix view template approval branch (not_required); add web regression test

Invoices / PEPPOL:
- Use the same Factur-X embed and PDF/A-3 normalization for export and
  email attachments; Associated File Data + text/xml metadata
- CII/UBL validators, pdfa3, zugferd, and invoice_pdf_postprocess helper
- Bundle compact sRGB ICC (app/resources/icc/); INVOICE_SRGB_ICC_PATH override
- Package data in setup.py; extend PEPPOL_EINVOICING.md and tests
2026-04-12 13:34:58 +02:00
Dries Peeters 9449a46a42 feat(integrations): Linear connector and shared HTTP/sync helpers
- Add Linear import (GraphQL, personal API key, optional team key filter).
- Centralize integration HTTP via integration_session and session_request.
- Add integration_sync_context for project/task refs and custom_fields metadata.
- Refactor Asana, GitHub, GitLab, Jira, Trello, ActivityWatch, and QuickBooks to use helpers.
- Extend integration UI, settings, and scheduled sync behavior as needed.
2026-04-05 08:39:18 +02:00
Dries Peeters 5df748b30e feat(api): v1 CSV import, bulk time entries, idempotency, and rate limits
- Add POST /api/v1/time-entries/import-csv and POST /api/v1/time-entries/bulk.
- Support Idempotency-Key on POST /api/v1/time-entries with 24h replay per token.
- Enforce per-token minute/hour limits (Redis when available, local fallback otherwise).
- Extract bulk and CSV import logic into dedicated services; trim legacy api route surface.
2026-04-05 08:39:14 +02:00
Dries Peeters 07387ebf2e fix(tests): stabilize smoke suite for SA2 flush, auth, and admin routes
Detect SQLAlchemy 2.0 flush execution via _warn_on_events in
Settings._session_in_flush so get_settings() does not add/commit
during flush_context.execute(), avoiding ResourceClosedError in
invoice currency smoke tests.

Payment smoke tests now set a password on factory users and submit
it on login, matching local AUTH_METHOD requirements (fixes 302 to
login on /payments).

Allow HTTP 403 in test_non_admin_cannot_access_roles when the app
denies non-admins directly instead of redirecting with 200.
2026-03-28 20:07:19 +01:00
Dries Peeters 4007ee2ca8 feat(observability): add OpenTelemetry traces, OTLP metrics, and log correlation
Introduce a centralized OTel layer (app/telemetry/otel_setup.py) that reuses
the existing OTLP endpoint and token, exports traces and metrics over OTLP/HTTP,
and instruments Flask plus SQLAlchemy. Manual OTLP log export remains for base
and product analytics; log records now include trace_id, span_id, and
event_category where tracing is active.

Business spans and product metrics cover invoices, timers, reports, auth,
webhook delivery, and scheduled jobs. RED-style HTTP metrics are recorded in
after_request alongside existing Prometheus counters. ENABLE_TRACING and
ENABLE_METRICS default on when credentials exist; graceful no-op when they do not.

Privacy is preserved: user_id appears on traces only when detailed analytics is
opted in; metrics never carry user_id; _remove_pii behavior for analytics is
unchanged. Responses inject traceparent when tracing is enabled for future
browser correlation.

Tests: test_otel_integration.py and per-test reset_for_testing() in conftest
so each app factory can reinitialize OTel.
2026-03-28 17:32:18 +01:00
Dries Peeters 8228c43821 test(timer): integration tests for own-entry schedule edits (#572)
Cover GET edit form and PATCH API when the user has edit_own_time_entries
on their own entries, complementing the timer route and API changes in the
mobile shell / timer edit work.
2026-03-27 06:41:03 +01:00
evilguy4000 1b5d019560 feat(admin): persist test recipient and send invoice email template tests
Add Settings.mail_test_recipient (migration 142) and wire Admin → Email Configuration to save, load, and prefill the SMTP test recipient field.

Extract invoice email PDF/HTML building into _build_invoice_email_payload for reuse. New send_invoice_template_test_email sends a real message with subject "Invoice template test: …", reusing production rendering and PDF attachment, without updating invoice status or creating InvoiceEmail records.

Add POST /admin/email-templates/<id>/send-test (optional recipient override, optional invoice_id) and Send test email UI on template view and edit pages. Extend smoke and unit tests.
2026-03-27 06:39:16 +01:00
evilguy4000 5fd0625e3a fix(inventory): stop 500 on purchase order detail view (#576)
Purchase orders with line items crashed the detail page because the template
referenced item.stock_item without a SQLAlchemy relationship, and used
datetime.now() in Jinja where datetime was not in context.

Add PurchaseOrderItem.stock_item, pass default_received_date from the view
route, and add a regression test for viewing a PO that includes line items.
2026-03-27 06:38:47 +01:00
Dries Peeters 631f0af2fa fix(telemetry): use embedded config and add stable install identifiers
Read telemetry/sentry status in the admin dashboard from build-injected analytics defaults with env fallback, so release images correctly show OTLP configuration. Include both install_id and telemetry_fingerprint in base and detailed telemetry payloads to reliably differentiate installations, and add tests for the new fingerprint fields.
2026-03-26 18:25:10 +01:00
Dries Peeters 905f6fbd37 feat(telemetry): migrate analytics pipeline from PostHog to OTLP
Switch product and installation telemetry to OTLP/Grafana across runtime config, CI injection, docs, and tests to unify telemetry transport and simplify privacy-focused opt-in behavior.
2026-03-26 17:01:55 +01:00
Dries Peeters 4e2183caed fix(inventory): harden purchase-order creation and stock idempotency
Prevent 500s during first/parallel purchase-order creation by using collision-safe PO numbering, explicit validation, and reliable commit/error handling in web and API flows. Add regressions for purchase-order edge cases and invoice stock-reduction idempotency to catch adjacent inventory failures before release.
2026-03-26 14:52:06 +01:00
Dries Peeters 60d4d55027 feat(invoices): add fully configurable invoice number patterns
Implement issue #575 by introducing token-based invoice number patterns in settings and unifying number generation across invoice creation paths. This removes hardcoded INV/date formatting and aligns export filenames and bootstrap schemas with stored invoice numbers.
2026-03-26 14:51:55 +01:00
Dries Peeters 3654a6a5d3 feat(offline): store method, headers, and body in queue for correct POST/PUT replay
- queueForOffline now saves url, method, headers, body (replay-safe for localStorage);
  legacy items with options only still replayed via fallback
- processOfflineQueue builds fetch options from stored method/body so replayed
  requests send the same payload when back online
- Make queueForOffline async and await it in handleFetchResponse/handleFetchException
- Add tests asserting queue stores method/body and replay uses them
2026-03-16 16:44:09 +01:00
Dries Peeters 2808140e4c fix(invoices): handle and surface PEPPOL compliance check exceptions
- Catch AttributeError/KeyError/TypeError and generic Exception in PEPPOL block;
  log with exc_info and show generic warning to user so view still renders
- Avoid silent pass that hid configuration or data errors
- Add test for exception path (mock get_custom_field to raise)
2026-03-16 16:43:44 +01:00
Dries Peeters 346d7169da feat(client-portal): add report date range and CSV export
- Reports accept ?days=1-365 (default 30) for configurable date range
- ?format=csv returns CSV download (summary, hours by project, time by date)
  with same access control as reports page
- Subtitle shows 'Last N days' when date range is applied
- Add tests for days param and CSV export
2026-03-16 16:43:35 +01:00
Dries Peeters f05d772dbb feat(api): add read:inventory and write:inventory scopes for inventory-only access
- New scopes read:inventory and write:inventory; existing read/write:projects
  still grant same inventory access for backward compatibility
- require_api_token() accepts tuple of scopes (any one required); inventory
  endpoints accept (read:inventory | read:projects) and (write:inventory | write:projects)
- ApiTokenService: add new scopes to allowed list; document in API_TOKEN_SCOPES.md
- Add tests for inventory report endpoints with scope checks
2026-03-16 16:43:08 +01:00
Dries Peeters 8c2714bec3 fix(activity-feed): validate date params and return 400 for invalid API input
- /api/activity: return 400 with clear message when start_date/end_date
  are not valid ISO 8601; avoid silent pass on parse errors
- Web route /activity: catch ValueError, log and skip filter instead of 500
- Add tests for invalid date formats on API and web routes
2026-03-16 16:42:53 +01:00
Dries Peeters 7e059a0a52 feat(jira): add optional webhook signature verification (HMAC-SHA256)
- When webhook_secret is set in Jira integration, verify incoming webhooks
  via X-Hub-Signature-256, X-Atlassian-Webhook-Signature, or X-Hub-Signature
- Reject requests with missing or invalid signature; no secret = accept all (unchanged)
- Add webhook_secret password field to Connection Settings in Jira config
- Add tests for verification success, missing sig, and invalid sig
2026-03-16 16:42:32 +01:00
Dries Peeters c35a12ca4a test: add and update tests for client portal, shortcuts, Jira, inventory API
- Client portal, enhanced UI, keyboard shortcuts and shortcuts API
- Jira integration; API v1 inventory reports and transfers
- Silent exception handling fixes
2026-03-16 15:16:11 +01:00
Dries Peeters 4a5a5ceff9 chore: stop tracking gitignored files
Remove from index (keep on disk): .cursor/plans, logs/.gitkeep, logs/app.jsonl,
mobile lib files, tests/__pycache__/*.pyc. These are already in .gitignore;
stopping tracking so future changes are ignored.
2026-03-16 13:04:52 +01:00
Dries Peeters 76b3d48562 test(telemetry): consent gate, base first_seen/heartbeat, install_id
- test_installation_config: assert install_id UUID format and config persistence
- test_telemetry_consent_and_base: analytics not sent when opt-out, sent when opt-in
- test_telemetry_consent_and_base: base first_seen idempotent, heartbeat payload schema
- test_telemetry_consent_and_base: install_id stable across calls
2026-03-16 13:01:41 +01:00
Dries Peeters b4486a627f fix: CI tests, code quality, and duplicate DB indexes
- Webhook models: remove duplicate index definitions so db.create_all()
  no longer raises 'index already exists' (columns already have index=True)
- ImportService: fix circular import by late-importing ClientService,
  ProjectService, TimeTrackingService in __init__
- reports: fix F823 by renaming unpack variable _ to _entry_count to avoid
  shadowing gettext _ in export_task_excel()
- Code quality: add .flake8 with extend-ignore so flake8 CI passes;
  simplify pyproject.toml isort config (drop unsupported options)
- Format: run black and isort on app/
- tests: restore minimal app fixture in test_import_export_models
2026-03-15 10:51:52 +01:00
Dries Peeters d2cac0b3fa chore: move invoice template and tests; remove obsolete root files
- Move pdf_styles_default.css to app/templates/invoices/
- Move test_logo_pdf.py and test_quick_wins.py to tests/
- Remove fix_expense_schema.sql, temp_migration.sql, packages.txt,
  install_log.txt, temp_translated.txt
2026-03-15 10:16:49 +01:00
Dries Peeters 548de62dde test: extend fixtures and add scope, auth, recurring, reports tests
- Extend conftest and factories for API and scope tests
- Add test_auth, test_reports_scope, test_timer_scope
- Add test_recurring_invoice_service, test_scope_filter
- Add test_admin_dashboard_charts, test_api_contract, test_reports_task_report
- Update test_invoices, test_project_archiving_models, test_project_costs, test_time_entry_repository, test_utils
2026-03-15 09:37:15 +01:00
Dries Peeters eefb529ef0 test(overtime): YTD helpers and overtime-as-leave validation (Issue #560)
- TestOvertimeYTD: get_overtime_ytd / get_overtime_last_12_months structure and values
- test_overtime_leave: request within YTD succeeds, exceeding YTD fails with validation
- Smoke test: assert get_overtime_ytd is available on overtime module
2026-03-11 17:39:37 +01:00
Dries Peeters 55f2ef29fd feat(overtime): allow overtime calculation by weekly hours (Issue #551) 2026-03-09 20:33:48 +01:00
Dries Peeters 3641b277f5 Update tests 2026-03-08 06:50:42 +01:00
Dries Peeters 2e1c18a345 feat(invoicing): add Factur-X CII export validation and transport guidance
Switch embedded invoice PDFs to Factur-X CII payloads and tighten the PDF/A-3 and AS4 handling so exports better match the standards they advertise. Document the experimental native Peppol transport path and cover the new validation and embedding behavior with focused tests.
2026-03-06 22:15:29 +01:00