- Add cascade='all, delete-orphan' to the notes backref so client notes
are removed when a client is deleted.
- In test_client_has_notes_relationship use client.notes.count() instead
of len(client.notes) since the backref uses lazy='dynamic'.
- test_client_portal_dashboard_requires_access: expect 302 redirect to
client portal login instead of 403. The client portal 403 handler
redirects authenticated non-portal users to login by design.
- Run routes unit group with -n 0 in CI to avoid SQLite 'database is
locked' errors from audit logging under pytest-xdist parallel workers;
fixes client_portal and admin client-portal test failures.
The logout route uses current_app.config for AUTH_METHOD and Config
for OIDC_POST_LOGOUT_REDIRECT_URI. Two tests only patched Config, so
auth_method stayed local and the handler never hit the IdP redirect
branch, causing redirects to /login and assertion failures.
Set app.config AUTH_METHOD to oidc in
test_logout_with_post_logout_uri_config and
test_logout_oidc_provider_has_revocation_endpoint_only so the route
enters the OIDC branch and the tests pass.
- custom_field_definitions: capture definition_id before delete and use it in
safe_commit to avoid touching detached definition; in tests re-query Client
by id after request instead of db.session.refresh() to avoid 'not persistent'
- permissions: test_delete_role_flow asserts by name (deletable_role) instead
of Role.query.get(role_id) so redirect-triggered sync_permissions_and_roles
id reuse does not cause false failure
- uploads: add password to authenticated_admin_client login_data in
test_uploads_persistence so login succeeds and logo upload tests see
company_logo_filename
- currency_display: run PRAGMAs only for file-based SQLite and use text();
skip for in-memory sqlite:// to avoid ResourceClosedError in admin_user
fixture during commit
- Skip dashboard cache when app.testing so cached ORM objects are never
served in a later request, avoiding 'Instance not bound to a Session'
in test_base_layout_has_sidebar_toggle and test_non_admin_cannot_access_roles.
- In test_admin_can_reset_user_password: ensure Role 'user' exists before
POST (edit_user requires it), use role='user' in form data, and accept
'Manage Users' or success flash as success.
- Audit: remove session.flush() from after_flush handler to avoid
'Session is already flushing' when logging creates
- Audit smoke tests: make assertions robust to fixture-created logs
(filter by user_id/action, expect >= counts where appropriate)
- PDF preview: add id and client to mock invoice SimpleNamespace and
use getattr(invoice, 'id', None) in exception logging
- PDF layout tests: assert custom_css is contained in saved CSS
(app normalizes with @page); create template before preview test
- Session: add password to login data in smoke tests that use the
login endpoint (admin_users, permissions_routes, tasks_templates,
time_entry_resume, invoices) so sessions persist across requests
- Add merge migration 116_merge_three_heads to join heads
090_add_push_subscriptions, 100_gantt_colors_modules, and
115_add_exclude_weekends so 'flask db upgrade' runs cleanly.
- Fix undefined-name and scope issues for CI code-quality:
- api_v1: import InvalidOperation in amount_paid Decimal block
- custom_reports, invoice_approvals, reports, scheduled_reports,
tasks: add current_app to Flask imports
- integrations: set user_integration before POST branches so
update_config path can use it
- invoices: use _ign for unpacking in export_invoice_ubl to avoid
shadowing gettext _ (F823)
- data_import, excel_export: add module logger (logging.getLogger)
- Add user status tracking (online/offline/away) based on last_login
- Implement is_online() and get_status() methods in User model
- Include status in user.to_dict() for API responses
- Create persistent chat widget that remains open across page navigation
- Floating chat button in bottom-right corner (always visible)
- Expandable chat panel with channels, direct messages, and message input
- State persistence using localStorage (remembers open/closed and active channel)
- Auto-refreshes channels and messages periodically
- Integrates with user selector for starting new chats
- Add chat user selection popup component
- Searchable user list with avatars and status indicators
- Color-coded status badges (green=online, yellow=away, gray=offline)
- Creates or finds existing direct message channels
- Add API endpoints for chat functionality
- GET /api/chat/users: List all active users with status
- POST /api/chat/direct-message/<user_id>: Create or find direct message channel
- Add chat button to header navigation
- Opens persistent chat widget or user selector
- Only visible when team_chat module is enabled
- Add status indicators throughout chat interface
- Show user status in direct messages list
- Display status badges in channel member lists
- Status visible in user selection popup
- Fix z-index and positioning issues
- Chat widget positioned above other floating elements (z-[60])
- Adjusted position to avoid overlap with quick actions button
- Fix CSRF token handling
- Use FormData for message submission to properly handle CSRF
- Include CSRF token in user selector requests
- Fix file_size variable in upload_attachment endpoint
- Replace basic stat cards with enhanced cards featuring icons, color-coded borders, and hover effects
- Add 8 comprehensive stat cards: Total Users, Active Users, Total Projects, Active Projects, Total Entries, Active Timers, Total Hours, Billable Hours
- Implement three interactive Chart.js visualizations:
* User Activity line chart (30-day trend)
* Project Status doughnut chart
* Time Entry Trends bar chart (30-day daily hours)
- Enhance admin section buttons with gradient backgrounds, hover animations, and improved spacing
- Improve recent activity table with icons, better styling, alternating row colors, and enhanced empty state
- Add System Health indicators section showing database status, OIDC configuration, and OIDC user count
- Add chart data calculations in backend route for user activity, project status, and daily time entries
- All improvements maintain dark mode compatibility and follow existing design system patterns
Move module disabling functionality from Admin->Settings to Admin->Module Management where users would logically expect to find it.
Changes:
- Updated manage_modules() route to handle POST requests and module disabling
- Transformed Module Management page from informational to interactive with full controls
- Removed misleading text about users customizing modules in profile settings
- Removed module visibility section from Settings page
- Cleaned up module-related code from settings() route
This fixes the UX issue where module disabling was in Settings but users expected it in Module Management, and removes inaccurate messaging about profile settings customization.
Add exclude_weekends feature to allow users to set weekly goals for
Monday-Friday (5-day work week) instead of Monday-Sunday (7-day week).
This addresses client feedback requesting the ability to exclude weekends
when setting weekly goals, making it more realistic for standard work
schedules.
Changes:
- Add exclude_weekends boolean column to weekly_time_goals table
- Update WeeklyTimeGoal model to calculate week_end_date as Friday when
exclude_weekends is True
- Filter weekend hours from actual_hours calculation when enabled
- Update days_remaining to count only weekdays for 5-day goals
- Add checkbox option in create/edit forms with helpful tooltips
- Update view template to show 5-day work week badge and exclude weekends
from daily breakdown
- Update tips section to mention the 5-day option
The feature is backward compatible - existing goals default to 7-day weeks.
All calculations (hours, days remaining, averages) correctly account for
the selected work week type.
- Add @module_enabled decorator to all module routes (30+ route files)
- Protects routes for inventory, mileage, per_diem, project_templates,
gantt, kanban, weekly_goals, issues, time_entry_templates, reports,
custom_reports, scheduled_reports, invoice_approvals, recurring_invoices,
payments, payment_gateways, budget_alerts, analytics, integrations,
import_export, saved_filters, workflows, time_approvals, activity_feed,
recurring_tasks, team_chat, client_portal, kiosk, and more
- Ensures disabled modules are not accessible to users
- Fix indentation errors in route files
- Remove duplicate module_enabled imports incorrectly placed inside
function bodies in 8 files (import_export, client_portal, custom_reports,
integrations, kiosk, payment_gateways, scheduled_reports, team_chat)
- Move all imports to top of files for proper scope
- Fix Jinja2 template error in admin/settings.html
- Replace invalid loop.parent.loop.last with namespace-based approach
- Use Jinja2 namespace feature to track first item for comma placement
- Fixes UndefinedError when rendering module dependencies and names
- Fix JavaScript syntax error in admin/settings.html
- Remove orphaned closing braces causing parse errors
- Restores toggleCategory function availability
- Update task templates to include module visibility checks
- Add module_enabled checks to task creation and editing templates
This commit completes the module management system, allowing administrators
to globally enable/disable modules, with all routes properly protected and
UI elements conditionally rendered based on module status.
Add ability to manually trigger scheduled reports for testing purposes
without modifying cron schedules.
- Add API endpoint /api/reports/scheduled/<id>/trigger to manually execute
a scheduled report
- Add 'Trigger Now' button (play icon) in scheduled reports table for
active schedules
- Add JavaScript handler with loading state and user feedback
- Include CSRF token protection for the trigger endpoint
This feature allows users to test scheduled reports immediately without
waiting for the next scheduled run or modifying cron expressions.
The properties panel used strict equality check (attrs.name === 'decorative-image')
which failed when the element name was modified (e.g., 'decorative-image element-overlap').
This caused the upload button to disappear when reselecting a decorative image
that wasn't uploaded immediately after creation.
Changed the check to use includes('decorative-image') to match the behavior
of the event listeners, ensuring the upload button always appears for
decorative image elements regardless of name modifications.
Fixes issue where users couldn't upload images to decorative image elements
after deselecting and reselecting them.
The code was checking \if not db.session.commit():\ which always evaluated to True since commit() returns None on success, not a boolean. This caused scheduled report creation to always fail with a database error even when the commit was successful.
Removed the incorrect check. Database errors will still be properly caught by the existing exception handler.
The Recent Activity widget was only showing deleted time entries because Activity.log was not being called when entries were created or updated. This commit adds Activity.log calls for 'created' and 'updated' actions across all time entry creation and update endpoints.
Changes:
- Add Activity.log for 'created' action in timer.py (manual entry creation)
- Add Activity.log for 'created' action in api.py (API entry creation)
- Add Activity.log for 'created' action in api_v1.py (API v1 entry creation)
- Add Activity.log for 'updated' action in api_v1.py (API v1 entry update)
- Add Activity.log for 'updated' action in api.py (API entry update)
- Add Activity.log for 'updated' action in timer.py (timer edit route)
All Activity.log calls follow the same pattern as existing 'deleted' and 'stopped' actions, including proper entity_name formatting, descriptive messages, extra_data with project/client/task information, and IP/user agent tracking.
- Add admin.manage_modules to admin_settings_open check to keep System Settings dropdown open on Module Management page
- Preserve sidebar scroll position across page navigations within the same section
- Prevent unwanted scroll-to-top behavior for main content on navigation
- Restore scroll positions for back/forward navigation and same-section navigation
Fixes issues where:
- System Settings > Module Management caused sidebar to close and reset
- Admin Dashboard navigation caused sidebar to collapse and scroll to top
- E-Mail Templates navigation caused page to scroll to top unnecessarily
Add comprehensive audit logging for TimeEntry operations including:
- Client/project context and creation timestamps
- Full entity state before/after changes
- User-provided reasons for deletions and modifications
- Enhanced UI for entering reasons in delete/edit dialogs
Database Changes:
- Add migration 114: reason, entity_metadata, full_old_state, full_new_state columns
- Use JSON column type for entity_metadata for better type handling
Model Updates:
- Extend AuditLog model with new fields and helper methods
- Update log_change() to accept reason, metadata, and full states
- Add get_entity_metadata(), get_full_old_state(), get_full_new_state() methods
- Use JSON column for entity_metadata (returns dict/list directly)
Service Layer:
- Update TimeTrackingService to capture full TimeEntry state and metadata
- Accept reason parameter in delete_entry() and update_entry()
- Create comprehensive audit logs with all context
API Routes:
- Update api.py, api_v1.py, and timer.py routes to accept reason parameter
- Refactor routes to use service layer for consistent audit logging
- Add reason support to bulk delete operations
UI Enhancements:
- Add reason textarea to bulk delete confirmation dialog
- Add reason textarea to time entry edit forms (admin and regular users)
- Update JavaScript to handle reason submission
Audit Log Display:
- Show client/project information and creation timestamp in list view
- Display full old/new states, reason, and metadata in detail view
- Format JSON states for better readability
Bug Fixes:
- Fix duration_seconds reference in timer stop route
- Improve error handling in timer operations with proper exception handling
- Add dashboard cache invalidation after manual entry creation
Keep Report Builder and Scheduled Reports only under the Reports submenu
in Finance & Expenses. They were previously shown both inside the Reports
dropdown and as standalone items; the redundant standalone links are removed.
The System Maintenance > Telemetry page was not respecting dark mode, making it look broken in dark theme. This commit adds proper dark mode classes throughout the template:
- Updated all card backgrounds to use bg-card-light dark:bg-card-dark
- Added dark mode variants for all text colors (headings, body text, muted text)
- Updated status badges with dark mode colors (green and gray variants)
- Fixed info boxes with appropriate dark backgrounds and borders
- Updated code blocks and links with dark mode support
- Applied consistent dark mode patterns matching the rest of the application
Import window and web activity from a local ActivityWatch aw-server
(https://activitywatch.net/) as automatic time entries (source='auto').
- Add ActivityWatchConnector: test_connection, sync_data, get_config_schema
- Per-user integration; config: server_url, default_project_id, lookback_days,
optional bucket_ids (default: aw-watcher-window_* and aw-watcher-web_*)
- No OAuth; setup at /integrations/activitywatch/setup
- Idempotent sync via IntegrationExternalEventLink and external_uid
- Register connector; treat activitywatch as per-user in IntegrationService
- activitywatch_setup route and template; connect redirect and is_global updates
- View/manage: Configure and Edit Configuration links for activitywatch
- docs/integrations/ACTIVITYWATCH.md; tests for connector and idempotency
Scheduled reports (per-salesman, unpaid-only)
- Schedule form: add email distribution (single / SalesmanEmailMapping /
template) and recipient template when "Split by custom field" is on.
- Support {value} and {value_lower} in recipient_email_template
(e.g. {value_lower}@test.de).
- Add use_last_month_dates on ReportEmailSchedule: optional "Use previous
calendar month" for monthly runs; migration 111.
- Override report date range in ScheduledReportService when
cadence=monthly and use_last_month_dates=true.
- Wire use_last_month_dates through schedule form, API, and
create_schedule.
Report Builder
- Add "Unpaid time entries" quick-start (Time Entries + unpaid only +
last 30 days) and applyUnpaidPreset().
- Clarify "Unpaid only" help: "Unpaid = billable, not yet on any invoice."
- Define canvas at top of script so edit-mode IIFE and addDataSourceToCanvas
can use it; fix applyUnpaidPreset/onclick when script failed to parse.
- Click-to-add for Data Sources and Components (in addition to drag-and-drop).
- Set dataTransfer.effectAllowed = 'copy' in dragstart for drop compatibility.
- Fix save-form handler: remove orphan try { with no catch that caused
SyntaxError and prevented applyUnpaidPreset (and rest of script) from loading.
Documentation
- Add docs/reports/UNPAID_BY_SALESMAN_AND_SCHEDULED_REPORTS.md (unpaid
definition, unpaid-by-salesman setup, SalesmanEmailMapping, template use).
- Add settings.disabled_module_ids (JSON) to store admin-disabled module IDs
- Migration 110: add disabled_module_ids column to settings
- ModuleRegistry.is_enabled() respects settings.disabled_module_ids
- Admin > System Settings: new 'Module visibility' section with toggles
for all non-core modules; disabled modules are hidden from all users.
- Core modules stay always on; default empty list keeps current behavior.
Audit logs were not recording any changes because after_flush runs
after SQL is emitted; by then session.new, session.dirty, and
session.deleted can be cleared and attribute history for updates is
often consumed, so the handler saw nothing to log.
Changes:
- Add receive_before_flush: process session.dirty (updates) and
session.deleted (deletes) while history is still valid; stash
session.new (creates) in session.info for after_flush.
- Simplify receive_after_flush: only handle pending creates from
session.info (instances now have ids), then session.flush() so
audit rows are in the same transaction.
- Register receive_before_flush for before_flush on Session,
sessionmaker class, and SignallingSession.
- Make receive_before_flush accept (session, flush_context, instances)
to match SQLAlchemy's before_flush signature.
- Remove db.session.flush() from AuditLog.log_change to avoid
nested flush; rely on main flush or explicit flush in after_flush.
- check_audit_logging.py: use entity_type='TimeEntry' to match
get_entity_type (model __class__.__name__).
- test_audit_logging: assert at least one AuditLog for create/update/
delete; use test_client for create; fix update to merge then mutate.
- Fix formatting when i18n labels wrap (e.g. 'Finanzen und Ausgaben'):
- text-align: start and min-w-0 on labels for proper wrapped alignment
- flex-shrink: 0 on icons/chevron to keep them vertically centered
- Add sidebar-nav-item class and CSS for all main nav items
- Add direct Report Builder and Scheduled Reports links to Finance & Expenses dropdown
- Add app/static/css/gantt-chart.css to override Frappe Gantt:
- Card-style container, grid, and popup using app palette
- Primary (#4A90E2) for projects and today column; tasks #10b981
- Dark mode via .dark for grid, text, bars, arrows, and tooltip
- Themed today highlight, bar labels, and dependency arrows
- In gantt/view.html: link gantt-chart.css, drop inline overrides
- Gantt options: bar_height 24, bar_corner_radius 6, padding 20
- Add Project.color (hex) and migration for projects.color
- Projects create/edit: Gantt color field with Pickr (swatch + hex input),
Pickr theme CSS and gantt-color-picker.js for init and sync
- Gantt API: include color in JSON for projects and tasks (tasks use project color)
- Gantt view: set custom_class from color, inject CSS for .bar and .bar-progress,
fix selectors for .gantt .bar-wrapper and :hover/.active overrides; add
fallback styles for gantt-project and gantt-task
InventoryReportService: use moved_at and reference_type/reference_id instead of non-existent movement_date and reference to avoid AttributeError in get_inventory_turnover, _get_stock_at_date, get_movement_history.
_ensure_legacy_lot: run only for outflows (movement_qty < 0) or record_devaluation (movement_qty None). For outflows use pre-movement total (updated_stock + abs(qty)) so FIFO consumption stays in sync with WarehouseStock. Skip for inbound to prevent double-count of new lots.
record_movement: stop swallowing exceptions from _apply_lot_changes; re-raise so callers can roll back and avoid inconsistent WarehouseStock vs StockLot state.
Movement form: dynamic quantity hint by type (return/waste/devaluation/default), required devaluation fields when shown, client-side sign checks for return (positive) and waste (negative).
Tests: test_first_inbound_with_no_lots_matches_warehouse_stock, test_first_outbound_with_no_lots_matches_warehouse_stock.
When changing Admin settings or toggling telemetry, users could be
redirected to the Welcome screen (/setup) because installation.json
was sometimes overwritten without setup_complete, and
get_telemetry_preference() could poison the in-memory config with a
bad load.
- _save_config(): merge with on-disk state before write so existing
keys (e.g. setup_complete) are never dropped.
- get_telemetry_preference(): use a local load only; do not overwrite
self._config to avoid poisoning the shared state when the file is
corrupt or empty.
Add tests to ensure set_telemetry_preference does not remove
setup_complete and that a bad get_telemetry_preference load does not
lead to setup_complete being wiped on the next set_telemetry_preference.
Pagination used url_for(..., **filters) which included:
- client_custom_field (a dict): URL encoding cannot handle dict values
- page: overwrote the explicit page param in Prev/Next links
Introduce url_filters: exclude client_custom_field and page, expand
client_custom_field into custom_field_<key> query params. Use url_filters
in _time_entries_list.html for all pagination url_for calls.
- Add custom error handlers (403, 404, 500) with user-friendly error pages
- Create new error.html template with consistent styling and navigation
- Enhance context processor to inject pending approvals and notifications counts
- Add error handling to client approval service with proper rollback
- Update all client portal templates with improved UI/UX
- Improve base template with better navigation and data injection
- Add graceful error handling to prevent cascading failures
This update significantly improves the user experience in the client portal
by providing clear error messages and better visual feedback throughout
all pages.
- Fix horizontal overflow in action bar on smaller screens with responsive wrapping
- Fix canvas header overflow by adding flex-wrap and responsive stacking
- Fix canvas toolbar overflow with proper wrapping and button sizing
- Hide page size help text on mobile to prevent overflow
- Replace purple gradient sidebar with clean white card design
- Update colors to use app's primary blue (#3B82F6) and neutral grays
- Redesign element items with proper card styling and hover effects
- Update search box and tabs to match app's input/button components
- Add comprehensive dark mode support throughout toolbox
- Improve visual consistency between invoice and quote PDF editors
All fixes applied to both invoice and quote PDF editors for consistent
responsive behavior across all screen sizes.
The trackable item validation was running too early, blocking all return/waste movements even when devaluation wasn't enabled. Move the check to only run when devaluation is actually being used.
- Move trackable validation to devaluation-specific code paths
- Allow non-trackable items for return/waste without devaluation
- Update form to show all active items (trackability only required for devaluation)
Fixes#385
- Inline asset preparation logic in PowerShell script
- Add better error handling and diagnostics for missing assets
- Improve icon file detection and generation guidance
- Add ASSETS_PREPARED environment variable to prevent duplicate work
- Fix path handling and output messages
- Bump desktop package version to 4.10.6
- Remove .assets_prepared build artifact from version control
- Add iOS archive creation step to build-mobile.yml
- Enhance error handling and diagnostics in cd-release.yml
- Add file existence checks and directory listings for debugging
- Change artifact upload from 'ignore' to 'error' for better failure detection
- Add date_format column to invoice_pdf_templates and quote_pdf_templates tables
- Default date format set to DD.MM.YYYY (%d.%m.%Y)
- Update PDF generators to use template-specific date format
- Add date format configuration in admin PDF template editor
- Replace Babel date formatting with strftime for consistent formatting
- Update template filters to use DD.MM.YYYY format by default
This allows users to customize date formatting per PDF template while
maintaining backward compatibility with existing templates.
Fixes issue #432 where decorative images would disappear after saving
the layout and PDF preview would show mostly black.
Root causes:
- Konva's toJSON() doesn't serialize custom attributes like imageUrl
- Warning system adds 'element-overlap' suffix to names, breaking exact matches
- PDF generation tried to render images with empty/invalid sources
Fixes applied:
1. Serialization fixes (quote_pdf_layout.html, pdf_layout.html):
- Manually inject imageUrl into JSON after Konva serialization
- Store imageUrl in a map before serialization and match by position/index
- Ensure primary name is 'decorative-image' before serialization
- Fix name matching to handle 'decorative-image element-overlap' names
2. Restoration fixes (quote_pdf_layout.html, pdf_layout.html):
- Search for decorative images using .includes() instead of exact match
- Match by position when searching saved JSON for imageUrl
- Create placeholder elements when imageUrl is missing
- Ensure decorative image groups remain visible even without imageUrl
3. PDF generation fixes (pdf_generator_reportlab.py):
- Skip decorative images with empty/invalid sources gracefully
- Log warnings instead of attempting to render invalid images
- Prevents black screen in PDF preview
4. Enhanced logging:
- Added [INVOICE] and [SAVE]/[LOAD] prefixes for better debugging
- Verify imageUrl presence in JSON before saving and after loading
The fixes ensure decorative images are properly saved with their imageUrl
attribute, correctly restored on load, and don't break PDF generation when
the image source is missing or invalid.
- Add comprehensive logging with [INVOICE] prefixes for better traceability
- Fix decorative image detection to handle modified names (e.g., 'decorative-image element-overlap')
- Implement position-based matching for imageUrl restoration from saved JSON
- Improve robustness when searching for decorative-image groups in Konva layer
- Add fallback mechanisms for finding imageUrl when position matching fails
- Enhance error messages and warnings with detailed context
- Ensure primary name 'decorative-image' is preserved before serialization
- Add verification logging to track imageUrl assignment and retrieval
These changes address issues where decorative images could lose their imageUrl
when saved/loaded, especially when elements have additional names or classes
applied (like 'element-overlap'). The position-based matching ensures correct
imageUrl restoration even when multiple decorative images exist.