Commit Graph

944 Commits

Author SHA1 Message Date
Dries Peeters 8f3041f260 Fix Client.notes backref: add delete-orphan cascade and fix dynamic loader test
- 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'.
2026-01-25 09:44:46 +01:00
Dries Peeters dffcf04b24 fix(tests): resolve routes unit test failures in CI
- 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.
2026-01-25 09:41:39 +01:00
Dries Peeters 239b393ffb fix(tests): set app.config AUTH_METHOD in OIDC logout security tests
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.
2026-01-25 09:40:30 +01:00
Dries Peeters d61f36918c fix(tests): resolve integration test failures (custom fields, roles, uploads, currency)
- 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
2026-01-25 09:38:11 +01:00
Dries Peeters bd4c7787e5 fix(smoke): resolve 3 failing smoke tests (dashboard cache, password reset)
- 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.
2026-01-25 09:13:14 +01:00
Dries Peeters d1b7e47835 fix(tests): resolve smoke test failures (audit, session, PDF)
- 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
2026-01-25 08:59:54 +01:00
Dries Peeters 5d4099422c fix: resolve migration multiple heads and flake8 F821/F823
- 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)
2026-01-25 08:59:47 +01:00
Dries Peeters 8d3469d741 Version Bump 2026-01-25 08:36:22 +01:00
Dries Peeters 01dea80245 fix(weekly-goals): use 5 workdays for days_remaining when exclude_weekends is on
- days_remaining now counts only Mon-Fri when exclude_weekends=True
- Fixes avg hours/day for 5-day goals (e.g. 30h shows 6h/day not 5h/day)
- Add tests for exclude_weekends: creation, days_remaining, avg hours/day,
  weekend exclusion, and actual_hours excluding weekend entries

Fixes GitHub Discussion #441
2026-01-25 08:36:02 +01:00
Dries Peeters 84975f5065 Version Bump 2026-01-23 22:39:45 +01:00
Dries Peeters 456d2074b7 feat: Add persistent chat widget with user selection and status indicators
- 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
2026-01-23 22:39:06 +01:00
Dries Peeters b498272d88 feat: enhance admin dashboard with visual improvements and charts
- 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
2026-01-23 21:31:50 +01:00
Dries Peeters e5584d58f8 Enhance dashboard visual design with modern UI improvements
- Replace basic stat cards with gradient designs (blue/green/purple)
  - Add icon containers with semi-transparent backgrounds
  - Implement hover effects with transform and shadow transitions
  - Improve typography and spacing

- Enhance timer widget with active state styling
  - Add gradient background when timer is running
  - Implement pulsing animation indicator
  - Improve button styling with better shadows
  - Add icon badges and visual hierarchy

- Improve recent entries table design
  - Add row hover effects and colored badges for projects/clients
  - Enhance action buttons with icon containers
  - Improve empty state with centered icon
  - Better spacing and typography

- Enhance top projects widget
  - Add progress bars showing relative project hours
  - Implement numbered badges for ranking
  - Improve list item styling with hover effects
  - Fix division by zero error when max_hours is 0

- Improve activity timeline
  - Add gradient icon containers
  - Better spacing and visual connections
  - Live indicator badge with animation
  - Enhanced empty state design

- Polish overall layout
  - Improve page header spacing
  - Enhance weekly goal widget with backdrop blur
  - Consistent card styling (rounded-xl, shadow-lg)
  - Improve donation widget styling
  - Better spacing throughout

All changes follow design patterns from client portal dashboard and maintain
consistency with existing Tailwind CSS configuration.
2026-01-23 21:25:57 +01:00
Dries Peeters f4e280e4d9 Fix module management UI inconsistency
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.
2026-01-23 21:16:04 +01:00
Dries Peeters 3ac5488a9c Version Bump 2026-01-22 20:18:08 +01:00
Dries Peeters fca242033e feat: Add 5-day work week option for weekly time goals
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.
2026-01-22 20:17:04 +01:00
Dries Peeters 606e7a9dc1 feat: Add comprehensive module management system with route protection
- 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.
2026-01-22 19:47:22 +01:00
Dries Peeters d9e7e82ab2 Add manual trigger for scheduled reports
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.
2026-01-22 14:31:38 +01:00
Dries Peeters a22919c51f Fix decorative image upload button not appearing after reselection
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.
2026-01-22 14:14:40 +01:00
Dries Peeters 1de4615696 Fix scheduled report creation always failing due to incorrect commit check
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.
2026-01-22 14:06:55 +01:00
Dries Peeters 50d26d0ed7 Add activity logging for created and updated time entries
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.
2026-01-22 14:01:31 +01:00
Dries Peeters d01d6633c1 feat(admin): enhance module visibility management with dependency validation and improved UX
Significantly improve the admin module visibility settings page with comprehensive
dependency validation, enhanced UI, and better user experience.

Key improvements:

Phase 1 - Critical Features:
- Add dependency validation to prevent disabling modules with active dependents
- Add get_dependents() and validate_module_disable() methods to ModuleRegistry
- Server-side validation with clear error messages when dependencies conflict
- Display module descriptions and dependency information in UI

Phase 2 - UX Enhancements:
- Add module icons and visual status indicators (Enabled/Disabled badges)
- Implement search and filter functionality (by name, category, status, dependencies)
- Make categories collapsible/expandable for better organization
- Add summary statistics showing total, enabled, and disabled module counts

Phase 3 - Advanced Features:
- Add bulk operations (Enable All/Disable All globally and per category)
- Implement impact preview showing affected modules when disabling
- Add client-side validation with real-time feedback
- Highlight modules with dependency conflicts

Additional enhancements:
- Enhanced module cards with icons, descriptions, and dependency lists
- Real-time count updates and validation feedback
- Improved visual hierarchy and spacing
- CSS transitions for smooth interactions

Files modified:
- app/utils/module_registry.py: Add dependency validation methods
- app/routes/admin.py: Add server-side validation before saving
- app/templates/admin/settings.html: Complete UI overhaul with all new features
2026-01-22 13:47:31 +01:00
Dries Peeters 72d265c0b2 Fix sidebar navigation state and scroll position issues
- 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
2026-01-22 13:47:16 +01:00
Dries Peeters 7dcd58608a feat: Enhance TimeEntry audit logging with comprehensive tracking
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
2026-01-22 13:36:04 +01:00
Dries Peeters 71350adf7a fix(nav): remove duplicate Report Builder and Scheduled Reports from sidebar
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.
2026-01-22 13:16:53 +01:00
Dries Peeters b82e8cfc45 fix: Add dark mode support to Telemetry dashboard page
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
2026-01-22 13:16:52 +01:00
Dries Peeters f5405d24ab Version Bump 2026-01-21 15:14:08 +01:00
Dries Peeters 12d79816d0 feat(integrations): add ActivityWatch integration for automatic time tracking
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
2026-01-21 15:13:46 +01:00
Dries Peeters a15eb0c97a Add setting to make all invoices PEPPOL compliant
- Add invoices_peppol_compliant in Settings (Admin > Peppol e-Invoicing).
  When on: PDFs include seller/buyer PEPPOL identifiers; invoice view
  shows warnings for missing company/client PEPPOL data; UBL gets
  mandatory BIS Billing 3.0 elements.

- UBL: add InvoiceTypeCode 380 and BuyerReference (buyer_reference,
  project name, or invoice number).

- Optional buyer_reference on Invoice and create/edit forms (PEPPOL BT-10).

- Download UBL route and button when client is PEPPOL-ready and
  invoices_peppol_compliant or peppol_enabled.

- Migrations: 112 (settings.invoices_peppol_compliant),
  113 (invoices.buyer_reference).

- Update PEPPOL_EINVOICING.md; extend test_peppol_service UBL checks.
2026-01-21 15:13:26 +01:00
Dries Peeters f0b7e7a6df feat(reports): unpaid-by-salesman scheduled reports and report builder fixes
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).
2026-01-21 15:11:12 +01:00
Dries Peeters 8c070d08d5 feat(admin): restore admin-defined module visibility
- 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.
2026-01-21 14:20:36 +01:00
Dries Peeters 6881e554ce fix: restore audit logging by using before_flush for updates/deletes
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.
2026-01-21 13:59:13 +01:00
Dries Peeters bd642a57ec fix(sidebar): multi-line label layout and add Report Builder/Scheduled Reports to Finance menu
- 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
2026-01-21 13:58:23 +01:00
Dries Peeters 2ad89848f3 Version Bump
bump to version 4.11.1
2026-01-20 21:21:33 +01:00
Dries Peeters 17236a896c style(gantt): align Gantt chart with app theme and dark mode
- 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
2026-01-20 21:20:54 +01:00
Dries Peeters 2615fefa91 feat(gantt): project bar colors and Pickr color picker
- 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
2026-01-20 21:12:51 +01:00
Dries Peeters dafefd5d67 fix(inventory): stock devaluation and lot logic (fixes #385)
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.
2026-01-20 19:59:28 +01:00
Dries Peeters c46c2d9721 fix: prevent redirect to /setup when changing settings (fixes #436)
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.
2026-01-20 19:58:34 +01:00
Dries Peeters 0635a46de5 fix(routes): resolve 500 on /time-entries pagination links (#438)
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.
2026-01-20 19:58:25 +01:00
Dries Peeters d510617d3c Version Bump 2026-01-16 09:19:36 +01:00
Dries Peeters 2ca4fd3f1a feat(client-portal): enhance error handling and UI improvements
- 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.
2026-01-16 09:14:46 +01:00
Dries Peeters be88d867c7 Fix PDF editor overflow issues and refactor toolbox styling
- 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.
2026-01-15 21:18:41 +01:00
Dries Peeters 8a1d36b533 fix(inventory): fix trackable check blocking return/waste movements
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
2026-01-14 21:15:33 +01:00
Dries Peeters 785f09057b build: Improve desktop Windows build script
- 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
2026-01-14 21:15:30 +01:00
Dries Peeters b44028c5b5 ci: Improve iOS build artifact handling
- 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
2026-01-14 21:15:28 +01:00
Dries Peeters c5ada775d3 chore: Bump version to 4.10.7 2026-01-14 21:15:24 +01:00
Dries Peeters 0b76df53e2 feat: Add configurable date format for PDF templates
- 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.
2026-01-14 21:15:18 +01:00
Dries Peeters 64eee1acd9 Fix decorative image disappearing after save and PDF black screen issue
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.
2026-01-14 21:15:08 +01:00
Dries Peeters ac062182f2 fix(pdf-editor): improve decorative image handling and debugging
- 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.
2026-01-14 21:13:18 +01:00
Dries Peeters 936beff4c0 Update android & IOS app 2026-01-14 07:01:31 +01:00