SYMBOL INDEX (9292 symbols across 940 files) FILE: app.py function make_shell_context (line 13) | def make_shell_context(): function init_db (line 28) | def init_db(): function create_admin (line 53) | def create_admin(): FILE: app/__init__.py function log_event (line 61) | def log_event(name: str, **kwargs): function identify_user (line 77) | def identify_user(user_id, properties=None): function track_event (line 90) | def track_event(user_id, event_name, properties=None): function track_page_view (line 103) | def track_page_view(page_name, user_id=None, properties=None): function create_app (line 127) | def create_app(config=None): function init_database (line 1338) | def init_database(app): FILE: app/blueprint_registry.py function _is_dev_fail_fast (line 11) | def _is_dev_fail_fast(app): function _record_blueprint_status (line 16) | def _record_blueprint_status( function register_all_blueprints (line 47) | def register_all_blueprints(app, logger=None): function _register_optional_blueprints (line 211) | def _register_optional_blueprints(app, logger=None): FILE: app/config.py class Config (line 5) | class Config: class DevelopmentConfig (line 301) | class DevelopmentConfig(Config): class TestingConfig (line 314) | class TestingConfig(Config): method __init__ (line 325) | def __init__(self): class ProductionConfig (line 331) | class ProductionConfig(Config): method __init__ (line 342) | def __init__(self): FILE: app/config/__init__.py class Config (line 40) | class Config: FILE: app/config/analytics_defaults.py function get_version_from_setup (line 33) | def get_version_from_setup(): function get_analytics_config (line 118) | def get_analytics_config(): function has_analytics_configured (line 165) | def has_analytics_configured(): FILE: app/config/support_ui.py function get_support_portal_base (line 9) | def get_support_portal_base(config: Dict[str, Any] | Any) -> str: function build_support_checkout_urls (line 20) | def build_support_checkout_urls(config: Dict[str, Any] | Any) -> Dict[st... function get_long_session_minutes (line 45) | def get_long_session_minutes() -> int: function get_social_proof_text (line 52) | def get_social_proof_text(config: Dict[str, Any] | Any) -> str: FILE: app/constants.py class TimeEntryStatus (line 9) | class TimeEntryStatus(Enum): class TimeEntrySource (line 18) | class TimeEntrySource(Enum): class ProjectStatus (line 28) | class ProjectStatus(Enum): class InvoiceStatus (line 36) | class InvoiceStatus(Enum): class PaymentStatus (line 49) | class PaymentStatus(Enum): class TaskStatus (line 58) | class TaskStatus(Enum): class UserRole (line 68) | class UserRole(Enum): class BillableStatus (line 77) | class BillableStatus(Enum): class AuditAction (line 138) | class AuditAction(Enum): class WebhookEvent (line 154) | class WebhookEvent(Enum): class NotificationType (line 189) | class NotificationType(Enum): class CacheKey (line 199) | class CacheKey: FILE: app/integrations/activitywatch.py function _to_local_naive (line 30) | def _to_local_naive(dt: datetime) -> datetime: function _normalize_server_url (line 38) | def _normalize_server_url(url: str) -> str: class ActivityWatchConnector (line 45) | class ActivityWatchConnector(BaseConnector): method provider_name (line 53) | def provider_name(self) -> str: method get_authorization_url (line 57) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 60) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 63) | def refresh_access_token(self) -> Dict[str, Any]: method _get_server_url (line 67) | def _get_server_url(self) -> str: method _get (line 74) | def _get(self, path: str, params: Optional[Dict[str, Any]] = None) -> ... method test_connection (line 91) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 101) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method get_config_schema (line 328) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/asana.py class AsanaConnector (line 15) | class AsanaConnector(BaseConnector): method provider_name (line 25) | def provider_name(self) -> str: method get_authorization_url (line 28) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 46) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 107) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 148) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 162) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method get_config_schema (line 291) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/base.py class BaseConnector (line 10) | class BaseConnector(ABC): method __init__ (line 18) | def __init__(self, integration, credentials): method provider_name (line 31) | def provider_name(self) -> str: method display_name (line 37) | def display_name(self) -> str: method get_authorization_url (line 42) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 56) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 70) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 80) | def test_connection(self) -> Dict[str, Any]: method get_access_token (line 89) | def get_access_token(self) -> Optional[str]: method sync_data (line 110) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method handle_webhook (line 123) | def handle_webhook( method get_config_schema (line 140) | def get_config_schema(self) -> Dict[str, Any]: method validate_config (line 191) | def validate_config(self, config: Dict[str, Any]) -> Dict[str, Any]: method get_sync_settings (line 260) | def get_sync_settings(self) -> Dict[str, Any]: method get_field_mappings (line 285) | def get_field_mappings(self) -> Dict[str, str]: method get_status_mappings (line 296) | def get_status_mappings(self) -> Dict[str, str]: FILE: app/integrations/caldav_calendar.py function _ns (line 39) | def _ns(tag: str, ns: str) -> str: function _ensure_trailing_slash (line 43) | def _ensure_trailing_slash(u: str) -> str: function _to_local_naive (line 53) | def _to_local_naive(dt: datetime) -> datetime: function _to_utc_aware (line 64) | def _to_utc_aware(dt_local_naive: datetime) -> datetime: function _datetime_to_caldav_utc (line 71) | def _datetime_to_caldav_utc(dt_utc: datetime) -> str: class CalDAVCalendar (line 82) | class CalDAVCalendar: class CalDAVClient (line 87) | class CalDAVClient: method __init__ (line 92) | def __init__(self, username: str, password: str, verify_ssl: bool = Tr... method _request (line 98) | def _request(self, method: str, url: str, *, headers: Optional[Dict[st... method _propfind (line 129) | def _propfind(self, url: str, xml_body: str, depth: str = "0") -> ET.E... method _report (line 144) | def _report(self, url: str, xml_body: str, depth: str = "1") -> ET.Ele... method discover_calendars (line 160) | def discover_calendars(self, server_url: str) -> List[CalDAVCalendar]: method fetch_events (line 246) | def fetch_events(self, calendar_url: str, time_min_utc: datetime, time... method create_or_update_event (line 421) | def create_or_update_event( method _find_href (line 554) | def _find_href(self, root: ET.Element, prop_paths: List[Tuple[str, ...... class CalDAVCalendarConnector (line 577) | class CalDAVCalendarConnector(BaseConnector): method provider_name (line 585) | def provider_name(self) -> str: method get_authorization_url (line 589) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 592) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 595) | def refresh_access_token(self) -> Dict[str, Any]: method _get_basic_creds (line 599) | def _get_basic_creds(self) -> Tuple[str, str]: method _client (line 608) | def _client(self) -> CalDAVClient: method test_connection (line 614) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 671) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method _sync_calendar_to_time_tracker (line 803) | def _sync_calendar_to_time_tracker( method _sync_time_tracker_to_calendar (line 1025) | def _sync_time_tracker_to_calendar(self, cfg: Dict[str, Any], calendar... method _generate_icalendar_event (line 1459) | def _generate_icalendar_event( method get_config_schema (line 1493) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/github.py class GitHubConnector (line 17) | class GitHubConnector(BaseConnector): method provider_name (line 25) | def provider_name(self) -> str: method get_authorization_url (line 28) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 46) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 104) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 119) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 140) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method handle_webhook (line 378) | def handle_webhook( method get_config_schema (line 477) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/gitlab.py class GitLabConnector (line 15) | class GitLabConnector(BaseConnector): method provider_name (line 23) | def provider_name(self) -> str: method _get_base_url (line 26) | def _get_base_url(self) -> str: method get_authorization_url (line 35) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 61) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 125) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 172) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 192) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method get_config_schema (line 345) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/google_calendar.py class GoogleCalendarConnector (line 20) | class GoogleCalendarConnector(BaseConnector): method provider_name (line 31) | def provider_name(self) -> str: method get_authorization_url (line 34) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 72) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 131) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 169) | def test_connection(self) -> Dict[str, Any]: method _get_calendar_service (line 197) | def _get_calendar_service(self): method sync_data (line 234) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method _create_calendar_event (line 660) | def _create_calendar_event(self, service, calendar_id: str, time_entry... method _update_calendar_event (line 712) | def _update_calendar_event(self, service, calendar_id: str, event_id: ... method _create_calendar_event_from_event (line 764) | def _create_calendar_event_from_event(self, service, calendar_id: str,... method _update_calendar_event_from_event (line 817) | def _update_calendar_event_from_event(self, service, calendar_id: str,... method get_config_schema (line 870) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/jira.py class JiraConnector (line 24) | class JiraConnector(BaseConnector): method provider_name (line 32) | def provider_name(self) -> str: method get_authorization_url (line 35) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 60) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 102) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 140) | def test_connection(self) -> Dict[str, Any]: method _extract_description_text (line 160) | def _extract_description_text(self, issue_fields: Dict[str, Any]) -> O... method _upsert_task_from_issue (line 175) | def _upsert_task_from_issue(self, issue: Dict[str, Any], actor_id: int... method sync_data (line 249) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method sync_issue (line 309) | def sync_issue(self, issue_key: str) -> Dict[str, Any]: method _map_jira_status (line 384) | def _map_jira_status(self, jira_status: str) -> str: method handle_webhook (line 400) | def handle_webhook( method get_config_schema (line 528) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/linear.py class LinearConnector (line 20) | class LinearConnector(BaseConnector): method provider_name (line 28) | def provider_name(self) -> str: method get_authorization_url (line 31) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 34) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 37) | def refresh_access_token(self) -> Dict[str, Any]: method _api_key (line 40) | def _api_key(self) -> Optional[str]: method _graphql (line 45) | def _graphql(self, query: str, variables: Optional[Dict] = None) -> Di... method test_connection (line 64) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 73) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method get_config_schema (line 235) | def get_config_schema(cls) -> Dict[str, Any]: FILE: app/integrations/microsoft_teams.py class MicrosoftTeamsConnector (line 15) | class MicrosoftTeamsConnector(BaseConnector): method provider_name (line 30) | def provider_name(self) -> str: method _get_tenant_id (line 33) | def _get_tenant_id(self) -> str: method get_authorization_url (line 42) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 69) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 133) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 184) | def test_connection(self) -> Dict[str, Any]: method send_message (line 205) | def send_message(self, channel_id: str, message: str) -> Dict[str, Any]: method sync_data (line 226) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method get_config_schema (line 250) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/outlook_calendar.py class OutlookCalendarConnector (line 15) | class OutlookCalendarConnector(BaseConnector): method provider_name (line 30) | def provider_name(self) -> str: method _get_tenant_id (line 33) | def _get_tenant_id(self) -> str: method get_authorization_url (line 42) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 69) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 134) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 185) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 203) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method _create_calendar_event (line 265) | def _create_calendar_event(self, token: str, calendar_id: str, time_en... method _update_calendar_event (line 309) | def _update_calendar_event(self, token: str, calendar_id: str, event_i... method get_config_schema (line 350) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/peppol.py function _bool_env (line 31) | def _bool_env(name: str, default: bool = False) -> bool: function peppol_enabled (line 36) | def peppol_enabled() -> bool: class PeppolParty (line 60) | class PeppolParty: function _money (line 73) | def _money(v: Any) -> str: function _qty (line 82) | def _qty(v: Any) -> str: function _text (line 90) | def _text(parent: ET.Element, tag: str, text: Optional[str]) -> Optional... function _party (line 101) | def _party(parent: ET.Element, kind: str, party: PeppolParty) -> None: function build_peppol_ubl_invoice_xml (line 140) | def build_peppol_ubl_invoice_xml(invoice: Any, supplier: PeppolParty, cu... class PeppolAccessPointError (line 302) | class PeppolAccessPointError(RuntimeError): function send_ubl_via_access_point (line 306) | def send_ubl_via_access_point( FILE: app/integrations/peppol_as4.py class PeppolAS4Error (line 38) | class PeppolAS4Error(RuntimeError): function _soap_envelope (line 44) | def _soap_envelope( function build_as4_message (line 97) | def build_as4_message( function send_as4_message (line 153) | def send_as4_message( FILE: app/integrations/peppol_identifiers.py class PeppolIdentifierError (line 184) | class PeppolIdentifierError(ValueError): method __init__ (line 187) | def __init__(self, message: str, field: Optional[str] = None): function validate_scheme_id (line 192) | def validate_scheme_id(scheme_id: Optional[str], field: str = "scheme_id... function validate_endpoint_id (line 210) | def validate_endpoint_id(endpoint_id: Optional[str], field: str = "endpo... function validate_participant_identifiers (line 228) | def validate_participant_identifiers( FILE: app/integrations/peppol_smp.py class PeppolSMPError (line 27) | class PeppolSMPError(RuntimeError): function _get_sml_base_url (line 33) | def _get_sml_base_url() -> str: function _participant_identifier_to_hostname (line 42) | def _participant_identifier_to_hostname(participant_id: str, scheme_id: ... function get_smp_url (line 53) | def get_smp_url(participant_id: str, scheme_id: str, sml_base_url: Optio... function get_recipient_endpoint_url (line 111) | def get_recipient_endpoint_url( FILE: app/integrations/peppol_transport.py class PeppolTransportError (line 21) | class PeppolTransportError(RuntimeError): class PeppolTransportProtocol (line 27) | class PeppolTransportProtocol(ABC): method send (line 31) | def send( class GenericTransport (line 48) | class GenericTransport(PeppolTransportProtocol): method __init__ (line 51) | def __init__( method send (line 61) | def send( class NativePeppolTransport (line 98) | class NativePeppolTransport(PeppolTransportProtocol): method __init__ (line 101) | def __init__( method send (line 113) | def send( FILE: app/integrations/quickbooks.py class QuickBooksConnector (line 19) | class QuickBooksConnector(BaseConnector): method provider_name (line 30) | def provider_name(self) -> str: method get_base_url (line 33) | def get_base_url(self): method get_authorization_url (line 38) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 66) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 124) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 169) | def test_connection(self) -> Dict[str, Any]: method _api_request (line 188) | def _api_request( method sync_data (line 240) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method _create_quickbooks_invoice (line 378) | def _create_quickbooks_invoice(self, invoice, access_token: str, realm... method _create_quickbooks_expense (line 542) | def _create_quickbooks_expense(self, expense, access_token: str, realm... method get_config_schema (line 643) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/registry.py function register_connectors (line 23) | def register_connectors(): FILE: app/integrations/slack.py class SlackConnector (line 14) | class SlackConnector(BaseConnector): method provider_name (line 22) | def provider_name(self) -> str: method get_authorization_url (line 25) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 43) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 87) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 127) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 148) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method handle_webhook (line 222) | def handle_webhook( method send_message (line 253) | def send_message(self, channel: str, text: str) -> Dict[str, Any]: method get_config_schema (line 275) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/trello.py class TrelloConnector (line 18) | class TrelloConnector(BaseConnector): method provider_name (line 28) | def provider_name(self) -> str: method get_authorization_url (line 31) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 56) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 95) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 100) | def test_connection(self) -> Dict[str, Any]: method sync_data (line 122) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method _sync_trello_to_timetracker (line 183) | def _sync_trello_to_timetracker( method _sync_timetracker_to_trello (line 285) | def _sync_timetracker_to_trello( method _map_trello_list_to_status (line 437) | def _map_trello_list_to_status(self, list_id: str) -> str: method get_config_schema (line 469) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/integrations/xero.py class XeroConnector (line 19) | class XeroConnector(BaseConnector): method provider_name (line 29) | def provider_name(self) -> str: method get_authorization_url (line 32) | def get_authorization_url(self, redirect_uri: str, state: str = None) ... method exchange_code_for_tokens (line 63) | def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Di... method refresh_access_token (line 121) | def refresh_access_token(self) -> Dict[str, Any]: method test_connection (line 167) | def test_connection(self) -> Dict[str, Any]: method _api_request (line 191) | def _api_request( method sync_data (line 223) | def sync_data(self, sync_type: str = "full") -> Dict[str, Any]: method _create_xero_invoice (line 285) | def _create_xero_invoice(self, invoice, access_token: str, tenant_id: ... method _create_xero_expense (line 340) | def _create_xero_expense(self, expense, access_token: str, tenant_id: ... method get_config_schema (line 373) | def get_config_schema(self) -> Dict[str, Any]: FILE: app/models/activity.py class Activity (line 6) | class Activity(db.Model): method __repr__ (line 47) | def __repr__(self): method log (line 51) | def log( method get_recent (line 128) | def get_recent(cls, user_id=None, limit=50, entity_type=None): method to_dict (line 146) | def to_dict(self): method get_icon (line 163) | def get_icon(self): method get_color (line 179) | def get_color(self): FILE: app/models/api_idempotency_key.py class ApiIdempotencyKey (line 8) | class ApiIdempotencyKey(db.Model): FILE: app/models/api_token.py class ApiToken (line 11) | class ApiToken(db.Model): method __repr__ (line 42) | def __repr__(self): method generate_token (line 46) | def generate_token(): method hash_token (line 53) | def hash_token(token): method create_token (line 60) | def create_token(cls, user_id, name, description="", scopes="", expire... method verify_token (line 93) | def verify_token(self, plain_token): method is_valid (line 97) | def is_valid(self): method has_scope (line 105) | def has_scope(self, required_scope): method record_usage (line 134) | def record_usage(self, ip_address=None): method to_dict (line 140) | def to_dict(self, include_token=False): FILE: app/models/audit_log.py class AuditLog (line 8) | class AuditLog(db.Model): method __repr__ (line 80) | def __repr__(self): method log_change (line 84) | def log_change( method _encode_value (line 184) | def _encode_value(value): method _decode_value (line 200) | def _decode_value(value_str): method get_old_value (line 211) | def get_old_value(self): method get_new_value (line 215) | def get_new_value(self): method get_entity_metadata (line 219) | def get_entity_metadata(self): method get_full_old_state (line 227) | def get_full_old_state(self): method get_full_new_state (line 231) | def get_full_new_state(self): method get_for_entity (line 236) | def get_for_entity(cls, entity_type, entity_id, limit=100): method get_for_user (line 246) | def get_for_user(cls, user_id, limit=100): method get_recent (line 251) | def get_recent(cls, limit=100, entity_type=None, user_id=None, action=... method to_dict (line 266) | def to_dict(self): method get_icon (line 291) | def get_icon(self): method get_color (line 300) | def get_color(self): FILE: app/models/budget_alert.py class BudgetAlert (line 6) | class BudgetAlert(db.Model): method __init__ (line 33) | def __init__( method __repr__ (line 44) | def __repr__(self): method acknowledge (line 47) | def acknowledge(self, user_id): method to_dict (line 54) | def to_dict(self): method get_active_alerts (line 73) | def get_active_alerts(cls, project_id=None, acknowledged=False): method create_alert (line 83) | def create_alert(cls, project_id, alert_type, budget_consumed_percent,... method _generate_message (line 119) | def _generate_message(alert_type, budget_consumed_percent, budget_amou... method get_alert_summary (line 129) | def get_alert_summary(cls, project_id=None): FILE: app/models/calendar_event.py function _isoformat_calendar (line 7) | def _isoformat_calendar(dt): class CalendarEvent (line 14) | class CalendarEvent(db.Model): method __init__ (line 69) | def __init__(self, user_id, title, start_time, end_time, **kwargs): method __repr__ (line 88) | def __repr__(self): method to_dict (line 91) | def to_dict(self): method duration_hours (line 116) | def duration_hours(self): method get_events_in_range (line 124) | def get_events_in_range(user_id, start_date, end_date, include_tasks=F... FILE: app/models/calendar_integration.py class CalendarIntegration (line 8) | class CalendarIntegration(db.Model): method __repr__ (line 48) | def __repr__(self): class CalendarSyncEvent (line 52) | class CalendarSyncEvent(db.Model): method __repr__ (line 88) | def __repr__(self): FILE: app/models/client.py class Client (line 14) | class Client(db.Model): method __init__ (line 50) | def __init__( method __repr__ (line 86) | def __repr__(self): method is_active (line 90) | def is_active(self): method total_projects (line 95) | def total_projects(self): method active_projects (line 100) | def active_projects(self): method total_hours (line 105) | def total_hours(self): method total_billable_hours (line 113) | def total_billable_hours(self): method estimated_total_cost (line 121) | def estimated_total_cost(self): method prepaid_plan_enabled (line 130) | def prepaid_plan_enabled(self): method prepaid_hours_decimal (line 139) | def prepaid_hours_decimal(self): method prepaid_month_start (line 148) | def prepaid_month_start(self, reference_datetime): method get_prepaid_consumed_hours (line 180) | def get_prepaid_consumed_hours(self, month_start): method get_prepaid_remaining_hours (line 196) | def get_prepaid_remaining_hours(self, month_start): method archive (line 204) | def archive(self): method activate (line 209) | def activate(self): method get_custom_field (line 214) | def get_custom_field(self, key, default=None): method set_custom_field (line 220) | def set_custom_field(self, key, value): method remove_custom_field (line 228) | def remove_custom_field(self, key): method get_rendered_links (line 235) | def get_rendered_links(self): method to_dict (line 262) | def to_dict(self): method get_active_clients (line 287) | def get_active_clients(cls): method get_all_clients (line 292) | def get_all_clients(cls): method set_portal_password (line 297) | def set_portal_password(self, password): method check_portal_password (line 304) | def check_portal_password(self, password): method has_portal_access (line 311) | def has_portal_access(self): method get_portal_data (line 315) | def get_portal_data(self): method generate_password_setup_token (line 341) | def generate_password_setup_token(self, expires_hours=24): method verify_password_setup_token (line 348) | def verify_password_setup_token(self, token): method clear_password_setup_token (line 361) | def clear_password_setup_token(self): method authenticate_portal (line 367) | def authenticate_portal(cls, username, password): method find_by_password_token (line 382) | def find_by_password_token(cls, token): FILE: app/models/client_attachment.py function local_now (line 8) | def local_now(): class ClientAttachment (line 13) | class ClientAttachment(db.Model): method __init__ (line 42) | def __init__(self, client_id, filename, original_filename, file_path, ... method __repr__ (line 53) | def __repr__(self): method file_size_mb (line 57) | def file_size_mb(self): method file_size_kb (line 62) | def file_size_kb(self): method file_size_display (line 67) | def file_size_display(self): method file_extension (line 77) | def file_extension(self): method is_image (line 82) | def is_image(self): method is_pdf (line 87) | def is_pdf(self): method is_document (line 92) | def is_document(self): method download_url (line 97) | def download_url(self): method to_dict (line 103) | def to_dict(self): method get_client_attachments (line 126) | def get_client_attachments(cls, client_id, include_client_visible=True): FILE: app/models/client_note.py class ClientNote (line 7) | class ClientNote(db.Model): method __init__ (line 40) | def __init__(self, content, user_id, client_id, is_important=False): method __repr__ (line 60) | def __repr__(self): method author_name (line 64) | def author_name(self): method client_name (line 71) | def client_name(self): method can_edit (line 75) | def can_edit(self, user): method can_delete (line 79) | def can_delete(self, user): method edit_content (line 83) | def edit_content(self, new_content, user, is_important=None): method to_dict (line 102) | def to_dict(self): method get_client_notes (line 119) | def get_client_notes(cls, client_id, order_by_important=False): method get_important_notes (line 136) | def get_important_notes(cls, client_id=None): method get_user_notes (line 146) | def get_user_notes(cls, user_id, limit=None): method get_recent_notes (line 156) | def get_recent_notes(cls, limit=10): FILE: app/models/client_notification.py class NotificationType (line 12) | class NotificationType(enum.Enum): class ClientNotification (line 28) | class ClientNotification(db.Model): method __repr__ (line 62) | def __repr__(self): method mark_as_read (line 65) | def mark_as_read(self): method to_dict (line 71) | def to_dict(self): method get_unread_count (line 88) | def get_unread_count(cls, client_id): method get_recent_notifications (line 93) | def get_recent_notifications(cls, client_id, limit=20): class ClientNotificationPreferences (line 98) | class ClientNotificationPreferences(db.Model): method __repr__ (line 131) | def __repr__(self): method should_send_email (line 134) | def should_send_email(self, notification_type): method to_dict (line 152) | def to_dict(self): FILE: app/models/client_portal_customization.py class ClientPortalCustomization (line 11) | class ClientPortalCustomization(db.Model): method __repr__ (line 59) | def __repr__(self): method to_dict (line 62) | def to_dict(self): method get_css_variables (line 87) | def get_css_variables(self): FILE: app/models/client_portal_dashboard_preference.py class ClientPortalDashboardPreference (line 22) | class ClientPortalDashboardPreference(db.Model): method __repr__ (line 52) | def __repr__(self): method to_dict (line 55) | def to_dict(self): FILE: app/models/client_prepaid_consumption.py class ClientPrepaidConsumption (line 7) | class ClientPrepaidConsumption(db.Model): method __repr__ (line 28) | def __repr__(self): method hours_consumed (line 33) | def hours_consumed(self) -> Decimal: FILE: app/models/client_time_approval.py class ClientApprovalStatus (line 14) | class ClientApprovalStatus(enum.Enum): class ClientTimeApproval (line 23) | class ClientTimeApproval(db.Model): method __repr__ (line 58) | def __repr__(self): method to_dict (line 61) | def to_dict(self): method approve (line 78) | def approve(self, contact_id: int, comment: str = None): method reject (line 86) | def reject(self, contact_id: int, reason: str): method cancel (line 94) | def cancel(self): class ClientApprovalPolicy (line 100) | class ClientApprovalPolicy(db.Model): method __repr__ (line 128) | def __repr__(self): method to_dict (line 131) | def to_dict(self): method applies_to_entry (line 143) | def applies_to_entry(self, time_entry) -> bool: FILE: app/models/comment.py class Comment (line 7) | class Comment(db.Model): method __init__ (line 47) | def __init__( method __repr__ (line 90) | def __repr__(self): method is_reply (line 109) | def is_reply(self): method target_type (line 114) | def target_type(self): method target_name (line 125) | def target_name(self): method reply_count (line 136) | def reply_count(self): method can_edit (line 140) | def can_edit(self, user): method can_delete (line 144) | def can_delete(self, user): method edit_content (line 148) | def edit_content(self, new_content, user): method delete_comment (line 157) | def delete_comment(self, user): method to_dict (line 172) | def to_dict(self): method get_project_comments (line 213) | def get_project_comments(cls, project_id, include_replies=True): method get_task_comments (line 223) | def get_task_comments(cls, task_id, include_replies=True): method get_user_comments (line 233) | def get_user_comments(cls, user_id, limit=None): method get_quote_comments (line 243) | def get_quote_comments(cls, quote_id, include_replies=True, include_in... method get_recent_comments (line 256) | def get_recent_comments(cls, limit=10): FILE: app/models/comment_attachment.py function local_now (line 8) | def local_now(): class CommentAttachment (line 13) | class CommentAttachment(db.Model): method __init__ (line 38) | def __init__(self, comment_id, filename, original_filename, file_path,... method __repr__ (line 47) | def __repr__(self): method file_size_mb (line 51) | def file_size_mb(self): method file_size_kb (line 56) | def file_size_kb(self): method file_size_display (line 61) | def file_size_display(self): method file_extension (line 71) | def file_extension(self): method is_image (line 76) | def is_image(self): method is_pdf (line 81) | def is_pdf(self): method is_document (line 86) | def is_document(self): method download_url (line 91) | def download_url(self): method to_dict (line 97) | def to_dict(self): method get_comment_attachments (line 118) | def get_comment_attachments(cls, comment_id): FILE: app/models/contact.py function local_now (line 7) | def local_now(): class Contact (line 12) | class Contact(db.Model): method __init__ (line 57) | def __init__(self, client_id, first_name, last_name, created_by, **kwa... method __repr__ (line 76) | def __repr__(self): method full_name (line 80) | def full_name(self): method display_name (line 85) | def display_name(self): method to_dict (line 91) | def to_dict(self): method get_active_contacts (line 117) | def get_active_contacts(cls, client_id=None): method get_primary_contact (line 125) | def get_primary_contact(cls, client_id): method set_as_primary (line 129) | def set_as_primary(self): FILE: app/models/contact_communication.py function local_now (line 7) | def local_now(): class ContactCommunication (line 12) | class ContactCommunication(db.Model): method __init__ (line 52) | def __init__(self, contact_id, type, created_by, **kwargs): method __repr__ (line 68) | def __repr__(self): method to_dict (line 71) | def to_dict(self): method get_recent_communications (line 92) | def get_recent_communications(cls, contact_id=None, limit=50): FILE: app/models/currency.py class Currency (line 6) | class Currency(db.Model): method __repr__ (line 19) | def __repr__(self): class ExchangeRate (line 23) | class ExchangeRate(db.Model): method __repr__ (line 40) | def __repr__(self): FILE: app/models/custom_field_definition.py class CustomFieldDefinition (line 10) | class CustomFieldDefinition(db.Model): method __repr__ (line 29) | def __repr__(self): method to_dict (line 32) | def to_dict(self): method get_active_definitions (line 48) | def get_active_definitions(cls): method get_mandatory_definitions (line 92) | def get_mandatory_definitions(cls): method get_by_key (line 136) | def get_by_key(cls, field_key): method count_clients_with_value (line 179) | def count_clients_with_value(self): FILE: app/models/custom_report.py class CustomReportConfig (line 10) | class CustomReportConfig(db.Model): method __repr__ (line 42) | def __repr__(self): method to_dict (line 45) | def to_dict(self): FILE: app/models/deal.py function local_now (line 8) | def local_now(): class Deal (line 13) | class Deal(db.Model): method __init__ (line 68) | def __init__(self, name, created_by, **kwargs): method __repr__ (line 89) | def __repr__(self): method weighted_value (line 93) | def weighted_value(self): method is_open (line 100) | def is_open(self): method is_won (line 105) | def is_won(self): method is_lost (line 110) | def is_lost(self): method close_won (line 114) | def close_won(self, close_date=None): method close_lost (line 122) | def close_lost(self, reason=None, close_date=None): method to_dict (line 132) | def to_dict(self): method get_open_deals (line 164) | def get_open_deals(cls, user_id=None): method get_deals_by_stage (line 172) | def get_deals_by_stage(cls, stage): FILE: app/models/deal_activity.py function local_now (line 7) | def local_now(): class DealActivity (line 12) | class DealActivity(db.Model): method __init__ (line 42) | def __init__(self, deal_id, type, created_by, **kwargs): method __repr__ (line 54) | def __repr__(self): method to_dict (line 57) | def to_dict(self): FILE: app/models/donation_interaction.py class DonationInteraction (line 23) | class DonationInteraction(db.Model): method __repr__ (line 51) | def __repr__(self): method record_interaction (line 55) | def record_interaction( method has_recent_donation_click (line 80) | def has_recent_donation_click(user_id: int, days: int = 30) -> bool: method get_user_engagement_metrics (line 94) | def get_user_engagement_metrics(user_id: int) -> dict: FILE: app/models/expense.py class Expense (line 9) | class Expense(db.Model): method __init__ (line 83) | def __init__(self, user_id, title, category, amount, expense_date, **k... method __repr__ (line 108) | def __repr__(self): method is_approved (line 112) | def is_approved(self): method is_rejected (line 117) | def is_rejected(self): method is_reimbursed (line 122) | def is_reimbursed(self): method is_invoiced (line 127) | def is_invoiced(self): method total_amount (line 132) | def total_amount(self): method tag_list (line 137) | def tag_list(self): method approve (line 143) | def approve(self, approved_by_user_id, notes=None): method reject (line 152) | def reject(self, rejected_by_user_id, reason): method mark_as_reimbursed (line 160) | def mark_as_reimbursed(self): method mark_as_invoiced (line 167) | def mark_as_invoiced(self, invoice_id): method unmark_as_invoiced (line 173) | def unmark_as_invoiced(self): method to_dict (line 179) | def to_dict(self): method get_expenses (line 221) | def get_expenses( method get_total_expenses (line 266) | def get_total_expenses( method get_expenses_by_category (line 307) | def get_expenses_by_category(cls, user_id=None, start_date=None, end_d... method get_pending_approvals (line 335) | def get_pending_approvals(cls, user_id=None): method get_pending_reimbursements (line 345) | def get_pending_reimbursements(cls, user_id=None): method get_uninvoiced_expenses (line 355) | def get_uninvoiced_expenses(cls, project_id=None, client_id=None): method get_expense_categories (line 368) | def get_expense_categories(cls): method get_payment_methods (line 384) | def get_payment_methods(cls): FILE: app/models/expense_category.py class ExpenseCategory (line 9) | class ExpenseCategory(db.Model): method __init__ (line 37) | def __init__(self, name, **kwargs): method __repr__ (line 52) | def __repr__(self): method get_spent_amount (line 55) | def get_spent_amount(self, start_date, end_date): method get_budget_utilization (line 69) | def get_budget_utilization(self, period="monthly"): method to_dict (line 103) | def to_dict(self): method get_active_categories (line 125) | def get_active_categories(cls): method get_categories_over_budget (line 130) | def get_categories_over_budget(cls, period="monthly"): FILE: app/models/expense_gps.py class MileageTrack (line 13) | class MileageTrack(db.Model): method __repr__ (line 55) | def __repr__(self): method to_dict (line 58) | def to_dict(self): method calculate_distance (line 79) | def calculate_distance(self): method calculate_distance_from_track_points (line 108) | def calculate_distance_from_track_points(self) -> Optional[float]: FILE: app/models/extra_good.py class ExtraGood (line 7) | class ExtraGood(db.Model): method __init__ (line 48) | def __init__( method __repr__ (line 92) | def __repr__(self): method update_total (line 95) | def update_total(self): method to_dict (line 100) | def to_dict(self): method get_project_goods (line 123) | def get_project_goods(cls, project_id, billable_only=False): method get_invoice_goods (line 133) | def get_invoice_goods(cls, invoice_id): method get_total_amount (line 138) | def get_total_amount(cls, project_id=None, invoice_id=None, billable_o... method get_goods_by_category (line 155) | def get_goods_by_category(cls, project_id=None, invoice_id=None): FILE: app/models/focus_session.py class FocusSession (line 6) | class FocusSession(db.Model): method to_dict (line 39) | def to_dict(self): FILE: app/models/gamification.py class Badge (line 12) | class Badge(db.Model): method __repr__ (line 35) | def __repr__(self): method to_dict (line 38) | def to_dict(self): class UserBadge (line 52) | class UserBadge(db.Model): method __repr__ (line 76) | def __repr__(self): method to_dict (line 79) | def to_dict(self): class Leaderboard (line 91) | class Leaderboard(db.Model): method __repr__ (line 121) | def __repr__(self): method to_dict (line 124) | def to_dict(self): class LeaderboardEntry (line 137) | class LeaderboardEntry(db.Model): method __repr__ (line 169) | def __repr__(self): method to_dict (line 172) | def to_dict(self): FILE: app/models/import_export.py class DataImport (line 10) | class DataImport(db.Model): method __init__ (line 33) | def __init__(self, user_id, import_type, source_file=None): method __repr__ (line 42) | def __repr__(self): method start_processing (line 45) | def start_processing(self): method complete (line 50) | def complete(self): method fail (line 56) | def fail(self, error_message=None): method partial_complete (line 77) | def partial_complete(self): method update_progress (line 83) | def update_progress(self, total, successful, failed): method add_error (line 94) | def add_error(self, error_message, record_data=None): method set_summary (line 117) | def set_summary(self, summary_dict): method to_dict (line 124) | def to_dict(self): class DataExport (line 145) | class DataExport(db.Model): method __init__ (line 169) | def __init__(self, user_id, export_type, export_format="json", filters... method __repr__ (line 180) | def __repr__(self): method start_processing (line 183) | def start_processing(self): method complete (line 188) | def complete(self, file_path, file_size, record_count): method fail (line 199) | def fail(self, error_message): method is_expired (line 206) | def is_expired(self): method to_dict (line 212) | def to_dict(self): FILE: app/models/integration.py class Integration (line 12) | class Integration(db.Model): method __repr__ (line 42) | def __repr__(self): class IntegrationCredential (line 46) | class IntegrationCredential(db.Model): method __repr__ (line 67) | def __repr__(self): method is_expired (line 71) | def is_expired(self): method needs_refresh (line 77) | def needs_refresh(self): class IntegrationEvent (line 86) | class IntegrationEvent(db.Model): method __repr__ (line 106) | def __repr__(self): FILE: app/models/integration_external_event_link.py class IntegrationExternalEventLink (line 12) | class IntegrationExternalEventLink(db.Model): method __repr__ (line 39) | def __repr__(self): FILE: app/models/invoice.py class Invoice (line 8) | class Invoice(db.Model): method __init__ (line 75) | def __init__(self, invoice_number, project_id, client_name, due_date, ... method __repr__ (line 103) | def __repr__(self): method is_overdue (line 107) | def is_overdue(self): method days_overdue (line 112) | def days_overdue(self): method is_paid (line 119) | def is_paid(self): method is_partially_paid (line 124) | def is_partially_paid(self): method outstanding_amount (line 129) | def outstanding_amount(self): method payment_percentage (line 135) | def payment_percentage(self): method sorted_payments (line 142) | def sorted_payments(self): method update_payment_status (line 148) | def update_payment_status(self): method record_payment (line 160) | def record_payment( method calculate_totals (line 200) | def calculate_totals(self): method _apply_tax_rules_if_any (line 219) | def _apply_tax_rules_if_any(self): method to_dict (line 250) | def to_dict(self): method generate_invoice_number (line 290) | def generate_invoice_number(cls): class InvoiceItem (line 295) | class InvoiceItem(db.Model): method __init__ (line 324) | def __init__( method __repr__ (line 337) | def __repr__(self): method task_name_from_time_entries (line 341) | def task_name_from_time_entries(self): method to_dict (line 358) | def to_dict(self): FILE: app/models/invoice_approval.py class InvoiceApproval (line 8) | class InvoiceApproval(db.Model): method __repr__ (line 49) | def __repr__(self): method is_pending (line 53) | def is_pending(self): method is_approved (line 58) | def is_approved(self): method is_rejected (line 63) | def is_rejected(self): method to_dict (line 67) | def to_dict(self): FILE: app/models/invoice_email.py function local_now (line 7) | def local_now(): class InvoiceEmail (line 12) | class InvoiceEmail(db.Model): method __init__ (line 48) | def __init__(self, invoice_id, recipient_email, subject, sent_by, **kw... method __repr__ (line 56) | def __repr__(self): method mark_opened (line 59) | def mark_opened(self): method mark_paid (line 68) | def mark_paid(self): method mark_failed (line 74) | def mark_failed(self, error_message): method mark_bounced (line 79) | def mark_bounced(self): method to_dict (line 83) | def to_dict(self): FILE: app/models/invoice_image.py function local_now (line 8) | def local_now(): class InvoiceImage (line 13) | class InvoiceImage(db.Model): method __init__ (line 44) | def __init__(self, invoice_id, filename, original_filename, file_path,... method __repr__ (line 59) | def __repr__(self): method file_size_mb (line 63) | def file_size_mb(self): method file_size_kb (line 68) | def file_size_kb(self): method file_size_display (line 73) | def file_size_display(self): method file_extension (line 83) | def file_extension(self): method is_image (line 88) | def is_image(self): method to_dict (line 92) | def to_dict(self): method get_invoice_images (line 116) | def get_invoice_images(cls, invoice_id): FILE: app/models/invoice_pdf_template.py class InvoicePDFTemplate (line 11) | class InvoicePDFTemplate(db.Model): method __repr__ (line 39) | def __repr__(self): method get_template (line 43) | def get_template(cls, page_size="A4"): method get_all_templates (line 78) | def get_all_templates(cls): method get_default_template (line 83) | def get_default_template(cls): method ensure_default_templates (line 88) | def ensure_default_templates(cls): method to_dict (line 113) | def to_dict(self): method get_template_json (line 127) | def get_template_json(self): method set_template_json (line 138) | def set_template_json(self, template_dict): method get_page_dimensions_mm (line 144) | def get_page_dimensions_mm(self): method get_page_dimensions_px (line 148) | def get_page_dimensions_px(self, dpi=72): method ensure_template_json (line 156) | def ensure_template_json(self): FILE: app/models/invoice_peppol.py class InvoicePeppolTransmission (line 6) | class InvoicePeppolTransmission(db.Model): method mark_sent (line 35) | def mark_sent(self, message_id=None, response_payload=None): method mark_failed (line 43) | def mark_failed(self, error_message, response_payload=None): method to_dict (line 49) | def to_dict(self): FILE: app/models/invoice_template.py class InvoiceTemplate (line 6) | class InvoiceTemplate(db.Model): method __repr__ (line 21) | def __repr__(self): FILE: app/models/issue.py class Issue (line 7) | class Issue(db.Model): method __init__ (line 48) | def __init__( method __repr__ (line 76) | def __repr__(self): method is_open (line 80) | def is_open(self): method is_resolved (line 85) | def is_resolved(self): method is_closed (line 90) | def is_closed(self): method status_display (line 95) | def status_display(self): method priority_display (line 107) | def priority_display(self): method priority_class (line 113) | def priority_class(self): method mark_in_progress (line 123) | def mark_in_progress(self): method mark_resolved (line 132) | def mark_resolved(self): method mark_closed (line 142) | def mark_closed(self): method cancel (line 149) | def cancel(self): method link_to_task (line 158) | def link_to_task(self, task_id): method create_task_from_issue (line 174) | def create_task_from_issue(self, project_id, assigned_to=None, created... method reassign (line 206) | def reassign(self, user_id): method update_priority (line 212) | def update_priority(self, priority): method to_dict (line 222) | def to_dict(self): method get_issues_by_client (line 256) | def get_issues_by_client(cls, client_id, status=None, priority=None): method get_issues_by_project (line 269) | def get_issues_by_project(cls, project_id, status=None): method get_issues_by_task (line 279) | def get_issues_by_task(cls, task_id): method get_user_issues (line 284) | def get_user_issues(cls, user_id, status=None): method get_open_issues (line 294) | def get_open_issues(cls): FILE: app/models/kanban_column.py class KanbanColumn (line 5) | class KanbanColumn(db.Model): method __init__ (line 28) | def __init__(self, **kwargs): method __repr__ (line 32) | def __repr__(self): method to_dict (line 36) | def to_dict(self): method get_active_columns (line 54) | def get_active_columns(cls, project_id=None): method get_all_columns (line 74) | def get_all_columns(cls, project_id=None): method get_column_by_key (line 94) | def get_column_by_key(cls, key, project_id=None): method get_valid_status_keys (line 110) | def get_valid_status_keys(cls, project_id=None): method initialize_default_columns (line 119) | def initialize_default_columns(cls, project_id=None): method reorder_columns (line 181) | def reorder_columns(cls, column_ids, project_id=None): FILE: app/models/lead.py function local_now (line 8) | def local_now(): class Lead (line 13) | class Lead(db.Model): method __init__ (line 67) | def __init__(self, first_name, last_name, created_by, **kwargs): method __repr__ (line 86) | def __repr__(self): method full_name (line 90) | def full_name(self): method display_name (line 95) | def display_name(self): method is_converted (line 102) | def is_converted(self): method is_lost (line 107) | def is_lost(self): method convert_to_client (line 111) | def convert_to_client(self, client_id, user_id): method convert_to_deal (line 119) | def convert_to_deal(self, deal_id, user_id): method mark_lost (line 127) | def mark_lost(self): method to_dict (line 132) | def to_dict(self): method get_active_leads (line 164) | def get_active_leads(cls, user_id=None): method get_leads_by_status (line 172) | def get_leads_by_status(cls, status): FILE: app/models/lead_activity.py function local_now (line 7) | def local_now(): class LeadActivity (line 12) | class LeadActivity(db.Model): method __init__ (line 42) | def __init__(self, lead_id, type, created_by, **kwargs): method __repr__ (line 54) | def __repr__(self): method to_dict (line 57) | def to_dict(self): FILE: app/models/link_template.py class LinkTemplate (line 10) | class LinkTemplate(db.Model): method __repr__ (line 30) | def __repr__(self): method render_url (line 33) | def render_url(self, field_value): method to_dict (line 53) | def to_dict(self): method get_active_templates (line 70) | def get_active_templates(cls, field_key=None): FILE: app/models/mileage.py class Mileage (line 9) | class Mileage(db.Model): method __init__ (line 83) | def __init__(self, user_id, trip_date, purpose, start_location, end_lo... method __repr__ (line 116) | def __repr__(self): method total_distance_km (line 120) | def total_distance_km(self): method total_amount (line 126) | def total_amount(self): method approve (line 131) | def approve(self, approved_by_user_id, notes=None): method reject (line 140) | def reject(self, rejected_by_user_id, reason): method mark_as_reimbursed (line 148) | def mark_as_reimbursed(self): method create_expense (line 155) | def create_expense(self): method to_dict (line 177) | def to_dict(self): method get_default_rates (line 220) | def get_default_rates(cls): method get_pending_approvals (line 231) | def get_pending_approvals(cls, user_id=None): method get_total_distance (line 241) | def get_total_distance(cls, user_id=None, start_date=None, end_date=No... FILE: app/models/payment_gateway.py class PaymentGateway (line 9) | class PaymentGateway(db.Model): method __repr__ (line 33) | def __repr__(self): class PaymentTransaction (line 37) | class PaymentTransaction(db.Model): method __repr__ (line 81) | def __repr__(self): method to_dict (line 84) | def to_dict(self): FILE: app/models/payments.py class Payment (line 7) | class Payment(db.Model): method __repr__ (line 35) | def __repr__(self): method calculate_net_amount (line 38) | def calculate_net_amount(self): method to_dict (line 45) | def to_dict(self): class CreditNote (line 66) | class CreditNote(db.Model): method __repr__ (line 80) | def __repr__(self): class InvoiceReminderSchedule (line 84) | class InvoiceReminderSchedule(db.Model): method __repr__ (line 99) | def __repr__(self): FILE: app/models/per_diem.py class PerDiemRate (line 9) | class PerDiemRate(db.Model): method __init__ (line 45) | def __init__(self, country, full_day_rate, half_day_rate, effective_fr... method __repr__ (line 60) | def __repr__(self): method to_dict (line 64) | def to_dict(self): method get_rate_for_location (line 86) | def get_rate_for_location(cls, country, city=None, date=None): class PerDiem (line 116) | class PerDiem(db.Model): method __init__ (line 197) | def __init__(self, user_id, trip_purpose, start_date, end_date, countr... method _calculate_amount (line 232) | def _calculate_amount(self): method recalculate_amount (line 244) | def recalculate_amount(self): method __repr__ (line 249) | def __repr__(self): method total_days (line 254) | def total_days(self): method trip_duration (line 259) | def trip_duration(self): method approve (line 263) | def approve(self, approved_by_user_id, notes=None): method reject (line 272) | def reject(self, rejected_by_user_id, reason): method mark_as_reimbursed (line 280) | def mark_as_reimbursed(self): method create_expense (line 287) | def create_expense(self): method to_dict (line 311) | def to_dict(self): method calculate_days_from_dates (line 358) | def calculate_days_from_dates(cls, start_date, end_date, departure_tim... method get_pending_approvals (line 415) | def get_pending_approvals(cls, user_id=None): FILE: app/models/permission.py class Permission (line 8) | class Permission(db.Model): method __init__ (line 21) | def __init__(self, name, description=None, category="general"): method __repr__ (line 26) | def __repr__(self): method to_dict (line 29) | def to_dict(self): class Role (line 49) | class Role(db.Model): method __init__ (line 69) | def __init__(self, name, description=None, is_system_role=False, hidde... method __repr__ (line 76) | def __repr__(self): method has_permission (line 79) | def has_permission(self, permission_name): method add_permission (line 83) | def add_permission(self, permission): method remove_permission (line 88) | def remove_permission(self, permission): method get_permission_names (line 93) | def get_permission_names(self): method to_dict (line 97) | def to_dict(self, include_permissions=False): FILE: app/models/project.py class Project (line 7) | class Project(db.Model): method __init__ (line 44) | def __init__( method __repr__ (line 101) | def __repr__(self): method client (line 105) | def client(self): method is_active (line 110) | def is_active(self): method is_archived (line 115) | def is_archived(self): method archived_by_user (line 120) | def archived_by_user(self): method code_display (line 129) | def code_display(self): method total_hours (line 143) | def total_hours(self): method total_billable_hours (line 156) | def total_billable_hours(self): method estimated_cost (line 169) | def estimated_cost(self): method total_costs (line 176) | def total_costs(self): method total_billable_costs (line 186) | def total_billable_costs(self): method total_project_value (line 199) | def total_project_value(self): method actual_hours (line 204) | def actual_hours(self): method budget_consumed_amount (line 209) | def budget_consumed_amount(self): method budget_threshold_exceeded (line 227) | def budget_threshold_exceeded(self): method get_entries_by_user (line 236) | def get_entries_by_user(self, user_id=None, start_date=None, end_date=... method get_user_totals (line 253) | def get_user_totals(self, start_date=None, end_date=None): method archive (line 282) | def archive(self, user_id=None, reason=None): method unarchive (line 296) | def unarchive(self): method deactivate (line 305) | def deactivate(self): method activate (line 311) | def activate(self): method is_favorited_by (line 317) | def is_favorited_by(self, user): method get_custom_field (line 328) | def get_custom_field(self, key, default=None): method set_custom_field (line 334) | def set_custom_field(self, key, value): method remove_custom_field (line 341) | def remove_custom_field(self, key): method get_rendered_links (line 347) | def get_rendered_links(self): method to_dict (line 374) | def to_dict(self, user=None): FILE: app/models/project_attachment.py function local_now (line 8) | def local_now(): class ProjectAttachment (line 13) | class ProjectAttachment(db.Model): method __init__ (line 42) | def __init__(self, project_id, filename, original_filename, file_path,... method __repr__ (line 53) | def __repr__(self): method file_size_mb (line 57) | def file_size_mb(self): method file_size_kb (line 62) | def file_size_kb(self): method file_size_display (line 67) | def file_size_display(self): method file_extension (line 77) | def file_extension(self): method is_image (line 82) | def is_image(self): method is_pdf (line 87) | def is_pdf(self): method is_document (line 92) | def is_document(self): method download_url (line 97) | def download_url(self): method to_dict (line 103) | def to_dict(self): method get_project_attachments (line 126) | def get_project_attachments(cls, project_id, include_client_visible=Tr... FILE: app/models/project_cost.py class ProjectCost (line 7) | class ProjectCost(db.Model): method __init__ (line 38) | def __init__( method __repr__ (line 62) | def __repr__(self): method is_invoiced (line 66) | def is_invoiced(self): method mark_as_invoiced (line 70) | def mark_as_invoiced(self, invoice_id): method unmark_as_invoiced (line 76) | def unmark_as_invoiced(self): method to_dict (line 82) | def to_dict(self): method get_project_costs (line 105) | def get_project_costs(cls, project_id, start_date=None, end_date=None,... method get_total_costs (line 124) | def get_total_costs(cls, project_id, start_date=None, end_date=None, u... method get_uninvoiced_costs (line 144) | def get_uninvoiced_costs(cls, project_id): method get_costs_by_category (line 153) | def get_costs_by_category(cls, project_id, start_date=None, end_date=N... FILE: app/models/project_stock_allocation.py class ProjectStockAllocation (line 9) | class ProjectStockAllocation(db.Model): method __init__ (line 32) | def __init__(self, project_id, stock_item_id, warehouse_id, quantity_a... method __repr__ (line 41) | def __repr__(self): method quantity_remaining (line 45) | def quantity_remaining(self): method record_usage (line 49) | def record_usage(self, quantity): method to_dict (line 56) | def to_dict(self): FILE: app/models/project_template.py class ProjectTemplate (line 9) | class ProjectTemplate(db.Model): method __repr__ (line 46) | def __repr__(self): method to_dict (line 49) | def to_dict(self): FILE: app/models/purchase_order.py function _normalize_optional_text (line 9) | def _normalize_optional_text(value): function _normalize_required_text (line 17) | def _normalize_required_text(value, field_name): class PurchaseOrder (line 25) | class PurchaseOrder(db.Model): method __init__ (line 59) | def __init__( method __repr__ (line 84) | def __repr__(self): method calculate_totals (line 87) | def calculate_totals(self): method mark_as_sent (line 94) | def mark_as_sent(self): method mark_as_received (line 100) | def mark_as_received(self, received_date=None): method cancel (line 135) | def cancel(self): method to_dict (line 141) | def to_dict(self): class PurchaseOrderItem (line 165) | class PurchaseOrderItem(db.Model): method __init__ (line 194) | def __init__( method __repr__ (line 220) | def __repr__(self): method update_line_total (line 223) | def update_line_total(self): method to_dict (line 228) | def to_dict(self): FILE: app/models/push_subscription.py class PushSubscription (line 12) | class PushSubscription(db.Model): method __init__ (line 33) | def __init__(self, user_id, endpoint, keys, user_agent=None): method __repr__ (line 40) | def __repr__(self): method to_dict (line 43) | def to_dict(self): method update_last_used (line 56) | def update_last_used(self): method get_user_subscriptions (line 63) | def get_user_subscriptions(cls, user_id): method find_by_endpoint (line 68) | def find_by_endpoint(cls, user_id, endpoint): FILE: app/models/quote.py function local_now (line 10) | def local_now(): class Quote (line 15) | class Quote(db.Model): method __init__ (line 107) | def __init__(self, quote_number, client_id, title, created_by, **kwargs): method __repr__ (line 137) | def __repr__(self): method is_draft (line 141) | def is_draft(self): method is_sent (line 146) | def is_sent(self): method is_accepted (line 151) | def is_accepted(self): method is_rejected (line 156) | def is_rejected(self): method is_expired (line 161) | def is_expired(self): method can_be_accepted (line 168) | def can_be_accepted(self): method has_project (line 173) | def has_project(self): method can_be_sent (line 178) | def can_be_sent(self): method calculate_totals (line 186) | def calculate_totals(self): method discount_value (line 209) | def discount_value(self): method subtotal_after_discount (line 221) | def subtotal_after_discount(self): method calculate_due_date_from_payment_terms (line 225) | def calculate_due_date_from_payment_terms(self, issue_date=None): method send (line 273) | def send(self): method request_approval (line 281) | def request_approval(self): method approve (line 290) | def approve(self, user_id, notes=None): method reject_approval (line 303) | def reject_approval(self, user_id, reason): method accept (line 315) | def accept(self, user_id, project_id=None): method reject (line 327) | def reject(self): method expire (line 336) | def expire(self): method to_dict (line 342) | def to_dict(self): method generate_quote_number (line 387) | def generate_quote_number(cls): class QuoteItem (line 411) | class QuoteItem(db.Model): method __init__ (line 448) | def __init__( method __repr__ (line 501) | def __repr__(self): method to_dict (line 504) | def to_dict(self): class QuotePDFTemplate (line 527) | class QuotePDFTemplate(db.Model): method __repr__ (line 555) | def __repr__(self): method get_template (line 559) | def get_template(cls, page_size="A4"): method get_all_templates (line 591) | def get_all_templates(cls): method get_default_template (line 596) | def get_default_template(cls): method get_template_json (line 605) | def get_template_json(self): method set_template_json (line 616) | def set_template_json(self, template_dict): method ensure_template_json (line 622) | def ensure_template_json(self): FILE: app/models/quote_attachment.py function local_now (line 8) | def local_now(): class QuoteAttachment (line 13) | class QuoteAttachment(db.Model): method __init__ (line 42) | def __init__(self, quote_id, filename, original_filename, file_path, f... method __repr__ (line 53) | def __repr__(self): method file_size_mb (line 57) | def file_size_mb(self): method file_size_kb (line 62) | def file_size_kb(self): method file_size_display (line 67) | def file_size_display(self): method file_extension (line 77) | def file_extension(self): method is_image (line 82) | def is_image(self): method is_pdf (line 87) | def is_pdf(self): method is_document (line 92) | def is_document(self): method download_url (line 97) | def download_url(self): method to_dict (line 103) | def to_dict(self): method get_quote_attachments (line 126) | def get_quote_attachments(cls, quote_id, include_client_visible=True): FILE: app/models/quote_image.py function local_now (line 8) | def local_now(): class QuoteImage (line 13) | class QuoteImage(db.Model): method __init__ (line 44) | def __init__(self, quote_id, filename, original_filename, file_path, f... method __repr__ (line 59) | def __repr__(self): method file_size_mb (line 63) | def file_size_mb(self): method file_size_kb (line 68) | def file_size_kb(self): method file_size_display (line 73) | def file_size_display(self): method file_extension (line 83) | def file_extension(self): method is_image (line 88) | def is_image(self): method to_dict (line 92) | def to_dict(self): method get_quote_images (line 116) | def get_quote_images(cls, quote_id): FILE: app/models/quote_template.py function local_now (line 8) | def local_now(): class QuoteTemplate (line 13) | class QuoteTemplate(db.Model): method __init__ (line 50) | def __init__(self, name, created_by, **kwargs): method __repr__ (line 67) | def __repr__(self): method items_list (line 71) | def items_list(self): method items_list (line 81) | def items_list(self, value): method data_dict (line 89) | def data_dict(self): method data_dict (line 99) | def data_dict(self, value): method increment_usage (line 106) | def increment_usage(self): method apply_to_quote (line 111) | def apply_to_quote(self, quote): method to_dict (line 138) | def to_dict(self): method get_user_templates (line 162) | def get_user_templates(cls, user_id, include_public=True): method get_public_templates (line 170) | def get_public_templates(cls): method get_popular_templates (line 175) | def get_popular_templates(cls, limit=10): FILE: app/models/quote_version.py function local_now (line 8) | def local_now(): class QuoteVersion (line 13) | class QuoteVersion(db.Model): method __init__ (line 37) | def __init__(self, quote_id, version_number, quote_data, changed_by, *... method __repr__ (line 45) | def __repr__(self): method data_dict (line 49) | def data_dict(self): method to_dict (line 56) | def to_dict(self): method create_version (line 71) | def create_version(cls, quote, changed_by, change_summary=None, fields... method get_quote_versions (line 122) | def get_quote_versions(cls, quote_id): method get_latest_version (line 127) | def get_latest_version(cls, quote_id): FILE: app/models/rate_override.py class RateOverride (line 7) | class RateOverride(db.Model): method resolve_rate (line 35) | def resolve_rate(cls, project, user_id=None, on_date=None): FILE: app/models/recurring_block.py class RecurringBlock (line 6) | class RecurringBlock(db.Model): method to_dict (line 48) | def to_dict(self): FILE: app/models/recurring_invoice.py class RecurringInvoice (line 9) | class RecurringInvoice(db.Model): method __init__ (line 58) | def __init__(self, name, project_id, client_id, frequency, next_run_da... method __repr__ (line 82) | def __repr__(self): method calculate_next_run_date (line 85) | def calculate_next_run_date(self, from_date=None): method should_generate_today (line 101) | def should_generate_today(self): method generate_invoice (line 115) | def generate_invoice(self): method to_dict (line 121) | def to_dict(self): FILE: app/models/recurring_task.py class RecurringTask (line 13) | class RecurringTask(db.Model): method __init__ (line 53) | def __init__(self, name, project_id, frequency, next_run_date, created... method __repr__ (line 71) | def __repr__(self): method calculate_next_run_date (line 74) | def calculate_next_run_date(self, from_date=None): method create_task (line 90) | def create_task(self): method to_dict (line 124) | def to_dict(self): FILE: app/models/reporting.py class SavedReportView (line 6) | class SavedReportView(db.Model): method __repr__ (line 25) | def __repr__(self): class ReportEmailSchedule (line 29) | class ReportEmailSchedule(db.Model): method __repr__ (line 60) | def __repr__(self): FILE: app/models/salesman_email_mapping.py class SalesmanEmailMapping (line 13) | class SalesmanEmailMapping(db.Model): method __init__ (line 28) | def __init__(self, salesman_initial, email_address=None, email_pattern... method __repr__ (line 36) | def __repr__(self): method get_email (line 39) | def get_email(self): method to_dict (line 51) | def to_dict(self): method get_email_for_initial (line 67) | def get_email_for_initial(cls, initial): method get_all_active (line 79) | def get_all_active(cls): FILE: app/models/saved_filter.py class SavedFilter (line 6) | class SavedFilter(db.Model): method to_dict (line 28) | def to_dict(self): FILE: app/models/settings.py function _session_in_flush (line 14) | def _session_in_flush(session): class Settings (line 36) | class Settings(db.Model): method __init__ (line 206) | def __init__(self, **kwargs): method __repr__ (line 316) | def __repr__(self): method get_logo_url (line 319) | def get_logo_url(self): method get_logo_path (line 325) | def get_logo_path(self): method has_logo (line 340) | def has_logo(self): method get_mail_config (line 348) | def get_mail_config(self): method get_ai_config (line 362) | def get_ai_config(self, *, include_secrets: bool = False) -> dict: method get_integration_credentials (line 408) | def get_integration_credentials(self, provider: str, *, include_secret... method to_dict (line 502) | def to_dict(self): method set_secret (line 622) | def set_secret(self, field: str, value: str) -> None: method get_secret (line 635) | def get_secret(self, field: str) -> str: method _encrypt_secrets_if_needed (line 640) | def _encrypt_secrets_if_needed(self) -> bool: method get_settings (line 656) | def get_settings(cls): method update_settings (line 778) | def update_settings(cls, **kwargs): method get_system_instance_id (line 801) | def get_system_instance_id(cls): method _initialize_from_env (line 824) | def _initialize_from_env(cls, settings_instance): method sync_from_env (line 882) | def sync_from_env(cls): FILE: app/models/stock_item.py class StockItem (line 9) | class StockItem(db.Model): method __init__ (line 46) | def __init__( method __repr__ (line 86) | def __repr__(self): method total_quantity_on_hand (line 90) | def total_quantity_on_hand(self): method total_quantity_reserved (line 100) | def total_quantity_reserved(self): method total_quantity_available (line 112) | def total_quantity_available(self): method is_low_stock (line 121) | def is_low_stock(self): method get_stock_level (line 132) | def get_stock_level(self, warehouse_id): method get_available_quantity (line 141) | def get_available_quantity(self, warehouse_id): method to_dict (line 152) | def to_dict(self): FILE: app/models/stock_lot.py class StockLot (line 13) | class StockLot(db.Model): method adjust_on_hand (line 51) | def adjust_on_hand(self, quantity): method __repr__ (line 56) | def __repr__(self): class StockLotAllocation (line 63) | class StockLotAllocation(db.Model): method __repr__ (line 85) | def __repr__(self): FILE: app/models/stock_movement.py class StockMovement (line 11) | class StockMovement(db.Model): method __init__ (line 42) | def __init__( method __repr__ (line 66) | def __repr__(self): method to_dict (line 69) | def to_dict(self): method record_movement (line 87) | def record_movement( method _ensure_legacy_lot (line 169) | def _ensure_legacy_lot(cls, item, warehouse_id, moved_by, updated_stoc... method _apply_lot_changes (line 214) | def _apply_lot_changes( method record_devaluation (line 442) | def record_devaluation( FILE: app/models/stock_reservation.py class StockReservation (line 9) | class StockReservation(db.Model): method __init__ (line 36) | def __init__( method __repr__ (line 57) | def __repr__(self): method is_expired (line 61) | def is_expired(self): method fulfill (line 67) | def fulfill(self): method cancel (line 81) | def cancel(self): method expire (line 96) | def expire(self): method create_reservation (line 111) | def create_reservation( method to_dict (line 166) | def to_dict(self): FILE: app/models/supplier.py class Supplier (line 8) | class Supplier(db.Model): method __init__ (line 36) | def __init__( method __repr__ (line 68) | def __repr__(self): method to_dict (line 71) | def to_dict(self): FILE: app/models/supplier_stock_item.py class SupplierStockItem (line 9) | class SupplierStockItem(db.Model): method __init__ (line 36) | def __init__( method __repr__ (line 62) | def __repr__(self): method to_dict (line 65) | def to_dict(self): FILE: app/models/task.py class Task (line 7) | class Task(db.Model): method __init__ (line 42) | def __init__( method __repr__ (line 66) | def __repr__(self): method is_active (line 70) | def is_active(self): method is_overdue (line 75) | def is_overdue(self): method total_hours (line 84) | def total_hours(self): method total_billable_hours (line 105) | def total_billable_hours(self): method progress_percentage (line 121) | def progress_percentage(self): method status_display (line 133) | def status_display(self): method priority_display (line 155) | def priority_display(self): method priority_class (line 161) | def priority_class(self): method tag_list (line 172) | def tag_list(self): method start_task (line 178) | def start_task(self): method pause_task (line 188) | def pause_task(self): method mark_for_review (line 197) | def mark_for_review(self): method complete_task (line 206) | def complete_task(self): method cancel_task (line 216) | def cancel_task(self): method reassign (line 225) | def reassign(self, user_id): method update_priority (line 231) | def update_priority(self, priority): method update_due_date (line 241) | def update_due_date(self, due_date): method to_dict (line 247) | def to_dict(self): method get_tasks_by_project (line 279) | def get_tasks_by_project(cls, project_id, status=None, priority=None): method get_user_tasks (line 292) | def get_user_tasks(cls, user_id, status=None, include_assigned=True, i... method get_overdue_tasks (line 312) | def get_overdue_tasks(cls): FILE: app/models/task_activity.py class TaskActivity (line 5) | class TaskActivity(db.Model): method __init__ (line 20) | def __init__(self, task_id, event, user_id=None, details=None): method __repr__ (line 26) | def __repr__(self): FILE: app/models/tax_rule.py class TaxRule (line 6) | class TaxRule(db.Model): method __repr__ (line 28) | def __repr__(self): FILE: app/models/team_chat.py class ChatChannel (line 12) | class ChatChannel(db.Model): method __repr__ (line 41) | def __repr__(self): method to_dict (line 44) | def to_dict(self): class ChatChannelMember (line 59) | class ChatChannelMember(db.Model): method __repr__ (line 87) | def __repr__(self): class ChatMessage (line 91) | class ChatMessage(db.Model): method __repr__ (line 133) | def __repr__(self): method to_dict (line 136) | def to_dict(self): method parse_mentions (line 156) | def parse_mentions(self): class ChatReadReceipt (line 175) | class ChatReadReceipt(db.Model): method __repr__ (line 191) | def __repr__(self): FILE: app/models/time_entry.py function local_now (line 8) | def local_now(): class TimeEntry (line 17) | class TimeEntry(db.Model): method __init__ (line 46) | def __init__( method __repr__ (line 121) | def __repr__(self): method is_active (line 132) | def is_active(self): method is_paused (line 137) | def is_paused(self): method break_formatted (line 142) | def break_formatted(self): method duration_hours (line 151) | def duration_hours(self): method duration_formatted (line 158) | def duration_formatted(self): method tag_list (line 176) | def tag_list(self): method current_duration_seconds (line 183) | def current_duration_seconds(self): method _naive_dt (line 198) | def _naive_dt(self, dt): method calculate_duration (line 209) | def calculate_duration(self): method stop_timer (line 240) | def stop_timer(self, end_time=None): method pause_timer (line 256) | def pause_timer(self): method resume_timer (line 266) | def resume_timer(self): method update_notes (line 281) | def update_notes(self, notes): method update_tags (line 287) | def update_tags(self, tags): method set_billable (line 293) | def set_billable(self, billable): method set_paid (line 299) | def set_paid(self, paid, invoice_number=None): method to_dict (line 310) | def to_dict(self): method get_active_timers (line 342) | def get_active_timers(cls): method get_user_active_timer (line 347) | def get_user_active_timer(cls, user_id): method get_entries_for_period (line 352) | def get_entries_for_period(cls, start_date=None, end_date=None, user_i... method get_total_hours_for_period (line 374) | def get_total_hours_for_period( FILE: app/models/time_entry_approval.py class ApprovalStatus (line 13) | class ApprovalStatus(enum.Enum): class TimeEntryApproval (line 22) | class TimeEntryApproval(db.Model): method __repr__ (line 70) | def __repr__(self): method to_dict (line 73) | def to_dict(self): method approve (line 90) | def approve(self, approver_id: int, comment: str = None): method reject (line 98) | def reject(self, approver_id: int, reason: str): method cancel (line 106) | def cancel(self): class ApprovalPolicy (line 112) | class ApprovalPolicy(db.Model): method __repr__ (line 148) | def __repr__(self): method to_dict (line 152) | def to_dict(self): method get_approvers (line 168) | def get_approvers(self): method applies_to_entry (line 174) | def applies_to_entry(self, time_entry) -> bool: FILE: app/models/time_entry_template.py class TimeEntryTemplate (line 6) | class TimeEntryTemplate(db.Model): method __repr__ (line 39) | def __repr__(self): method default_duration (line 43) | def default_duration(self): method default_duration (line 50) | def default_duration(self, hours): method record_usage (line 57) | def record_usage(self): method increment_usage (line 62) | def increment_usage(self): method to_dict (line 68) | def to_dict(self): FILE: app/models/time_off.py class TimeOffRequestStatus (line 10) | class TimeOffRequestStatus(enum.Enum): class LeaveType (line 18) | class LeaveType(db.Model): method to_dict (line 31) | def to_dict(self): class TimeOffRequest (line 47) | class TimeOffRequest(db.Model): method to_dict (line 84) | def to_dict(self): class CompanyHoliday (line 107) | class CompanyHoliday(db.Model): method to_dict (line 120) | def to_dict(self): FILE: app/models/timesheet_period.py class TimesheetPeriodStatus (line 10) | class TimesheetPeriodStatus(enum.Enum): class TimesheetPeriod (line 18) | class TimesheetPeriod(db.Model): method is_locked (line 66) | def is_locked(self) -> bool: method contains_date (line 72) | def contains_date(self, value: date) -> bool: method to_dict (line 75) | def to_dict(self): FILE: app/models/timesheet_policy.py class TimesheetPolicy (line 6) | class TimesheetPolicy(db.Model): method get_approver_ids (line 21) | def get_approver_ids(self): method to_dict (line 35) | def to_dict(self): FILE: app/models/user.py class User (line 11) | class User(UserMixin, db.Model): method __init__ (line 184) | def __init__(self, username, role="user", email=None, full_name=None): method __repr__ (line 193) | def __repr__(self): method set_password (line 196) | def set_password(self, password): method check_password (line 206) | def check_password(self, password): method has_password (line 216) | def has_password(self): method set_two_factor_secret (line 220) | def set_two_factor_secret(self, secret: str) -> None: method get_two_factor_secret (line 230) | def get_two_factor_secret(self) -> str: method is_admin (line 234) | def is_admin(self): method is_super_admin (line 243) | def is_super_admin(self): method active_timer (line 249) | def active_timer(self): method total_hours (line 256) | def total_hours(self): method display_name (line 269) | def display_name(self): method get_recent_entries (line 275) | def get_recent_entries(self, limit=10): method update_last_login (line 286) | def update_last_login(self): method is_online (line 291) | def is_online(self): method get_status (line 300) | def get_status(self): method to_dict (line 320) | def to_dict(self, total_hours_override=None): method get_avatar_url (line 362) | def get_avatar_url(self): method get_avatar_path (line 368) | def get_avatar_path(self): method has_avatar (line 382) | def has_avatar(self): method add_favorite_project (line 388) | def add_favorite_project(self, project): method remove_favorite_project (line 394) | def remove_favorite_project(self, project): method is_project_favorite (line 400) | def is_project_favorite(self, project): method get_favorite_projects (line 411) | def get_favorite_projects(self, status="active"): method has_permission (line 419) | def has_permission(self, permission_name): method _auto_assign_role_from_legacy (line 446) | def _auto_assign_role_from_legacy(self): method has_any_permission (line 461) | def has_any_permission(self, *permission_names): method has_all_permissions (line 465) | def has_all_permissions(self, *permission_names): method add_role (line 469) | def add_role(self, role): method remove_role (line 474) | def remove_role(self, role): method get_all_permissions (line 479) | def get_all_permissions(self): method get_role_names (line 487) | def get_role_names(self): method primary_role_name (line 492) | def primary_role_name(self): method is_scope_restricted (line 503) | def is_scope_restricted(self): method is_client_portal_user (line 508) | def is_client_portal_user(self): method get_allowed_client_ids (line 512) | def get_allowed_client_ids(self): method get_allowed_project_ids (line 523) | def get_allowed_project_ids(self): method get_client_portal_data (line 538) | def get_client_portal_data(self): FILE: app/models/user_client.py class UserClient (line 8) | class UserClient(db.Model): method __repr__ (line 20) | def __repr__(self): FILE: app/models/user_favorite_project.py class UserFavoriteProject (line 6) | class UserFavoriteProject(db.Model): method __repr__ (line 19) | def __repr__(self): method to_dict (line 22) | def to_dict(self): FILE: app/models/user_smart_notification_dismissal.py class UserSmartNotificationDismissal (line 8) | class UserSmartNotificationDismissal(db.Model): FILE: app/models/warehouse.py class Warehouse (line 8) | class Warehouse(db.Model): method __init__ (line 32) | def __init__( method __repr__ (line 54) | def __repr__(self): method to_dict (line 57) | def to_dict(self): FILE: app/models/warehouse_stock.py class WarehouseStock (line 9) | class WarehouseStock(db.Model): method __init__ (line 33) | def __init__(self, warehouse_id, stock_item_id, quantity_on_hand=0, qu... method __repr__ (line 40) | def __repr__(self): method quantity_available (line 44) | def quantity_available(self): method reserve (line 48) | def reserve(self, quantity): method release_reservation (line 57) | def release_reservation(self, quantity): method adjust_on_hand (line 65) | def adjust_on_hand(self, quantity): method record_count (line 73) | def record_count(self, counted_quantity, counted_by=None): method to_dict (line 81) | def to_dict(self): FILE: app/models/webhook.py class Webhook (line 13) | class Webhook(db.Model): method __repr__ (line 65) | def __repr__(self): method generate_secret (line 69) | def generate_secret(): method set_secret (line 73) | def set_secret(self, secret=None): method verify_signature (line 79) | def verify_signature(self, payload, signature): method generate_signature (line 103) | def generate_signature(self, payload): method subscribes_to (line 122) | def subscribes_to(self, event_type): method to_dict (line 135) | def to_dict(self, include_secret=False): class WebhookDelivery (line 167) | class WebhookDelivery(db.Model): method __repr__ (line 214) | def __repr__(self): method hash_payload (line 218) | def hash_payload(payload): method mark_success (line 224) | def mark_success(self, status_code, response_body=None, response_heade... method mark_failed (line 241) | def mark_failed( method mark_retrying (line 261) | def mark_retrying(self, next_retry_at): method to_dict (line 267) | def to_dict(self): FILE: app/models/weekly_time_goal.py function local_now (line 8) | def local_now(): class WeeklyTimeGoal (line 20) | class WeeklyTimeGoal(db.Model): method __init__ (line 41) | def __init__(self, user_id, target_hours, week_start_date=None, notes=... method __repr__ (line 82) | def __repr__(self): method actual_hours (line 86) | def actual_hours(self): method progress_percentage (line 107) | def progress_percentage(self): method remaining_hours (line 115) | def remaining_hours(self): method is_completed (line 121) | def is_completed(self): method is_overdue (line 126) | def is_overdue(self): method days_remaining (line 132) | def days_remaining(self): method average_hours_per_day (line 153) | def average_hours_per_day(self): method week_label (line 160) | def week_label(self): method update_status (line 168) | def update_status(self): method to_dict (line 186) | def to_dict(self): method get_current_week_goal (line 210) | def get_current_week_goal(user_id): method get_or_create_current_week (line 231) | def get_or_create_current_week(user_id, default_target_hours=40): FILE: app/models/workflow.py class WorkflowRule (line 12) | class WorkflowRule(db.Model): method __repr__ (line 46) | def __repr__(self): method to_dict (line 49) | def to_dict(self): class WorkflowExecution (line 68) | class WorkflowExecution(db.Model): method __repr__ (line 89) | def __repr__(self): method to_dict (line 92) | def to_dict(self): FILE: app/repositories/base_repository.py class BaseRepository (line 25) | class BaseRepository(Generic[ModelType]): method __init__ (line 41) | def __init__(self, model: type[ModelType]): method get_by_id (line 50) | def get_by_id(self, id: int) -> Optional[ModelType]: method get_all (line 62) | def get_all(self, limit: Optional[int] = None, offset: int = 0) -> Lis... method find_by (line 78) | def find_by(self, **kwargs) -> List[ModelType]: method find_one_by (line 90) | def find_one_by(self, **kwargs) -> Optional[ModelType]: method create (line 102) | def create(self, **kwargs) -> ModelType: method update (line 116) | def update(self, instance: ModelType, **kwargs) -> ModelType: method delete (line 132) | def delete(self, instance: ModelType) -> bool: method count (line 148) | def count(self, **kwargs) -> int: method exists (line 163) | def exists(self, **kwargs) -> bool: method query (line 175) | def query(self) -> Query: FILE: app/repositories/client_repository.py class ClientRepository (line 14) | class ClientRepository(BaseRepository[Client]): method __init__ (line 17) | def __init__(self): method get_with_projects (line 20) | def get_with_projects(self, client_id: int) -> Optional[Client]: method get_active_clients (line 24) | def get_active_clients(self) -> List[Client]: method get_by_name (line 28) | def get_by_name(self, name: str) -> Optional[Client]: FILE: app/repositories/comment_repository.py class CommentRepository (line 14) | class CommentRepository(BaseRepository[Comment]): method __init__ (line 17) | def __init__(self): method get_by_project (line 20) | def get_by_project( method get_by_task (line 34) | def get_by_task(self, task_id: int, include_replies: bool = True, incl... method get_by_quote (line 46) | def get_by_quote( method get_replies (line 67) | def get_replies(self, parent_id: int, include_relations: bool = False)... FILE: app/repositories/expense_repository.py class ExpenseRepository (line 15) | class ExpenseRepository(BaseRepository[Expense]): method __init__ (line 18) | def __init__(self): method get_by_project (line 21) | def get_by_project( method get_billable (line 42) | def get_billable( method get_total_amount (line 59) | def get_total_amount( FILE: app/repositories/invoice_repository.py class InvoiceRepository (line 16) | class InvoiceRepository(BaseRepository[Invoice]): method __init__ (line 19) | def __init__(self): method get_by_project (line 22) | def get_by_project(self, project_id: int, include_relations: bool = Fa... method get_by_client (line 31) | def get_by_client( method get_by_status (line 45) | def get_by_status(self, status: str, include_relations: bool = False) ... method get_overdue (line 54) | def get_overdue(self, include_relations: bool = False) -> List[Invoice]: method get_with_relations (line 66) | def get_with_relations(self, invoice_id: int) -> Optional[Invoice]: method generate_invoice_number (line 70) | def generate_invoice_number(self) -> str: method mark_as_sent (line 74) | def mark_as_sent(self, invoice_id: int) -> Optional[Invoice]: method mark_as_paid (line 82) | def mark_as_paid( FILE: app/repositories/payment_repository.py class PaymentRepository (line 17) | class PaymentRepository(BaseRepository[Payment]): method __init__ (line 20) | def __init__(self): method get_by_invoice (line 23) | def get_by_invoice(self, invoice_id: int, include_relations: bool = Fa... method get_by_date_range (line 32) | def get_by_date_range(self, start_date: date, end_date: date, include_... method get_by_status (line 43) | def get_by_status(self, status: str, include_relations: bool = False) ... method get_total_amount (line 52) | def get_total_amount( method get_total_for_invoice (line 77) | def get_total_for_invoice(self, invoice_id: int) -> Decimal: FILE: app/repositories/project_repository.py class ProjectRepository (line 15) | class ProjectRepository(BaseRepository[Project]): method __init__ (line 18) | def __init__(self): method get_active_projects (line 21) | def get_active_projects( method get_by_client (line 39) | def get_by_client( method get_with_stats (line 53) | def get_with_stats(self, project_id: int) -> Optional[Project]: method archive (line 60) | def archive(self, project_id: int, archived_by: int, reason: Optional[... method unarchive (line 73) | def unarchive(self, project_id: int) -> Optional[Project]: method get_billable_projects (line 84) | def get_billable_projects(self, client_id: Optional[int] = None) -> Li... FILE: app/repositories/recurring_invoice_repository.py class RecurringInvoiceRepository (line 11) | class RecurringInvoiceRepository(BaseRepository[RecurringInvoice]): method __init__ (line 14) | def __init__(self): method list_for_user (line 17) | def list_for_user( FILE: app/repositories/task_repository.py class TaskRepository (line 15) | class TaskRepository(BaseRepository[Task]): method __init__ (line 18) | def __init__(self): method get_by_project (line 21) | def get_by_project( method get_by_assignee (line 35) | def get_by_assignee( method get_by_status (line 49) | def get_by_status( method get_overdue (line 63) | def get_overdue(self, include_relations: bool = False) -> List[Task]: FILE: app/repositories/time_entry_repository.py class TimeEntryRepository (line 17) | class TimeEntryRepository(BaseRepository[TimeEntry]): method __init__ (line 20) | def __init__(self): method get_active_timer (line 23) | def get_active_timer(self, user_id: int) -> Optional[TimeEntry]: method get_by_user (line 27) | def get_by_user( method get_by_project (line 48) | def get_by_project( method get_by_date_range (line 69) | def get_by_date_range( method count_for_date_range (line 100) | def count_for_date_range( method get_billable_entries (line 123) | def get_billable_entries( method stop_timer (line 151) | def stop_timer(self, entry_id: int, end_time: datetime) -> Optional[Ti... method create_timer (line 160) | def create_timer( method create_manual_entry (line 184) | def create_manual_entry( method get_distinct_project_ids_for_user (line 222) | def get_distinct_project_ids_for_user(self, user_id: int) -> List[int]: method get_total_duration (line 233) | def get_total_duration( method get_task_aggregates (line 268) | def get_task_aggregates( FILE: app/repositories/user_repository.py class UserRepository (line 13) | class UserRepository(BaseRepository[User]): method __init__ (line 16) | def __init__(self): method get_by_username (line 19) | def get_by_username(self, username: str) -> Optional[User]: method get_by_role (line 23) | def get_by_role(self, role: str) -> List[User]: method get_active_users (line 27) | def get_active_users(self) -> List[User]: method get_admins (line 31) | def get_admins(self) -> List[User]: FILE: app/routes/activity_feed.py function activity_feed (line 22) | def activity_feed(): function api_activity_feed (line 89) | def api_activity_feed(): FILE: app/routes/admin.py function _ldap_admin_display (line 55) | def _ldap_admin_display(): function _inject_ldap_admin_display (line 89) | def _inject_ldap_admin_display(): function _convert_json_template_to_html_css (line 101) | def _convert_json_template_to_html_css(template_json, page_size="A4", in... function admin_required (line 602) | def admin_required(f): function allowed_logo_file (line 620) | def allowed_logo_file(filename): function get_upload_folder (line 625) | def get_upload_folder(): function admin_dashboard (line 640) | def admin_dashboard(): function admin_dashboard_alias (line 791) | def admin_dashboard_alias(): function list_users (line 803) | def list_users(): function create_user (line 821) | def create_user(): function edit_user (line 888) | def edit_user(user_id): function delete_user (line 1046) | def delete_user(user_id): function telemetry_dashboard (line 1088) | def telemetry_dashboard(): function toggle_telemetry (line 1130) | def toggle_telemetry(): function clear_cache (line 1160) | def clear_cache(): function manage_modules (line 1168) | def manage_modules(): function settings (line 1298) | def settings(): function admin_ldap_test (line 1607) | def admin_ldap_test(): function admin_verify_donate_hide_code (line 1617) | def admin_verify_donate_hide_code(): function pdf_layout (line 1656) | def pdf_layout(): function pdf_layout_reset (line 1960) | def pdf_layout_reset(): function quote_pdf_layout (line 2006) | def quote_pdf_layout(): function quote_pdf_layout_reset (line 2282) | def quote_pdf_layout_reset(): function quote_pdf_layout_export_json (line 2320) | def quote_pdf_layout_export_json(page_size): function quote_pdf_layout_import_json (line 2355) | def quote_pdf_layout_import_json(): function pdf_layout_export_json (line 2431) | def pdf_layout_export_json(page_size): function pdf_layout_import_json (line 2466) | def pdf_layout_import_json(): function pdf_layout_debug (line 2542) | def pdf_layout_debug(): function pdf_layout_default (line 2593) | def pdf_layout_default(): function pdf_layout_preview (line 2628) | def pdf_layout_preview(): function quote_pdf_layout_preview (line 3300) | def quote_pdf_layout_preview(): function upload_logo (line 3885) | def upload_logo(): function remove_logo (line 3957) | def remove_logo(): function upload_template_image (line 3986) | def upload_template_image(): function serve_template_image (line 4039) | def serve_template_image(filename): function serve_uploaded_logo (line 4051) | def serve_uploaded_logo(filename): function backups_management (line 4073) | def backups_management(): function create_backup_manual (line 4102) | def create_backup_manual(): function download_backup (line 4119) | def download_backup(filename): function delete_backup (line 4140) | def delete_backup(filename): function restore (line 4168) | def restore(filename=None): function system_info (line 4245) | def system_info(): function oidc_debug (line 4286) | def oidc_debug(): function oidc_test (line 4357) | def oidc_test(): function oidc_user_detail (line 4553) | def oidc_user_detail(user_id): function oidc_setup_wizard (line 4566) | def oidc_setup_wizard(): function oidc_wizard_test_connection (line 4598) | def oidc_wizard_test_connection(): function oidc_wizard_validate_config (line 4667) | def oidc_wizard_validate_config(): function oidc_wizard_generate_config (line 4721) | def oidc_wizard_generate_config(): function _ldap_wizard_truthy (line 4802) | def _ldap_wizard_truthy(val) -> bool: function _ldap_wizard_int (line 4811) | def _ldap_wizard_int(val, default: int, *, lo: int | None = None, hi: in... function _ldap_wizard_cfg_from_json (line 4823) | def _ldap_wizard_cfg_from_json(data: dict) -> dict[str, object]: function _ldap_wizard_escape_env_value (line 4848) | def _ldap_wizard_escape_env_value(value: object) -> str: function ldap_setup_wizard (line 4859) | def ldap_setup_wizard(): function ldap_wizard_test_connection (line 4894) | def ldap_wizard_test_connection(): function ldap_wizard_validate_config (line 4908) | def ldap_wizard_validate_config(): function ldap_wizard_generate_config (line 4970) | def ldap_wizard_generate_config(): function api_tokens (line 5047) | def api_tokens(): function create_api_token (line 5060) | def create_api_token(): function toggle_api_token (line 5112) | def toggle_api_token(token_id): function delete_api_token (line 5133) | def delete_api_token(token_id): function email_support (line 5157) | def email_support(): function test_email (line 5175) | def test_email(): function email_config_status (line 5206) | def email_config_status(): function save_email_config (line 5218) | def save_email_config(): function get_email_config (line 5291) | def get_email_config(): function list_email_templates (line 5319) | def list_email_templates(): function create_email_template (line 5331) | def create_email_template(): function send_email_template_test (line 5393) | def send_email_template_test(template_id): function view_email_template (line 5431) | def view_email_template(template_id): function edit_email_template (line 5443) | def edit_email_template(template_id): function delete_email_template (line 5492) | def delete_email_template(template_id): function list_integrations_admin (line 5519) | def list_integrations_admin(): function integration_setup (line 5527) | def integration_setup(provider): FILE: app/routes/analytics.py function analytics_dashboard (line 18) | def analytics_dashboard(): function hours_by_day (line 38) | def hours_by_day(): function hours_forecast (line 100) | def hours_forecast(): function hours_by_project (line 163) | def hours_by_project(): function hours_by_user (line 221) | def hours_by_user(): function hours_by_hour (line 266) | def hours_by_hour(): function billable_vs_nonbillable (line 312) | def billable_vs_nonbillable(): function weekly_trends (line 358) | def weekly_trends(): function overtime_analytics (line 455) | def overtime_analytics(): function project_efficiency (line 558) | def project_efficiency(): function today_by_task (line 619) | def today_by_task(): function summary_with_comparison (line 687) | def summary_with_comparison(): function task_completion (line 775) | def task_completion(): function revenue_metrics (line 844) | def revenue_metrics(): function insights (line 945) | def insights(): function payments_over_time (line 1064) | def payments_over_time(): function payments_by_status (line 1123) | def payments_by_status(): function payments_by_method (line 1164) | def payments_by_method(): function payment_summary (line 1213) | def payment_summary(): function revenue_vs_payments (line 1295) | def revenue_vs_payments(): FILE: app/routes/api.py function _ai_error_response (line 38) | def _ai_error_response(exc: AIServiceError): function health_check (line 44) | def health_check(): function ai_context_preview (line 51) | def ai_context_preview(): function ai_test_connection (line 62) | def ai_test_connection(): function ai_chat (line 74) | def ai_chat(): function ai_confirm_action (line 86) | def ai_confirm_action(): function _effective_user_for_version_api (line 96) | def _effective_user_for_version_api(): function api_version_check (line 110) | def api_version_check(): function api_version_dismiss (line 123) | def api_version_dismiss(): function timer_status (line 155) | def timer_status(): function get_recent_tags (line 180) | def get_recent_tags(): function search (line 210) | def search(): function upcoming_deadlines (line 249) | def upcoming_deadlines(): function list_tasks_for_project (line 290) | def list_tasks_for_project(): function api_start_timer (line 316) | def api_start_timer(): function api_stop_timer (line 368) | def api_stop_timer(): function api_stop_timer_at (line 396) | def api_stop_timer_at(): function api_resume_timer (line 448) | def api_resume_timer(): function get_entries (line 510) | def get_entries(): function project_burndown (line 575) | def project_burndown(project_id): function start_focus_session (line 636) | def start_focus_session(): function finish_focus_session (line 669) | def finish_focus_session(): function focus_sessions_summary (line 690) | def focus_sessions_summary(): function recurring_blocks_list_create (line 704) | def recurring_blocks_list_create(): function recurring_block_update_delete (line 761) | def recurring_block_update_delete(block_id): function saved_filters_list_create (line 798) | def saved_filters_list_create(): function delete_saved_filter (line 820) | def delete_saved_filter(filter_id): function create_entry (line 833) | def create_entry(): function bulk_entries_action (line 935) | def bulk_entries_action(): function calendar_events (line 961) | def calendar_events(): function calendar_export (line 1122) | def calendar_export(): function get_projects (line 1247) | def get_projects(): function get_project_tasks (line 1256) | def get_project_tasks(project_id): function create_task_inline (line 1287) | def create_task_inline(): function get_entry (line 1405) | def get_entry(entry_id): function get_users (line 1417) | def get_users(): function get_stats (line 1442) | def get_stats(): function value_dashboard_stats (line 1486) | def value_dashboard_stats(): function week_comparison (line 1495) | def week_comparison(): function update_entry (line 1573) | def update_entry(entry_id): function delete_entry (line 1671) | def delete_entry(entry_id): function allowed_image_file (line 1708) | def allowed_image_file(filename: str) -> bool: function get_editor_upload_folder (line 1712) | def get_editor_upload_folder() -> str: function upload_editor_image (line 1720) | def upload_editor_image(): function upload_editor_images_bulk (line 1743) | def upload_editor_images_bulk(): function serve_editor_image (line 1787) | def serve_editor_image(filename): function get_activities (line 1801) | def get_activities(): function dashboard_stats (line 1868) | def dashboard_stats(): function dashboard_sparklines (line 1909) | def dashboard_sparklines(): function summary_today (line 1957) | def summary_today(): function api_smart_notifications (line 1967) | def api_smart_notifications(): function api_smart_notifications_dismiss (line 1976) | def api_smart_notifications_dismiss(): function activity_timeline (line 1995) | def activity_timeline(): function get_activity_stats (line 2028) | def get_activity_stats(): function handle_connect (line 2091) | def handle_connect(): function handle_disconnect (line 2097) | def handle_disconnect(): function handle_join_user_room (line 2103) | def handle_join_user_room(data): function handle_leave_user_room (line 2112) | def handle_leave_user_room(data): function _get_client_id_from_session (line 2121) | def _get_client_id_from_session(): function handle_join_client_room (line 2139) | def handle_join_client_room(data): function handle_leave_client_room (line 2149) | def handle_leave_client_room(data): FILE: app/routes/api_docs.py function openapi_spec (line 32) | def openapi_spec(): FILE: app/routes/api_v1.py function api_info (line 90) | def api_info(): function health_check (line 206) | def health_check(): function auth_login (line 223) | def auth_login(): function list_time_entry_approvals (line 274) | def list_time_entry_approvals(): function get_time_entry_approval (line 288) | def get_time_entry_approval(approval_id): function approve_time_entry (line 306) | def approve_time_entry(approval_id): function reject_time_entry (line 323) | def reject_time_entry(approval_id): function cancel_time_entry_approval (line 343) | def cancel_time_entry_approval(approval_id): function request_time_entry_approval (line 359) | def request_time_entry_approval(entry_id): function bulk_approve_time_entries (line 381) | def bulk_approve_time_entries(): function list_per_diems (line 402) | def list_per_diems(): function get_per_diem (line 438) | def get_per_diem(pd_id): function create_per_diem (line 456) | def create_per_diem(): function update_per_diem (line 503) | def update_per_diem(pd_id): function delete_per_diem (line 549) | def delete_per_diem(pd_id): function list_per_diem_rates (line 569) | def list_per_diem_rates(): function create_per_diem_rate (line 598) | def create_per_diem_rate(): function list_budget_alerts (line 643) | def list_budget_alerts(): function create_budget_alert (line 680) | def create_budget_alert(): function acknowledge_budget_alert (line 707) | def acknowledge_budget_alert(alert_id): function list_calendar_events (line 726) | def list_calendar_events(): function get_calendar_event (line 759) | def get_calendar_event(event_id): function create_calendar_event (line 777) | def create_calendar_event(): function update_calendar_event (line 815) | def update_calendar_event(event_id): function delete_calendar_event (line 846) | def delete_calendar_event(event_id): function list_kanban_columns (line 869) | def list_kanban_columns(): function create_kanban_column (line 886) | def create_kanban_column(): function update_kanban_column (line 915) | def update_kanban_column(col_id): function delete_kanban_column (line 935) | def delete_kanban_column(col_id): function reorder_kanban_columns (line 955) | def reorder_kanban_columns(): function list_saved_filters (line 975) | def list_saved_filters(): function get_saved_filter (line 1007) | def get_saved_filter(filter_id): function create_saved_filter (line 1025) | def create_saved_filter(): function update_saved_filter (line 1050) | def update_saved_filter(filter_id): function delete_saved_filter (line 1073) | def delete_saved_filter(filter_id): function list_time_entry_templates (line 1096) | def list_time_entry_templates(): function get_time_entry_template (line 1128) | def get_time_entry_template(tpl_id): function create_time_entry_template (line 1150) | def create_time_entry_template(): function update_time_entry_template (line 1179) | def update_time_entry_template(tpl_id): function delete_time_entry_template (line 1215) | def delete_time_entry_template(tpl_id): function list_comments (line 1242) | def list_comments(): function create_comment (line 1268) | def create_comment(): function list_quotes (line 1292) | def list_quotes(): function get_quote (line 1345) | def get_quote(quote_id): function create_quote (line 1369) | def create_quote(): function update_quote (line 1454) | def update_quote(quote_id): function delete_quote (line 1545) | def delete_quote(quote_id): function update_comment (line 1578) | def update_comment(comment_id): function delete_comment (line 1608) | def delete_comment(comment_id): function list_client_notes (line 1634) | def list_client_notes(client_id): function create_client_note (line 1665) | def create_client_note(client_id): function get_client_note (line 1684) | def get_client_note(note_id): function update_client_note (line 1701) | def update_client_note(note_id): function delete_client_note (line 1728) | def delete_client_note(note_id): function list_project_costs (line 1753) | def list_project_costs(project_id): function create_project_cost (line 1795) | def create_project_cost(project_id): function get_project_cost (line 1829) | def get_project_cost(cost_id): function update_project_cost (line 1843) | def update_project_cost(cost_id): function delete_project_cost (line 1872) | def delete_project_cost(cost_id): function list_tax_rules (line 1891) | def list_tax_rules(): function create_tax_rule (line 1921) | def create_tax_rule(): function update_tax_rule (line 1954) | def update_tax_rule(rule_id): function delete_tax_rule (line 1994) | def delete_tax_rule(rule_id): function list_currencies (line 2006) | def list_currencies(): function create_currency (line 2026) | def create_currency(): function update_currency (line 2049) | def update_currency(code): function list_exchange_rates (line 2061) | def list_exchange_rates(): function create_exchange_rate (line 2094) | def create_exchange_rate(): function update_exchange_rate (line 2123) | def update_exchange_rate(rate_id): function list_favorite_projects (line 2148) | def list_favorite_projects(): function add_favorite_project (line 2155) | def add_favorite_project(): function remove_favorite_project (line 2172) | def remove_favorite_project(project_id): function list_audit_logs (line 2184) | def list_audit_logs(): function list_activities (line 2206) | def list_activities(): function list_invoice_pdf_templates (line 2220) | def list_invoice_pdf_templates(): function get_invoice_pdf_template (line 2227) | def get_invoice_pdf_template(page_size): function list_invoice_templates (line 2237) | def list_invoice_templates(): function get_invoice_template (line 2261) | def get_invoice_template(template_id): function create_invoice_template (line 2281) | def create_invoice_template(): function update_invoice_template (line 2306) | def update_invoice_template(template_id): function delete_invoice_template (line 2331) | def delete_invoice_template(template_id): function list_recurring_invoices (line 2344) | def list_recurring_invoices(): function get_recurring_invoice (line 2386) | def get_recurring_invoice(ri_id): function create_recurring_invoice (line 2401) | def create_recurring_invoice(): function update_recurring_invoice (line 2447) | def update_recurring_invoice(ri_id): function delete_recurring_invoice (line 2495) | def delete_recurring_invoice(ri_id): function generate_from_recurring_invoice (line 2505) | def generate_from_recurring_invoice(ri_id): function list_credit_notes (line 2520) | def list_credit_notes(): function get_credit_note (line 2572) | def get_credit_note(cn_id): function create_credit_note (line 2595) | def create_credit_note(): function update_credit_note (line 2643) | def update_credit_note(cn_id): function delete_credit_note (line 2665) | def delete_credit_note(cn_id): function report_summary (line 2681) | def report_summary(): function get_current_user (line 2783) | def get_current_user(): function list_users (line 2808) | def list_users(): function list_webhooks (line 2859) | def list_webhooks(): function create_webhook (line 2901) | def create_webhook(): function get_webhook (line 2972) | def get_webhook(webhook_id): function update_webhook (line 3003) | def update_webhook(webhook_id): function delete_webhook (line 3086) | def delete_webhook(webhook_id): function list_webhook_deliveries (line 3120) | def list_webhook_deliveries(webhook_id): function list_webhook_events (line 3171) | def list_webhook_events(): function list_stock_items_api (line 3194) | def list_stock_items_api(): function get_stock_item_api (line 3220) | def get_stock_item_api(item_id): function create_stock_item_api (line 3228) | def create_stock_item_api(): function update_stock_item_api (line 3264) | def update_stock_item_api(item_id): function delete_stock_item_api (line 3304) | def delete_stock_item_api(item_id): function get_stock_availability_api (line 3321) | def get_stock_availability_api(item_id): function list_warehouses_api (line 3351) | def list_warehouses_api(): function get_stock_levels_api (line 3367) | def get_stock_levels_api(): function create_stock_movement_api (line 3404) | def create_stock_movement_api(): function list_transfers_api (line 3655) | def list_transfers_api(): function create_transfer_api (line 3734) | def create_transfer_api(): function get_transfer_api (line 3842) | def get_transfer_api(reference_id): function get_inventory_valuation_report_api (line 3881) | def get_inventory_valuation_report_api(): function get_inventory_movement_history_report_api (line 3903) | def get_inventory_movement_history_report_api(): function get_inventory_turnover_report_api (line 3935) | def get_inventory_turnover_report_api(): function get_inventory_low_stock_report_api (line 3966) | def get_inventory_low_stock_report_api(): function list_suppliers_api (line 3985) | def list_suppliers_api(): function get_supplier_api (line 4011) | def get_supplier_api(supplier_id): function create_supplier_api (line 4021) | def create_supplier_api(): function update_supplier_api (line 4060) | def update_supplier_api(supplier_id): function delete_supplier_api (line 4102) | def delete_supplier_api(supplier_id): function get_supplier_stock_items_api (line 4121) | def get_supplier_stock_items_api(supplier_id): function list_purchase_orders_api (line 4146) | def list_purchase_orders_api(): function get_purchase_order_api (line 4171) | def get_purchase_order_api(po_id): function create_purchase_order_api (line 4181) | def create_purchase_order_api(): function update_purchase_order_api (line 4289) | def update_purchase_order_api(po_id): function delete_purchase_order_api (line 4371) | def delete_purchase_order_api(po_id): function receive_purchase_order_api (line 4405) | def receive_purchase_order_api(po_id): function search (line 4451) | def search(): function _is_api_approver (line 4549) | def _is_api_approver(user) -> bool: function list_timesheet_periods (line 4564) | def list_timesheet_periods(): function create_or_get_timesheet_period (line 4582) | def create_or_get_timesheet_period(): function submit_timesheet_period (line 4600) | def submit_timesheet_period(period_id): function approve_timesheet_period (line 4611) | def approve_timesheet_period(period_id): function reject_timesheet_period (line 4628) | def reject_timesheet_period(period_id): function close_timesheet_period (line 4647) | def close_timesheet_period(period_id): function delete_timesheet_period_api (line 4664) | def delete_timesheet_period_api(period_id): function get_timesheet_policy (line 4675) | def get_timesheet_policy(): function update_timesheet_policy (line 4686) | def update_timesheet_policy(): function list_leave_types_api (line 4720) | def list_leave_types_api(): function create_leave_type_api (line 4730) | def create_leave_type_api(): function delete_leave_type_api (line 4757) | def delete_leave_type_api(leave_type_id): function list_time_off_requests_api (line 4770) | def list_time_off_requests_api(): function create_time_off_request_api (line 4798) | def create_time_off_request_api(): function approve_time_off_request_api (line 4833) | def approve_time_off_request_api(request_id): function reject_time_off_request_api (line 4850) | def reject_time_off_request_api(request_id): function delete_time_off_request_api (line 4867) | def delete_time_off_request_api(request_id): function time_off_balances_api (line 4882) | def time_off_balances_api(): function list_holidays_api (line 4894) | def list_holidays_api(): function create_holiday_api (line 4910) | def create_holiday_api(): function delete_holiday_api (line 4933) | def delete_holiday_api(holiday_id): function export_payroll_csv (line 4949) | def export_payroll_csv(): function capacity_report_api (line 5018) | def capacity_report_api(): function compliance_locked_periods_api (line 5047) | def compliance_locked_periods_api(): function compliance_audit_events_api (line 5061) | def compliance_audit_events_api(): function mileage_gps_start_api (line 5080) | def mileage_gps_start_api(): function mileage_gps_add_point_api (line 5097) | def mileage_gps_add_point_api(track_id): function mileage_gps_stop_api (line 5114) | def mileage_gps_stop_api(track_id): function mileage_gps_create_expense_api (line 5131) | def mileage_gps_create_expense_api(track_id): function mileage_gps_list_api (line 5147) | def mileage_gps_list_api(): function not_found (line 5165) | def not_found(error): function internal_error (line 5171) | def internal_error(error): FILE: app/routes/api_v1_ai.py function _ai_error_response (line 11) | def _ai_error_response(exc: AIServiceError): function ai_context_preview (line 17) | def ai_context_preview(): function ai_chat (line 27) | def ai_chat(): function ai_confirm_action (line 38) | def ai_confirm_action(): FILE: app/routes/api_v1_clients.py function list_clients (line 19) | def list_clients(): function get_client (line 50) | def get_client(client_id): function create_client (line 67) | def create_client(): function _resolve_actor_for_invoice_unbilled (line 98) | def _resolve_actor_for_invoice_unbilled(): function post_client_invoice_unbilled (line 177) | def post_client_invoice_unbilled(client_id): FILE: app/routes/api_v1_common.py function paginate_query (line 9) | def paginate_query(query, page=None, per_page=None): function parse_datetime (line 32) | def parse_datetime(dt_str): function _parse_date (line 52) | def _parse_date(dstr): function _parse_date_range (line 64) | def _parse_date_range(start_date_str, end_date_str): function _require_module_enabled_for_api (line 75) | def _require_module_enabled_for_api(module_id: str): FILE: app/routes/api_v1_contacts.py function list_contacts (line 19) | def list_contacts(client_id): function create_contact (line 35) | def create_contact(client_id): function get_contact (line 77) | def get_contact(contact_id): function update_contact (line 88) | def update_contact(contact_id): function delete_contact (line 128) | def delete_contact(contact_id): FILE: app/routes/api_v1_deals.py function list_deals (line 21) | def list_deals(): function get_deal (line 61) | def get_deal(deal_id): function create_deal (line 74) | def create_deal(): function update_deal (line 119) | def update_deal(deal_id): function delete_deal (line 157) | def delete_deal(deal_id): FILE: app/routes/api_v1_expenses.py function list_expenses (line 19) | def list_expenses(): function get_expense (line 67) | def get_expense(expense_id): function create_expense (line 85) | def create_expense(): function update_expense (line 137) | def update_expense(expense_id): function delete_expense (line 171) | def delete_expense(expense_id): FILE: app/routes/api_v1_invoices.py function list_invoices (line 18) | def list_invoices(): function get_invoice (line 49) | def get_invoice(invoice_id): function create_invoice (line 65) | def create_invoice(): function update_invoice (line 114) | def update_invoice(invoice_id): function delete_invoice (line 153) | def delete_invoice(invoice_id): FILE: app/routes/api_v1_leads.py function list_leads (line 22) | def list_leads(): function get_lead (line 71) | def get_lead(lead_id): function create_lead (line 84) | def create_lead(): function update_lead (line 124) | def update_lead(lead_id): function delete_lead (line 164) | def delete_lead(lead_id): FILE: app/routes/api_v1_mileage.py function list_mileage (line 21) | def list_mileage(): function get_mileage (line 63) | def get_mileage(entry_id): function create_mileage (line 79) | def create_mileage(): function update_mileage (line 126) | def update_mileage(entry_id): function delete_mileage (line 174) | def delete_mileage(entry_id): FILE: app/routes/api_v1_payments.py function list_payments (line 19) | def list_payments(): function get_payment (line 48) | def get_payment(payment_id): function create_payment (line 60) | def create_payment(): function update_payment (line 101) | def update_payment(payment_id): function delete_payment (line 128) | def delete_payment(payment_id): FILE: app/routes/api_v1_projects.py function list_projects (line 23) | def list_projects(): function get_project (line 58) | def get_project(project_id): function create_project (line 76) | def create_project(): function update_project (line 114) | def update_project(project_id): function delete_project (line 150) | def delete_project(project_id): FILE: app/routes/api_v1_tasks.py function list_tasks (line 17) | def list_tasks(): function get_task (line 51) | def get_task(task_id): function create_task (line 67) | def create_task(): function update_task (line 99) | def update_task(task_id): function delete_task (line 131) | def delete_task(task_id): FILE: app/routes/api_v1_time_entries.py function list_time_entries (line 24) | def list_time_entries(): function get_time_entry (line 75) | def get_time_entry(entry_id): function import_time_entries_csv (line 93) | def import_time_entries_csv(): function bulk_time_entries (line 115) | def bulk_time_entries(): function create_time_entry (line 145) | def create_time_entry(): function update_time_entry (line 246) | def update_time_entry(entry_id): function delete_time_entry (line 318) | def delete_time_entry(entry_id): function timer_status (line 341) | def timer_status(): function start_timer (line 351) | def start_timer(): function pause_timer (line 392) | def pause_timer(): function resume_timer (line 409) | def resume_timer(): function stop_timer (line 426) | def stop_timer(): FILE: app/routes/audit_logs.py function list_audit_logs (line 20) | def list_audit_logs(): function view_audit_log (line 111) | def view_audit_log(log_id): function entity_history (line 124) | def entity_history(entity_type, entity_id): function api_audit_logs (line 203) | def api_audit_logs(): function audit_logs_status (line 233) | def audit_logs_status(): FILE: app/routes/auth.py function allowed_avatar_file (line 37) | def allowed_avatar_file(filename: str) -> bool: function get_avatar_upload_folder (line 41) | def get_avatar_upload_folder() -> str: function _login_template_vars (line 51) | def _login_template_vars(): function _password_reset_serializer (line 73) | def _password_reset_serializer(): function _make_password_reset_token (line 79) | def _make_password_reset_token(user: User) -> str: function _verify_password_reset_token (line 84) | def _verify_password_reset_token(token: str, *, max_age_seconds: int) ->... function _finalize_login_after_verification (line 106) | def _finalize_login_after_verification(user: User, *, log_auth_method: s... function forgot_password (line 168) | def forgot_password(): function reset_password (line 235) | def reset_password(token: str): function login (line 282) | def login(): function two_factor (line 545) | def two_factor(): function two_factor_setup (line 590) | def two_factor_setup(): function logout (line 683) | def logout(): function profile (line 755) | def profile(): function edit_profile (line 762) | def edit_profile(): function change_password (line 870) | def change_password(): function remove_avatar (line 923) | def remove_avatar(): function serve_uploaded_avatar (line 947) | def serve_uploaded_avatar(filename): function update_theme_preference (line 954) | def update_theme_preference(): function login_oidc (line 977) | def login_oidc(): function oidc_callback (line 1126) | def oidc_callback(): FILE: app/routes/budget_alerts.py function budget_dashboard (line 33) | def budget_dashboard(): function get_burn_rate (line 96) | def get_burn_rate(project_id): function get_completion_estimate (line 124) | def get_completion_estimate(project_id): function get_resource_allocation (line 151) | def get_resource_allocation(project_id): function get_cost_trends (line 178) | def get_cost_trends(project_id): function get_project_budget_status (line 210) | def get_project_budget_status(project_id): function get_alerts (line 234) | def get_alerts(): function acknowledge_alert (line 261) | def acknowledge_alert(alert_id): function check_project_alerts (line 287) | def check_project_alerts(project_id): function project_budget_detail (line 321) | def project_budget_detail(project_id): function get_budget_summary (line 378) | def get_budget_summary(): FILE: app/routes/calendar.py function view_calendar (line 25) | def view_calendar(): function get_events (line 76) | def get_events(): function create_event (line 170) | def create_event(): function get_event (line 229) | def get_event(event_id): function update_event (line 242) | def update_event(event_id): function delete_event (line 309) | def delete_event(event_id): function move_event (line 344) | def move_event(event_id): function resize_event (line 375) | def resize_event(event_id): function view_event (line 409) | def view_event(event_id): function new_event (line 423) | def new_event(): function edit_event (line 460) | def edit_event(event_id): function list_integrations (line 481) | def list_integrations(): function connect_google (line 489) | def connect_google(): function disconnect_integration (line 496) | def disconnect_integration(integration_id): FILE: app/routes/client_notes.py function _enforce_clients_module (line 14) | def _enforce_clients_module(): function create_note (line 29) | def create_note(client_id): function edit_note (line 66) | def edit_note(client_id, note_id): function delete_note (line 112) | def delete_note(client_id, note_id): function toggle_important (line 148) | def toggle_important(client_id, note_id): function list_notes (line 187) | def list_notes(client_id): function get_note (line 206) | def get_note(note_id): function get_important_notes (line 220) | def get_important_notes(): function get_recent_notes (line 236) | def get_recent_notes(): function get_user_notes (line 252) | def get_user_notes(user_id): FILE: app/routes/client_portal.py function handle_forbidden (line 56) | def handle_forbidden(error): function handle_not_found (line 97) | def handle_not_found(error): function handle_internal_error (line 116) | def handle_internal_error(error): function get_current_client (line 137) | def get_current_client(): function inject_get_current_client (line 156) | def inject_get_current_client(): function check_client_portal_access (line 187) | def check_client_portal_access(): function get_portal_data (line 270) | def get_portal_data(client): function get_dashboard_preferences (line 292) | def get_dashboard_preferences(client_id, user_id=None): function get_effective_widget_layout (line 306) | def get_effective_widget_layout(client_id, user_id=None): function login (line 316) | def login(): function logout (line 354) | def logout(): function set_password (line 362) | def set_password(): function client_portal_base (line 409) | def client_portal_base(): function dashboard (line 419) | def dashboard(): function dashboard_preferences_get (line 496) | def dashboard_preferences_get(): function dashboard_preferences_post (line 508) | def dashboard_preferences_post(): function projects (line 555) | def projects(): function invoices (line 581) | def invoices(): function view_invoice (line 610) | def view_invoice(invoice_id): function quotes (line 627) | def quotes(): function view_quote (line 643) | def view_quote(quote_id): function time_entries (line 660) | def time_entries(): function issues (line 709) | def issues(): function new_issue (line 743) | def new_issue(): function view_issue (line 835) | def view_issue(issue_id): function time_entry_approvals (line 860) | def time_entry_approvals(): function view_approval (line 903) | def view_approval(approval_id): function approve_time_entry (line 923) | def approve_time_entry(approval_id): function reject_time_entry (line 963) | def reject_time_entry(approval_id): function accept_quote (line 1009) | def accept_quote(quote_id): function reject_quote (line 1054) | def reject_quote(quote_id): function pay_invoice (line 1105) | def pay_invoice(invoice_id): function project_comments (line 1142) | def project_comments(project_id): function notifications (line 1199) | def notifications(): function mark_notification_read (line 1228) | def mark_notification_read(notification_id): function mark_all_notifications_read (line 1247) | def mark_all_notifications_read(): function documents (line 1267) | def documents(): function download_attachment (line 1316) | def download_attachment(attachment_id): function _report_days_from_request (line 1364) | def _report_days_from_request(): function reports (line 1373) | def reports(): function _reports_csv_response (line 1407) | def _reports_csv_response(client, report_data, date_range_days): function activity_feed (line 1448) | def activity_feed(): FILE: app/routes/client_portal_customization.py function allowed_file (line 34) | def allowed_file(filename): function get_upload_folder (line 38) | def get_upload_folder(): function edit_customization (line 47) | def edit_customization(client_id): function update_customization (line 66) | def update_customization(client_id): function serve_portal_upload (line 144) | def serve_portal_upload(filename): FILE: app/routes/clients.py function _wants_json_response (line 41) | def _wants_json_response() -> bool: function _enforce_clients_module (line 54) | def _enforce_clients_module(): function list_clients (line 77) | def list_clients(): function create_client (line 230) | def create_client(): function view_client (line 432) | def view_client(client_id): function edit_client (line 573) | def edit_client(client_id): function send_portal_password_email (line 736) | def send_portal_password_email(client_id): function archive_client (line 809) | def archive_client(client_id): function activate_client (line 838) | def activate_client(client_id): function delete_client (line 865) | def delete_client(client_id): function bulk_delete_clients (line 924) | def bulk_delete_clients(): function bulk_status_change (line 1014) | def bulk_status_change(): function export_clients (line 1084) | def export_clients(): function api_clients (line 1226) | def api_clients(): function upload_client_attachment (line 1245) | def upload_client_attachment(client_id): function download_client_attachment (line 1363) | def download_client_attachment(attachment_id): function delete_client_attachment (line 1387) | def delete_client_attachment(attachment_id): FILE: app/routes/comments.py function create_comment (line 18) | def create_comment(): function edit_comment (line 103) | def edit_comment(comment_id): function delete_comment (line 146) | def delete_comment(comment_id): function list_comments (line 186) | def list_comments(): function get_comment (line 223) | def get_comment(comment_id): function get_recent_comments (line 235) | def get_recent_comments(): function get_user_comments (line 249) | def get_user_comments(user_id): function upload_comment_attachment (line 268) | def upload_comment_attachment(comment_id): function download_attachment (line 360) | def download_attachment(attachment_id): function delete_attachment (line 379) | def delete_attachment(attachment_id): FILE: app/routes/contacts.py function list_contacts (line 21) | def list_contacts(client_id): function create_contact (line 30) | def create_contact(client_id): function view_contact (line 73) | def view_contact(contact_id): function edit_contact (line 82) | def edit_contact(contact_id): function delete_contact (line 120) | def delete_contact(contact_id): function set_primary_contact (line 139) | def set_primary_contact(contact_id): function create_communication (line 156) | def create_communication(contact_id): FILE: app/routes/custom_field_definitions.py function list_custom_field_definitions (line 20) | def list_custom_field_definitions(): function create_custom_field_definition (line 32) | def create_custom_field_definition(): function edit_custom_field_definition (line 87) | def edit_custom_field_definition(definition_id): function delete_custom_field_definition (line 143) | def delete_custom_field_definition(definition_id): FILE: app/routes/custom_reports.py function report_builder (line 29) | def report_builder(view_id=None): function save_report_view (line 86) | def save_report_view(): function view_custom_report (line 186) | def view_custom_report(view_id): function preview_report (line 220) | def preview_report(): function get_report_data (line 252) | def get_report_data(view_id): function generate_report_data (line 275) | def generate_report_data(config, user_id=None): function list_saved_views (line 638) | def list_saved_views(): function edit_saved_view (line 655) | def edit_saved_view(view_id): function get_custom_field_values (line 671) | def get_custom_field_values(): function delete_saved_view (line 693) | def delete_saved_view(view_id): function _generate_iterative_reports (line 723) | def _generate_iterative_reports(saved_view: SavedReportView, config: dic... FILE: app/routes/deals.py function list_deals (line 26) | def list_deals(): function pipeline_view (line 70) | def pipeline_view(): function create_deal (line 96) | def create_deal(): function view_deal (line 162) | def view_deal(deal_id): function edit_deal (line 179) | def edit_deal(deal_id): function close_won (line 242) | def close_won(deal_id): function close_lost (line 268) | def close_lost(deal_id): function create_activity (line 296) | def create_activity(deal_id): function get_deal_contacts (line 337) | def get_deal_contacts(deal_id): FILE: app/routes/expense_categories.py function list_categories (line 19) | def list_categories(): function create_category (line 38) | def create_category(): function view_category (line 107) | def view_category(category_id): function edit_category (line 132) | def edit_category(category_id): function delete_category (line 193) | def delete_category(category_id): function api_list_categories (line 221) | def api_list_categories(): function api_get_category (line 230) | def api_get_category(category_id): function api_budget_alerts (line 240) | def api_budget_alerts(): FILE: app/routes/expenses.py function allowed_file (line 38) | def allowed_file(filename): function get_receipt_upload_folder (line 43) | def get_receipt_upload_folder(): function list_expenses (line 84) | def list_expenses(): function create_expense (line 250) | def create_expense(): function view_expense (line 429) | def view_expense(expense_id): function serve_receipt (line 449) | def serve_receipt(filename): function edit_expense (line 501) | def edit_expense(expense_id): function delete_expense (line 656) | def delete_expense(expense_id): function bulk_delete_expenses (line 699) | def bulk_delete_expenses(): function bulk_update_status (line 769) | def bulk_update_status(): function approve_expense (line 833) | def approve_expense(expense_id): function reject_expense (line 865) | def reject_expense(expense_id): function mark_reimbursed (line 901) | def mark_reimbursed(expense_id): function export_expenses (line 936) | def export_expenses(): function dashboard (line 1049) | def dashboard(): function api_list_expenses (line 1137) | def api_list_expenses(): function api_get_expense (line 1178) | def api_get_expense(expense_id): function api_scan_receipt (line 1191) | def api_scan_receipt(): function scan_receipt_page (line 1253) | def scan_receipt_page(): function create_expense_from_scan (line 1340) | def create_expense_from_scan(): FILE: app/routes/gantt.py function gantt_view (line 21) | def gantt_view(): function gantt_data (line 31) | def gantt_data(): FILE: app/routes/import_export.py function import_export_page (line 38) | def import_export_page(): function import_csv (line 46) | def import_csv(): function import_toggl (line 89) | def import_toggl(): function import_harvest (line 148) | def import_harvest(): function import_status (line 207) | def import_status(import_id): function import_history (line 221) | def import_history(): function export_gdpr (line 241) | def export_gdpr(): function export_filtered (line 293) | def export_filtered(): function export_backup (line 361) | def export_backup(): function download_export (line 405) | def download_export(export_id): function export_status (line 433) | def export_status(export_id): function export_history (line 447) | def export_history(): function restore_backup (line 467) | def restore_backup(): function start_migration_wizard (line 558) | def start_migration_wizard(): function preview_migration (line 598) | def preview_migration(wizard_id): function execute_migration (line 615) | def execute_migration(wizard_id): function import_csv_clients_route (line 634) | def import_csv_clients_route(): function download_csv_template (line 747) | def download_csv_template(): function download_csv_template_clients (line 766) | def download_csv_template_clients(): FILE: app/routes/integrations.py function has_setup_wizard (line 30) | def has_setup_wizard(provider): function list_integrations (line 43) | def list_integrations(): function integrations_health (line 64) | def integrations_health(): function connect_integration (line 99) | def connect_integration(provider): function oauth_callback (line 201) | def oauth_callback(provider): function manage_integration (line 319) | def manage_integration(provider): function view_integration (line 798) | def view_integration(integration_id): function test_integration (line 846) | def test_integration(integration_id): function delete_integration (line 889) | def delete_integration(integration_id): function reset_integration (line 914) | def reset_integration(integration_id): function sync_integration (line 942) | def sync_integration(integration_id): function caldav_setup (line 1009) | def caldav_setup(): function activitywatch_setup (line 1180) | def activitywatch_setup(): function integration_webhook (line 1299) | def integration_webhook(provider): function setup_wizard (line 1361) | def setup_wizard(provider): function test_connection_wizard (line 1579) | def test_connection_wizard(provider): FILE: app/routes/inventory.py function _provisional_po_number (line 35) | def _provisional_po_number(): function _finalize_po_number (line 40) | def _finalize_po_number(purchase_order): function search_stock_items (line 53) | def search_stock_items(): function get_item_availability (line 90) | def get_item_availability(item_id): function list_stock_items (line 122) | def list_stock_items(): function new_stock_item (line 179) | def new_stock_item(): function view_stock_item (line 313) | def view_stock_item(item_id): function edit_stock_item (line 437) | def edit_stock_item(item_id): function delete_stock_item (line 581) | def delete_stock_item(item_id): function list_warehouses (line 613) | def list_warehouses(): function new_warehouse (line 631) | def new_warehouse(): function view_warehouse (line 673) | def view_warehouse(warehouse_id): function edit_warehouse (line 699) | def edit_warehouse(warehouse_id): function delete_warehouse (line 739) | def delete_warehouse(warehouse_id): function stock_levels (line 770) | def stock_levels(): function stock_levels_by_warehouse (line 819) | def stock_levels_by_warehouse(warehouse_id): function stock_levels_by_item (line 864) | def stock_levels_by_item(item_id): function list_movements (line 880) | def list_movements(): function new_movement (line 916) | def new_movement(): function list_transfers (line 1187) | def list_transfers(): function new_transfer (line 1230) | def new_transfer(): function list_adjustments (line 1341) | def list_adjustments(): function new_adjustment (line 1394) | def new_adjustment(): function stock_item_history (line 1446) | def stock_item_history(item_id): function low_stock_alerts (line 1503) | def low_stock_alerts(): function list_reservations (line 1547) | def list_reservations(): function fulfill_reservation (line 1565) | def fulfill_reservation(reservation_id): function cancel_reservation (line 1586) | def cancel_reservation(reservation_id): function list_suppliers (line 1610) | def list_suppliers(): function new_supplier (line 1633) | def new_supplier(): function view_supplier (line 1680) | def view_supplier(supplier_id): function edit_supplier (line 1703) | def edit_supplier(supplier_id): function delete_supplier (line 1749) | def delete_supplier(supplier_id): function list_purchase_orders (line 1781) | def list_purchase_orders(): function new_purchase_order (line 1811) | def new_purchase_order(): function view_purchase_order (line 1946) | def view_purchase_order(po_id): function edit_purchase_order (line 1961) | def edit_purchase_order(po_id): function send_purchase_order (line 2071) | def send_purchase_order(po_id): function cancel_purchase_order (line 2095) | def cancel_purchase_order(po_id): function delete_purchase_order (line 2118) | def delete_purchase_order(po_id): function receive_purchase_order (line 2148) | def receive_purchase_order(po_id): function reports_dashboard (line 2194) | def reports_dashboard(): function reports_valuation (line 2247) | def reports_valuation(): function reports_movement_history (line 2320) | def reports_movement_history(): function reports_turnover (line 2375) | def reports_turnover(): function reports_low_stock (line 2439) | def reports_low_stock(): FILE: app/routes/invoice_approvals.py function request_approval (line 23) | def request_approval(invoice_id): function list_approvals (line 64) | def list_approvals(): function approve (line 75) | def approve(approval_id): function reject (line 94) | def reject(approval_id): function view_approval (line 118) | def view_approval(approval_id): FILE: app/routes/invoices.py function list_invoices (line 57) | def list_invoices(): function create_invoice (line 96) | def create_invoice(): function view_invoice (line 251) | def view_invoice(invoice_id): function edit_invoice (line 385) | def edit_invoice(invoice_id): function update_invoice_status (line 613) | def update_invoice_status(invoice_id): function delete_invoice (line 739) | def delete_invoice(invoice_id): function bulk_delete_invoices (line 764) | def bulk_delete_invoices(): function bulk_update_status (line 821) | def bulk_update_status(): function generate_from_time (line 888) | def generate_from_time(invoice_id): function export_invoice_csv (line 1058) | def export_invoice_csv(invoice_id): function export_invoice_ubl (line 1111) | def export_invoice_ubl(invoice_id): function export_invoice_pdf (line 1140) | def export_invoice_pdf(invoice_id): function duplicate_invoice (line 1315) | def duplicate_invoice(invoice_id): function export_invoices_excel (line 1388) | def export_invoices_excel(): function send_invoice_email_route (line 1413) | def send_invoice_email_route(invoice_id): function send_invoice_peppol_route (line 1472) | def send_invoice_peppol_route(invoice_id): function get_invoice_email_history (line 1497) | def get_invoice_email_history(invoice_id): function resend_invoice_email (line 1518) | def resend_invoice_email(invoice_id, email_id): function upload_invoice_image (line 1580) | def upload_invoice_image(invoice_id): function update_invoice_image_position (line 1713) | def update_invoice_image_position(invoice_id, image_id): function delete_invoice_image (line 1748) | def delete_invoice_image(invoice_id, image_id): function get_invoice_image_base64 (line 1800) | def get_invoice_image_base64(invoice_id, image_id): FILE: app/routes/invoices_refactored.py function list_invoices (line 32) | def list_invoices(): function create_invoice (line 105) | def create_invoice(): function mark_invoice_sent (line 210) | def mark_invoice_sent(invoice_id): function mark_invoice_paid (line 229) | def mark_invoice_paid(invoice_id): FILE: app/routes/issues.py function list_issues (line 25) | def list_issues(): function new_issue (line 162) | def new_issue(): function view_issue (line 244) | def view_issue(issue_id): function edit_issue (line 302) | def edit_issue(issue_id): function link_task (line 392) | def link_task(issue_id): function create_task_from_issue (line 413) | def create_task_from_issue(issue_id): function update_status (line 439) | def update_status(issue_id): function assign_issue (line 474) | def assign_issue(issue_id): function update_priority (line 491) | def update_priority(issue_id): function delete_issue (line 512) | def delete_issue(issue_id): FILE: app/routes/kanban.py function board (line 17) | def board(): function list_columns (line 97) | def list_columns(): function create_column (line 122) | def create_column(): function edit_column (line 227) | def edit_column(column_id): function delete_column (line 293) | def delete_column(column_id): function toggle_column (line 368) | def toggle_column(column_id): function reorder_columns (line 416) | def reorder_columns(): function api_list_columns (line 457) | def api_list_columns(): FILE: app/routes/kiosk.py function kiosk_dashboard (line 24) | def kiosk_dashboard(): function kiosk_login (line 84) | def kiosk_login(): function kiosk_logout (line 159) | def kiosk_logout(): function barcode_lookup (line 186) | def barcode_lookup(): function adjust_stock (line 256) | def adjust_stock(): function transfer_stock (line 338) | def transfer_stock(): function kiosk_start_timer (line 449) | def kiosk_start_timer(): function kiosk_stop_timer (line 513) | def kiosk_stop_timer(): function kiosk_timer_status (line 538) | def kiosk_timer_status(): function kiosk_warehouses (line 566) | def kiosk_warehouses(): function kiosk_projects (line 576) | def kiosk_projects(): function kiosk_settings_api (line 621) | def kiosk_settings_api(): FILE: app/routes/leads.py function list_leads (line 28) | def list_leads(): function create_lead (line 78) | def create_lead(): function view_lead (line 123) | def view_lead(lead_id): function edit_lead (line 134) | def edit_lead(lead_id): function convert_to_client (line 177) | def convert_to_client(lead_id): function convert_to_deal (line 232) | def convert_to_deal(lead_id): function mark_lost (line 291) | def mark_lost(lead_id): function create_activity (line 309) | def create_activity(lead_id): FILE: app/routes/link_templates.py function list_link_templates (line 20) | def list_link_templates(): function create_link_template (line 29) | def create_link_template(): function edit_link_template (line 83) | def edit_link_template(template_id): function delete_link_template (line 136) | def delete_link_template(template_id): FILE: app/routes/main.py function dashboard (line 33) | def dashboard(): function health_check (line 290) | def health_check(): function readiness_check (line 296) | def readiness_check(): function about (line 306) | def about(): function help (line 312) | def help(): function donate (line 319) | def donate(): function track_donation_click (line 356) | def track_donation_click(): function track_banner_dismissal (line 385) | def track_banner_dismissal(): function track_support_impression (line 413) | def track_support_impression(): function request_soft_support_prompt (line 437) | def request_soft_support_prompt(): function track_support_event (line 470) | def track_support_event(): function debug_i18n (line 510) | def debug_i18n(): function set_language (line 546) | def set_language(): function search (line 604) | def search(): function manifest (line 629) | def manifest(): function offline_page (line 635) | def offline_page(): function service_worker (line 643) | def service_worker(): FILE: app/routes/mileage.py function list_mileage (line 22) | def list_mileage(): function _mileage_export_query (line 147) | def _mileage_export_query(): function export_mileage_csv (line 205) | def export_mileage_csv(): function export_mileage_pdf (line 272) | def export_mileage_pdf(): function create_mileage (line 321) | def create_mileage(): function view_mileage (line 428) | def view_mileage(mileage_id): function edit_mileage (line 447) | def edit_mileage(mileage_id): function delete_mileage (line 520) | def delete_mileage(mileage_id): function bulk_delete_mileage (line 549) | def bulk_delete_mileage(): function bulk_update_status (line 619) | def bulk_update_status(): function approve_mileage (line 687) | def approve_mileage(mileage_id): function reject_mileage (line 720) | def reject_mileage(mileage_id): function mark_reimbursed (line 757) | def mark_reimbursed(mileage_id): function gps_tracking_page (line 789) | def gps_tracking_page(): function web_gps_start (line 799) | def web_gps_start(): function web_gps_add_point (line 816) | def web_gps_add_point(track_id): function web_gps_stop (line 835) | def web_gps_stop(track_id): function web_gps_create_expense (line 852) | def web_gps_create_expense(track_id): function api_list_mileage (line 869) | def api_list_mileage(): function api_get_mileage (line 889) | def api_get_mileage(mileage_id): function api_get_default_rates (line 903) | def api_get_default_rates(): FILE: app/routes/offers.py function list_quotes (line 18) | def list_quotes(): function create_quote (line 42) | def create_quote(): function view_quote (line 180) | def view_quote(quote_id): function edit_quote (line 189) | def edit_quote(quote_id): function send_quote (line 280) | def send_quote(quote_id): function accept_quote (line 304) | def accept_quote(quote_id): function reject_quote (line 366) | def reject_quote(quote_id): function delete_quote (line 394) | def delete_quote(quote_id): FILE: app/routes/payment_gateways.py function list_gateways (line 26) | def list_gateways(): function create_gateway (line 36) | def create_gateway(): function pay_invoice (line 72) | def pay_invoice(invoice_id): function stripe_webhook (line 128) | def stripe_webhook(): function payment_success (line 222) | def payment_success(invoice_id): FILE: app/routes/payments.py function list_payments (line 21) | def list_payments(): function view_payment (line 126) | def view_payment(payment_id): function create_payment (line 141) | def create_payment(): function edit_payment (line 319) | def edit_payment(payment_id): function delete_payment (line 427) | def delete_payment(payment_id): function bulk_delete_payments (line 466) | def bulk_delete_payments(): function bulk_update_status (line 532) | def bulk_update_status(): function payment_stats (line 606) | def payment_stats(): function export_payments_excel (line 674) | def export_payments_excel(): function get_user_invoices (line 733) | def get_user_invoices(): FILE: app/routes/per_diem.py function list_per_diem (line 23) | def list_per_diem(): function _per_diem_export_query (line 114) | def _per_diem_export_query(): function export_per_diem_csv (line 161) | def export_per_diem_csv(): function export_per_diem_pdf (line 226) | def export_per_diem_pdf(): function create_per_diem (line 275) | def create_per_diem(): function view_per_diem (line 429) | def view_per_diem(per_diem_id): function edit_per_diem (line 448) | def edit_per_diem(per_diem_id): function delete_per_diem (line 518) | def delete_per_diem(per_diem_id): function bulk_delete_per_diem (line 547) | def bulk_delete_per_diem(): function bulk_update_status (line 605) | def bulk_update_status(): function approve_per_diem (line 661) | def approve_per_diem(per_diem_id): function reject_per_diem (line 694) | def reject_per_diem(per_diem_id): function list_rates (line 733) | def list_rates(): function create_rate (line 752) | def create_rate(): function edit_rate (line 806) | def edit_rate(rate_id): function delete_rate (line 865) | def delete_rate(rate_id): function api_list_per_diem (line 905) | def api_list_per_diem(): function api_search_rates (line 925) | def api_search_rates(): function api_calculate_days (line 947) | def api_calculate_days(): FILE: app/routes/permissions.py function _get_modules_by_category_for_roles (line 18) | def _get_modules_by_category_for_roles(): function _sanitize_hidden_module_ids (line 31) | def _sanitize_hidden_module_ids(module_ids): function list_roles (line 49) | def list_roles(): function create_role (line 62) | def create_role(): function edit_role (line 133) | def edit_role(role_id): function view_role (line 222) | def view_role(role_id): function delete_role (line 238) | def delete_role(role_id): function list_permissions (line 271) | def list_permissions(): function manage_user_roles (line 298) | def manage_user_roles(user_id): function get_user_permissions (line 368) | def get_user_permissions(user_id): function get_role_permissions (line 390) | def get_role_permissions(role_id): FILE: app/routes/project_templates.py function _parse_tasks_from_request_form (line 20) | def _parse_tasks_from_request_form(): function list_templates (line 64) | def list_templates(): function create_template (line 101) | def create_template(): function view_template (line 176) | def view_template(template_id): function edit_template (line 196) | def edit_template(template_id): function delete_template (line 283) | def delete_template(template_id): function create_project_from_template (line 301) | def create_project_from_template(template_id): FILE: app/routes/projects.py function list_projects (line 55) | def list_projects(): function export_projects (line 181) | def export_projects(): function create_project (line 299) | def create_project(): function view_project (line 549) | def view_project(project_id): function project_dashboard (line 658) | def project_dashboard(project_id): function project_time_entries_overview (line 842) | def project_time_entries_overview(project_id): function edit_project (line 905) | def edit_project(project_id): function archive_project (line 1107) | def archive_project(project_id): function unarchive_project (line 1149) | def unarchive_project(project_id): function deactivate_project (line 1186) | def deactivate_project(project_id): function activate_project (line 1209) | def activate_project(project_id): function delete_project (line 1233) | def delete_project(project_id): function bulk_delete_projects (line 1268) | def bulk_delete_projects(): function bulk_status_change (line 1338) | def bulk_status_change(): function favorite_project (line 1440) | def favorite_project(project_id): function unfavorite_project (line 1485) | def unfavorite_project(project_id): function list_costs (line 1533) | def list_costs(project_id): function add_cost (line 1587) | def add_cost(project_id): function edit_cost (line 1647) | def edit_cost(project_id, cost_id): function delete_cost (line 1714) | def delete_cost(project_id, cost_id): function api_project_costs (line 1747) | def api_project_costs(project_id): function list_goods (line 1788) | def list_goods(project_id): function add_good (line 1814) | def add_good(project_id): function edit_good (line 1878) | def edit_good(project_id, good_id): function delete_good (line 1949) | def delete_good(project_id, good_id): function api_project_goods (line 1982) | def api_project_goods(project_id): function upload_project_attachment (line 2004) | def upload_project_attachment(project_id): function download_project_attachment (line 2122) | def download_project_attachment(attachment_id): function delete_project_attachment (line 2146) | def delete_project_attachment(attachment_id): FILE: app/routes/projects_refactored_example.py function list_projects (line 26) | def list_projects(): function view_project (line 97) | def view_project(project_id): function create_project (line 172) | def create_project(): FILE: app/routes/push_notifications.py function subscribe_push (line 20) | def subscribe_push(): function unsubscribe_push (line 66) | def unsubscribe_push(): function list_subscriptions (line 97) | def list_subscriptions(): FILE: app/routes/quotes.py function _parse_quote_form_date (line 18) | def _parse_quote_form_date(value): function _pad_form_list (line 27) | def _pad_form_list(values, length): function _quote_form_inventory_context (line 34) | def _quote_form_inventory_context(): function list_quotes (line 64) | def list_quotes(): function create_quote (line 114) | def create_quote(): function view_quote (line 479) | def view_quote(quote_id): function edit_quote (line 509) | def edit_quote(quote_id): function send_quote (line 860) | def send_quote(quote_id): function accept_quote (line 935) | def accept_quote(quote_id): function reject_quote (line 1049) | def reject_quote(quote_id): function delete_quote (line 1077) | def delete_quote(quote_id): function upload_attachment (line 1103) | def upload_attachment(quote_id): function download_attachment (line 1218) | def download_attachment(attachment_id): function delete_attachment (line 1247) | def delete_attachment(attachment_id): function request_approval (line 1292) | def request_approval(quote_id): function approve_quote (line 1335) | def approve_quote(quote_id): function reject_approval (line 1375) | def reject_approval(quote_id): function list_templates (line 1417) | def list_templates(): function create_template (line 1426) | def create_template(): function save_template_from_quote (line 1503) | def save_template_from_quote(template_id): function export_quote_pdf (line 1567) | def export_quote_pdf(quote_id): function send_quote_email (line 1656) | def send_quote_email(quote_id): function duplicate_quote (line 1723) | def duplicate_quote(quote_id): function bulk_action (line 1818) | def bulk_action(): function upload_quote_image (line 1959) | def upload_quote_image(quote_id): function update_quote_image_position (line 2093) | def update_quote_image_position(quote_id, image_id): function delete_quote_image (line 2129) | def delete_quote_image(quote_id, image_id): function get_quote_image_base64 (line 2181) | def get_quote_image_base64(quote_id, image_id): FILE: app/routes/recurring_invoices.py function list_recurring_invoices (line 21) | def list_recurring_invoices(): function create_recurring_invoice (line 43) | def create_recurring_invoice(): function view_recurring_invoice (line 167) | def view_recurring_invoice(recurring_id): function edit_recurring_invoice (line 185) | def edit_recurring_invoice(recurring_id): function delete_recurring_invoice (line 245) | def delete_recurring_invoice(recurring_id): function generate_invoice_now (line 267) | def generate_invoice_now(recurring_id): FILE: app/routes/recurring_tasks.py function list_recurring_tasks (line 22) | def list_recurring_tasks(): function create_recurring_task (line 37) | def create_recurring_task(): function view_recurring_task (line 76) | def view_recurring_task(task_id): function toggle_recurring_task (line 90) | def toggle_recurring_task(task_id): FILE: app/routes/reports.py function reports (line 48) | def reports(): function week_in_review (line 75) | def week_in_review(): function comparison_view (line 90) | def comparison_view(): function project_report (line 103) | def project_report(): function user_report (line 162) | def user_report(): function export_form (line 285) | def export_form(): function export_csv (line 335) | def export_csv(): function export_summary_pdf (line 527) | def export_summary_pdf(): function summary_report (line 587) | def summary_report(): function task_report (line 669) | def task_report(): function _time_entries_report_query (line 764) | def _time_entries_report_query(request, require_dates=True, return_query... function time_entries_report (line 853) | def time_entries_report(): function time_entries_export_excel (line 954) | def time_entries_export_excel(): function time_entries_export_csv (line 995) | def time_entries_export_csv(): function export_excel (line 1058) | def export_excel(): function export_project_excel (line 1138) | def export_project_excel(): function export_user_excel (line 1235) | def export_user_excel(): function export_user_entries_excel (line 1404) | def export_user_entries_excel(): function export_task_excel (line 1489) | def export_task_excel(): function unpaid_hours_report (line 1627) | def unpaid_hours_report(): function export_unpaid_hours_excel (line 1734) | def export_unpaid_hours_excel(): FILE: app/routes/salesman_reports.py function list_email_mappings (line 24) | def list_email_mappings(): function get_email_mappings_api (line 36) | def get_email_mappings_api(): function create_email_mapping (line 47) | def create_email_mapping(): function update_email_mapping (line 88) | def update_email_mapping(mapping_id): function delete_email_mapping (line 121) | def delete_email_mapping(mapping_id): function get_unpaid_hours_by_salesman (line 141) | def get_unpaid_hours_by_salesman(): function preview_salesman_email (line 211) | def preview_salesman_email(): function generate_salesman_reports (line 248) | def generate_salesman_reports(): FILE: app/routes/saved_filters.py function list_filters (line 28) | def list_filters(): function get_filters_api (line 45) | def get_filters_api(): function create_filter_api (line 62) | def create_filter_api(): function get_filter_api (line 126) | def get_filter_api(filter_id): function update_filter_api (line 136) | def update_filter_api(filter_id): function delete_filter_api (line 198) | def delete_filter_api(filter_id): function delete_filter (line 240) | def delete_filter(filter_id): FILE: app/routes/scheduled_reports.py function api_list_scheduled (line 23) | def api_list_scheduled(): function list_scheduled (line 61) | def list_scheduled(): function create_scheduled (line 111) | def create_scheduled(): function delete_scheduled (line 162) | def delete_scheduled(schedule_id): function api_create_scheduled (line 178) | def api_create_scheduled(): function api_toggle_scheduled (line 243) | def api_toggle_scheduled(schedule_id): function api_delete_scheduled (line 261) | def api_delete_scheduled(schedule_id): function api_saved_views (line 275) | def api_saved_views(): function fix_scheduled (line 295) | def fix_scheduled(schedule_id): function api_trigger_scheduled (line 347) | def api_trigger_scheduled(schedule_id): FILE: app/routes/settings.py function index (line 19) | def index(): function keyboard_shortcuts (line 27) | def keyboard_shortcuts(): function profile (line 35) | def profile(): function preferences (line 43) | def preferences(): function _keyboard_shortcuts_config (line 53) | def _keyboard_shortcuts_config(): function api_keyboard_shortcuts_get (line 62) | def api_keyboard_shortcuts_get(): function api_keyboard_shortcuts_save (line 71) | def api_keyboard_shortcuts_save(): function api_keyboard_shortcuts_reset (line 94) | def api_keyboard_shortcuts_reset(): FILE: app/routes/setup.py function initial_setup (line 24) | def initial_setup(): function _render_setup (line 136) | def _render_setup(settings, timezones): FILE: app/routes/tasks.py function _is_safe_next_url (line 34) | def _is_safe_next_url(next_url): function list_tasks (line 48) | def list_tasks(): function create_task (line 175) | def create_task(): function view_task (line 316) | def view_task(task_id): function edit_task (line 389) | def edit_task(task_id): function update_task_status (line 619) | def update_task_status(task_id): function update_task_priority (line 729) | def update_task_priority(task_id): function assign_task (line 750) | def assign_task(task_id): function delete_task (line 777) | def delete_task(task_id): function bulk_delete_tasks (line 826) | def bulk_delete_tasks(): function bulk_update_status (line 908) | def bulk_update_status(): function bulk_update_due_date (line 977) | def bulk_update_due_date(): function bulk_update_priority (line 1056) | def bulk_update_priority(): function bulk_assign_tasks (line 1131) | def bulk_assign_tasks(): function bulk_move_project (line 1190) | def bulk_move_project(): function export_tasks (line 1267) | def export_tasks(): function my_tasks (line 1393) | def my_tasks(): function overdue_tasks (line 1481) | def overdue_tasks(): function api_task (line 1495) | def api_task(task_id): function api_update_status (line 1508) | def api_update_status(task_id): FILE: app/routes/team_chat.py function chat_index (line 23) | def chat_index(): function chat_channel (line 50) | def chat_channel(channel_id): function send_message (line 95) | def send_message(channel_id): function api_channels (line 181) | def api_channels(): function api_messages (line 226) | def api_messages(channel_id): function api_message (line 337) | def api_message(message_id): function api_react (line 367) | def api_react(message_id): function download_attachment (line 396) | def download_attachment(channel_id, message_id): function upload_attachment (line 437) | def upload_attachment(channel_id): function api_chat_users (line 533) | def api_chat_users(): function api_create_direct_message (line 549) | def api_create_direct_message(user_id): FILE: app/routes/time_approvals.py function list_approvals (line 21) | def list_approvals(): function view_approval (line 39) | def view_approval(approval_id): function approve_entry (line 62) | def approve_entry(approval_id): function reject_entry (line 83) | def reject_entry(approval_id): function request_approval (line 111) | def request_approval(entry_id): function cancel_approval (line 137) | def cancel_approval(approval_id): function bulk_approve (line 157) | def bulk_approve(): function api_pending_approvals (line 174) | def api_pending_approvals(): FILE: app/routes/time_entry_templates.py function list_templates (line 28) | def list_templates(): function create_template (line 45) | def create_template(): function view_template (line 137) | def view_template(template_id): function edit_template (line 153) | def edit_template(template_id): function delete_template (line 240) | def delete_template(template_id): function get_templates_api (line 278) | def get_templates_api(): function get_template_api (line 295) | def get_template_api(template_id): function use_template_api (line 311) | def use_template_api(template_id): function get_project_tasks_api (line 334) | def get_project_tasks_api(project_id): FILE: app/routes/timer.py function _parse_optional_int (line 28) | def _parse_optional_int(value): function _edit_timer_form_projects_tasks (line 38) | def _edit_timer_form_projects_tasks(timer, can_edit_schedule): function _edit_timer_render_kwargs (line 55) | def _edit_timer_render_kwargs(timer, can_edit_schedule, show_source_drop... function start_timer (line 68) | def start_timer(): function start_timer_from_template (line 332) | def start_timer_from_template(template_id): function start_timer_for_project (line 426) | def start_timer_for_project(project_id): function stop_timer (line 527) | def stop_timer(): function pause_timer (line 647) | def pause_timer(): function resume_timer (line 672) | def resume_timer(): function adjust_timer (line 697) | def adjust_timer(): function timer_status (line 740) | def timer_status(): function edit_timer (line 768) | def edit_timer(timer_id): function view_timer (line 972) | def view_timer(timer_id): function delete_timer (line 1028) | def delete_timer(timer_id): function bulk_delete_time_entries (line 1139) | def bulk_delete_time_entries(): function manual_entry (line 1219) | def manual_entry(): function manual_entry_for_project (line 1567) | def manual_entry_for_project(project_id): function bulk_entry (line 1605) | def bulk_entry(): function timer_page (line 1847) | def timer_page(): function calendar_view (line 1924) | def calendar_view(): function bulk_entry_for_project (line 1933) | def bulk_entry_for_project(project_id): function duplicate_timer (line 1953) | def duplicate_timer(timer_id): function resume_timer_by_id (line 2013) | def resume_timer_by_id(timer_id): function time_entries_overview (line 2209) | def time_entries_overview(): function export_time_entries_csv (line 2572) | def export_time_entries_csv(): function export_time_entries_pdf (line 2785) | def export_time_entries_pdf(): function bulk_mark_paid (line 2974) | def bulk_mark_paid(): FILE: app/routes/timer_refactored.py function start_timer (line 29) | def start_timer(): function stop_timer (line 118) | def stop_timer(): function api_timer_status (line 170) | def api_timer_status(): function api_start_timer (line 196) | def api_start_timer(): FILE: app/routes/user.py function profile (line 25) | def profile(): function settings (line 47) | def settings(): function license (line 239) | def license(): function verify_donate_hide_code (line 277) | def verify_donate_hide_code(): function update_preferences (line 311) | def update_preferences(): function set_theme (line 369) | def set_theme(): function set_language (line 390) | def set_language(): function set_language_direct (line 419) | def set_language_direct(language): FILE: app/routes/webhooks.py function list_webhooks (line 20) | def list_webhooks(): function create_webhook (line 34) | def create_webhook(): function view_webhook (line 97) | def view_webhook(webhook_id): function edit_webhook (line 120) | def edit_webhook(webhook_id): function delete_webhook (line 163) | def delete_webhook(webhook_id): function test_webhook (line 186) | def test_webhook(webhook_id): FILE: app/routes/weekly_goals.py function index (line 19) | def index(): function create (line 65) | def create(): function view (line 139) | def view(goal_id): function edit (line 202) | def edit(goal_id): function delete (line 269) | def delete(goal_id): function api_current_goal (line 306) | def api_current_goal(): function api_list_goals (line 322) | def api_list_goals(): function api_get_goal (line 346) | def api_get_goal(goal_id): function api_stats (line 363) | def api_stats(): FILE: app/routes/workflows.py function list_workflows (line 21) | def list_workflows(): function create_workflow (line 35) | def create_workflow(): function view_workflow (line 90) | def view_workflow(workflow_id): function edit_workflow (line 111) | def edit_workflow(workflow_id): function delete_workflow (line 162) | def delete_workflow(workflow_id): function toggle_workflow (line 182) | def toggle_workflow(workflow_id): function api_list_workflows (line 198) | def api_list_workflows(): function api_create_workflow (line 207) | def api_create_workflow(): function api_get_workflow (line 232) | def api_get_workflow(workflow_id): function api_update_workflow (line 245) | def api_update_workflow(workflow_id): function api_delete_workflow (line 270) | def api_delete_workflow(workflow_id): function test_workflow (line 286) | def test_workflow(workflow_id): FILE: app/routes/workforce.py function _parse_date (line 16) | def _parse_date(value): function _can_approve (line 25) | def _can_approve() -> bool: function dashboard (line 34) | def dashboard(): function create_period (line 110) | def create_period(): function submit_period (line 130) | def submit_period(period_id): function approve_period (line 145) | def approve_period(period_id): function reject_period (line 167) | def reject_period(period_id): function close_period (line 189) | def close_period(period_id): function delete_period (line 211) | def delete_period(period_id): function update_policy (line 226) | def update_policy(): function create_leave_type (line 249) | def create_leave_type(): function delete_leave_type (line 276) | def delete_leave_type(leave_type_id): function create_time_off_request (line 294) | def create_time_off_request(): function approve_time_off_request (line 329) | def approve_time_off_request(request_id): function reject_time_off_request (line 353) | def reject_time_off_request(request_id): function delete_time_off_request (line 377) | def delete_time_off_request(request_id): function create_holiday (line 396) | def create_holiday(): function delete_holiday (line 417) | def delete_holiday(holiday_id): function payroll_export_csv (line 435) | def payroll_export_csv(): function capacity_export_csv (line 499) | def capacity_export_csv(): function locked_periods_export_csv (line 563) | def locked_periods_export_csv(): function audit_events_export_csv (line 612) | def audit_events_export_csv(): FILE: app/schemas/client_schema.py class ClientSchema (line 10) | class ClientSchema(Schema): class ClientCreateSchema (line 29) | class ClientCreateSchema(Schema): class ClientUpdateSchema (line 41) | class ClientUpdateSchema(Schema): FILE: app/schemas/comment_schema.py class CommentSchema (line 8) | class CommentSchema(Schema): class CommentCreateSchema (line 29) | class CommentCreateSchema(Schema): class CommentUpdateSchema (line 40) | class CommentUpdateSchema(Schema): FILE: app/schemas/expense_schema.py class ExpenseSchema (line 10) | class ExpenseSchema(Schema): class ExpenseCreateSchema (line 30) | class ExpenseCreateSchema(Schema): class ExpenseUpdateSchema (line 42) | class ExpenseUpdateSchema(Schema): FILE: app/schemas/invoice_schema.py class InvoiceItemSchema (line 12) | class InvoiceItemSchema(Schema): class InvoiceSchema (line 23) | class InvoiceSchema(Schema): class InvoiceCreateSchema (line 58) | class InvoiceCreateSchema(Schema): class InvoiceUpdateSchema (line 70) | class InvoiceUpdateSchema(Schema): FILE: app/schemas/payment_schema.py class PaymentSchema (line 11) | class PaymentSchema(Schema): class PaymentCreateSchema (line 35) | class PaymentCreateSchema(Schema): class PaymentUpdateSchema (line 50) | class PaymentUpdateSchema(Schema): FILE: app/schemas/project_schema.py class ProjectSchema (line 12) | class ProjectSchema(Schema): class ProjectCreateSchema (line 39) | class ProjectCreateSchema(Schema): class ProjectUpdateSchema (line 54) | class ProjectUpdateSchema(Schema): FILE: app/schemas/task_schema.py class TaskSchema (line 10) | class TaskSchema(Schema): class TaskCreateSchema (line 31) | class TaskCreateSchema(Schema): class TaskUpdateSchema (line 43) | class TaskUpdateSchema(Schema): FILE: app/schemas/time_entry_schema.py class TimeEntrySchema (line 12) | class TimeEntrySchema(Schema): class TimeEntryCreateSchema (line 40) | class TimeEntryCreateSchema(Schema): method validate_end_time (line 56) | def validate_end_time(self, value, **kwargs): method validate_project_or_client (line 64) | def validate_project_or_client(self, value, **kwargs): method validate_client_or_project (line 74) | def validate_client_or_project(self, value, **kwargs): method validate_task_with_project (line 84) | def validate_task_with_project(self, value, **kwargs): class TimeEntryUpdateSchema (line 92) | class TimeEntryUpdateSchema(Schema): class TimerStartSchema (line 112) | class TimerStartSchema(Schema): class TimerStopSchema (line 121) | class TimerStopSchema(Schema): FILE: app/schemas/user_schema.py class UserSchema (line 10) | class UserSchema(Schema): class UserCreateSchema (line 27) | class UserCreateSchema(Schema): class UserUpdateSchema (line 38) | class UserUpdateSchema(Schema): FILE: app/schemas/version_check.py class VersionCheckResponse (line 6) | class VersionCheckResponse(TypedDict): FILE: app/services/ai_categorization_service.py class AICategorizationService (line 19) | class AICategorizationService: method categorize_time_entry (line 62) | def categorize_time_entry(self, time_entry: TimeEntry) -> Dict[str, Any]: method suggest_project_for_entry (line 96) | def suggest_project_for_entry(self, description: str, user_id: int) ->... method suggest_task_for_entry (line 127) | def suggest_task_for_entry(self, description: str, project_id: int) ->... method auto_categorize_batch (line 153) | def auto_categorize_batch(self, time_entries: List[TimeEntry]) -> Dict... method _categorize_text (line 163) | def _categorize_text(self, text: str) -> List[tuple]: method _calculate_match_score (line 189) | def _calculate_match_score(self, description: str, entity) -> float: method learn_from_user_patterns (line 208) | def learn_from_user_patterns(self, user_id: int) -> Dict[str, Any]: FILE: app/services/ai_suggestion_service.py class AISuggestionService (line 18) | class AISuggestionService: method get_time_entry_suggestions (line 21) | def get_time_entry_suggestions(self, user_id: int, context: str = None... method _analyze_recent_patterns (line 47) | def _analyze_recent_patterns(self, user_id: int) -> List[Dict]: method _suggest_from_active_tasks (line 94) | def _suggest_from_active_tasks(self, user_id: int) -> List[Dict]: method _suggest_by_time_pattern (line 130) | def _suggest_by_time_pattern(self, user_id: int) -> List[Dict]: method _suggest_by_deadlines (line 172) | def _suggest_by_deadlines(self, user_id: int) -> List[Dict]: method _estimate_duration (line 209) | def _estimate_duration(self, entries: List[TimeEntry], project_id: int... method _deduplicate_suggestions (line 224) | def _deduplicate_suggestions(self, suggestions: List[Dict]) -> List[Di... method _rank_suggestions (line 237) | def _rank_suggestions(self, suggestions: List[Dict], user_id: int) -> ... method get_project_suggestion (line 251) | def get_project_suggestion(self, description: str, user_id: int) -> Op... FILE: app/services/analytics_service.py class AnalyticsService (line 17) | class AnalyticsService: method __init__ (line 20) | def __init__(self): method get_dashboard_stats (line 26) | def get_dashboard_stats(self, user_id: Optional[int] = None) -> Dict[s... method get_dashboard_top_projects (line 75) | def get_dashboard_top_projects(self, user_id: int, days: int = 30, lim... method get_time_by_project_chart (line 124) | def get_time_by_project_chart(self, user_id: int, days: int = 7, limit... method get_trends (line 153) | def get_trends(self, user_id: Optional[int] = None, days: int = 30) ->... FILE: app/services/api_token_service.py class ApiTokenService (line 15) | class ApiTokenService: method create_token (line 44) | def create_token( method rotate_token (line 114) | def rotate_token(self, token_id: int, user_id: int) -> Dict[str, Any]: method revoke_token (line 178) | def revoke_token(self, token_id: int, user_id: int) -> Dict[str, Any]: method get_expiring_tokens (line 217) | def get_expiring_tokens(self, days_ahead: int = 7) -> List[ApiToken]: method validate_scopes (line 236) | def validate_scopes(self, scopes: str) -> Dict[str, Any]: method check_token_rate_limit (line 285) | def check_token_rate_limit(self, token_id: int, max_requests_per_hour:... FILE: app/services/backup_service.py class BackupService (line 17) | class BackupService: method __init__ (line 20) | def __init__(self): method create_database_backup (line 24) | def create_database_backup(self, backup_name: Optional[str] = None) ->... method list_backups (line 97) | def list_backups(self) -> List[Dict[str, Any]]: method delete_backup (line 128) | def delete_backup(self, backup_name: str) -> Dict[str, Any]: FILE: app/services/base_crud_service.py class BaseCRUDService (line 20) | class BaseCRUDService(Generic[ModelType, RepositoryType]): method __init__ (line 29) | def __init__(self, repository: RepositoryType, model_name: str = "Reco... method get_by_id (line 40) | def get_by_id(self, record_id: int) -> Dict[str, Any]: method create (line 57) | def create(self, **kwargs) -> Dict[str, Any]: method update (line 85) | def update(self, record_id: int, **kwargs) -> Dict[str, Any]: method delete (line 119) | def delete(self, record_id: int) -> Dict[str, Any]: method list_all (line 157) | def list_all(self, page: int = 1, per_page: int = 20, **filters) -> Di... FILE: app/services/calendar_integration_service.py class CalendarIntegrationService (line 18) | class CalendarIntegrationService: method create_integration (line 23) | def create_integration( method get_integration (line 89) | def get_integration(self, integration_id: int) -> Optional[CalendarInt... method get_user_integrations (line 93) | def get_user_integrations(self, user_id: int, provider: Optional[str] ... method sync_time_entry_to_calendar (line 100) | def sync_time_entry_to_calendar( method update_sync_status (line 138) | def update_sync_status( method deactivate_integration (line 190) | def deactivate_integration(self, integration_id: int, user_id: int) ->... FILE: app/services/client_activity_feed_service.py function get_client_activity_feed (line 14) | def get_client_activity_feed( function _activity_to_feed_item (line 115) | def _activity_to_feed_item( FILE: app/services/client_approval_service.py class ClientApprovalService (line 17) | class ClientApprovalService: method request_approval (line 20) | def request_approval(self, time_entry_id: int, requested_by: int, comm... method approve (line 79) | def approve(self, approval_id: int, contact_id: int, comment: str = No... method reject (line 94) | def reject(self, approval_id: int, contact_id: int, reason: str) -> Di... method get_pending_approvals_for_client (line 109) | def get_pending_approvals_for_client(self, client_id: int) -> List[Cli... method _emit_approval_update (line 127) | def _emit_approval_update(self, approval: ClientTimeApproval, event: s... method _notify_client_contacts (line 141) | def _notify_client_contacts(self, client: Client, approval: ClientTime... method _notify_requester (line 167) | def _notify_requester(self, approval: ClientTimeApproval, status: str,... FILE: app/services/client_notification_service.py class ClientNotificationService (line 18) | class ClientNotificationService: method create_notification (line 21) | def create_notification( method notify_invoice_created (line 72) | def notify_invoice_created(self, invoice_id: int, client_id: int): method notify_invoice_paid (line 91) | def notify_invoice_paid(self, invoice_id: int, client_id: int, amount:... method notify_invoice_overdue (line 110) | def notify_invoice_overdue(self, invoice_id: int, client_id: int, days... method notify_time_entry_approval (line 129) | def notify_time_entry_approval(self, approval_id: int, client_id: int): method notify_quote_available (line 148) | def notify_quote_available(self, quote_id: int, client_id: int): method notify_project_milestone (line 167) | def notify_project_milestone(self, project_id: int, client_id: int, mi... method notify_budget_alert (line 186) | def notify_budget_alert(self, project_id: int, client_id: int, budget_... method _send_email_notification (line 205) | def _send_email_notification(self, notification: ClientNotification): method mark_as_read (line 240) | def mark_as_read(self, notification_id: int, client_id: int) -> bool: method mark_all_as_read (line 249) | def mark_all_as_read(self, client_id: int) -> int: method get_unread_count (line 257) | def get_unread_count(self, client_id: int) -> int: method get_notifications (line 261) | def get_notifications(self, client_id: int, limit: int = 50, unread_on... FILE: app/services/client_report_service.py function build_report_data (line 16) | def build_report_data( function _task_summary_for_projects (line 98) | def _task_summary_for_projects(project_ids: List[int]) -> Dict[str, Any]: FILE: app/services/client_service.py class ClientService (line 14) | class ClientService: method __init__ (line 17) | def __init__(self): method get_by_id (line 20) | def get_by_id(self, client_id: int) -> Optional[Client]: method get_by_name (line 29) | def get_by_name(self, name: str) -> Optional[Client]: method create_client (line 38) | def create_client( method update_client (line 80) | def update_client(self, client_id: int, user_id: int, **kwargs) -> Dic... method get_active_clients (line 104) | def get_active_clients(self) -> List[Client]: FILE: app/services/comment_service.py class CommentService (line 14) | class CommentService: method __init__ (line 17) | def __init__(self): method create_comment (line 22) | def create_comment( method get_project_comments (line 113) | def get_project_comments(self, project_id: int, include_replies: bool ... method get_task_comments (line 119) | def get_task_comments(self, task_id: int, include_replies: bool = True... method delete_comment (line 123) | def delete_comment(self, comment_id: int, user_id: int) -> Dict[str, A... FILE: app/services/currency_service.py class CurrencyService (line 18) | class CurrencyService: method convert (line 25) | def convert(amount: Decimal, from_currency: str, to_currency: str, con... method get_exchange_rate (line 42) | def get_exchange_rate(base_currency: str, quote_currency: str, rate_da... method fetch_exchange_rate (line 70) | def fetch_exchange_rate(base_currency: str, quote_currency: str, rate_... method store_exchange_rate (line 104) | def store_exchange_rate(base_currency: str, quote_currency: str, rate_... method update_exchange_rates (line 121) | def update_exchange_rates(base_currency: str = "EUR", currencies: list... method get_historical_rates (line 145) | def get_historical_rates(base_currency: str, quote_currency: str, star... method auto_convert_invoice (line 161) | def auto_convert_invoice(invoice) -> Dict[str, Decimal]: FILE: app/services/custom_report_service.py class CustomReportService (line 21) | class CustomReportService: method build_report (line 24) | def build_report(self, config_id: int, filters: Dict = None) -> Dict[s... method _build_time_report (line 45) | def _build_time_report(self, config: CustomReportConfig, filters: Dict... method _build_project_report (line 80) | def _build_project_report(self, config: CustomReportConfig, filters: D... method _build_invoice_report (line 91) | def _build_invoice_report(self, config: CustomReportConfig, filters: D... method _build_expense_report (line 107) | def _build_expense_report(self, config: CustomReportConfig, filters: D... method _build_combined_report (line 123) | def _build_combined_report(self, config: CustomReportConfig, filters: ... method _apply_groupings (line 131) | def _apply_groupings(self, entries: List, groupings: List[str]) -> Dict: method _format_columns (line 154) | def _format_columns(self, data: Dict, columns: List[str]) -> List[Dict]: method _calculate_summary (line 180) | def _calculate_summary(self, entries: List[TimeEntry]) -> Dict: FILE: app/services/email_service.py class EmailService (line 14) | class EmailService: method __init__ (line 17) | def __init__(self): method send_invoice_email (line 20) | def send_invoice_email( method send_notification_email (line 76) | def send_notification_email( FILE: app/services/enhanced_ocr_service.py class EnhancedOCRService (line 16) | class EnhancedOCRService: method scan_receipt_enhanced (line 19) | def scan_receipt_enhanced(self, image_path: str, lang: str = "eng") ->... method _extract_merchant (line 50) | def _extract_merchant(self, text: str) -> Optional[str]: method _extract_date (line 66) | def _extract_date(self, text: str) -> Optional[str]: method _extract_total (line 88) | def _extract_total(self, text: str) -> Optional[Decimal]: method _extract_tax (line 115) | def _extract_tax(self, text: str) -> Optional[Decimal]: method _extract_items (line 134) | def _extract_items(self, text: str) -> List[Dict[str, Any]]: method _extract_currency (line 164) | def _extract_currency(self, text: str) -> Optional[str]: method _extract_receipt_number (line 186) | def _extract_receipt_number(self, text: str) -> Optional[str]: method _calculate_confidence (line 202) | def _calculate_confidence(self, text: str) -> float: FILE: app/services/expense_service.py class ExpenseService (line 15) | class ExpenseService: method __init__ (line 18) | def __init__(self): method create_expense (line 22) | def create_expense( method get_project_expenses (line 93) | def get_project_expenses( method get_total_expenses (line 101) | def get_total_expenses( method list_expenses (line 113) | def list_expenses( method update_expense (line 164) | def update_expense(self, expense_id: int, user_id: int, is_admin: bool... method delete_expense (line 202) | def delete_expense(self, expense_id: int, user_id: int, is_admin: bool... FILE: app/services/export_service.py class ExportService (line 14) | class ExportService: method __init__ (line 17) | def __init__(self): method export_time_entries_csv (line 23) | def export_time_entries_csv( method export_projects_csv (line 91) | def export_projects_csv(self, status: Optional[str] = None, client_id:... method export_invoices_csv (line 141) | def export_invoices_csv(self, status: Optional[str] = None, client_id:... FILE: app/services/gamification_service.py class GamificationService (line 18) | class GamificationService: method check_and_award_badges (line 21) | def check_and_award_badges(self, user_id: int, event_type: str, event_... method _check_badge_criteria (line 47) | def _check_badge_criteria(self, user_id: int, badge: Badge, event_type... method _get_total_hours (line 84) | def _get_total_hours(self, user_id: int, criteria: Dict) -> float: method _get_completed_tasks (line 96) | def _get_completed_tasks(self, user_id: int, criteria: Dict) -> int: method _get_streak (line 105) | def _get_streak(self, user_id: int, criteria: Dict) -> int: method _get_completed_projects (line 123) | def _get_completed_projects(self, user_id: int, criteria: Dict) -> int: method get_user_badges (line 133) | def get_user_badges(self, user_id: int) -> List[Dict]: method get_user_points (line 139) | def get_user_points(self, user_id: int) -> int: method calculate_leaderboard (line 145) | def calculate_leaderboard( method _get_period_dates (line 183) | def _get_period_dates(self, period: str) -> tuple: method _calculate_scores (line 206) | def _calculate_scores(self, leaderboard: Leaderboard, start: datetime,... method get_leaderboard (line 248) | def get_leaderboard(self, leaderboard_id: int, limit: int = 100) -> Li... FILE: app/services/gantt_service.py function calculate_project_progress (line 14) | def calculate_project_progress(project: Project, tasks: Optional[List[Ta... function calculate_task_progress (line 24) | def calculate_task_progress(task: Task) -> int: class GanttService (line 35) | class GanttService: method get_gantt_data (line 38) | def get_gantt_data( FILE: app/services/global_search_service.py function _parse_search_types (line 15) | def _parse_search_types(types_filter: str) -> Set[str]: function run_global_search (line 24) | def run_global_search( FILE: app/services/gps_tracking_service.py class GPSTrackingService (line 16) | class GPSTrackingService: method start_tracking (line 19) | def start_tracking( method add_track_point (line 32) | def add_track_point( method stop_tracking (line 50) | def stop_tracking( method create_expense_from_track (line 84) | def create_expense_from_track( method calculate_route_distance (line 120) | def calculate_route_distance( method get_user_tracks (line 151) | def get_user_tracks( FILE: app/services/health_service.py class HealthService (line 14) | class HealthService: method get_health_status (line 17) | def get_health_status(self) -> Dict[str, Any]: method get_readiness_status (line 55) | def get_readiness_status(self) -> Dict[str, Any]: FILE: app/services/import_service.py class ImportService (line 15) | class ImportService: method __init__ (line 18) | def __init__(self): method import_time_entries_csv (line 28) | def import_time_entries_csv(self, file, user_id: int, default_project_... method import_projects_csv (line 109) | def import_projects_csv(self, file, created_by: int) -> Dict[str, Any]: FILE: app/services/integration_service.py class IntegrationService (line 18) | class IntegrationService: method register_connector (line 33) | def register_connector(cls, provider: str, connector_class): method get_connector (line 38) | def get_connector(cls, integration: Integration) -> Optional[Any]: method create_integration (line 56) | def create_integration( method get_integration (line 122) | def get_integration( method list_integrations (line 154) | def list_integrations(self, user_id: Optional[int] = None) -> List[Int... method get_global_integration (line 183) | def get_global_integration(self, provider: str) -> Optional[Integration]: method delete_integration (line 187) | def delete_integration(self, integration_id: int, user_id: Optional[in... method reset_integration (line 222) | def reset_integration(self, integration_id: int, user_id: Optional[int... method save_credentials (line 258) | def save_credentials( method test_connection (line 295) | def test_connection( method _log_event (line 318) | def _log_event( method update_integration_active_status (line 337) | def update_integration_active_status(self, integration_id: int): method get_available_providers (line 349) | def get_available_providers(cls) -> List[Dict[str, Any]]: FILE: app/services/inventory_report_service.py class InventoryReportService (line 18) | class InventoryReportService: method get_stock_valuation (line 29) | def get_stock_valuation( method get_inventory_turnover (line 204) | def get_inventory_turnover( method _calculate_average_stock (line 281) | def _calculate_average_stock(self, item_id: int, start_date: datetime,... method _get_stock_at_date (line 290) | def _get_stock_at_date(self, item_id: int, date: datetime) -> Decimal: method get_movement_history (line 309) | def get_movement_history( method get_low_stock (line 397) | def get_low_stock(self, warehouse_id: Optional[int] = None) -> Dict[st... FILE: app/services/invoice_approval_service.py class InvoiceApprovalService (line 15) | class InvoiceApprovalService: method request_approval (line 20) | def request_approval( method approve (line 90) | def approve(self, approval_id: int, approver_id: int, comments: Option... method reject (line 150) | def reject(self, approval_id: int, rejector_id: int, reason: str) -> D... method get_approval (line 197) | def get_approval(self, approval_id: int) -> Optional[InvoiceApproval]: method get_invoice_approval (line 201) | def get_invoice_approval(self, invoice_id: int) -> Optional[InvoiceApp... method list_pending_approvals (line 207) | def list_pending_approvals(self, user_id: Optional[int] = None) -> Lis... FILE: app/services/invoice_service.py class InvoiceService (line 18) | class InvoiceService: method __init__ (line 21) | def __init__(self): method create_invoice_from_time_entries (line 25) | def create_invoice_from_time_entries( method create_invoice (line 164) | def create_invoice( method mark_as_sent (line 262) | def mark_as_sent(self, invoice_id: int) -> Dict[str, Any]: method mark_as_paid (line 285) | def mark_as_paid( method mark_time_entries_as_paid (line 312) | def mark_time_entries_as_paid(self, invoice: Invoice) -> int: method update_invoice (line 346) | def update_invoice(self, invoice_id: int, user_id: int, **kwargs) -> D... method delete_invoice (line 386) | def delete_invoice(self, invoice_id: int, user_id: int) -> Dict[str, A... method list_invoices (line 416) | def list_invoices( method get_invoice_with_details (line 510) | def get_invoice_with_details(self, invoice_id: int) -> Optional[Invoice]: method get_unbilled_data_for_invoice (line 522) | def get_unbilled_data_for_invoice(self, invoice: Invoice) -> Dict[str,... method _time_entry_hours_decimal (line 624) | def _time_entry_hours_decimal(self, entry: TimeEntry) -> Decimal: method _billed_time_entry_ids_for_client (line 629) | def _billed_time_entry_ids_for_client(self, client_id: int) -> set: method _client_unbilled_invoice_state (line 649) | def _client_unbilled_invoice_state(self, client_id: int) -> Dict[str, ... method get_client_unbilled_invoice_preview (line 726) | def get_client_unbilled_invoice_preview(self, client_id: int) -> Dict[... method create_client_unbilled_invoice (line 774) | def create_client_unbilled_invoice(self, client_id: int, acting_user_i... FILE: app/services/ldap_service.py function _config (line 30) | def _config() -> MutableMapping[str, Any]: function _group_search_base (line 34) | def _group_search_base(cfg: Mapping[str, Any]) -> str: function _user_search_base (line 44) | def _user_search_base(cfg: Mapping[str, Any]) -> str: function _make_server (line 54) | def _make_server(cfg: Mapping[str, Any]) -> Any: function _service_connection (line 73) | def _service_connection(cfg: Mapping[str, Any]) -> Optional[Any]: function _user_dn_member_of_group (line 95) | def _user_dn_member_of_group( class LDAPService (line 113) | class LDAPService: method authenticate (line 117) | def authenticate(username: str, password: str) -> Optional[User]: method _entry_to_attrs (line 244) | def _entry_to_attrs( method _get_or_create_user (line 285) | def _get_or_create_user( method test_connection (line 343) | def test_connection(cfg: Mapping[str, Any] | None = None) -> dict[str,... FILE: app/services/llm_service.py class AIServiceError (line 28) | class AIServiceError(Exception): method __init__ (line 31) | def __init__(self, message: str, code: str = "ai_error", status_code: ... class AIProviderConfig (line 39) | class AIProviderConfig: method from_settings (line 51) | def from_settings(cls) -> "AIProviderConfig": method public_dict (line 56) | def public_dict(self) -> Dict[str, Any]: class LLMService (line 68) | class LLMService: method __init__ (line 71) | def __init__(self, config: Optional[AIProviderConfig] = None): method ensure_enabled (line 74) | def ensure_enabled(self) -> None: method test_connection (line 82) | def test_connection(self) -> Dict[str, Any]: method build_context (line 93) | def build_context(self, user: User, limit: Optional[int] = None) -> Di... method chat (line 139) | def chat(self, user: User, prompt: str, history: Optional[List[Dict[st... method context_preview (line 157) | def context_preview(self, user: User) -> Dict[str, Any]: method context_preview_from_context (line 160) | def context_preview_from_context(self, context: Dict[str, Any]) -> Dic... method confirm_action (line 169) | def confirm_action(self, user: User, action: Dict[str, Any]) -> Dict[s... method _chat_completion (line 180) | def _chat_completion(self, messages: List[Dict[str, str]], max_tokens:... method _build_messages (line 211) | def _build_messages(self, prompt: str, context: Dict[str, Any], histor... method _extract_actions (line 230) | def _extract_actions(self, content: str) -> List[Dict[str, Any]]: method _confirm_start_timer (line 244) | def _confirm_start_timer(self, user: User, payload: Dict[str, Any]) ->... method _confirm_create_time_entry (line 257) | def _confirm_create_time_entry(self, user: User, payload: Dict[str, An... method _resolve_entry_times (line 278) | def _resolve_entry_times(self, payload: Dict[str, Any]) -> Tuple[datet... method _parse_datetime (line 288) | def _parse_datetime(self, value: Any) -> Optional[datetime]: method _int_or_none (line 296) | def _int_or_none(self, value: Any) -> Optional[int]: method _entry_dict (line 302) | def _entry_dict(self, entry: Optional[TimeEntry]) -> Optional[Dict[str... method _task_dict (line 320) | def _task_dict(self, task: Task) -> Dict[str, Any]: method _project_dict (line 332) | def _project_dict(self, project: Project) -> Dict[str, Any]: FILE: app/services/notification_service.py function get_today_summary_for_user (line 23) | def get_today_summary_for_user(user) -> Dict[str, Any]: function parse_hhmm (line 31) | def parse_hhmm(raw: Optional[str]) -> Optional[Tuple[int, int]]: function user_local_today_bounds_utc (line 41) | def user_local_today_bounds_utc(user) -> Tuple[datetime, datetime, str]: function _entry_start_as_utc_aware (line 58) | def _entry_start_as_utc_aware(dt: Optional[datetime]) -> Optional[dateti... function _dismissed_kinds (line 66) | def _dismissed_kinds(user_id: int, local_date: str) -> Set[str]: function _completed_hours_today (line 75) | def _completed_hours_today(user_id: int, start_utc: datetime, end_utc: d... function completed_projects_today_count (line 90) | def completed_projects_today_count(user_id: int, start_utc: datetime, en... function _completed_entry_count_today (line 105) | def _completed_entry_count_today(user_id: int, start_utc: datetime, end_... function _in_hour_slot (line 116) | def _in_hour_slot(user_local_now: datetime, target_hour: int, slot_minut... class NotificationService (line 121) | class NotificationService: method dismiss (line 127) | def dismiss(cls, user, kind: str, local_date: str) -> bool: method build_for_user (line 149) | def build_for_user(cls, user, now_utc: Optional[datetime] = None) -> D... FILE: app/services/payment_gateway_service.py class PaymentGatewayService (line 19) | class PaymentGatewayService: method create_gateway (line 24) | def create_gateway( method get_gateway (line 65) | def get_gateway(self, gateway_id: int) -> Optional[PaymentGateway]: method get_active_gateway (line 69) | def get_active_gateway(self, provider: Optional[str] = None) -> Option... method process_payment (line 76) | def process_payment( method update_transaction_status (line 144) | def update_transaction_status( method get_transaction (line 215) | def get_transaction(self, transaction_id: int) -> Optional[PaymentTran... method get_invoice_transactions (line 219) | def get_invoice_transactions(self, invoice_id: int) -> List[PaymentTra... FILE: app/services/payment_service.py class PaymentService (line 17) | class PaymentService: method __init__ (line 20) | def __init__(self): method create_payment (line 24) | def create_payment( method get_invoice_payments (line 113) | def get_invoice_payments(self, invoice_id: int) -> List[Payment]: method get_total_paid (line 117) | def get_total_paid(self, invoice_id: int) -> Decimal: method update_payment (line 121) | def update_payment(self, payment_id: int, user_id: int, **kwargs) -> D... method delete_payment (line 166) | def delete_payment(self, payment_id: int, user_id: int) -> Dict[str, A... FILE: app/services/peppol_service.py class PeppolService (line 13) | class PeppolService: method _get_sender_party (line 22) | def _get_sender_party(self) -> PeppolParty: method _get_recipient_party (line 49) | def _get_recipient_party(self, invoice) -> Tuple[PeppolParty, str, str]: method send_invoice (line 78) | def send_invoice( FILE: app/services/permission_service.py class PermissionService (line 13) | class PermissionService: method __init__ (line 16) | def __init__(self): method check_permission (line 19) | def check_permission(self, user_id: int, permission_name: str) -> bool: method grant_permission (line 44) | def grant_permission(self, role_name: str, permission_name: str) -> Di... method revoke_permission (line 73) | def revoke_permission(self, role_name: str, permission_name: str) -> D... method get_user_permissions (line 98) | def get_user_permissions(self, user_id: int) -> List[str]: FILE: app/services/pomodoro_service.py class PomodoroService (line 17) | class PomodoroService: method start_session (line 20) | def start_session( method complete_cycle (line 75) | def complete_cycle(self, session_id: int) -> Dict[str, Any]: method end_session (line 94) | def end_session(self, session_id: int, notes: str = None) -> Dict[str,... method log_interruption (line 125) | def log_interruption(self, session_id: int, reason: str = None) -> Dic... method get_session_stats (line 141) | def get_session_stats(self, user_id: int, days: int = 30) -> Dict[str,... method get_active_session (line 163) | def get_active_session(self, user_id: int) -> Optional[FocusSession]: FILE: app/services/project_service.py class ProjectService (line 15) | class ProjectService: method __init__ (line 39) | def __init__(self): method get_by_id (line 46) | def get_by_id(self, project_id: int) -> Optional[Project]: method create_project (line 55) | def create_project( method update_project (line 133) | def update_project(self, project_id: int, user_id: int, **kwargs) -> D... method archive_project (line 157) | def archive_project(self, project_id: int, user_id: int, reason: Optio... method get_active_projects (line 178) | def get_active_projects(self, user_id: Optional[int] = None, client_id... method get_project_with_details (line 182) | def get_project_with_details( method list_projects (line 219) | def list_projects( method get_project_view_data (line 387) | def get_project_view_data( FILE: app/services/project_template_service.py class ProjectTemplateService (line 14) | class ProjectTemplateService: method create_template (line 19) | def create_template( method create_project_from_template (line 65) | def create_project_from_template( method get_template (line 214) | def get_template(self, template_id: int) -> Optional[ProjectTemplate]: method list_templates (line 218) | def list_templates( method update_template (line 249) | def update_template(self, template_id: int, user_id: int, **kwargs) ->... method delete_template (line 302) | def delete_template(self, template_id: int, user_id: int) -> Dict[str,... FILE: app/services/quote_service.py class QuoteService (line 18) | class QuoteService: method __init__ (line 21) | def __init__(self): method list_quotes (line 24) | def list_quotes( method _calculate_analytics (line 71) | def _calculate_analytics(self, user_id: Optional[int], is_admin: bool)... method get_quote_with_details (line 131) | def get_quote_with_details( method create_quote (line 155) | def create_quote( method update_quote (line 213) | def update_quote(self, quote_id: int, user_id: int, is_admin: bool = F... FILE: app/services/recurring_invoice_service.py class RecurringInvoiceService (line 14) | class RecurringInvoiceService: method __init__ (line 17) | def __init__(self): method list_recurring_invoices (line 20) | def list_recurring_invoices( method get_by_id (line 33) | def get_by_id(self, recurring_invoice_id: int) -> Optional[RecurringIn... method generate_invoice (line 37) | def generate_invoice(self, recurring_invoice): method _add_time_entry_items (line 87) | def _add_time_entry_items(self, recurring_invoice, invoice): FILE: app/services/reporting_service.py class ReportingService (line 31) | class ReportingService: method __init__ (line 39) | def __init__(self): method get_time_summary (line 46) | def get_time_summary( method get_reports_summary (line 96) | def get_reports_summary(self, user_id: Optional[int] = None, is_admin:... method get_project_summary (line 201) | def get_project_summary( method get_user_productivity (line 255) | def get_user_productivity( method get_week_in_review (line 303) | def get_week_in_review(self, user_id: Optional[int] = None, is_admin: ... method get_comparison_data (line 354) | def get_comparison_data( method get_project_report_data (line 406) | def get_project_report_data( method get_unpaid_hours_report_data (line 520) | def get_unpaid_hours_report_data( FILE: app/services/scheduled_report_service.py class ScheduledReportService (line 22) | class ScheduledReportService: method __init__ (line 27) | def __init__(self): method create_schedule (line 31) | def create_schedule( method generate_and_send_report (line 93) | def generate_and_send_report(self, schedule_id: int) -> Dict[str, Any]: method _generate_report_data (line 190) | def _generate_report_data(self, saved_view: SavedReportView, config: D... method _calculate_next_run (line 226) | def _calculate_next_run(self, cadence: str, cron: Optional[str], timez... method get_schedule (line 263) | def get_schedule(self, schedule_id: int) -> Optional[ReportEmailSchedu... method list_schedules (line 267) | def list_schedules(self, user_id: Optional[int] = None, active_only: b... method update_schedule (line 278) | def update_schedule(self, schedule_id: int, user_id: int, **kwargs) ->... method delete_schedule (line 310) | def delete_schedule(self, schedule_id: int, user_id: int) -> Dict[str,... method _generate_and_send_custom_field_reports (line 329) | def _generate_and_send_custom_field_reports( method _get_recipients_for_field_value (line 526) | def _get_recipients_for_field_value( FILE: app/services/stats_service.py class StatsService (line 25) | class StatsService: method get_value_dashboard (line 29) | def get_value_dashboard(cls, user) -> Dict[str, Any]: method _compute_value_dashboard (line 42) | def _compute_value_dashboard(cls, user) -> Dict[str, Any]: method _dow_expression (line 113) | def _dow_expression(cls): method _most_productive_day_english (line 121) | def _most_productive_day_english(cls, base_filter) -> Optional[str]: method _last_7_days_hours (line 149) | def _last_7_days_hours( method _estimated_value_tracked (line 194) | def _estimated_value_tracked(cls, base_filter) -> float: function compute_value_dashboard_for_tests (line 215) | def compute_value_dashboard_for_tests(user) -> Dict[str, Any]: FILE: app/services/support_prompt_service.py class SupportPromptService (line 8) | class SupportPromptService: method _base_eligible (line 22) | def _base_eligible( method consume_layout_prompt (line 40) | def consume_layout_prompt( method pick_dashboard_prompt (line 66) | def pick_dashboard_prompt( method mark_prompt_shown (line 100) | def mark_prompt_shown(session: Dict[str, Any], variant: str) -> None: method long_session_prompt_allowed (line 110) | def long_session_prompt_allowed( FILE: app/services/task_service.py class TaskService (line 15) | class TaskService: method __init__ (line 39) | def __init__(self): method create_task (line 48) | def create_task( method get_task_with_details (line 117) | def get_task_with_details( method update_task (line 157) | def update_task(self, task_id: int, user_id: int, **kwargs) -> Dict[st... method get_project_tasks (line 181) | def get_project_tasks(self, project_id: int, status: Optional[str] = N... method list_tasks (line 185) | def list_tasks( FILE: app/services/time_approval_service.py class TimeApprovalService (line 17) | class TimeApprovalService: method request_approval (line 20) | def request_approval( method approve (line 65) | def approve(self, approval_id: int, approver_id: int, comment: str = N... method reject (line 101) | def reject(self, approval_id: int, approver_id: int, reason: str) -> D... method cancel_approval (line 125) | def cancel_approval(self, approval_id: int, user_id: int) -> Dict[str,... method get_pending_approvals (line 149) | def get_pending_approvals(self, approver_id: int = None) -> List[TimeE... method bulk_approve (line 166) | def bulk_approve(self, approval_ids: List[int], approver_id: int, comm... method _get_approvers_for_entry (line 180) | def _get_approvers_for_entry(self, time_entry: TimeEntry) -> List[int]: method _get_all_approver_ids (line 209) | def _get_all_approver_ids(self, user_id: int) -> List[int]: method _mark_entry_approved (line 220) | def _mark_entry_approved(self, time_entry: TimeEntry): method _notify_approvers (line 225) | def _notify_approvers(self, approval: TimeEntryApproval, approver_ids:... method _notify_requester (line 239) | def _notify_requester(self, approval: TimeEntryApproval, status: str, ... FILE: app/services/time_entry_bulk_service.py function apply_bulk_time_entry_actions (line 13) | def apply_bulk_time_entry_actions( FILE: app/services/time_entry_csv_import_service.py function _parse_dt (line 14) | def _parse_dt(val: str): function _parse_bool (line 26) | def _parse_bool(val: Any) -> bool: function import_time_entries_from_csv_text (line 34) | def import_time_entries_from_csv_text( function user_can_access_project_by_id (line 128) | def user_can_access_project_by_id(user_id: int, project_id: int, is_admi... FILE: app/services/time_tracking_service.py class TimeTrackingService (line 21) | class TimeTrackingService: method __init__ (line 24) | def __init__(self): method _is_locked_period (line 28) | def _is_locked_period(self, user_id: int, start_time: datetime, end_ti... method can_start_timer (line 37) | def can_start_timer(self, user_id: int) -> tuple[bool, Optional[str]]: method start_timer (line 50) | def start_timer( method stop_timer (line 150) | def stop_timer(self, user_id: int, entry_id: Optional[int] = None) -> ... method pause_timer (line 184) | def pause_timer(self, user_id: int) -> Dict[str, Any]: method resume_timer (line 199) | def resume_timer(self, user_id: int) -> Dict[str, Any]: method create_manual_entry (line 214) | def create_manual_entry( method get_user_entries (line 362) | def get_user_entries( method get_active_timer (line 389) | def get_active_timer(self, user_id: int) -> Optional[TimeEntry]: method update_entry (line 393) | def update_entry( method delete_entry (line 610) | def delete_entry( FILE: app/services/unpaid_hours_service.py class UnpaidHoursService (line 21) | class UnpaidHoursService: method get_unpaid_time_entries (line 24) | def get_unpaid_time_entries( method _filter_by_custom_fields (line 97) | def _filter_by_custom_fields( method get_unpaid_hours_summary (line 140) | def get_unpaid_hours_summary( method group_by_salesman (line 192) | def group_by_salesman( method get_unpaid_hours_by_salesman (line 241) | def get_unpaid_hours_by_salesman( FILE: app/services/usage_stats_service.py class UsageStatsService (line 10) | class UsageStatsService: method get_for_user (line 14) | def get_for_user(user_id: int, month_hours: Optional[float] = None) ->... method increment_reports_generated (line 37) | def increment_reports_generated(user_id: int) -> None: FILE: app/services/user_service.py class UserService (line 14) | class UserService: method __init__ (line 17) | def __init__(self): method create_user (line 20) | def create_user( method update_user (line 63) | def update_user(self, user_id: int, updated_by: int, **kwargs) -> Dict... method deactivate_user (line 97) | def deactivate_user(self, user_id: int, deactivated_by: int) -> Dict[s... method get_active_users (line 120) | def get_active_users(self) -> List[User]: method get_by_role (line 124) | def get_by_role(self, role: str) -> List[User]: FILE: app/services/version_service.py class GithubReleaseData (line 23) | class GithubReleaseData: function _release_to_dict (line 30) | def _release_to_dict(r: GithubReleaseData) -> dict[str, str]: function _dict_to_release (line 39) | def _dict_to_release(d: dict[str, Any]) -> GithubReleaseData | None: function _github_headers (line 54) | def _github_headers() -> dict[str, str]: function parse_release_object (line 65) | def parse_release_object(data: dict[str, Any]) -> GithubReleaseData | None: function resolve_current_installed_version (line 89) | def resolve_current_installed_version() -> tuple[str | None, str]: class VersionService (line 111) | class VersionService: method _cache_keys (line 115) | def _cache_keys(repo: str) -> tuple[str, str]: method _fetch_from_github_api (line 120) | def _fetch_from_github_api(cls) -> GithubReleaseData | None: method get_latest_release (line 184) | def get_latest_release(cls) -> GithubReleaseData | None: method build_check_response (line 219) | def build_check_response(cls, user: User | None) -> VersionCheckResponse: FILE: app/services/workflow_engine.py class WorkflowEngine (line 19) | class WorkflowEngine: method evaluate_trigger (line 23) | def evaluate_trigger(rule: WorkflowRule, event: Dict[str, Any]) -> bool: method _evaluate_conditions (line 39) | def _evaluate_conditions(conditions: List[Dict], event_data: Dict) -> ... method _compare_values (line 57) | def _compare_values(actual: Any, operator: str, expected: Any) -> bool: method execute_rule (line 82) | def execute_rule(rule: WorkflowRule, event: Dict[str, Any]) -> Dict[st... method _perform_action (line 170) | def _perform_action(action: Dict[str, Any], context: Dict[str, Any], r... method _action_log_time (line 194) | def _action_log_time(action: Dict, context: Dict, rule: WorkflowRule) ... method _action_send_notification (line 228) | def _action_send_notification(action: Dict, context: Dict) -> Dict: method _action_update_status (line 252) | def _action_update_status(action: Dict, context: Dict) -> Dict: method _action_assign_task (line 278) | def _action_assign_task(action: Dict, context: Dict) -> Dict: method _action_create_task (line 295) | def _action_create_task(action: Dict, context: Dict) -> Dict: method _action_update_project (line 319) | def _action_update_project(action: Dict, context: Dict) -> Dict: method _action_send_email (line 340) | def _action_send_email(action: Dict, context: Dict) -> Dict: method _action_webhook (line 357) | def _action_webhook(action: Dict, context: Dict) -> Dict: method _resolve_template (line 373) | def _resolve_template(value: Any, context: Dict) -> Any: method trigger_event (line 395) | def trigger_event(event_type: str, event_data: Dict[str, Any]) -> List... FILE: app/services/workforce_governance_service.py class WorkforceGovernanceService (line 17) | class WorkforceGovernanceService: method get_or_create_default_policy (line 20) | def get_or_create_default_policy(self) -> TimesheetPolicy: method resolve_period_range (line 29) | def resolve_period_range(self, reference: date, period_type: str = "we... method get_or_create_period_for_date (line 36) | def get_or_create_period_for_date( method list_periods (line 59) | def list_periods( method _has_open_timer_in_range (line 78) | def _has_open_timer_in_range(self, user_id: int, period: TimesheetPeri... method submit_period (line 87) | def submit_period(self, period_id: int, actor_id: int) -> Dict[str, Any]: method approve_period (line 104) | def approve_period(self, period_id: int, approver_id: int, comment: Op... method reject_period (line 118) | def reject_period(self, period_id: int, approver_id: int, reason: str)... method close_period (line 131) | def close_period(self, period_id: int, closer_id: int, reason: Optiona... method is_time_entry_locked (line 146) | def is_time_entry_locked(self, user_id: int, start_time: datetime, end... method apply_auto_lock (line 159) | def apply_auto_lock(self, actor_id: Optional[int] = None) -> int: method list_leave_types (line 178) | def list_leave_types(self, enabled_only: bool = True) -> List[LeaveType]: method get_overtime_leave_type (line 184) | def get_overtime_leave_type(self) -> Optional[LeaveType]: method create_leave_request (line 188) | def create_leave_request( method review_leave_request (line 236) | def review_leave_request( method get_leave_balance (line 257) | def get_leave_balance(self, user_id: int) -> List[Dict[str, Any]]: method is_holiday (line 289) | def is_holiday(self, day: date) -> bool: method capacity_report (line 297) | def capacity_report( method locked_periods_report (line 359) | def locked_periods_report(self, start_date: Optional[date], end_date: ... method compliance_audit_events (line 368) | def compliance_audit_events( method payroll_rows (line 408) | def payroll_rows( method delete_period (line 472) | def delete_period(self, period_id: int, actor_id: int) -> Dict[str, Any]: method delete_leave_request (line 489) | def delete_leave_request(self, request_id: int, actor_id: int, actor_c... method delete_leave_type (line 507) | def delete_leave_type(self, leave_type_id: int) -> Dict[str, Any]: method delete_holiday (line 521) | def delete_holiday(self, holiday_id: int) -> Dict[str, Any]: FILE: app/static/activity-feed.js class ActivityFeed (line 6) | class ActivityFeed { method constructor (line 7) | constructor(containerId, options = {}) { method init (line 31) | init() { method loadActivities (line 38) | async loadActivities(page = 1, append = false) { method render (line 72) | render() { method renderActivity (line 103) | renderActivity(activity) { method getActivityIcon (line 125) | getActivityIcon(activity) { method formatActivityDescription (line 141) | formatActivityDescription(activity) { method formatTimeAgo (line 146) | formatTimeAgo(timestamp) { method formatExtraData (line 162) | formatExtraData(extraData) { method setupAutoRefresh (line 167) | setupAutoRefresh() { method setupWebSocket (line 175) | setupWebSocket() { method showLoading (line 190) | showLoading() { method hideLoading (line 197) | hideLoading() { method showError (line 204) | showError(message) { method setFilters (line 211) | setFilters(filters) { method destroy (line 217) | destroy() { FILE: app/static/admin-version-update.js function getCsrfToken (line 8) | function getCsrfToken() { function localDismissedMatches (line 13) | function localDismissedMatches(latest) { function setLocalDismissed (line 21) | function setLocalDismissed(latest) { function hide (line 27) | function hide(root) { function show (line 31) | function show(root) { function postDismiss (line 35) | function postDismiss(latest, onDone) { function renderNotes (line 104) | function renderNotes() { function wireClose (line 138) | function wireClose() { FILE: app/static/ai-helper.js function csrfToken (line 2) | function csrfToken() { function el (line 7) | function el(id) { function escapeHtml (line 11) | function escapeHtml(value) { function addMessage (line 20) | function addMessage(role, text) { function setStatus (line 33) | function setStatus(text, isError) { function postJson (line 42) | async function postJson(url, body) { function loadContextPreview (line 56) | async function loadContextPreview() { function renderActions (line 76) | function renderActions(actions) { function openDrawer (line 118) | function openDrawer() { function closeDrawer (line 125) | function closeDrawer() { FILE: app/static/base-init.js function isTyping (line 8) | function isTyping(e) { function toggleTimer (line 39) | async function toggleTimer() { FILE: app/static/calendar.js class Calendar (line 6) | class Calendar { method constructor (line 7) | constructor(options) { method init (line 24) | init() { method setupEventListeners (line 30) | setupEventListeners() { method navigatePrevious (line 79) | navigatePrevious() { method navigateNext (line 95) | navigateNext() { method loadEvents (line 111) | async loadEvents() { method saveCalendarColors (line 181) | async saveCalendarColors() { method getDateRange (line 214) | getDateRange() { method updateViewLinks (line 245) | updateViewLinks() { method render (line 258) | render() { method updateTitle (line 274) | updateTitle() { method renderDayView (line 296) | renderDayView() { method renderTimeSlots (line 310) | renderTimeSlots() { method assignOverlapColumnsByTime (line 330) | assignOverlapColumnsByTime(items) { method assignOverlapColumnsByPosition (line 353) | assignOverlapColumnsByPosition(items) { method columnStyle (line 374) | columnStyle(col, totalCols) { method renderDayEvents (line 382) | renderDayEvents() { method renderWeekView (line 516) | renderWeekView() { method renderWeekDayBlocks (line 560) | renderWeekDayBlocks(day) { method renderMonthView (line 668) | renderMonthView() { method renderMonthCellEvents (line 712) | renderMonthCellEvents(day) { method isToday (line 778) | isToday(date) { method showEventDetails (line 785) | showEventDetails(id, type, clickEvent) { method _positionModalNearClick (line 882) | _positionModalNearClick(modal, clickEvent) { method escapeHtml (line 908) | escapeHtml(text) { FILE: app/static/charts.js class ChartManager (line 6) | class ChartManager { method constructor (line 7) | constructor() { method createTimeSeriesChart (line 18) | createTimeSeriesChart(canvasId, data, options = {}) { method createBarChart (line 91) | createBarChart(canvasId, data, options = {}) { method createDoughnutChart (line 154) | createDoughnutChart(canvasId, data, options = {}) { method createProgressChart (line 223) | createProgressChart(canvasId, value, max, options = {}) { method createSparkline (line 288) | createSparkline(canvasId, data, options = {}) { method createStackedAreaChart (line 340) | createStackedAreaChart(canvasId, data, options = {}) { method updateChart (line 401) | updateChart(canvasId, newData) { method destroyChart (line 421) | destroyChart(canvasId) { method hexToRgba (line 432) | hexToRgba(hex, alpha = 1) { method getChart (line 442) | getChart(canvasId) { method exportChart (line 449) | exportChart(canvasId, filename = 'chart.png') { function formatHours (line 465) | function formatHours(hours) { function formatCurrency (line 470) | function formatCurrency(value, currency = 'USD') { FILE: app/static/commands.js function $ (line 11) | function $(sel, root){ return (root||document).querySelector(sel); } function $all (line 12) | function $all(sel, root){ return Array.from((root||document).querySelect... function openModal (line 14) | function openModal(){ function closeModal (line 28) | function closeModal(){ function getActiveTimer (line 36) | async function getActiveTimer(){ function startTimerQuick (line 45) | async function startTimerQuick(){ function stopTimerQuick (line 50) | async function stopTimerQuick(){ function addCommand (line 68) | function addCommand(cmd){ registry.push(cmd); } function nav (line 69) | function nav(href){ window.location.href = href; } function clearFilter (line 104) | function clearFilter(){ function normalize (line 111) | function normalize(s){ return (s||'').toLowerCase(); } function isMatch (line 112) | function isMatch(cmd, q){ function refreshCommands (line 120) | async function refreshCommands(){ function renderList (line 127) | function renderList(){ function highlightSelected (line 145) | function highlightSelected(){ function onInput (line 153) | function onInput(){ function onKeyDown (line 160) | function onKeyDown(ev){ function resetSeq (line 174) | function resetSeq(){ seq = []; if (seqTimer) { clearTimeout(seqTimer); s... function isTypingInField (line 177) | function isTypingInField(ev){ function sequenceHandler (line 181) | function sequenceHandler(ev){ FILE: app/static/dashboard-enhancements.js function isDashboardPage (line 23) | function isDashboardPage() { function init (line 31) | function init() { function initSparklines (line 41) | function initSparklines() { function createSparkline (line 60) | function createSparkline(containerId, data, color = '#3b82f6') { function initActivityTimeline (line 136) | function initActivityTimeline() { function loadActivityTimeline (line 147) | async function loadActivityTimeline() { function renderActivityTimeline (line 169) | function renderActivityTimeline(activities) { function getActivityIcon (line 212) | function getActivityIcon(type) { function getActivityColor (line 228) | function getActivityColor(type) { function formatTimeAgo (line 244) | function formatTimeAgo(dateString) { function initRealTimeUpdates (line 268) | function initRealTimeUpdates() { function updateDashboardData (line 298) | async function updateDashboardData() { function updateStats (line 326) | async function updateStats() { function updateStatCard (line 377) | function updateStatCard(id, value) { function animateValue (line 389) | function animateValue(element, start, end, duration) { function updateSparklines (line 408) | async function updateSparklines() { function initValueDashboard (line 438) | function initValueDashboard() { function loadWeekComparison (line 445) | async function loadWeekComparison() { function loadValueDashboard (line 611) | async function loadValueDashboard() { function renderValueDashboardChart (line 687) | function renderValueDashboardChart(container, series) { FILE: app/static/dashboard-widgets.js class DashboardWidgetManager (line 6) | class DashboardWidgetManager { method constructor (line 7) | constructor() { method init (line 15) | init() { method defineAvailableWidgets (line 21) | defineAvailableWidgets() { method createContainer (line 82) | createContainer() { method createCustomizeButton (line 90) | createCustomizeButton() { method renderWidgets (line 98) | renderWidgets() { method createWidgetElement (line 124) | createWidgetElement(widget) { method getSizeClass (line 148) | getSizeClass(size) { method renderQuickStats (line 157) | renderQuickStats() { method renderActiveTimer (line 173) | renderActiveTimer() { method renderRecentProjects (line 186) | renderRecentProjects() { method renderUpcomingDeadlines (line 202) | renderUpcomingDeadlines() { method renderTimeChart (line 217) | renderTimeChart() { method renderProductivityScore (line 224) | renderProductivityScore() { method renderActivityFeed (line 237) | renderActivityFeed() { method renderQuickActions (line 252) | renderQuickActions() { method toggleEditMode (line 268) | toggleEditMode() { method showWidgetSelector (line 278) | showWidgetSelector() { method makeDraggable (line 302) | makeDraggable(element) { method getDragAfterElement (line 326) | getDragAfterElement(container, y) { method saveLayout (line 340) | saveLayout() { method loadLayout (line 352) | loadLayout() { FILE: app/static/data-tables-enhanced.js class DataTableEnhanced (line 9) | class DataTableEnhanced { method constructor (line 10) | constructor(table, options = {}) { method init (line 36) | init() { method extractData (line 53) | extractData() { method loadPreferences (line 71) | loadPreferences() { method savePreferences (line 86) | savePreferences() { method initSorting (line 98) | initSorting() { method sort (line 143) | sort(columnIndex) { method updateSortIndicators (line 190) | updateSortIndicators() { method initColumnVisibility (line 208) | initColumnVisibility() { method populateColumnVisibilityDropdown (line 335) | populateColumnVisibilityDropdown(dropdown) { method toggleColumnVisibilityDropdown (line 369) | toggleColumnVisibilityDropdown(dropdown) { method toggleColumn (line 376) | toggleColumn(columnIndex, show) { method initStickyHeader (line 397) | initStickyHeader() { method updateStickyHeader (line 426) | updateStickyHeader(container) { method initPagination (line 437) | initPagination() { method renderPagination (line 459) | renderPagination() { method renderPaginationButtons (line 520) | renderPaginationButtons(totalPages) { method goToPage (line 582) | goToPage(page) { method render (line 593) | render() { FILE: app/static/date-picker-init.js function getFlatpickrAltFormat (line 7) | function getFlatpickrAltFormat() { function getFirstDayOfWeek (line 18) | function getFirstDayOfWeek() { function initUserDateInputs (line 25) | function initUserDateInputs() { function onReady (line 43) | function onReady() { FILE: app/static/enhanced-search.js class EnhancedSearch (line 9) | class EnhancedSearch { method constructor (line 10) | constructor(input, options = {}) { method init (line 34) | init() { method createSearchUI (line 49) | createSearchUI() { method bindEvents (line 88) | bindEvents() { method handleInput (line 106) | handleInput(e) { method handleFocus (line 137) | handleFocus() { method handleBlur (line 145) | handleBlur(e) { method handleKeydown (line 154) | handleKeydown(e) { method setActive (line 186) | setActive(items) { method performSearch (line 196) | async performSearch(query) { method renderResults (line 221) | renderResults(query) { method renderItem (line 250) | renderItem(item, query) { method groupResults (line 272) | groupResults(results) { method highlightMatch (line 284) | highlightMatch(text, query) { method highlightQuery (line 289) | highlightQuery(query) { method showRecentSearches (line 293) | showRecentSearches() { method showNoResults (line 343) | showNoResults(query) { method showError (line 353) | showError() { method bindItemEvents (line 363) | bindItemEvents() { method showAutocomplete (line 381) | showAutocomplete() { method hideAutocomplete (line 386) | hideAutocomplete() { method clear (line 391) | clear() { method loadRecentSearches (line 400) | loadRecentSearches() { method saveRecentSearch (line 408) | saveRecentSearch(query) { method clearRecentSearches (line 419) | clearRecentSearches() { method getIcon (line 425) | getIcon(type) { method formatCategory (line 438) | formatCategory(category) { method escapeHTML (line 442) | escapeHTML(str) { method escapeRegex (line 448) | escapeRegex(str) { FILE: app/static/enhanced-tables.js class EnhancedTable (line 9) | class EnhancedTable { method constructor (line 10) | constructor(table, options = {}) { method init (line 35) | init() { method extractData (line 49) | extractData() { method createWrapper (line 61) | createWrapper() { method createToolbar (line 87) | createToolbar() { method bindToolbarEvents (line 143) | bindToolbarEvents(toolbar) { method createBulkActionsBar (line 187) | createBulkActionsBar() { method enableSorting (line 208) | enableSorting() { method sort (line 220) | sort(columnIndex) { method handleSearch (line 260) | handleSearch(query) { method enableResizing (line 276) | enableResizing() { method enableSelection (line 311) | enableSelection() { method updateBulkActions (line 364) | updateBulkActions() { method enableEditing (line 378) | enableEditing() { method editCell (line 388) | editCell(cell) { method onCellEdit (line 447) | onCellEdit(cell, oldValue, newValue) { method render (line 461) | render() { method renderPagination (line 487) | renderPagination() { method updatePagination (line 499) | updatePagination() { method getPaginationButtons (line 538) | getPaginationButtons(totalPages) { method goToPage (line 559) | goToPage(page) { method toggleColumnsDropdown (line 567) | toggleColumnsDropdown() { method renderColumnsDropdown (line 576) | renderColumnsDropdown(dropdown) { method toggleColumn (line 597) | toggleColumn(index, show) { method toggleExportMenu (line 610) | toggleExportMenu() { method exportData (line 615) | exportData(format) { method exportCSV (line 625) | exportCSV() { method exportJSON (line 640) | exportJSON() { method downloadFile (line 656) | downloadFile(content, filename, type) { FILE: app/static/enhanced-ui.js class EnhancedTable (line 9) | class EnhancedTable { method constructor (line 10) | constructor(tableElement) { method init (line 17) | init() { method initSorting (line 25) | initSorting() { method sortColumn (line 33) | sortColumn(columnIndex, header) { method initBulkSelect (line 74) | initBulkSelect() { method toggleRowSelection (line 113) | toggleRowSelection(row, selected) { method updateBulkActionsBar (line 123) | updateBulkActionsBar() { method createBulkActionsBar (line 140) | createBulkActionsBar() { method initColumnResize (line 160) | initColumnResize() { method initInlineEdit (line 194) | initInlineEdit() { method makeEditable (line 201) | makeEditable(cell) { method getSelectedRowData (line 232) | getSelectedRowData() { class LiveSearch (line 243) | class LiveSearch { method constructor (line 244) | constructor(inputElement, options = {}) { method init (line 257) | init() { method handleInput (line 300) | handleInput(e) { method displayResults (line 323) | displayResults(results) { method clear (line 340) | clear() { class FilterManager (line 355) | class FilterManager { method constructor (line 356) | constructor(formElement) { method init (line 364) | init() { method addQuickFilters (line 432) | addQuickFilters() { method applyQuickFilter (line 452) | applyQuickFilter(filter) { method updateFilters (line 466) | updateFilters() { method renderChips (line 481) | renderChips() { method removeFilter (line 523) | removeFilter(key) { method clearAll (line 544) | clearAll() { method submitForm (line 571) | submitForm() { method submitViaAjax (line 596) | submitViaAjax() { class ToastManager (line 803) | class ToastManager { method constructor (line 804) | constructor() { method init (line 809) | init() { method show (line 815) | show(message, type = 'info', duration = 5000) { method remove (line 851) | remove(toast) { method success (line 856) | success(message, duration) { method error (line 860) | error(message, duration) { method warning (line 864) | warning(message, duration) { method info (line 868) | info(message, duration) { class UndoManager (line 876) | class UndoManager { method constructor (line 877) | constructor() { method addAction (line 882) | addAction(action, undoFn, data) { method undo (line 890) | undo() { method showUndoBar (line 902) | showUndoBar(action) { class FormAutoSave (line 928) | class FormAutoSave { method constructor (line 929) | constructor(formElement, options = {}) { method init (line 942) | init() { method scheduleAutoSave (line 1018) | scheduleAutoSave() { method save (line 1023) | save() { method load (line 1078) | load() { method showIndicator (line 1101) | showIndicator(state) { method clear (line 1146) | clear() { class RecentlyViewedTracker (line 1156) | class RecentlyViewedTracker { method constructor (line 1157) | constructor(maxItems = 10) { method track (line 1162) | track(item) { method getItems (line 1180) | getItems() { method clear (line 1188) | clear() { class FavoritesManager (line 1196) | class FavoritesManager { method constructor (line 1197) | constructor() { method toggle (line 1201) | toggle(item) { method isFavorite (line 1216) | isFavorite(id, type) { method getFavorites (line 1220) | getFavorites() { method save (line 1228) | save(favorites) { class DragDropManager (line 1236) | class DragDropManager { method constructor (line 1237) | constructor(containerElement, options = {}) { method init (line 1247) | init() { method handleDragStart (line 1258) | handleDragStart(e) { method handleDragEnd (line 1264) | handleDragEnd(e) { method handleDragOver (line 1268) | handleDragOver(e) { method handleDrop (line 1286) | handleDrop(e) { method getDragAfterElement (line 1304) | getDragAfterElement(y) { function animateCount (line 1448) | function animateCount(element, start, end, duration, decimals = 0) { function easeOutQuad (line 1466) | function easeOutQuad(t) { function setSubmitButtonLoading (line 1474) | function setSubmitButtonLoading(button, loading, loadingText) { function bulkDelete (line 1495) | async function bulkDelete() { function bulkExport (line 1511) | function bulkExport() { function clearSelection (line 1520) | function clearSelection() { FILE: app/static/error-handling-enhanced.js class EnhancedErrorHandler (line 6) | class EnhancedErrorHandler { method constructor (line 7) | constructor() { method init (line 19) | init() { method setupNetworkMonitoring (line 42) | setupNetworkMonitoring() { method checkOnlineStatus (line 61) | checkOnlineStatus() { method handleOnline (line 77) | handleOnline() { method handleOffline (line 88) | handleOffline() { method showOnlineIndicator (line 93) | showOnlineIndicator() { method showOfflineIndicator (line 103) | showOfflineIndicator() { method addOfflineIndicatorStyles (line 123) | addOfflineIndicatorStyles() { method setupFetchInterceptor (line 232) | setupFetchInterceptor() { method handleFetchError (line 254) | async handleFetchError(response, url, options) { method handleFetchException (line 274) | async handleFetchException(error, url, options) { method retryFetch (line 295) | async retryFetch(url, options) { method getUserFriendlyMessage (line 329) | getUserFriendlyMessage(status, errorData) { method showErrorWithRetry (line 359) | showErrorWithRetry(message, status, retryCallback) { method showError (line 427) | showError(message, title = 'Error') { method isDuplicateError (line 446) | isDuplicateError(message) { method getRecoveryOptions (line 470) | getRecoveryOptions(status) { method queueForOffline (line 533) | async queueForOffline(url, options, errorId = null) { method saveOfflineQueue (line 585) | saveOfflineQueue() { method loadOfflineQueue (line 593) | loadOfflineQueue() { method processOfflineQueue (line 605) | async processOfflineQueue() { method updateOfflineQueueIndicator (line 638) | updateOfflineQueueIndicator() { method setupOfflineQueue (line 651) | setupOfflineQueue() { method setupGlobalErrorHandlers (line 664) | setupGlobalErrorHandlers() { method handleJavaScriptError (line 676) | handleJavaScriptError(error, message, filename, lineno) { method handleUnhandledRejection (line 706) | handleUnhandledRejection(reason) { method setupGracefulDegradation (line 729) | setupGracefulDegradation() { method checkRequiredFeatures (line 737) | checkRequiredFeatures() { method setupFeatureFallbacks (line 768) | setupFeatureFallbacks() { method polyfillFetch (line 782) | polyfillFetch() { method polyfillLocalStorage (line 862) | polyfillLocalStorage() { method retryFailedOperations (line 912) | retryFailedOperations() { method shouldIgnoreFrontendNoise (line 926) | shouldIgnoreFrontendNoise(error, message) { FILE: app/static/floating-actions.js function getDock (line 8) | function getDock() { function getRoot (line 12) | function getRoot() { function getButton (line 16) | function getButton() { function getMenu (line 20) | function getMenu() { function getUrl (line 24) | function getUrl(name, fallback) { function setOpen (line 29) | function setOpen(open) { function close (line 45) | function close() { function toggle (line 49) | function toggle() { function startTimer (line 55) | function startTimer() { function navigateTo (line 67) | function navigateTo(attr, fallback) { function runAction (line 72) | function runAction(action) { FILE: app/static/floating-timer-bar.js function syncFabDesktopHide (line 10) | function syncFabDesktopHide(timerData) { class FloatingTimerBar (line 18) | class FloatingTimerBar { method constructor (line 19) | constructor() { method init (line 30) | init() { method fetchStatus (line 41) | async fetchStatus() { method startElapsedUpdater (line 61) | startElapsedUpdater() { method stopElapsedUpdater (line 87) | stopElapsedUpdater() { method startTimer (line 94) | startTimer() { method stopTimer (line 104) | async stopTimer() { method resumeTimer (line 126) | async resumeTimer() { method getCsrfToken (line 148) | getCsrfToken() { method getLabel (line 153) | getLabel() { method render (line 158) | render() { method destroy (line 189) | destroy() { function escapeHtml (line 195) | function escapeHtml(text) { FILE: app/static/form-validation.js class FormValidator (line 6) | class FormValidator { method constructor (line 7) | constructor(formElement, options = {}) { method init (line 25) | init() { method setupField (line 71) | setupField(input) { method getLabel (line 111) | getLabel(input) { method markAsRequired (line 131) | markAsRequired(label) { method createMessageContainer (line 158) | createMessageContainer(input, type) { method setupValidationRules (line 226) | setupValidationRules(field) { method debouncedValidate (line 375) | debouncedValidate(field, event) { method validateField (line 388) | validateField(field, event) { method updateFieldState (line 424) | updateFieldState(field) { method showErrorMessage (line 467) | showErrorMessage(field) { method hideErrorMessage (line 475) | hideErrorMessage(field) { method showSuccessMessage (line 482) | showSuccessMessage(field) { method hideSuccessMessage (line 499) | hideSuccessMessage(field) { method handleSubmit (line 506) | handleSubmit(event) { method showFormError (line 535) | showFormError(message) { method hideFormError (line 549) | hideFormError() { method validate (line 557) | validate() { method reset (line 567) | reset() { FILE: app/static/global-fab.js function getRoot (line 7) | function getRoot() { function setOpen (line 11) | function setOpen(open) { function close (line 21) | function close() { function open (line 25) | function open() { function toggle (line 29) | function toggle() { function dashboardUrl (line 35) | function dashboardUrl() { function manualUrl (line 41) | function manualUrl() { function newTaskUrl (line 47) | function newTaskUrl() { function onStartTimer (line 53) | function onStartTimer() { function onLogTime (line 65) | function onLogTime() { function onNewTask (line 70) | function onNewTask() { FILE: app/static/idle.js function getIdleThresholdMs (line 5) | function getIdleThresholdMs(){ function markActive (line 17) | function markActive(){ function getTimer (line 26) | async function getTimer(){ function formatTime (line 34) | function formatTime(d){ function stopAt (line 38) | async function stopAt(ts){ function showIdlePrompt (line 55) | function showIdlePrompt(stopTs){ function tick (line 89) | async function tick(){ FILE: app/static/interactions.js function init (line 16) | function init() { function initRippleEffects (line 29) | function initRippleEffects() { function initLoadingStates (line 43) | function initLoadingStates() { function addLoadingState (line 71) | function addLoadingState(element) { function removeLoadingState (line 81) | function removeLoadingState(element) { function initSmoothScrolling (line 94) | function initSmoothScrolling() { function initAnimationsOnScroll (line 117) | function initAnimationsOnScroll() { function initCountUpAnimations (line 144) | function initCountUpAnimations() { function animateCountUp (line 166) | function animateCountUp(element) { function initTooltipEnhancements (line 187) | function initTooltipEnhancements() { function initFormEnhancements (line 202) | function initFormEnhancements() { function showSkeleton (line 261) | function showSkeleton(container) { function hideSkeleton (line 271) | function hideSkeleton(container) { function createLoadingOverlay (line 281) | function createLoadingOverlay(text = 'Loading...') { function showToast (line 296) | function showToast(message, type = 'info', duration = 3000) { function createToastContainer (line 332) | function createToastContainer() { function staggerAnimation (line 344) | function staggerAnimation(container, itemSelector = '> *') { function showSuccessAnimation (line 356) | function showSuccessAnimation(container) { FILE: app/static/js/command-palette.js function showToast (line 65) | function showToast(message, level = 'info') { function normalize (line 79) | function normalize(s) { function fuzzyRank (line 83) | function fuzzyRank(haystack, query) { function isTyping (line 95) | function isTyping(ev) { function openPalette (line 99) | function openPalette() { function closePalette (line 117) | function closePalette() { function nav (line 133) | function nav(href) { function fetchProjects (line 137) | async function fetchProjects() { function startTimerWithProject (line 147) | async function startTimerWithProject(projectId) { function setMode (line 165) | function setMode(mode, headerText = '') { function buildCommands (line 184) | function buildCommands() { function getActiveItems (line 209) | function getActiveItems() { function applyFilter (line 231) | function applyFilter() { function highlightSelected (line 254) | function highlightSelected() { function renderEmpty (line 263) | function renderEmpty(message) { function render (line 271) | function render() { function onInput (line 311) | function onInput() { function onPaletteKeydown (line 317) | function onPaletteKeydown(ev) { function onGlobalKeydown (line 350) | function onGlobalKeydown(ev) { function onBackdropClick (line 367) | function onBackdropClick(e) { function onRootClick (line 372) | function onRootClick(e) { function init (line 380) | function init() { FILE: app/static/js/gantt-color-picker.js function hexValid (line 7) | function hexValid(v) { function toHex (line 13) | function toHex(c) { function init (line 24) | function init() { FILE: app/static/js/integration_wizard.js class IntegrationWizard (line 13) | class IntegrationWizard { method constructor (line 14) | constructor(options) { method init (line 26) | init() { method setupEventListeners (line 36) | setupEventListeners() { method handleNext (line 63) | handleNext() { method handlePrevious (line 75) | handlePrevious() { method validateCurrentStep (line 82) | validateCurrentStep() { method validateStepFields (line 92) | validateStepFields() { method validateStep (line 131) | validateStep(stepNumber) { method addValidationCallback (line 136) | addValidationCallback(stepNumber, callback) { method onStepChange (line 140) | onStepChange(callback) { method updateStepUI (line 144) | updateStepUI() { method testConnection (line 219) | async testConnection(data) { method displayConnectionResults (line 258) | displayConnectionResults(result, resultsContainerId = 'connection-test... method showError (line 289) | showError(fieldId, message) { method clearError (line 303) | clearError(fieldId) { method clearAllErrors (line 314) | clearAllErrors() { method submitForm (line 319) | async submitForm() { method handleSubmit (line 354) | handleSubmit(e) { method copyToClipboard (line 363) | copyToClipboard(elementId, button) { method getCSRFToken (line 404) | getCSRFToken() { method escapeHtml (line 409) | escapeHtml(text) { method goToStep (line 416) | goToStep(stepNumber) { method getCurrentStep (line 423) | getCurrentStep() { FILE: app/static/js/ldap_wizard.js function getEndpoints (line 12) | function getEndpoints() { function collectPayload (line 24) | function collectPayload() { function handleNext (line 73) | function handleNext() { function handlePrevious (line 82) | function handlePrevious() { function validateCurrentStep (line 89) | function validateCurrentStep() { function validateStep1 (line 107) | function validateStep1() { function validateStep2 (line 116) | function validateStep2() { function validateStep3 (line 128) | function validateStep3() { function validateStep4 (line 140) | function validateStep4() { function validateStep5 (line 149) | function validateStep5() { function showError (line 153) | function showError(fieldId, message) { function clearErrors (line 167) | function clearErrors() { function updateStepUI (line 176) | function updateStepUI() { function handleTestConnection (line 234) | async function handleTestConnection() { function escapeHtml (line 265) | function escapeHtml(text) { function displayConnectionResults (line 271) | function displayConnectionResults(result) { function handleGenerateConfig (line 299) | async function handleGenerateConfig() { function displayConfigResults (line 343) | function displayConfigResults(result) { function copyToClipboard (line 352) | function copyToClipboard(elementId, button) { FILE: app/static/js/oidc_wizard.js function initializeWizard (line 19) | function initializeWizard() { function handleNext (line 39) | function handleNext() { function handlePrevious (line 48) | function handlePrevious() { function validateCurrentStep (line 55) | function validateCurrentStep() { function validateStep1 (line 72) | function validateStep1() { function validateStep2 (line 114) | function validateStep2() { function validateStep3 (line 129) | function validateStep3() { function validateStep4 (line 134) | function validateStep4() { function showError (line 139) | function showError(fieldId, message) { function clearErrors (line 154) | function clearErrors() { function updateStepUI (line 159) | function updateStepUI() { function handleTestConnection (line 219) | async function handleTestConnection() { function displayConnectionResults (line 259) | function displayConnectionResults(result) { function handleGenerateConfig (line 303) | async function handleGenerateConfig() { function displayConfigResults (line 350) | function displayConfigResults(result) { function copyToClipboard (line 361) | function copyToClipboard(elementId, button) { function escapeHtml (line 402) | function escapeHtml(text) { FILE: app/static/js/setup-wizard.js function getProgressLabel (line 10) | function getProgressLabel() { function setProgressLabel (line 14) | function setProgressLabel(text) { function validateStep2 (line 19) | function validateStep2() { function validateCurrentStep (line 46) | function validateCurrentStep() { function goNext (line 51) | function goNext() { function goBack (line 59) | function goBack() { function updateStepUI (line 66) | function updateStepUI() { function init (line 102) | function init() { FILE: app/static/js/sw.js constant CACHE_NAME (line 2) | const CACHE_NAME = 'timetracker-v1'; constant PRECACHE_URLS (line 4) | const PRECACHE_URLS = [ function isSameOrigin (line 44) | function isSameOrigin(url) { function cacheFirst (line 48) | async function cacheFirst(request) { function networkFirstDocument (line 66) | async function networkFirstDocument(request) { function networkFirstApi (line 79) | async function networkFirstApi(request) { FILE: app/static/keyboard-shortcuts-advanced.js class KeyboardShortcutManager (line 6) | class KeyboardShortcutManager { method constructor (line 7) | constructor() { method init (line 20) | init() { method register (line 30) | register(key, callback, options = {}) { method initDefaultShortcuts (line 71) | initDefaultShortcuts() { method applyUserOverrides (line 103) | applyUserOverrides() { method handleKeyPress (line 125) | handleKeyPress(e) { method getKeyCombo (line 207) | getKeyCombo(e) { method normalizeKey (line 230) | normalizeKey(key) { method isTyping (line 237) | isTyping(e) { method detectContext (line 246) | detectContext() { method showShortcutsPanel (line 271) | showShortcutsPanel() { method renderShortcutsList (line 308) | renderShortcutsList() { method loadCustomShortcuts (line 347) | loadCustomShortcuts() { method saveCustomShortcuts (line 359) | saveCustomShortcuts() { method openCommandPalette (line 364) | openCommandPalette() { method toggleSearch (line 385) | toggleSearch() { method toggleSidebar (line 399) | toggleSidebar() { method toggleDarkMode (line 405) | toggleDarkMode() { method navigateTo (line 410) | navigateTo(url) { method createProject (line 414) | createProject() { method createTask (line 420) | createTask() { method createClient (line 426) | createClient() { method startTimer (line 430) | startTimer() { method pauseTimer (line 435) | pauseTimer() { method logTime (line 440) | logTime() { method selectAllRows (line 444) | selectAllRows() { method deleteSelected (line 452) | deleteSelected() { method clearSelection (line 458) | clearSelection() { method closeModal (line 464) | closeModal() { method submitForm (line 473) | submitForm() { method saveForm (line 480) | saveForm() { method undo (line 488) | undo() { method redo (line 494) | redo() { method showQuickActions (line 500) | showQuickActions() { method executeAction (line 506) | executeAction(action) { method customizeShortcuts (line 510) | customizeShortcuts() { FILE: app/static/keyboard-shortcuts-enhanced.js class EnhancedKeyboardShortcuts (line 10) | class EnhancedKeyboardShortcuts { method constructor (line 11) | constructor() { method init (line 28) | init() { method registerDefaultShortcuts (line 44) | registerDefaultShortcuts() { method register (line 363) | register(keys, config, options = {}) { method bindGlobalListeners (line 384) | bindGlobalListeners() { method handleKeyDown (line 397) | handleKeyDown(e) { method handleKeyUp (line 465) | handleKeyUp(e) { method handleSequence (line 472) | handleSequence(e) { method getKeyCombo (line 519) | getKeyCombo(e) { method normalizeKeys (line 537) | normalizeKeys(keys) { method isTypingContext (line 547) | isTypingContext(e) { method isAllowedInInput (line 556) | isAllowedInInput(combo) { method detectContext (line 571) | detectContext() { method resetSequence (line 599) | resetSequence() { method recordUsage (line 607) | recordUsage(shortcutKey) { method navigate (line 623) | navigate(url) { method openCommandPalette (line 627) | openCommandPalette() { method focusSearch (line 642) | focusSearch() { method toggleSidebar (line 652) | toggleSidebar() { method toggleTheme (line 657) | toggleTheme() { method openNotifications (line 662) | openNotifications() { method startTimer (line 667) | async startTimer() { method stopTimer (line 676) | async stopTimer() { method selectAllRows (line 695) | selectAllRows() { method deleteSelected (line 703) | deleteSelected() { method clearSelection (line 709) | clearSelection() { method navigateRow (line 717) | navigateRow(direction) { method saveForm (line 740) | saveForm() { method submitForm (line 749) | submitForm() { method cancelForm (line 758) | cancelForm() { method closeModal (line 767) | closeModal() { method confirmModal (line 779) | confirmModal() { method jumpToMain (line 787) | jumpToMain() { method showToast (line 797) | showToast(message, type = 'info') { method createCheatSheetModal (line 812) | createCheatSheetModal() { method showCheatSheet (line 895) | showCheatSheet() { method hideCheatSheet (line 911) | hideCheatSheet() { method renderCheatSheet (line 919) | renderCheatSheet(filter = '', category = 'all') { method formatKeysForDisplay (line 1032) | formatKeysForDisplay(keys) { method filterCheatSheet (line 1048) | filterCheatSheet(query) { method openCustomization (line 1058) | openCustomization() { method printCheatSheet (line 1065) | printCheatSheet() { method setupOnboarding (line 1072) | setupOnboarding() { method showOnboardingHint (line 1085) | showOnboardingHint() { method handleRecording (line 1117) | handleRecording(e) { method startRecording (line 1132) | startRecording(callback) { method saveToStorage (line 1139) | saveToStorage(key, value) { method loadFromStorage (line 1147) | loadFromStorage(key) { method executeShortcut (line 1159) | executeShortcut(action) { FILE: app/static/keyboard-shortcuts.js class KeyboardShortcuts (line 9) | class KeyboardShortcuts { method constructor (line 10) | constructor(options = {}) { method init (line 26) | init() { method getDefaultShortcuts (line 34) | getDefaultShortcuts() { method registerDefaultShortcuts (line 178) | registerDefaultShortcuts() { method registerShortcut (line 184) | registerShortcut(shortcut) { method bindGlobalShortcuts (line 192) | bindGlobalShortcuts() { method checkShortcuts (line 239) | checkShortcuts(keySequence, event) { method matchesShortcut (line 249) | matchesShortcut(keySequence, shortcut, event) { method createCommandPalette (line 263) | createCommandPalette() { method bindCommandPaletteEvents (line 300) | bindCommandPaletteEvents() { method openCommandPalette (line 349) | openCommandPalette() { method closeCommandPalette (line 358) | closeCommandPalette() { method filterCommands (line 364) | filterCommands(query) { method renderCommandResults (line 381) | renderCommandResults() { method renderCommandItem (line 419) | renderCommandItem(command) { method formatShortcut (line 435) | formatShortcut(command) { method bindCommandItemEvents (line 449) | bindCommandItemEvents() { method setActivePaletteItem (line 468) | setActivePaletteItem(items) { method focusSearch (line 479) | focusSearch() { method toggleTimer (line 490) | toggleTimer() { method toggleTheme (line 501) | toggleTheme() { method showHelp (line 508) | showHelp() { method createHelpModal (line 513) | createHelpModal() { method renderShortcutsHelp (line 542) | renderShortcutsHelp() { method isTyping (line 574) | isTyping(event) { method detectKeyboardNavigation (line 581) | detectKeyboardNavigation() { method showHintIfFirstVisit (line 594) | showHintIfFirstVisit() { method showShortcutHint (line 604) | showShortcutHint() { FILE: app/static/kiosk-barcode.js function clearItemContent (line 17) | function clearItemContent() { function lookupBarcode (line 189) | async function lookupBarcode(barcode, retryCount = 0) { function displayItem (line 287) | function displayItem(item, stockLevels) { function showErrorWithRetry (line 688) | function showErrorWithRetry(message, retryCallback) { function showError (line 723) | function showError(message) { function showSuccess (line 755) | function showSuccess(message) { function toggleCameraScanner (line 781) | async function toggleCameraScanner() { function stopCameraScanner (line 836) | function stopCameraScanner() { function startCameraScanning (line 864) | function startCameraScanning(videoElement) { FILE: app/static/kiosk-mode.js function toggleFullscreen (line 115) | function toggleFullscreen() { function initAutoLogout (line 142) | async function initAutoLogout() { function initKeyboardShortcuts (line 213) | function initKeyboardShortcuts() { FILE: app/static/kiosk-timer.js constant TIMER_UPDATE_INTERVAL (line 7) | const TIMER_UPDATE_INTERVAL = 1000; constant TIMER_API_INTERVAL (line 8) | const TIMER_API_INTERVAL = 5000; function updateTimerDisplay (line 50) | async function updateTimerDisplay(useCache = false) { function startTimer (line 291) | async function startTimer() { function stopTimer (line 369) | async function stopTimer() { function showError (line 444) | function showError(message) { function showSuccess (line 457) | function showSuccess(message) { FILE: app/static/mentions.js class MentionsInput (line 6) | class MentionsInput { method constructor (line 7) | constructor(textarea, options = {}) { method init (line 26) | init() { method loadUsers (line 45) | async loadUsers() { method handleInput (line 55) | handleInput(e) { method showDropdown (line 106) | showDropdown(users) { method hideDropdown (line 141) | hideDropdown() { method handleKeydown (line 147) | handleKeydown(e) { method updateSelection (line 186) | updateSelection(items) { method insertMention (line 197) | insertMention(username, userId) { method getCaretPosition (line 223) | getCaretPosition() { method highlightMatch (line 233) | highlightMatch(text, query) { FILE: app/static/mobile.js method isMobile (line 9) | isMobile() { method isSmallMobile (line 12) | isSmallMobile() { method isTouchDevice (line 15) | isTouchDevice() { method isIOS (line 18) | isIOS() { class MobileSidebar (line 23) | class MobileSidebar { method constructor (line 24) | constructor() { method init (line 32) | init() { method toggle (line 50) | toggle() { method close (line 55) | close() { class MobileForms (line 62) | class MobileForms { method constructor (line 63) | constructor() { method init (line 67) | init() { method initFileInputs (line 92) | initFileInputs() { method initCharCounters (line 127) | initCharCounters() { method initSubmitButtons (line 138) | initSubmitButtons() { class MobileViewport (line 158) | class MobileViewport { method constructor (line 159) | constructor() { method init (line 163) | init() { method handleViewportChange (line 175) | handleViewportChange() { class MobilePerformance (line 181) | class MobilePerformance { method constructor (line 182) | constructor() { method init (line 186) | init() { class BottomNavMoreDrawer (line 210) | class BottomNavMoreDrawer { method constructor (line 211) | constructor() { method isOpen (line 221) | isOpen() { method open (line 225) | open() { method close (line 236) | close() { method _onDocKeydown (line 275) | _onDocKeydown(e) { method init (line 281) | init() { class MobileOffline (line 298) | class MobileOffline { method constructor (line 299) | constructor() { method init (line 304) | init() { FILE: app/static/offline-sync.js class OfflineSyncManager (line 6) | class OfflineSyncManager { method constructor (line 7) | constructor() { method init (line 16) | async init() { method openDB (line 28) | openDB() { method setupOnlineListener (line 83) | setupOnlineListener() { method setupServiceWorkerSync (line 93) | setupServiceWorkerSync() { method checkPendingSync (line 104) | async checkPendingSync() { method getPendingSyncCount (line 121) | async getPendingSyncCount() { method formatDateToISO (line 192) | formatDateToISO(dateValue) { method saveTimeEntryOffline (line 236) | async saveTimeEntryOffline(entryData) { method getOfflineTimeEntries (line 287) | async getOfflineTimeEntries() { method syncAll (line 301) | async syncAll() { method syncTimeEntries (line 324) | async syncTimeEntries() { method syncTasks (line 372) | async syncTasks() { method syncProjects (line 431) | async syncProjects() { method getUnsyncedEntries (line 491) | async getUnsyncedEntries(storeName) { method markAsSynced (line 546) | async markAsSynced(storeName, localId, serverId) { method processSyncQueue (line 596) | async processSyncQueue() { method updateUI (line 670) | updateUI() { method saveTaskOffline (line 716) | async saveTaskOffline(taskData) { method getOfflineTasks (line 764) | async getOfflineTasks() { method saveProjectOffline (line 778) | async saveProjectOffline(projectData) { method getOfflineProjects (line 821) | async getOfflineProjects() { method createTimeEntryOffline (line 835) | async createTimeEntryOffline(data) { method createTaskOffline (line 867) | async createTaskOffline(data) { method createProjectOffline (line 892) | async createProjectOffline(data) { method getPendingCount (line 917) | async getPendingCount() { method forceSync (line 921) | async forceSync() { FILE: app/static/onboarding-enhanced.js class EnhancedOnboardingManager (line 6) | class EnhancedOnboardingManager { method constructor (line 7) | constructor() { method init (line 19) | init() { method initTooltips (line 38) | initTooltips() { method addTooltipStyles (line 60) | addTooltipStyles() { method attachTooltips (line 180) | attachTooltips() { method initContextualHelp (line 223) | initContextualHelp() { method addHelpButton (line 254) | addHelpButton(element, helpId) { method showContextualHelp (line 276) | showContextualHelp(helpId) { method getHelpContent (line 284) | getHelpContent(helpId) { method showHelpModal (line 336) | showHelpModal(title, content) { method initFeatureDiscovery (line 364) | initFeatureDiscovery() { method addFeatureBadge (line 425) | addFeatureBadge(element, feature) { method showFeatureTooltip (line 447) | showFeatureTooltip(badge, feature) { method removeFeatureBadge (line 475) | removeFeatureBadge(element) { method markFeatureDiscovered (line 482) | markFeatureDiscovered(featureName) { method checkFirstTimeUser (line 495) | checkFirstTimeUser() { method startTour (line 517) | startTour() { method getEnhancedTourSteps (line 525) | getEnhancedTourSteps() { method isCompleted (line 626) | isCompleted() { method reset (line 630) | reset() { FILE: app/static/onboarding.js class OnboardingManager (line 6) | class OnboardingManager { method constructor (line 7) | constructor() { method init (line 18) | init(steps) { method createOverlay (line 51) | createOverlay() { method createTooltip (line 336) | createTooltip() { method showStep (line 345) | showStep(index) { method displayStep (line 413) | displayStep(target, step, index) { method highlightElement (line 454) | highlightElement(element) { method positionTooltip (line 537) | positionTooltip(element, step) { method updateTooltip (line 644) | updateTooltip(step, index) { method next (line 699) | next() { method previous (line 706) | previous() { method skip (line 713) | async skip() { method complete (line 773) | complete() { method isCompleted (line 803) | isCompleted() { method reset (line 810) | reset() { function restartTour (line 924) | function restartTour() { FILE: app/static/pwa-enhancements.js class PWAEnhancements (line 5) | class PWAEnhancements { method constructor (line 6) | constructor() { method init (line 13) | async init() { method setupOfflineDetection (line 50) | setupOfflineDetection() { method onOnline (line 68) | onOnline() { method onOffline (line 84) | onOffline() { method showOfflineIndicator (line 92) | showOfflineIndicator() { method hideOfflineIndicator (line 104) | hideOfflineIndicator() { method setupInstallPrompt (line 111) | setupInstallPrompt() { method showInstallButton (line 130) | showInstallButton(deferredPrompt) { method hideInstallButton (line 151) | hideInstallButton() { method setupPushNotifications (line 158) | async setupPushNotifications() { method requestNotificationPermission (line 202) | async requestNotificationPermission() { method urlBase64ToUint8Array (line 243) | urlBase64ToUint8Array(base64String) { method getVapidPublicKey (line 258) | getVapidPublicKey() { method sendSubscriptionToServer (line 263) | async sendSubscriptionToServer(subscription) { method setupIndexedDB (line 281) | async setupIndexedDB() { method storeTimeEntryOffline (line 318) | async storeTimeEntryOffline(entryData) { method getDB (line 332) | async getDB() { method syncPendingData (line 340) | async syncPendingData() { method syncTimeEntry (line 359) | async syncTimeEntry(entry) { method storePageState (line 378) | storePageState() { method showUpdateNotification (line 389) | showUpdateNotification() { method showNotification (line 427) | showNotification(title, body) { FILE: app/static/quick-actions.js class QuickActionsMenu (line 5) | class QuickActionsMenu { method constructor (line 6) | constructor() { method init (line 16) | init() { method defineActions (line 23) | defineActions() { method createButton (line 76) | createButton() { method createMenu (line 109) | createMenu() { method attachButtonListener (line 166) | attachButtonListener() { method attachMenuActionListeners (line 175) | attachMenuActionListeners() { method attachGlobalListeners (line 189) | attachGlobalListeners() { method toggle (line 208) | toggle() { method open (line 216) | open() { method close (line 224) | close() { method startTimer (line 232) | startTimer() { method addAction (line 243) | addAction(action) { method removeAction (line 248) | removeAction(actionId) { method recreateMenu (line 253) | recreateMenu() { FILE: app/static/reports-enhanced.js constant DATE_PRESETS (line 7) | const DATE_PRESETS = { function formatDate (line 119) | function formatDate(date) { function formatHours (line 126) | function formatHours(hours) { function formatCurrency (line 130) | function formatCurrency(amount, currency = '$') { function initDateRangePresets (line 135) | function initDateRangePresets() { function applyDatePreset (line 156) | function applyDatePreset(presetKey) { class ReportCharts (line 173) | class ReportCharts { method createProjectComparisonChart (line 183) | static createProjectComparisonChart(canvasId, data) { method createUserDistributionChart (line 240) | static createUserDistributionChart(canvasId, data) { method createTimelineChart (line 286) | static createTimelineChart(canvasId, data) { method createTaskCompletionChart (line 335) | static createTaskCompletionChart(canvasId, data) { function initTableSorting (line 385) | function initTableSorting() { function sortTable (line 402) | function sortTable(table, columnIndex, header) { function initTableSearch (line 446) | function initTableSearch() { function filterTable (line 460) | function filterTable(table, searchTerm) { function exportTableToCSV (line 472) | function exportTableToCSV(tableId, filename) { function downloadFile (line 494) | function downloadFile(content, filename, mimeType) { function printReport (line 507) | function printReport() { function animateStatCards (line 512) | function animateStatCards() { class TablePagination (line 530) | class TablePagination { method constructor (line 531) | constructor(tableId, itemsPerPage = 25) { method init (line 542) | init() { method createPaginationControls (line 551) | createPaginationControls() { method showPage (line 592) | showPage(page) { method updateControls (line 604) | updateControls() { FILE: app/static/smart-notifications.js class SmartNotificationManager (line 6) | class SmartNotificationManager { method constructor (line 7) | constructor() { method init (line 18) | init() { method checkPermissionStatus (line 30) | checkPermissionStatus() { method requestPermission (line 39) | async requestPermission() { method show (line 65) | show(options) { method showBrowserNotification (line 141) | showBrowserNotification(notification) { method schedule (line 177) | schedule(options, delay) { method recurring (line 186) | recurring(options, interval) { method checkIdleTime (line 200) | checkIdleTime() { method checkDeadlines (line 249) | checkDeadlines() { method startServerSmartNotificationsPolling (line 361) | startServerSmartNotificationsPolling() { method pollServerSmartNotifications (line 370) | async pollServerSmartNotifications() { method budgetAlert (line 457) | budgetAlert(project, percentage) { method achievement (line 480) | achievement(achievement) { method teamActivity (line 493) | teamActivity(activity) { method getAll (line 507) | getAll() { method getUnread (line 511) | getUnread() { method markAsRead (line 515) | markAsRead(id) { method markAllAsRead (line 524) | markAllAsRead() { method delete (line 530) | delete(id) { method deleteAll (line 536) | deleteAll() { method isEnabled (line 546) | isEnabled(type) { method shouldShow (line 550) | shouldShow(type, priority) { method updatePreferences (line 561) | updatePreferences(prefs) { method loadPreferences (line 566) | loadPreferences() { method saveNotifications (line 592) | saveNotifications() { method loadNotifications (line 598) | loadNotifications() { method generateId (line 611) | generateId() { method playSound (line 615) | playSound(type) { method emit (line 628) | emit(event, data) { method setupServiceWorkerMessaging (line 636) | setupServiceWorkerMessaging() { method startBackgroundTasks (line 646) | startBackgroundTasks() { class NotificationCenter (line 673) | class NotificationCenter { method constructor (line 674) | constructor(manager) { method createUI (line 680) | createUI() { method attachListeners (line 698) | attachListeners() { method updateBadge (line 710) | updateBadge() { method toggle (line 720) | toggle() { method createPanel (line 726) | createPanel() { method renderNotifications (line 774) | renderNotifications() { method getTypeColor (line 803) | getTypeColor(type) { method getTypeIcon (line 813) | getTypeIcon(type) { method formatTime (line 823) | formatTime(timestamp) { FILE: app/static/support-ui.js function getCsrfToken (line 8) | function getCsrfToken() { function parseSupportConfig (line 13) | function parseSupportConfig() { function postTrack (line 23) | function postTrack(cfg, event, extra) { function applyOfflineState (line 37) | function applyOfflineState(cfg) { function wireTierLinks (line 58) | function wireTierLinks(cfg) { function syncStatsFromConfig (line 77) | function syncStatsFromConfig(cfg) { function openSupportModal (line 91) | function openSupportModal() { function closeSupportModal (line 102) | function closeSupportModal() { function showSoftToast (line 112) | function showSoftToast(cfg, message, variant, source) { function maybeLongSessionPrompt (line 125) | function maybeLongSessionPrompt(cfg) { function layoutPromptFromConfig (line 172) | function layoutPromptFromConfig(cfg) { function dashboardPrompt (line 177) | function dashboardPrompt() { function headerPulse (line 184) | function headerPulse(btn) { function wireModalDom (line 196) | function wireModalDom(cfg) { FILE: app/static/time-entries-inline-edit.js function getNotesRaw (line 9) | function getNotesRaw(td) { function setNotesRaw (line 19) | function setNotesRaw(td, text) { function stripTruncate (line 23) | function stripTruncate(s, maxLen) { function parseDurationToSeconds (line 32) | function parseDurationToSeconds(str) { function parseLocalParts (line 47) | function parseLocalParts(isoLocal) { function formatLocalDatetime (line 60) | function formatLocalDatetime(d) { function isoToLocalDatetimeLocal (line 77) | function isoToLocalDatetimeLocal(iso) { function flashOk (line 84) | function flashOk(cell) { function toastError (line 103) | function toastError(msg) { function restoreNotesButton (line 111) | function restoreNotesButton(td, displayText, notesFull) { function restoreDurationButton (line 122) | function restoreDurationButton(td, formatted) { function finishNotesEdit (line 134) | function finishNotesEdit(td, textarea, entryId, originalNotes, originalD... function finishDurationEdit (line 171) | function finishDurationEdit(td, input, entryId, originalFormatted, meta) { function openNotesEditor (line 226) | function openNotesEditor(btn) { function openDurationEditor (line 267) | function openDurationEditor(btn) { function onClick (line 311) | function onClick(e) { FILE: app/static/toast-notifications.js class ToastNotificationManager (line 6) | class ToastNotificationManager { method constructor (line 7) | constructor() { method init (line 15) | init() { method applyResponsiveContainerStyles (line 46) | applyResponsiveContainerStyles() { method show (line 79) | show(options) { method createToast (line 152) | createToast(config, toastId) { method dismiss (line 382) | dismiss(toastId, reason) { method dismissAll (line 412) | dismissAll() { method findToastId (line 418) | findToastId(element) { method enforceLimit (line 427) | enforceLimit() { method getIcon (line 434) | getIcon(type) { method getDefaultTitle (line 444) | getDefaultTitle(type) { method success (line 463) | success(message, title, duration) { method error (line 467) | error(message, title, duration) { method warning (line 471) | warning(message, title, duration) { method info (line 475) | info(message, title, duration) { FILE: app/static/typing-utils.js function isTyping (line 34) | function isTyping(ev) { FILE: app/static/ui-enhancements.js function init (line 19) | function init() { function initContextMenus (line 31) | function initContextMenus() { function showContextMenu (line 68) | function showContextMenu(e, element) { function hideContextMenu (line 132) | function hideContextMenu() { function executeContextAction (line 141) | function executeContextAction(action, element) { function submitForm (line 187) | function submitForm(url, method) { function createBulkActionsBar (line 209) | function createBulkActionsBar() { function initBulkSelection (line 240) | function initBulkSelection() { function updateBulkSelection (line 292) | function updateBulkSelection(checkbox) { function updateBulkActionsBar (line 309) | function updateBulkActionsBar() { function clearBulkSelection (line 353) | function clearBulkSelection() { function isTyping (line 365) | function isTyping(e) { function initKeyboardShortcutsIndicator (line 372) | function initKeyboardShortcutsIndicator() { function showKeyboardShortcutsHint (line 382) | function showKeyboardShortcutsHint() { function openKeyboardShortcutsModal (line 391) | function openKeyboardShortcutsModal() { function initButtonPressAnimations (line 403) | function initButtonPressAnimations() { function initSuccessCheckmarks (line 420) | function initSuccessCheckmarks() { function showSuccessCheckmark (line 438) | function showSuccessCheckmark(element) { function initLoadingSpinners (line 458) | function initLoadingSpinners() { function addButtonLoading (line 485) | function addButtonLoading(button) { function removeButtonLoading (line 498) | function removeButtonLoading(button) { function handleAsyncFormSubmission (line 512) | function handleAsyncFormSubmission(form) { FILE: app/telemetry/otel_setup.py function _env_bool (line 42) | def _env_bool(name: str, default: bool = True) -> bool: function _deployment_environment (line 49) | def _deployment_environment() -> str: function _app_version (line 53) | def _app_version() -> str: function _metric_attrs (line 62) | def _metric_attrs() -> Dict[str, str]: function resolve_otlp_connection (line 66) | def resolve_otlp_connection() -> Optional[Tuple[str, Dict[str, str]]]: function install_id_attr (line 91) | def install_id_attr() -> Dict[str, str]: function trace_user_attrs (line 103) | def trace_user_attrs(user_id: Any) -> Dict[str, str]: function _flatten_attrs (line 115) | def _flatten_attrs(attrs: Dict[str, Any]) -> Dict[str, Any]: function business_span (line 128) | def business_span(name: str, *, user_id: Any = None, **attributes: Any) ... function get_trace_context_for_logs (line 139) | def get_trace_context_for_logs() -> Dict[str, Optional[str]]: function is_otel_tracing_active (line 157) | def is_otel_tracing_active() -> bool: function is_otel_metrics_active (line 161) | def is_otel_metrics_active() -> bool: function record_http_server_metrics (line 165) | def record_http_server_metrics(method: str, route: str, status_code: int... function record_invoice_created (line 185) | def record_invoice_created() -> None: function record_invoice_duration_seconds (line 194) | def record_invoice_duration_seconds(seconds: float, operation: str) -> N... function record_report_generated (line 208) | def record_report_generated() -> None: function record_export_duration_seconds (line 217) | def record_export_duration_seconds(seconds: float, export_kind: str) -> ... function record_background_job_outcome (line 227) | def record_background_job_outcome(job_id: str, success: bool) -> None: function record_webhook_delivery (line 240) | def record_webhook_delivery(event_type: str, success: bool) -> None: function inject_traceparent_headers (line 254) | def inject_traceparent_headers(response: Any) -> Any: function _active_timers_callback (line 271) | def _active_timers_callback(options: Any) -> Any: function _shutdown_providers (line 288) | def _shutdown_providers() -> None: function get_test_span_exporter (line 305) | def get_test_span_exporter() -> Any: function reset_for_testing (line 310) | def reset_for_testing() -> None: function init_opentelemetry (line 349) | def init_opentelemetry(app: Any) -> bool: FILE: app/telemetry/service.py function is_detailed_analytics_enabled (line 40) | def is_detailed_analytics_enabled() -> bool: function _build_base_telemetry_payload (line 46) | def _build_base_telemetry_payload(event_kind: str) -> Dict[str, Any]: function _otlp_enabled (line 76) | def _otlp_enabled() -> bool: function _build_otlp_auth_header (line 88) | def _build_otlp_auth_header(token: str) -> str: function _telemetry_debug_logging_enabled (line 105) | def _telemetry_debug_logging_enabled() -> bool: function _remove_pii (line 109) | def _remove_pii(properties: Dict[str, Any]) -> Dict[str, Any]: function event_category_for_event_name (line 114) | def event_category_for_event_name(event_name: str) -> str: function _otlp_correlation_attributes (line 123) | def _otlp_correlation_attributes(event_name: str) -> List[Dict[str, Any]]: function _to_otlp_any_value (line 144) | def _to_otlp_any_value(value: Any) -> Dict[str, Any]: function _build_otlp_logs_payload (line 154) | def _build_otlp_logs_payload( function _send_otlp_event (line 198) | def _send_otlp_event(event_name: str, identity: str, properties: Dict[st... function send_base_telemetry (line 267) | def send_base_telemetry(payload: Dict[str, Any]) -> bool: function send_base_first_seen (line 276) | def send_base_first_seen() -> bool: function send_base_heartbeat (line 291) | def send_base_heartbeat() -> bool: function identify_user (line 297) | def identify_user(user_id: Any, properties: Optional[Dict[str, Any]] = N... function send_analytics_event (line 303) | def send_analytics_event(user_id: Any, event_name: str, properties: Opti... FILE: app/utils/api_auth.py function extract_token_from_request (line 12) | def extract_token_from_request(): function authenticate_token (line 40) | def authenticate_token(token_string, record_usage: bool = True): function require_api_token (line 113) | def require_api_token(required_scope=None): function optional_api_token (line 224) | def optional_api_token(): FILE: app/utils/api_deprecation.py function apply_deprecated_headers_to_result (line 13) | def apply_deprecated_headers_to_result( function deprecated_session_api (line 38) | def deprecated_session_api(successor_path: Optional[str]) -> Callable[[C... FILE: app/utils/api_idempotency.py function _hash_key (line 24) | def _hash_key(raw: str) -> str: function normalize_idempotency_key (line 28) | def normalize_idempotency_key(header_value: Optional[str]) -> Optional[s... function lookup_idempotent_response (line 37) | def lookup_idempotent_response(api_token_id: int, scope: str, key: str) ... function store_idempotent_response (line 56) | def store_idempotent_response(api_token_id: int, scope: str, key: str, s... function replay_response (line 70) | def replay_response(status_code: int, body_json: str) -> Response: FILE: app/utils/api_rate_limit.py function _limits_from_config (line 24) | def _limits_from_config() -> Tuple[int, int]: function _redis_client (line 33) | def _redis_client(): function _cleanup_local (line 60) | def _cleanup_local(now: float) -> None: function consume_api_token_rate_limit (line 69) | def consume_api_token_rate_limit(token_id: int) -> Tuple[bool, Dict[str,... FILE: app/utils/api_responses.py function success_response (line 12) | def success_response( function error_response (line 43) | def error_response( function validation_error_response (line 80) | def validation_error_response(errors: Dict[str, List[str]], message: str... function not_found_response (line 94) | def not_found_response(resource: str = "Resource", resource_id: Optional... function unauthorized_response (line 112) | def unauthorized_response(message: str = "Authentication required") -> R... function forbidden_response (line 125) | def forbidden_response(message: str = "Insufficient permissions") -> Res... function paginated_response (line 138) | def paginated_response( function handle_validation_error (line 170) | def handle_validation_error(error: ValidationError) -> Response: function created_response (line 189) | def created_response(data: Any, message: Optional[str] = None, location:... function no_content_response (line 214) | def no_content_response() -> Response: FILE: app/utils/audit.py function get_audit_log_model (line 23) | def get_audit_log_model(): function get_current_user_id (line 74) | def get_current_user_id(): function get_request_info (line 84) | def get_request_info(): function get_entity_name (line 96) | def get_entity_name(instance): function get_entity_type (line 109) | def get_entity_type(instance): function should_track_model (line 114) | def should_track_model(instance): function should_track_field (line 119) | def should_track_field(field_name): function serialize_value (line 124) | def serialize_value(value): function capture_timeentry_metadata (line 158) | def capture_timeentry_metadata(entry): function capture_timeentry_state (line 181) | def capture_timeentry_state(entry): function receive_before_flush (line 220) | def receive_before_flush(session, flush_context, instances=None): function receive_after_flush (line 371) | def receive_after_flush(session, flush_context): function check_audit_table_exists (line 423) | def check_audit_table_exists(force_check=False): function reset_audit_table_cache (line 457) | def reset_audit_table_cache(): function track_model_changes (line 463) | def track_model_changes(model_class): FILE: app/utils/auth_method.py function normalize_auth_method (line 8) | def normalize_auth_method(raw: str | None) -> str: function auth_includes_local (line 14) | def auth_includes_local(auth_method: str | None) -> bool: function auth_includes_oidc (line 19) | def auth_includes_oidc(auth_method: str | None) -> bool: function auth_includes_ldap (line 24) | def auth_includes_ldap(auth_method: str | None) -> bool: function requires_password_form (line 29) | def requires_password_form(auth_method: str | None) -> bool: function forgot_password_available (line 35) | def forgot_password_available(auth_method: str | None) -> bool: function ldap_enabled_from_auth_method (line 40) | def ldap_enabled_from_auth_method(auth_method: str | None) -> bool: FILE: app/utils/backup.py function get_backup_root_dir (line 15) | def get_backup_root_dir(app) -> str: function _get_backup_root_dir (line 56) | def _get_backup_root_dir(app): function _now_timestamp (line 61) | def _now_timestamp(): function _detect_db_type_and_path (line 68) | def _detect_db_type_and_path(app): function _get_alembic_revision (line 84) | def _get_alembic_revision(db_session): function _write_manifest (line 97) | def _write_manifest(zf, manifest: dict): function _add_directory_to_zip (line 102) | def _add_directory_to_zip(zf, source_dir: str, arc_prefix: str): function create_backup (line 112) | def create_backup(app) -> str: function restore_backup (line 215) | def restore_backup(app, archive_path: str, progress_callback=None) -> tu... FILE: app/utils/budget_forecasting.py function calculate_burn_rate (line 20) | def calculate_burn_rate(project_id: int, days: int = 30) -> Dict: function estimate_completion_date (line 82) | def estimate_completion_date(project_id: int, analysis_days: int = 30) -... function analyze_resource_allocation (line 153) | def analyze_resource_allocation(project_id: int, days: int = 30) -> Dict: function analyze_cost_trends (line 238) | def analyze_cost_trends(project_id: int, days: int = 90, granularity: st... function get_budget_status (line 339) | def get_budget_status(project_id: int) -> Dict: function _get_period_key (line 388) | def _get_period_key(date_obj: date, granularity: str) -> str: function _calculate_confidence (line 402) | def _calculate_confidence(project_id: int, days: int) -> str: function check_budget_alerts (line 459) | def check_budget_alerts(project_id: int) -> List[Dict]: FILE: app/utils/cache.py class InMemoryCache (line 25) | class InMemoryCache: method __init__ (line 28) | def __init__(self, default_ttl: int = 3600): method get (line 32) | def get(self, key: str) -> Optional[Any]: method set (line 44) | def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None: method delete (line 50) | def delete(self, key: str) -> None: method clear (line 55) | def clear(self) -> None: method exists (line 59) | def exists(self, key: str) -> bool: class RedisCache (line 72) | class RedisCache: method __init__ (line 75) | def __init__(self, redis_url: str, default_ttl: int = 3600): method get (line 108) | def get(self, key: str) -> Optional[Any]: method set (line 123) | def set(self, key: str, value: Any, ttl: Optional[int] = None) -> None: method delete (line 137) | def delete(self, key: str) -> None: method clear (line 149) | def clear(self) -> None: method exists (line 161) | def exists(self, key: str) -> bool: function get_cache (line 178) | def get_cache(): function cache_key (line 208) | def cache_key(*args, **kwargs) -> str: function cached (line 215) | def cached(ttl: int = 3600, key_prefix: str = ""): function invalidate_cache (line 245) | def invalidate_cache(pattern: str) -> None: function invalidate_dashboard_for_user (line 256) | def invalidate_dashboard_for_user(user_id: int) -> None: function invalidate_pattern (line 266) | def invalidate_pattern(pattern: str) -> None: FILE: app/utils/cache_redis.py function get_redis_client (line 30) | def get_redis_client(): function cache_key (line 52) | def cache_key(prefix: str, *args, **kwargs) -> str: function get_cache (line 75) | def get_cache(key: str, default: Any = None) -> Optional[Any]: function set_cache (line 105) | def set_cache(key: str, value: Any, ttl: int = 3600) -> bool: function delete_cache (line 133) | def delete_cache(key: str) -> bool: function cache_result (line 161) | def cache_result(prefix: str, ttl: int = 3600, key_func: Optional[Callab... function invalidate_cache_pattern (line 203) | def invalidate_cache_pattern(pattern: str): class CacheKeys (line 217) | class CacheKeys: FILE: app/utils/cii_invoice.py class CIIParty (line 30) | class CIIParty: function _money (line 43) | def _money(v: Any) -> str: function _qty (line 51) | def _qty(v: Any) -> str: function _date_102 (line 59) | def _date_102(d: Any) -> str: function _sub (line 66) | def _sub(parent: ET.Element, tag: str) -> ET.Element: function _text_el (line 70) | def _text_el(parent: ET.Element, tag: str, text: Optional[str]) -> Optio... function _money_el (line 81) | def _money_el(parent: ET.Element, tag: str, value: Any, currency: str) -... function _date_el (line 89) | def _date_el(parent: ET.Element, d: Any) -> None: function _build_party (line 97) | def _build_party(parent: ET.Element, tag: str, party: CIIParty) -> None: function build_cii_invoice_xml (line 128) | def build_cii_invoice_xml( FILE: app/utils/cli.py function register_cli_commands (line 14) | def register_cli_commands(app): FILE: app/utils/client_lock.py function get_locked_client_id (line 16) | def get_locked_client_id() -> Optional[int]: function get_locked_client (line 44) | def get_locked_client(): function enforce_locked_client_id (line 82) | def enforce_locked_client_id(submitted_client_id: Optional[int]) -> Opti... FILE: app/utils/config_manager.py class ConfigManager (line 13) | class ConfigManager: method get_setting (line 17) | def get_setting(key: str, default: Any = None) -> Any: method set_setting (line 85) | def set_setting(key: str, value: Any) -> bool: method validate_config (line 110) | def validate_config() -> Dict[str, Any]: FILE: app/utils/context_processors.py function register_context_processors (line 18) | def register_context_processors(app): FILE: app/utils/data_export.py function export_user_data_gdpr (line 42) | def export_user_data_gdpr(user_id, export_format="json"): function export_filtered_data (line 123) | def export_filtered_data(user_id, filters, export_format="json"): function create_backup (line 212) | def create_backup(user_id): function _export_user_profile (line 272) | def _export_user_profile(user): function _export_time_entries (line 291) | def _export_time_entries(user): function _export_user_projects (line 297) | def _export_user_projects(user): function _export_user_tasks (line 305) | def _export_user_tasks(user): function _export_user_expenses (line 311) | def _export_user_expenses(user): function _export_user_mileage (line 317) | def _export_user_mileage(user): function _export_user_per_diems (line 323) | def _export_user_per_diems(user): function _export_user_invoices (line 329) | def _export_user_invoices(user): function _export_user_comments (line 337) | def _export_user_comments(user): function _export_user_focus_sessions (line 343) | def _export_user_focus_sessions(user): function _export_user_saved_filters (line 349) | def _export_user_saved_filters(user): function _export_user_project_costs (line 355) | def _export_user_project_costs(user): function _export_user_weekly_goals (line 361) | def _export_user_weekly_goals(user): function _export_user_activities (line 367) | def _export_user_activities(user): function _export_user_calendar_events (line 373) | def _export_user_calendar_events(user): function _time_entry_to_dict (line 382) | def _time_entry_to_dict(entry): function _project_to_dict (line 405) | def _project_to_dict(project): function _client_to_dict (line 424) | def _client_to_dict(client): function _task_to_dict (line 436) | def _task_to_dict(task): function _expense_to_dict (line 453) | def _expense_to_dict(expense): function _expense_category_to_dict (line 469) | def _expense_category_to_dict(category): function _mileage_to_dict (line 478) | def _mileage_to_dict(mileage): function _per_diem_to_dict (line 492) | def _per_diem_to_dict(per_diem): function _invoice_to_dict (line 505) | def _invoice_to_dict(invoice): function _comment_to_dict (line 520) | def _comment_to_dict(comment): function _focus_session_to_dict (line 530) | def _focus_session_to_dict(session): function _recurring_block_to_dict (line 542) | def _recurring_block_to_dict(block): function _saved_filter_to_dict (line 553) | def _saved_filter_to_dict(filter_obj): function _project_cost_to_dict (line 564) | def _project_cost_to_dict(cost): function _weekly_goal_to_dict (line 578) | def _weekly_goal_to_dict(goal): function _activity_to_dict (line 589) | def _activity_to_dict(activity): function _calendar_event_to_dict (line 600) | def _calendar_event_to_dict(event): function _list_to_csv (line 613) | def _list_to_csv(data_list): FILE: app/utils/data_import.py class ImportError (line 21) | class ImportError(Exception): function import_csv_time_entries (line 27) | def import_csv_time_entries(user_id, csv_content, import_record): function import_from_toggl (line 165) | def import_from_toggl(user_id, api_token, workspace_id, start_date, end_... function import_from_harvest (line 310) | def import_from_harvest(user_id, account_id, api_token, start_date, end_... function restore_from_backup (line 490) | def restore_from_backup(user_id, backup_file_path): function _parse_datetime (line 526) | def _parse_datetime(datetime_str): function import_csv_clients (line 571) | def import_csv_clients(user_id, csv_content, import_record, skip_duplica... FILE: app/utils/datetime_utils.py function parse_date (line 13) | def parse_date(date_str: str, format: Optional[str] = None) -> Optional[... function parse_datetime (line 46) | def parse_datetime(datetime_str: str, format: Optional[str] = None) -> O... function format_date (line 79) | def format_date(d: date, format: str = "%Y-%m-%d") -> str: function format_datetime (line 95) | def format_datetime(dt: datetime, format: str = "%Y-%m-%d %H:%M:%S") -> ... function get_date_range (line 111) | def get_date_range( function get_previous_period (line 157) | def get_previous_period(period: str = "month", reference_date: Optional[... function calculate_duration (line 200) | def calculate_duration(start: datetime, end: datetime) -> timedelta: function format_duration (line 217) | def format_duration(seconds: float, format: str = "hours") -> str: function is_business_day (line 258) | def is_business_day(d: date) -> bool: function add_business_days (line 271) | def add_business_days(start_date: date, days: int) -> date: function get_week_start_end (line 293) | def get_week_start_end(d: date) -> Tuple[date, date]: function get_month_start_end (line 308) | def get_month_start_end(d: date) -> Tuple[date, date]: FILE: app/utils/db.py function safe_query (line 11) | def safe_query(query_func: Callable[[], T], default: Optional[T] = None)... function safe_commit (line 65) | def safe_commit(action: Optional[str] = None, context: Optional[Dict[str... FILE: app/utils/decorators.py function admin_required (line 10) | def admin_required(f): FILE: app/utils/donate_hide_code.py function compute_donate_hide_code (line 20) | def compute_donate_hide_code(secret: str, system_id: str) -> str: function verify_ed25519_signature (line 37) | def verify_ed25519_signature(signature_b64: str, system_id: str, public_... FILE: app/utils/email.py function init_mail (line 16) | def init_mail(app): function reload_mail_config (line 62) | def reload_mail_config(app): function send_async_email (line 91) | def send_async_email(app, msg): function send_client_portal_password_setup_email (line 100) | def send_client_portal_password_setup_email(client, token): function send_email (line 188) | def send_email(subject, recipients, text_body, html_body=None, sender=No... function send_overdue_invoice_notification (line 240) | def send_overdue_invoice_notification(invoice, user): function send_task_assigned_notification (line 279) | def send_task_assigned_notification(task, user, assigned_by): function send_weekly_summary (line 318) | def send_weekly_summary(user, start_date, end_date, hours_worked, projec... function send_remind_to_log_email (line 366) | def send_remind_to_log_email(user): function send_comment_notification (line 392) | def send_comment_notification(comment, task, mentioned_users): function check_email_configuration (line 428) | def check_email_configuration(): function send_test_email (line 507) | def send_test_email(recipient_email, sender_name="TimeTracker Admin"): function _build_invoice_email_payload (line 598) | def _build_invoice_email_payload(invoice, email_template_id=None, custom... function send_invoice_template_test_email (line 740) | def send_invoice_template_test_email(template_id, recipient_email, invoi... function send_invoice_email (line 806) | def send_invoice_email(invoice, recipient_email, sender_user=None, custo... function send_quote_sent_notification (line 907) | def send_quote_sent_notification(quote, user): function send_quote_accepted_notification (line 942) | def send_quote_accepted_notification(quote, user): function send_quote_rejected_notification (line 978) | def send_quote_rejected_notification(quote, user): function send_quote_expired_notification (line 1013) | def send_quote_expired_notification(quote, user): function send_quote_email (line 1050) | def send_quote_email(quote, recipient_email, sender_user=None, custom_me... FILE: app/utils/env_validation.py class EnvValidationError (line 12) | class EnvValidationError(Exception): function validate_required_env_vars (line 18) | def validate_required_env_vars(required_vars: List[str], raise_on_error:... function validate_secret_key (line 41) | def validate_secret_key() -> bool: function validate_database_url (line 63) | def validate_database_url() -> bool: function validate_production_config (line 86) | def validate_production_config() -> Tuple[bool, List[str]]: function validate_optional_env_vars (line 121) | def validate_optional_env_vars() -> Dict[str, bool]: function validate_all (line 147) | def validate_all(raise_on_error: bool = False) -> Tuple[bool, Dict[str, ... FILE: app/utils/error_handlers.py function register_error_handlers (line 17) | def register_error_handlers(app): function create_error_response (line 180) | def create_error_response( FILE: app/utils/error_handling.py function safe_log (line 13) | def safe_log( function safe_file_remove (line 35) | def safe_file_remove(path: str, logger: Optional[logging.Logger] = None)... FILE: app/utils/event_bus.py class EventBus (line 14) | class EventBus: method __init__ (line 17) | def __init__(self): method subscribe (line 20) | def subscribe(self, event_type: str, handler: Callable) -> None: method unsubscribe (line 32) | def unsubscribe(self, event_type: str, handler: Callable) -> None: method emit (line 40) | def emit(self, event_type: str, data: Dict[str, Any]) -> None: method clear (line 55) | def clear(self) -> None: function get_event_bus (line 64) | def get_event_bus() -> EventBus: function emit_event (line 69) | def emit_event(event_type: str, data: Dict[str, Any]) -> None: function subscribe_to_event (line 80) | def subscribe_to_event(event_type: str): function handle_time_entry_created (line 99) | def handle_time_entry_created(event_type: str, data: Dict[str, Any]) -> ... function handle_project_created (line 110) | def handle_project_created(event_type: str, data: Dict[str, Any]) -> None: function handle_invoice_created (line 121) | def handle_invoice_created(event_type: str, data: Dict[str, Any]) -> None: FILE: app/utils/excel_export.py function _safe_user_dt_iso (line 16) | def _safe_user_dt_iso(dt): function _safe_user_date_iso (line 30) | def _safe_user_date_iso(dt): function create_time_entries_excel (line 77) | def create_time_entries_excel(entries, filename_prefix="timetracker_expo... function create_project_report_excel (line 202) | def create_project_report_excel(projects_data, start_date, end_date): function create_invoice_excel (line 314) | def create_invoice_excel(invoice, items): function create_invoices_list_excel (line 391) | def create_invoices_list_excel(invoices): function create_payments_list_excel (line 519) | def create_payments_list_excel(payments): FILE: app/utils/file_upload.py function validate_file_upload (line 15) | def validate_file_upload( function save_uploaded_file (line 74) | def save_uploaded_file( function delete_uploaded_file (line 129) | def delete_uploaded_file(filepath: str, upload_folder: str) -> bool: function get_file_info (line 151) | def get_file_info(filepath: str, upload_folder: str) -> Optional[dict]: FILE: app/utils/i18n.py function _needs_compile (line 7) | def _needs_compile(po_path: str, mo_path: str) -> bool: function compile_po_to_mo (line 16) | def compile_po_to_mo(po_path: str, mo_path: str) -> bool: function ensure_translations_compiled (line 44) | def ensure_translations_compiled(translations_dir: str) -> None: FILE: app/utils/i18n_helpers.py function get_task_status_display (line 13) | def get_task_status_display(status): function get_task_statuses (line 25) | def get_task_statuses(): function get_task_priority_display (line 37) | def get_task_priority_display(priority): function get_task_priorities (line 43) | def get_task_priorities(): function get_project_status_display (line 49) | def get_project_status_display(status): function get_project_statuses (line 55) | def get_project_statuses(): function get_invoice_status_display (line 61) | def get_invoice_status_display(status): function get_invoice_statuses (line 73) | def get_invoice_statuses(): function get_payment_status_display (line 85) | def get_payment_status_display(status): function get_payment_statuses (line 96) | def get_payment_statuses(): function get_payment_method_display (line 107) | def get_payment_method_display(method): function get_payment_methods (line 123) | def get_payment_methods(): function get_expense_status_display (line 139) | def get_expense_status_display(status): function get_expense_statuses (line 150) | def get_expense_statuses(): function get_expense_category_display (line 161) | def get_expense_category_display(category): function get_expense_categories (line 178) | def get_expense_categories(): function get_mileage_status_display (line 195) | def get_mileage_status_display(status): function get_mileage_statuses (line 200) | def get_mileage_statuses(): function get_per_diem_status_display (line 206) | def get_per_diem_status_display(status): function get_per_diem_statuses (line 211) | def get_per_diem_statuses(): function get_job_status_display (line 217) | def get_job_status_display(status): function get_job_statuses (line 229) | def get_job_statuses(): function get_goal_status_display (line 241) | def get_goal_status_display(status): function get_goal_statuses (line 252) | def get_goal_statuses(): function get_alert_type_display (line 263) | def get_alert_type_display(alert_type): function get_alert_level_display (line 273) | def get_alert_level_display(alert_level): function get_alert_levels (line 279) | def get_alert_levels(): function get_client_status_display (line 285) | def get_client_status_display(status): function get_client_statuses (line 291) | def get_client_statuses(): function get_status_badge_class (line 297) | def get_status_badge_class(status, status_type="generic"): function get_priority_badge_class (line 334) | def get_priority_badge_class(priority): function register_i18n_filters (line 347) | def register_i18n_filters(app): FILE: app/utils/installation.py class InstallationConfig (line 17) | class InstallationConfig: method __init__ (line 23) | def __init__(self): method _ensure_config_dir (line 29) | def _ensure_config_dir(self, config_dir=None): method _load_config (line 34) | def _load_config(self) -> Dict: method _save_config (line 44) | def _save_config(self): method get_installation_salt (line 56) | def get_installation_salt(self) -> str: method get_install_id (line 70) | def get_install_id(self) -> str: method get_installation_id (line 82) | def get_installation_id(self) -> str: method is_setup_complete (line 90) | def is_setup_complete(self) -> bool: method mark_setup_complete (line 94) | def mark_setup_complete(self, telemetry_enabled: bool = False): method is_initial_data_seeded (line 101) | def is_initial_data_seeded(self) -> bool: method mark_initial_data_seeded (line 105) | def mark_initial_data_seeded(self): method get_telemetry_preference (line 111) | def get_telemetry_preference(self) -> bool: method set_telemetry_preference (line 119) | def set_telemetry_preference(self, enabled: bool): method get_all_config (line 124) | def get_all_config(self) -> Dict: method get_base_first_seen_sent_at (line 128) | def get_base_first_seen_sent_at(self) -> Optional[str]: method set_base_first_seen_sent_at (line 132) | def set_base_first_seen_sent_at(self, iso_timestamp: str) -> None: function get_installation_config (line 144) | def get_installation_config() -> InstallationConfig: FILE: app/utils/integration_http.py function integration_session (line 19) | def integration_session( function session_request (line 44) | def session_request( FILE: app/utils/integration_sync_context.py function _import_client_name (line 27) | def _import_client_name() -> str: function get_or_create_integration_import_client (line 32) | def get_or_create_integration_import_client(): function resolve_integration_actor_user_id (line 47) | def resolve_integration_actor_user_id(integration) -> Optional[int]: function require_sync_context (line 74) | def require_sync_context(integration) -> Tuple[int, int]: function find_project_by_integration_ref (line 89) | def find_project_by_integration_ref(client_id: int, source: str, ref: str): function ensure_project_integration_fields (line 100) | def ensure_project_integration_fields( function find_task_by_integration_ref (line 118) | def find_task_by_integration_ref(project_id: int, ref: str, source: Opti... function set_task_integration_ref (line 133) | def set_task_integration_ref(task, *, source: str, ref: str, extra: Opti... function sync_result_item_count (line 142) | def sync_result_item_count(sync_result: Optional[Dict[str, Any]]) -> int: FILE: app/utils/invoice_numbering.py function sanitize_invoice_prefix (line 9) | def sanitize_invoice_prefix(prefix_value): function sanitize_invoice_pattern (line 16) | def sanitize_invoice_pattern(pattern_value): function validate_invoice_pattern (line 23) | def validate_invoice_pattern(pattern_value): function resolve_invoice_pattern (line 43) | def resolve_invoice_pattern(settings): function _normalize_start_number (line 51) | def _normalize_start_number(start_number): function _build_token_values (line 59) | def _build_token_values(now, prefix): function _materialize_pattern_without_seq (line 69) | def _materialize_pattern_without_seq(pattern, token_values): function _extract_seq_width (line 76) | def _extract_seq_width(pattern): function generate_next_invoice_number (line 80) | def generate_next_invoice_number(invoice_model, invoice_query=None, sett... FILE: app/utils/invoice_pdf_postprocess.py function postprocess_invoice_pdf_bytes (line 12) | def postprocess_invoice_pdf_bytes( FILE: app/utils/invoice_validators.py function validate_ubl_wellformed (line 27) | def validate_ubl_wellformed(ubl_xml: str) -> Tuple[bool, List[str]]: function validate_ubl_peppol_bis3 (line 45) | def validate_ubl_peppol_bis3(ubl_xml: str) -> Tuple[bool, List[str]]: function validate_cii_wellformed (line 146) | def validate_cii_wellformed(cii_xml: str) -> Tuple[bool, List[str]]: function validate_cii_en16931 (line 164) | def validate_cii_en16931(cii_xml: str) -> Tuple[bool, List[str]]: function validate_pdfa_verapdf (line 299) | def validate_pdfa_verapdf( FILE: app/utils/keyboard_shortcuts_defaults.py function normalize_key (line 59) | def normalize_key(key: str) -> str: function get_defaults_by_id (line 69) | def get_defaults_by_id() -> dict[str, dict[str, Any]]: function merge_overrides (line 79) | def merge_overrides(overrides: dict[str, str] | None) -> list[dict[str, ... function validate_overrides (line 101) | def validate_overrides( FILE: app/utils/legacy_migrations.py function migrate_task_management_tables (line 7) | def migrate_task_management_tables(): function migrate_issues_table (line 45) | def migrate_issues_table(): FILE: app/utils/license_utils.py function is_license_activated (line 10) | def is_license_activated(settings) -> bool: FILE: app/utils/logger.py function get_logger (line 13) | def get_logger(name: str) -> logging.Logger: function log_request (line 26) | def log_request(logger: logging.Logger, level: int = logging.INFO, extra... function log_error (line 52) | def log_error(logger: logging.Logger, error: Exception, context: Optiona... function log_business_event (line 75) | def log_business_event(logger: logging.Logger, event: str, user_id: Opti... function log_performance (line 96) | def log_performance(logger: logging.Logger, operation: str, duration: fl... FILE: app/utils/mileage_pdf.py function _safe_str (line 53) | def _safe_str(val, fallback=""): function _make_cell_paragraph (line 60) | def _make_cell_paragraph(text): function _page_footer (line 68) | def _page_footer(canvas, doc): function _build_report_header (line 77) | def _build_report_header(start_date=None, end_date=None, filters=None): function build_mileage_pdf (line 167) | def build_mileage_pdf(entries, start_date=None, end_date=None, filters=N... FILE: app/utils/module_helpers.py function module_enabled (line 19) | def module_enabled(module_id: str, redirect_to: str = None): function has_endpoint (line 83) | def has_endpoint(endpoint: str) -> bool: function is_module_enabled (line 102) | def is_module_enabled(module_id: str) -> bool: function get_enabled_modules (line 123) | def get_enabled_modules(category=None): function has_enabled_modules (line 155) | def has_enabled_modules(category=None) -> bool: function init_module_helpers (line 168) | def init_module_helpers(app): FILE: app/utils/module_registry.py class ModuleCategory (line 12) | class ModuleCategory(Enum): class ModuleDefinition (line 28) | class ModuleDefinition: method __post_init__ (line 46) | def __post_init__(self): class ModuleRegistry (line 54) | class ModuleRegistry: method register (line 61) | def register(cls, module: ModuleDefinition): method get (line 66) | def get(cls, module_id: str) -> Optional[ModuleDefinition]: method get_all (line 71) | def get_all(cls) -> Dict[str, ModuleDefinition]: method get_by_category (line 76) | def get_by_category(cls, category: ModuleCategory) -> List[ModuleDefin... method is_enabled (line 82) | def is_enabled(cls, module_id: str, settings=None, user=None) -> bool: method get_enabled_modules (line 158) | def get_enabled_modules(cls, settings=None, user=None) -> List[ModuleD... method get_dependents (line 167) | def get_dependents(cls, module_id: str) -> List[ModuleDefinition]: method validate_module_disable (line 189) | def validate_module_disable(cls, module_id: str, disabled_list: List[s... method initialize_defaults (line 224) | def initialize_defaults(cls): FILE: app/utils/ocr.py function is_ocr_available (line 27) | def is_ocr_available(): function extract_text_from_image (line 32) | def extract_text_from_image(image_path, lang="eng"): function parse_receipt_data (line 63) | def parse_receipt_data(text): function extract_amounts (line 130) | def extract_amounts(text): function extract_date (line 177) | def extract_date(text): function extract_currency (line 250) | def extract_currency(text): function scan_receipt (line 279) | def scan_receipt(image_path, lang="eng"): function get_suggested_expense_data (line 310) | def get_suggested_expense_data(receipt_data): FILE: app/utils/oidc_metadata.py class IPCache (line 29) | class IPCache: method __init__ (line 32) | def __init__(self, default_ttl: int = 300): method get (line 37) | def get(self, hostname: str) -> Optional[str]: method set (line 50) | def set(self, hostname: str, ip: str, ttl: Optional[int] = None): method clear (line 58) | def clear(self, hostname: Optional[str] = None): method _mask_ip (line 66) | def _mask_ip(self, ip: str) -> str: function initialize_ip_cache (line 79) | def initialize_ip_cache(ttl: int = 300): function detect_docker_environment (line 86) | def detect_docker_environment() -> bool: function resolve_hostname_socket (line 120) | def resolve_hostname_socket(hostname: str, timeout: int = 5) -> Tuple[bo... function resolve_hostname_getaddrinfo (line 151) | def resolve_hostname_getaddrinfo(hostname: str, timeout: int = 5) -> Tup... function resolve_hostname_multiple_strategies (line 188) | def resolve_hostname_multiple_strategies( function create_optimized_session (line 249) | def create_optimized_session(timeout: int = 10) -> requests.Session: function test_dns_resolution (line 286) | def test_dns_resolution( function try_docker_internal_name (line 303) | def try_docker_internal_name(hostname: str, issuer_url: str) -> Optional... function classify_error (line 353) | def classify_error(error: Exception) -> str: function fetch_oidc_metadata (line 394) | def fetch_oidc_metadata( FILE: app/utils/overtime.py function get_week_start_for_date (line 12) | def get_week_start_for_date(d: date, user: Any) -> date: function calculate_daily_overtime (line 25) | def calculate_daily_overtime(total_hours: float, standard_hours: float) ... function calculate_period_overtime (line 41) | def calculate_period_overtime( function _calculate_period_overtime_weekly (line 119) | def _calculate_period_overtime_weekly( function get_daily_breakdown (line 190) | def get_daily_breakdown(user, start_date: date, end_date: date, include_... function get_weekly_overtime_summary (line 289) | def get_weekly_overtime_summary(user, weeks: int = 4) -> List[Dict]: function get_overtime_ytd (line 359) | def get_overtime_ytd(user) -> Dict[str, float]: function get_overtime_last_12_months (line 369) | def get_overtime_last_12_months(user) -> Dict[str, float]: function get_overtime_statistics (line 378) | def get_overtime_statistics(user, start_date: date, end_date: date) -> D... FILE: app/utils/pagination.py function paginate_query (line 13) | def paginate_query( function get_pagination_params (line 53) | def get_pagination_params( function create_pagination_links (line 68) | def create_pagination_links(page: int, per_page: int, total: int, base_u... FILE: app/utils/pdf_generator.py function update_page_size_in_css (line 41) | def update_page_size_in_css(css_text, page_size): function update_wrapper_dimensions_in_css (line 115) | def update_wrapper_dimensions_in_css(css_text, page_size): function validate_page_size_in_css (line 193) | def validate_page_size_in_css(css_text, expected_page_size): class InvoicePDFGenerator (line 234) | class InvoicePDFGenerator: method __init__ (line 237) | def __init__(self, invoice, settings=None, page_size="A4"): method generate_pdf (line 242) | def generate_pdf(self): method _prepare_template_context (line 542) | def _prepare_template_context(self): method _generate_pdf_with_default (line 720) | def _generate_pdf_with_default(self): method _render_from_custom_template (line 727) | def _render_from_custom_template(self, template=None): method _generate_html (line 1035) | def _generate_html(self): method _escape (line 1183) | def _escape(self, value): method _nl2br (line 1186) | def _nl2br(self, value): method _get_company_logo_html (line 1191) | def _get_company_logo_html(self): method _get_company_tax_info (line 1221) | def _get_company_tax_info(self): method _get_client_email_html (line 1227) | def _get_client_email_html(self): method _get_client_address_html (line 1233) | def _get_client_address_html(self): method _get_project_description_html (line 1239) | def _get_project_description_html(self): method _generate_items_rows (line 1245) | def _generate_items_rows(self): method _get_time_entry_info_html (line 1295) | def _get_time_entry_info_html(self, item): method _generate_totals_rows (line 1302) | def _generate_totals_rows(self): method _get_additional_info_html (line 1339) | def _get_additional_info_html(self): method _format_currency (line 1367) | def _format_currency(self, value): method _get_payment_info_html (line 1374) | def _get_payment_info_html(self): method _generate_css (line 1383) | def _generate_css(self): function get_overflow_prevention_css (line 1615) | def get_overflow_prevention_css(): class QuotePDFGenerator (line 1724) | class QuotePDFGenerator: method __init__ (line 1727) | def __init__(self, quote, settings=None, page_size="A4"): method generate_pdf (line 1732) | def generate_pdf(self): method _prepare_quote_template_context (line 1968) | def _prepare_quote_template_context(self): method _generate_pdf_with_default (line 2080) | def _generate_pdf_with_default(self): method _render_from_custom_template (line 2087) | def _render_from_custom_template(self, template=None): method _generate_html (line 2314) | def _generate_html(self): method _generate_css (line 2318) | def _generate_css(self): FILE: app/utils/pdf_generator_fallback.py class InvoicePDFGeneratorFallback (line 22) | class InvoicePDFGeneratorFallback: method __init__ (line 25) | def __init__(self, invoice, settings=None): method _setup_custom_styles (line 31) | def _setup_custom_styles(self): method generate_pdf (line 66) | def generate_pdf(self): method _build_story (line 98) | def _build_story(self): method _build_header (line 123) | def _build_header(self): method _build_client_section (line 198) | def _build_client_section(self): method _build_items_table (line 233) | def _build_items_table(self): method _format_currency (line 342) | def _format_currency(self, value): method _add_page_number (line 349) | def _add_page_number(self, canv, doc): method _build_additional_info (line 372) | def _build_additional_info(self): method _build_footer (line 388) | def _build_footer(self): function format_quote_item_description_for_pdf (line 405) | def format_quote_item_description_for_pdf(item) -> str: class QuotePDFGeneratorFallback (line 423) | class QuotePDFGeneratorFallback: method __init__ (line 426) | def __init__(self, quote, settings=None): method _setup_custom_styles (line 432) | def _setup_custom_styles(self): method generate_pdf (line 467) | def generate_pdf(self): method _build_story (line 492) | def _build_story(self): method _build_header (line 517) | def _build_header(self): method _build_client_section (line 536) | def _build_client_section(self): method _build_items_table (line 568) | def _build_items_table(self): method _build_totals (line 608) | def _build_totals(self): method _build_additional_info (line 642) | def _build_additional_info(self): method _format_currency (line 657) | def _format_currency(self, value): method _add_page_number (line 662) | def _add_page_number(self, canv, doc): FILE: app/utils/pdf_generator_reportlab.py class AbsolutePositionedFlowable (line 51) | class AbsolutePositionedFlowable(Flowable): method __init__ (line 54) | def __init__(self, element_data): method draw (line 58) | def draw(self): method wrap (line 62) | def wrap(self, availWidth, availHeight): function _normalize_color (line 67) | def _normalize_color(color: Any) -> str: class ReportLabTemplateRenderer (line 129) | class ReportLabTemplateRenderer: method __init__ (line 132) | def __init__(self, template_json: Dict[str, Any], data_context: Dict[s... method _setup_custom_styles (line 171) | def _setup_custom_styles(self): method render_to_bytes (line 219) | def render_to_bytes(self) -> bytes: method _build_story (line 329) | def _build_story(self) -> List[Flowable]: method _render_element (line 401) | def _render_element(self, element: Dict[str, Any]) -> Optional[Flowable]: method _render_text (line 420) | def _render_text(self, element: Dict[str, Any]) -> Paragraph: method _render_image (line 438) | def _render_image(self, element: Dict[str, Any]) -> Optional[Image]: method _render_rectangle (line 530) | def _render_rectangle(self, element: Dict[str, Any]) -> Flowable: method _render_circle (line 567) | def _render_circle(self, element: Dict[str, Any]) -> Flowable: method _render_line (line 603) | def _render_line(self, element: Dict[str, Any]) -> Flowable: method _normalize_extra_good_for_items_row (line 632) | def _normalize_extra_good_for_items_row(self, good: Any) -> SimpleName... method _normalize_expense_for_items_row (line 651) | def _normalize_expense_for_items_row(self, expense: Any) -> SimpleName... method _render_table (line 666) | def _render_table(self, element: Dict[str, Any]) -> Table: method _get_table_style (line 752) | def _get_table_style(self, element: Dict[str, Any], columns: List[Dict... method _get_style (line 792) | def _get_style(self, element: Dict[str, Any], default_style_name: str ... method _get_alignment (line 812) | def _get_alignment(self, align: str) -> int: method _process_template_variables (line 822) | def _process_template_variables(self, text: str) -> str: method _resolve_data_source (line 837) | def _resolve_data_source(self, data_source: str) -> List[Any]: method _process_row_template (line 882) | def _process_row_template(self, field: str, template: str, item: Any) ... method _on_page (line 900) | def _on_page(self, canv: canvas.Canvas, doc: SimpleDocTemplate): method _draw_text_on_canvas (line 995) | def _draw_text_on_canvas( method _resolve_template_image_path (line 1053) | def _resolve_template_image_path(self, filename: str) -> Optional[str]: method _extract_template_image_filename (line 1086) | def _extract_template_image_filename(self, source: str) -> Optional[str]: method _draw_image_on_canvas (line 1100) | def _draw_image_on_canvas( method _draw_rectangle_on_canvas (line 1215) | def _draw_rectangle_on_canvas( method _draw_circle_on_canvas (line 1261) | def _draw_circle_on_canvas( method _draw_line_on_canvas (line 1308) | def _draw_line_on_canvas( FILE: app/utils/pdf_template_schema.py class PageSize (line 13) | class PageSize(str, Enum): class ElementType (line 24) | class ElementType(str, Enum): class TextAlign (line 36) | class TextAlign(str, Enum): function validate_template_json (line 56) | def validate_template_json(template_json: Dict[str, Any]) -> tuple[bool,... function get_default_template (line 117) | def get_default_template(page_size: str = "A4") -> Dict[str, Any]: function get_page_dimensions_mm (line 346) | def get_page_dimensions_mm(page_size: str) -> Dict[str, float]: function get_page_dimensions_points (line 359) | def get_page_dimensions_points(page_size: str) -> Dict[str, float]: FILE: app/utils/pdfa3.py function _srgb_icc_profile_bytes (line 36) | def _srgb_icc_profile_bytes() -> bytes: function _minimal_srgb_icc_profile (line 56) | def _minimal_srgb_icc_profile() -> bytes: function _ensure_pdfa3_xmp (line 170) | def _ensure_pdfa3_xmp(xmp_str: str) -> str: function convert_to_pdfa3 (line 187) | def convert_to_pdfa3(pdf_bytes: bytes) -> Tuple[bytes, Optional[str]]: FILE: app/utils/per_diem_pdf.py function _safe_str (line 52) | def _safe_str(val, fallback=""): function _make_cell_paragraph (line 59) | def _make_cell_paragraph(text): function _page_footer (line 67) | def _page_footer(canvas, doc): function _build_report_header (line 76) | def _build_report_header(start_date=None, end_date=None, filters=None): function build_per_diem_pdf (line 166) | def build_per_diem_pdf(entries, start_date=None, end_date=None, filters=... FILE: app/utils/performance.py function init_performance_logging (line 18) | def init_performance_logging(app): FILE: app/utils/permissions.py function permission_required (line 10) | def permission_required(*permissions, require_all=False): function admin_or_permission_required (line 52) | def admin_or_permission_required(*permissions): function check_permission (line 82) | def check_permission(user, permission_name): function check_any_permission (line 99) | def check_any_permission(user, *permission_names): function check_all_permissions (line 116) | def check_all_permissions(user, *permission_names): function get_user_permissions (line 133) | def get_user_permissions(user): function get_user_permission_names (line 149) | def get_user_permission_names(user): function init_permission_helpers (line 167) | def init_permission_helpers(app): FILE: app/utils/permissions_seed.py function seed_permissions (line 326) | def seed_permissions(): function seed_roles (line 360) | def seed_roles(silent=False): function sync_permissions_and_roles (line 409) | def sync_permissions_and_roles(): function migrate_legacy_users (line 422) | def migrate_legacy_users(): function seed_all (line 457) | def seed_all(): FILE: app/utils/posthog_funnels.py function is_funnel_tracking_enabled (line 13) | def is_funnel_tracking_enabled() -> bool: function track_funnel_step (line 22) | def track_funnel_step(user_id: Any, funnel_name: str, step: str, propert... class Funnels (line 68) | class Funnels: function track_onboarding_started (line 99) | def track_onboarding_started(user_id: Any, properties: Optional[Dict] = ... function track_onboarding_profile_completed (line 104) | def track_onboarding_profile_completed(user_id: Any, properties: Optiona... function track_onboarding_first_project (line 109) | def track_onboarding_first_project(user_id: Any, properties: Optional[Di... function track_onboarding_first_time_entry (line 114) | def track_onboarding_first_time_entry(user_id: Any, properties: Optional... function track_onboarding_first_timer (line 119) | def track_onboarding_first_timer(user_id: Any, properties: Optional[Dict... function track_onboarding_week_1_completed (line 124) | def track_onboarding_week_1_completed(user_id: Any, properties: Optional... function track_project_setup_started (line 134) | def track_project_setup_started(user_id: Any, properties: Optional[Dict]... function track_project_setup_basic_info (line 139) | def track_project_setup_basic_info(user_id: Any, properties: Optional[Di... function track_project_setup_billing_configured (line 144) | def track_project_setup_billing_configured(user_id: Any, properties: Opt... function track_project_setup_tasks_added (line 149) | def track_project_setup_tasks_added(user_id: Any, properties: Optional[D... function track_project_setup_completed (line 154) | def track_project_setup_completed(user_id: Any, properties: Optional[Dic... function track_invoice_page_viewed (line 164) | def track_invoice_page_viewed(user_id: Any, properties: Optional[Dict] =... function track_invoice_project_selected (line 169) | def track_invoice_project_selected(user_id: Any, properties: Optional[Di... function track_invoice_previewed (line 174) | def track_invoice_previewed(user_id: Any, properties: Optional[Dict] = N... function track_invoice_generated (line 179) | def track_invoice_generated(user_id: Any, properties: Optional[Dict] = N... function track_time_tracking_started (line 189) | def track_time_tracking_started(user_id: Any, properties: Optional[Dict]... function track_time_tracking_timer_started (line 194) | def track_time_tracking_timer_started(user_id: Any, properties: Optional... function track_time_tracking_timer_stopped (line 199) | def track_time_tracking_timer_stopped(user_id: Any, properties: Optional... function track_time_tracking_notes_added (line 204) | def track_time_tracking_notes_added(user_id: Any, properties: Optional[D... function track_time_tracking_saved (line 209) | def track_time_tracking_saved(user_id: Any, properties: Optional[Dict] =... function track_export_started (line 219) | def track_export_started(user_id: Any, properties: Optional[Dict] = None): function track_export_format_selected (line 224) | def track_export_format_selected(user_id: Any, properties: Optional[Dict... function track_export_filters_applied (line 229) | def track_export_filters_applied(user_id: Any, properties: Optional[Dict... function track_export_downloaded (line 234) | def track_export_downloaded(user_id: Any, properties: Optional[Dict] = N... function track_report_page_viewed (line 244) | def track_report_page_viewed(user_id: Any, properties: Optional[Dict] = ... function track_report_type_selected (line 249) | def track_report_type_selected(user_id: Any, properties: Optional[Dict] ... function track_report_filters_applied (line 254) | def track_report_filters_applied(user_id: Any, properties: Optional[Dict... function track_report_generated (line 259) | def track_report_generated(user_id: Any, properties: Optional[Dict] = No... function track_funnel_abandonment (line 269) | def track_funnel_abandonment( function get_funnel_context (line 295) | def get_funnel_context(funnel_name: str, additional_context: Optional[Di... FILE: app/utils/posthog_monitoring.py function is_monitoring_enabled (line 14) | def is_monitoring_enabled() -> bool: function track_error (line 28) | def track_error( function track_http_error (line 87) | def track_http_error(user_id: Any, status_code: int, error_message: str,... function track_validation_error (line 106) | def track_validation_error(user_id: Any, field: str, error_message: str,... function track_performance (line 124) | def track_performance( function measure_performance (line 173) | def measure_performance( function performance_tracked (line 191) | def performance_tracked(metric_name: str, threshold_ms: Optional[float] ... function track_query_performance (line 227) | def track_query_performance(user_id: Any, query_type: str, duration_ms: ... function track_api_call (line 251) | def track_api_call( function track_page_load (line 286) | def track_page_load(user_id: Any, page_name: str, duration_ms: float, co... function track_export_performance (line 310) | def track_export_performance( function track_health_check (line 343) | def track_health_check(status: str, checks: Dict[str, bool], response_ti... function track_resource_usage (line 375) | def track_resource_usage( function track_slow_operation (line 402) | def track_slow_operation( FILE: app/utils/posthog_segmentation.py function is_segmentation_enabled (line 12) | def is_segmentation_enabled() -> bool: function identify_user_with_segments (line 17) | def identify_user_with_segments(user_id: Any, user) -> None: function calculate_engagement_metrics (line 71) | def calculate_engagement_metrics(user_id: Any) -> Dict[str, Any]: function calculate_usage_patterns (line 130) | def calculate_usage_patterns(user_id: Any) -> Dict[str, Any]: function get_account_info (line 198) | def get_account_info(user) -> Dict[str, Any]: class UserCohorts (line 238) | class UserCohorts: function get_user_cohort_description (line 279) | def get_user_cohort_description(user_properties: Dict[str, Any]) -> str: function set_super_properties (line 304) | def set_super_properties(user_id: Any, user) -> None: function should_update_segments (line 340) | def should_update_segments(user_id: Any) -> bool: function update_user_segments_if_needed (line 357) | def update_user_segments_if_needed(user_id: Any, user) -> None: FILE: app/utils/powerpoint_export.py function create_report_powerpoint (line 28) | def create_report_powerpoint(entries, title="TimeTracker Report", filena... FILE: app/utils/prepaid_hours.py class ProcessedTimeEntry (line 16) | class ProcessedTimeEntry: class PrepaidMonthSummary (line 26) | class PrepaidMonthSummary: class PrepaidHoursAllocator (line 35) | class PrepaidHoursAllocator: method __init__ (line 38) | def __init__(self, client: Client, invoice: Optional[Invoice] = None): method process (line 48) | def process(self, entries: Iterable[TimeEntry]) -> List[ProcessedTimeE... method build_summary (line 112) | def build_summary(self, entries: Iterable[TimeEntry]) -> List[PrepaidM... method _reset_invoice_allocations (line 145) | def _reset_invoice_allocations(self): method _collect_months (line 163) | def _collect_months(self, entries: Iterable[TimeEntry]) -> Set[date]: method _load_existing_consumption (line 171) | def _load_existing_consumption(self, months: Set[date]): method _allocation_month (line 187) | def _allocation_month(self, entry: TimeEntry) -> Optional[date]: method _remaining_allowance (line 192) | def _remaining_allowance(self, month: date) -> Decimal: method _record_consumption (line 197) | def _record_consumption(self, entry: TimeEntry, month: date, prepaid_h... method _hours_from_entry (line 215) | def _hours_from_entry(entry: TimeEntry) -> Decimal: method _quantize_hours (line 220) | def _quantize_hours(value: Decimal) -> Decimal: FILE: app/utils/query_logging.py function enable_query_logging (line 19) | def enable_query_logging(app, slow_query_threshold: float = 0.1): function query_timer (line 63) | def query_timer(operation_name: str): function get_query_stats (line 85) | def get_query_stats() -> Dict[str, Any]: function log_query_count (line 100) | def log_query_count(): function enable_query_counting (line 111) | def enable_query_counting(app): FILE: app/utils/query_optimization.py function eager_load_relations (line 14) | def eager_load_relations(query: Query, model_class: Type, relations: Lis... function get_model_relations (line 38) | def get_model_relations(model_class: Type) -> List[str]: function optimize_list_query (line 52) | def optimize_list_query(query: Query, model_class: Type, common_relation... function batch_load_relations (line 80) | def batch_load_relations(items: List[Type], relation_name: str, model_cl... class QueryProfiler (line 107) | class QueryProfiler: method count_queries (line 111) | def count_queries(func): FILE: app/utils/quote_access.py function quote_list_scope_user_id (line 8) | def quote_list_scope_user_id(user: Any) -> Optional[int]: FILE: app/utils/rate_limiting.py function get_rate_limit_key (line 13) | def get_rate_limit_key() -> str: function rate_limit (line 33) | def rate_limit(per_minute: Optional[int] = None, per_hour: Optional[int]... function get_rate_limit_info (line 60) | def get_rate_limit_info() -> Dict[str, Any]: FILE: app/utils/role_migration.py function migrate_user_roles (line 9) | def migrate_user_roles(dry_run: bool = False) -> Dict[str, any]: function migrate_single_user (line 80) | def migrate_single_user(user_id: int, role_name: Optional[str] = None) -... FILE: app/utils/route_helpers.py function handle_service_result (line 20) | def handle_service_result( function json_api (line 72) | def json_api(f: Callable) -> Callable: function require_admin_or_owner (line 95) | def require_admin_or_owner(owner_id_getter: Callable[[Any], int]): FILE: app/utils/safe_template_render.py function render_sandboxed_string (line 10) | def render_sandboxed_string(source: str, *, autoescape: bool = True, **c... FILE: app/utils/scheduled_tasks.py function check_overdue_invoices (line 33) | def check_overdue_invoices(): function send_weekly_summaries (line 89) | def send_weekly_summaries(): function check_project_budget_alerts (line 165) | def check_project_budget_alerts(): function generate_recurring_invoices (line 209) | def generate_recurring_invoices(): function send_monthly_unpaid_hours_reports (line 272) | def send_monthly_unpaid_hours_reports(): function register_scheduled_tasks (line 368) | def register_scheduled_tasks(scheduler, app=None): function process_remind_to_log (line 644) | def process_remind_to_log(): function process_scheduled_reports (line 715) | def process_scheduled_reports(): function retry_failed_webhooks (line 756) | def retry_failed_webhooks(): function check_expiring_quotes (line 775) | def check_expiring_quotes(): function sync_integrations (line 847) | def sync_integrations(): FILE: app/utils/scope_filter.py function get_allowed_client_ids (line 8) | def get_allowed_client_ids(user=None): function get_allowed_project_ids (line 16) | def get_allowed_project_ids(user=None): function apply_client_scope (line 24) | def apply_client_scope(Client, query, user=None): function apply_project_scope (line 32) | def apply_project_scope(Project, query, user=None): function apply_client_scope_to_model (line 40) | def apply_client_scope_to_model(Client, user=None): function apply_project_scope_to_model (line 53) | def apply_project_scope_to_model(Project, user=None): function user_can_access_client (line 66) | def user_can_access_client(user, client_id): function user_can_access_project (line 78) | def user_can_access_project(user, project_id): function get_accessible_project_and_client_ids_for_user (line 90) | def get_accessible_project_and_client_ids_for_user(user_id: int) -> Tupl... FILE: app/utils/search.py function search_projects (line 12) | def search_projects(query: str, user_id: Optional[int] = None, status: O... function search_time_entries (line 34) | def search_time_entries(query: str, user_id: Optional[int] = None, proje... function search_tasks (line 59) | def search_tasks(query: str, project_id: Optional[int] = None, status: O... function search_invoices (line 84) | def search_invoices(query: str, status: Optional[str] = None) -> List[In... function search_clients (line 107) | def search_clients(query: str) -> List[Client]: function global_search (line 133) | def global_search(query: str, user_id: Optional[int] = None, limit_per_t... FILE: app/utils/secret_crypto.py function _load_key_from_env (line 11) | def _load_key_from_env() -> str: function is_configured (line 31) | def is_configured() -> bool: function get_fernet (line 35) | def get_fernet(): function encrypt_if_possible (line 61) | def encrypt_if_possible(value: str) -> str: function decrypt_if_needed (line 72) | def decrypt_if_needed(value: Optional[str]) -> str: FILE: app/utils/seed_dev_data.py function _ensure_development (line 39) | def _ensure_development(): function _make_time_entry (line 169) | def _make_time_entry( function run_seed (line 196) | def run_seed( FILE: app/utils/setup_logging.py function setup_logging (line 12) | def setup_logging(app: Flask) -> None: FILE: app/utils/stripe_integration.py class StripeIntegration (line 15) | class StripeIntegration: method __init__ (line 20) | def __init__(self, api_key: str): method create_payment_intent (line 30) | def create_payment_intent( method verify_webhook (line 67) | def verify_webhook(self, payload: bytes, signature: str, webhook_secre... method get_payment_intent (line 84) | def get_payment_intent(self, payment_intent_id: str) -> Optional[strip... method create_checkout_session (line 92) | def create_checkout_session( FILE: app/utils/summary_report_pdf.py function build_summary_report_pdf (line 27) | def build_summary_report_pdf(today_hours, week_hours, month_hours, proje... FILE: app/utils/support_report_generation.py function record_report_generation_for_current_user (line 6) | def record_report_generation_for_current_user() -> None: FILE: app/utils/telemetry.py function get_telemetry_fingerprint (line 16) | def get_telemetry_fingerprint() -> str: function is_telemetry_enabled (line 41) | def is_telemetry_enabled() -> bool: function get_installation_config (line 74) | def get_installation_config(): # type: ignore function send_telemetry_ping (line 78) | def send_telemetry_ping(event_type: str = "install", extra_data: Optiona... function send_install_ping (line 117) | def send_install_ping() -> bool: function send_update_ping (line 126) | def send_update_ping(old_version: str, new_version: str) -> bool: function send_health_ping (line 137) | def send_health_ping() -> bool: function should_send_telemetry (line 146) | def should_send_telemetry(marker_file: str = "/data/telemetry_sent") -> ... function mark_telemetry_sent (line 162) | def mark_telemetry_sent(marker_file: str = "/data/telemetry_sent") -> None: function check_and_send_telemetry (line 188) | def check_and_send_telemetry() -> bool: FILE: app/utils/template_filters.py function register_template_filters (line 20) | def register_template_filters(app): function get_logo_base64 (line 495) | def get_logo_base64(logo_path): function get_image_base64 (line 524) | def get_image_base64(image_path): FILE: app/utils/time_entries_pdf.py function _fmt_time (line 83) | def _fmt_time(dt): function _fmt_date_group (line 97) | def _fmt_date_group(dt): function _duration_hhmm (line 110) | def _duration_hhmm(seconds): function _safe_str (line 120) | def _safe_str(val, fallback=""): function _make_cell_paragraph (line 128) | def _make_cell_paragraph(text): function _make_notes_paragraph (line 138) | def _make_notes_paragraph(text): function _page_footer (line 148) | def _page_footer(canvas, doc): function _build_report_header (line 168) | def _build_report_header(start_date=None, end_date=None, filters=None): function build_time_entries_pdf (line 277) | def build_time_entries_pdf(entries, start_date=None, end_date=None, filt... function _group_entries_by_date (line 436) | def _group_entries_by_date(entries): function _build_summary_totals (line 450) | def _build_summary_totals(entry_count, total_seconds, billable_seconds): FILE: app/utils/time_entry_validation.py function validate_time_entry_requirements (line 13) | def validate_time_entry_requirements( FILE: app/utils/time_rounding.py function round_time_duration (line 7) | def round_time_duration(duration_seconds: int, rounding_minutes: int = 1... function get_user_rounding_settings (line 50) | def get_user_rounding_settings(user) -> dict: function apply_user_rounding (line 67) | def apply_user_rounding(duration_seconds: int, user) -> int: function format_rounding_interval (line 87) | def format_rounding_interval(minutes: int) -> str: function get_available_rounding_intervals (line 116) | def get_available_rounding_intervals() -> list: function get_available_rounding_methods (line 133) | def get_available_rounding_methods() -> list: FILE: app/utils/timezone.py function _get_system_date_format_key (line 27) | def _get_system_date_format_key(): function _get_system_time_format_key (line 51) | def _get_system_time_format_key(): function get_resolved_date_format_key (line 75) | def get_resolved_date_format_key(user=None): function get_resolved_time_format_key (line 85) | def get_resolved_time_format_key(user=None): function get_resolved_week_start_day (line 95) | def get_resolved_week_start_day(user=None): function get_user_date_format (line 105) | def get_user_date_format(user=None): function get_user_time_format (line 119) | def get_user_time_format(user=None): function get_user_datetime_format (line 133) | def get_user_datetime_format(user=None): function get_available_timezones (line 139) | def get_available_timezones(): function _get_authenticated_user (line 144) | def _get_authenticated_user(user=None): function get_app_timezone (line 161) | def get_app_timezone(): function get_timezone_obj (line 197) | def get_timezone_obj(): function get_user_timezone_name (line 207) | def get_user_timezone_name(user=None): function get_timezone_for_user (line 231) | def get_timezone_for_user(user=None): function now_in_app_timezone (line 242) | def now_in_app_timezone(): function now_in_user_timezone (line 249) | def now_in_user_timezone(user=None): function local_now (line 256) | def local_now(): function _localize_with_timezone (line 261) | def _localize_with_timezone(dt, tz): function convert_app_datetime_to_user (line 274) | def convert_app_datetime_to_user(dt, user=None): function utc_to_local (line 286) | def utc_to_local(utc_dt): function utc_to_user_local (line 299) | def utc_to_user_local(utc_dt, user=None): function local_to_utc (line 311) | def local_to_utc(local_dt): function user_local_to_utc (line 321) | def user_local_to_utc(local_dt, user=None): function parse_local_datetime (line 331) | def parse_local_datetime(date_str, time_str): function parse_local_datetime_from_string (line 350) | def parse_local_datetime_from_string(datetime_str): function parse_user_local_datetime (line 368) | def parse_user_local_datetime(date_str, time_str, user=None): function format_local_datetime (line 388) | def format_local_datetime(utc_dt, format_str="%Y-%m-%d %H:%M"): function format_user_datetime (line 397) | def format_user_datetime(dt, format_str=None, user=None, assume_app_time... function get_timezone_offset (line 424) | def get_timezone_offset(): function get_timezone_offset_for_timezone (line 433) | def get_timezone_offset_for_timezone(tz_name): FILE: app/utils/transactions.py function transactional (line 14) | def transactional(func: Callable) -> Callable: class Transaction (line 41) | class Transaction: method __enter__ (line 51) | def __enter__(self): method __exit__ (line 54) | def __exit__(self, exc_type, exc_val, exc_tb): function safe_transaction (line 70) | def safe_transaction(func: Callable) -> Callable: FILE: app/utils/validation.py function validate_required (line 14) | def validate_required(data: Dict[str, Any], fields: List[str]) -> Dict[s... function validate_date_range (line 39) | def validate_date_range(start_date: Any, end_date: Any) -> bool: function validate_decimal (line 69) | def validate_decimal(value: Any, min_value: Optional[Decimal] = None, ma... function validate_integer (line 98) | def validate_integer(value: Any, min_value: Optional[int] = None, max_va... function validate_string (line 127) | def validate_string(value: Any, min_length: Optional[int] = None, max_le... function validate_email (line 156) | def validate_email(email: str) -> str: function validate_json_request (line 180) | def validate_json_request() -> Dict[str, Any]: function sanitize_input (line 200) | def sanitize_input(value: str, max_length: Optional[int] = None) -> str: FILE: app/utils/version_compare.py function normalize_version_tag (line 8) | def normalize_version_tag(raw: str | None) -> str | None: function is_upgrade (line 25) | def is_upgrade(current: str | None, latest: str | None) -> bool: FILE: app/utils/webhook_dispatcher.py class WebhookDispatcher (line 15) | class WebhookDispatcher: method dispatch_event (line 19) | def dispatch_event( method map_activity_to_event (line 55) | def map_activity_to_event(action: str, entity_type: str) -> Optional[s... method build_payload_from_activity (line 104) | def build_payload_from_activity(activity, additional_data: Optional[Di... method on_activity_logged (line 144) | def on_activity_logged(activity): function dispatch_webhook (line 172) | def dispatch_webhook(event: str, data: Dict[str, Any], user_id: Optional... FILE: app/utils/webhook_service.py class WebhookDeliveryError (line 20) | class WebhookDeliveryError(Exception): class WebhookTimeoutError (line 26) | class WebhookTimeoutError(WebhookDeliveryError): class WebhookHTTPError (line 32) | class WebhookHTTPError(WebhookDeliveryError): class WebhookService (line 38) | class WebhookService: method deliver_webhook (line 42) | def deliver_webhook( method _send_request (line 179) | def _send_request(webhook: Webhook, payload_json: str, event_type: str... method _schedule_retry (line 229) | def _schedule_retry(delivery: WebhookDelivery, webhook: Webhook): method retry_failed_deliveries (line 248) | def retry_failed_deliveries(max_deliveries: int = 100) -> int: method get_available_events (line 344) | def get_available_events() -> List[str]: FILE: app/utils/zugferd.py function _get_seller_party (line 35) | def _get_seller_party(settings: Any) -> CIIParty: function _get_buyer_party (line 57) | def _get_buyer_party(invoice: Any) -> CIIParty: function _ensure_metadata_stream (line 105) | def _ensure_metadata_stream(pdf: Any) -> None: function _facturx_rdf_description (line 119) | def _facturx_rdf_description() -> str: function _add_facturx_xmp (line 131) | def _add_facturx_xmp(pdf: Any) -> None: function embed_zugferd_xml_in_pdf (line 160) | def embed_zugferd_xml_in_pdf(pdf_bytes: bytes, invoice: Any, settings: A... FILE: desktop/dist-renderer/assets/index-BqW2gGjC.js function i (line 1) | function i(o){const f={};return o.integrity&&(f.integrity=o.integrity),o... function s (line 1) | function s(o){if(o.ep)return;o.ep=!0;const f=i(o);fetch(o.href,f)} function nb (line 1) | function nb(){if(Xy)return Zu;Xy=1;var u=Symbol.for("react.transitional.... function ab (line 1) | function ab(){return Vy||(Vy=1,Uo.exports=nb()),Uo.exports} function lb (line 1) | function lb(){if(Zy)return me;Zy=1;var u=Symbol.for("react.transitional.... function Rf (line 1) | function Rf(){return Jy||(Jy=1,Mo.exports=lb()),Mo.exports} function ub (line 1) | function ub(){return Fy||(Fy=1,(function(u){function l(M,V){var W=M.leng... function ib (line 1) | function ib(){return $y||($y=1,qo.exports=ub()),qo.exports} function rb (line 1) | function rb(){if(Wy)return vt;Wy=1;var u=Rf();function l(v){var y="https... function sb (line 1) | function sb(){if(Iy)return Lo.exports;Iy=1;function u(){if(!(typeof __RE... function cb (line 1) | function cb(){if(Py)return Ju;Py=1;var u=ib(),l=Rf(),i=sb();function s(e... function ob (line 9) | function ob(){if(ep)return Bo.exports;ep=1;function u(){if(!(typeof __RE... function Cp (line 9) | function Cp(u,l){return function(){return u.apply(l,arguments)}} function di (line 9) | function di(u){return u!==null&&!Zl(u)&&u.constructor!==null&&!Zl(u.cons... function hb (line 9) | function hb(u){let l;return typeof ArrayBuffer<"u"&&ArrayBuffer.isView?l... function Ab (line 9) | function Ab(){return typeof globalThis<"u"?globalThis:typeof self<"u"?se... function mi (line 9) | function mi(u,l,{allOwnKeys:i=!1}={}){if(u===null||typeof u>"u")return;l... function Bp (line 9) | function Bp(u,l){if(di(u))return null;l=l.toLowerCase();const i=Object.k... function Io (line 9) | function Io(){const{caseless:u,skipUndefined:l}=qp(this)&&this||{},i={},... function Jb (line 9) | function Jb(u){return!!(u&&Dt(u.append)&&u[zp]==="FormData"&&u[hs])} method from (line 9) | static from(l,i,s,o,f,h){const m=new Kp(l.message,i||l.code,s,o,f);retur... method constructor (line 9) | constructor(l,i,s,o,f){super(l),Object.defineProperty(this,"message",{va... method toJSON (line 9) | toJSON(){return{message:this.message,name:this.name,description:this.des... function Po (line 9) | function Po(u){return B.isPlainObject(u)||B.isArray(u)} function kp (line 9) | function kp(u){return B.endsWith(u,"[]")?u.slice(0,-2):u} function Ko (line 9) | function Ko(u,l,i){return u?u.concat(l).map(function(o,f){return o=kp(o)... function tS (line 9) | function tS(u){return B.isArray(u)&&!u.some(Po)} function ps (line 9) | function ps(u,l,i){if(!B.isObject(u))throw new TypeError("target must be... function lp (line 9) | function lp(u){const l={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E... function Nf (line 9) | function Nf(u,l){this._pairs=[],u&&ps(u,this,l)} function aS (line 9) | function aS(u){return encodeURIComponent(u).replace(/%3A/gi,":").replace... function Gp (line 9) | function Gp(u,l,i){if(!l)return u;const s=i&&i.encode||aS,o=B.isFunction... class up (line 9) | class up{constructor(){this.handlers=[]}use(l,i,s){return this.handlers.... method constructor (line 9) | constructor(){this.handlers=[]} method use (line 9) | use(l,i,s){return this.handlers.push({fulfilled:l,rejected:i,synchrono... method eject (line 9) | eject(l){this.handlers[l]&&(this.handlers[l]=null)} method clear (line 9) | clear(){this.handlers&&(this.handlers=[])} method forEach (line 9) | forEach(l){B.forEach(this.handlers,function(s){s!==null&&l(s)})} function dS (line 9) | function dS(u,l){return ps(u,new gt.classes.URLSearchParams,{visitor:fun... function hS (line 9) | function hS(u){return B.matchAll(/\w+|\[(\w*)]/g,u).map(l=>l[0]==="[]"?"... function mS (line 9) | function mS(u){const l={},i=Object.keys(u);let s;const o=i.length;let f;... function Qp (line 9) | function Qp(u){function l(i,s,o,f){let h=i[f++];if(h==="__proto__")retur... function yS (line 9) | function yS(u,l,i){if(B.isString(u))try{return(l||JSON.parse)(u),B.trim(... function Xp (line 10) | function Xp(u,l){if(!(u===!1||u==null)){if(B.isArray(u)){u.forEach(i=>Xp... function Fu (line 10) | function Fu(u){return u&&String(u).trim().toLowerCase()} function bS (line 10) | function bS(u){let l=u.length;for(;l>0;){const i=u.charCodeAt(l-1);if(i!... function Zr (line 10) | function Zr(u){return u===!1||u==null?u:B.isArray(u)?u.map(Zr):bS(String... function SS (line 10) | function SS(u){const l=Object.create(null),i=/([^\s,;=]+)\s*(?:=\s*([^,;... function ko (line 10) | function ko(u,l,i,s,o){if(B.isFunction(s))return s.call(this,l,i);if(o&&... function ES (line 10) | function ES(u){return u.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(... function TS (line 10) | function TS(u,l){const i=B.toCamelCase(" "+l);["get","set","has"].forEac... method constructor (line 10) | constructor(l){l&&this.set(l)} method set (line 10) | set(l,i,s){const o=this;function f(m,v,y){const g=Fu(v);if(!g)throw new ... method get (line 10) | get(l,i){if(l=Fu(l),l){const s=B.findKey(this,l);if(s){const o=this[s];i... method has (line 10) | has(l,i){if(l=Fu(l),l){const s=B.findKey(this,l);return!!(s&&this[s]!==v... method delete (line 10) | delete(l,i){const s=this;let o=!1;function f(h){if(h=Fu(h),h){const m=B.... method clear (line 10) | clear(l){const i=Object.keys(this);let s=i.length,o=!1;for(;s--;){const ... method normalize (line 10) | normalize(l){const i=this,s={};return B.forEach(this,(o,f)=>{const h=B.f... method concat (line 10) | concat(...l){return this.constructor.concat(this,...l)} method toJSON (line 10) | toJSON(l){const i=Object.create(null);return B.forEach(this,(s,o)=>{s!=n... method [Symbol.iterator] (line 10) | [Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator... method toString (line 10) | toString(){return Object.entries(this.toJSON()).map(([l,i])=>l+": "+i).j... method getSetCookie (line 11) | getSetCookie(){return this.get("set-cookie")||[]} method [Symbol.toStringTag] (line 11) | get[Symbol.toStringTag](){return"AxiosHeaders"} method from (line 11) | static from(l){return l instanceof this?l:new this(l)} method concat (line 11) | static concat(l,...i){const s=new this(l);return i.forEach(o=>s.set(o)),s} method accessor (line 11) | static accessor(l){const s=(this[ip]=this[ip]={accessors:{}}).accessors,... method set (line 11) | set(s){this[i]=s} function Yo (line 11) | function Yo(u,l){const i=this||yi,s=l||i,o=Ct.from(s.headers);let f=s.da... function Vp (line 11) | function Vp(u){return!!(u&&u.__CANCEL__)} method constructor (line 11) | constructor(l,i,s){super(l??"canceled",fe.ERR_CANCELED,i,s),this.name="C... function Zp (line 11) | function Zp(u,l,i){const s=i.config.validateStatus;!i.status||!s||s(i.st... function AS (line 11) | function AS(u){const l=/^([-+\w]{1,25})(:?\/\/|:)/.exec(u);return l&&l[1... function OS (line 11) | function OS(u,l){u=u||10;const i=new Array(u),s=new Array(u);let o=0,f=0... function wS (line 11) | function wS(u,l){let i=0,s=1e3/l,o,f;const h=(y,g=Date.now())=>{i=g,o=nu... method write (line 11) | write(u,l,i,s,o,f,h){if(typeof document>"u")return;const m=[`${u}=${enco... method read (line 11) | read(u){if(typeof document>"u")return null;const l=document.cookie.match... method remove (line 11) | remove(u){this.write(u,"",Date.now()-864e5,"/")} method write (line 11) | write(){} method read (line 11) | read(){return null} method remove (line 11) | remove(){} function jS (line 11) | function jS(u){return typeof u!="string"?!1:/^([a-z][a-z\d+\-.]*:)?\/\//... function NS (line 11) | function NS(u,l){return l?u.replace(/\/?\/$/,"")+"/"+l.replace(/^\/+/,""... function Jp (line 11) | function Jp(u,l,i){let s=!jS(l);return u&&(s||i==!1)?NS(u,l):l} function $a (line 11) | function $a(u,l){l=l||{};const i={};function s(y,g,b,S){return B.isPlain... function E (line 11) | function E(){N&&N(),O&&O(),o.cancelToken&&o.cancelToken.unsubscribe(g),o... function j (line 11) | function j(){if(!A)return;const L=Ct.from("getAllResponseHeaders"in A&&A... method pull (line 11) | async pull(v){try{const{done:y,value:g}=await o.next();if(y){m(),v.close... method cancel (line 11) | cancel(v){return m(v),o.return()} method duplex (line 11) | get duplex(){return O=!0,"half"} function kS (line 11) | function kS(u,l){u=B.isArray(u)?u:[u];const{length:i}=u;let s,o;const f=... function Go (line 13) | function Go(u){if(u.cancelToken&&u.cancelToken.throwIfRequested(),u.sign... function pp (line 13) | function pp(u){return Go(u),u.headers=Ct.from(u.headers),u.data=Yo.call(... function o (line 13) | function o(f,h){return"[Axios v"+Ip+"] Transitional option '"+f+"'"+h+(s... function YS (line 13) | function YS(u,l,i){if(typeof u!="object")throw new fe("options must be a... method constructor (line 13) | constructor(l){this.defaults=l||{},this.interceptors={request:new up,res... method request (line 13) | async request(l,i){try{return await this._request(l,i)}catch(s){if(s ins... method _request (line 17) | _request(l,i){typeof l=="string"?(i=i||{},i.url=l):i=l||{},i=$a(this.def... method getUri (line 17) | getUri(l){l=$a(this.defaults,l);const i=Jp(l.baseURL,l.url,l.allowAbsolu... function i (line 17) | function i(s){return function(f,h,m){return this.request($a(m||{},{metho... method constructor (line 17) | constructor(l){if(typeof l!="function")throw new TypeError("executor mus... method throwIfRequested (line 17) | throwIfRequested(){if(this.reason)throw this.reason} method subscribe (line 17) | subscribe(l){if(this.reason){l(this.reason);return}this._listeners?this.... method unsubscribe (line 17) | unsubscribe(l){if(!this._listeners)return;const i=this._listeners.indexO... method toAbortSignal (line 17) | toAbortSignal(){const l=new AbortController,i=s=>{l.abort(s)};return thi... method source (line 17) | static source(){let l;return{token:new Pp(function(o){l=o}),cancel:l}} function QS (line 17) | function QS(u){return function(i){return u.apply(null,i)}} function XS (line 17) | function XS(u){return B.isObject(u)&&u.isAxiosError===!0} function ev (line 17) | function ev(u){const l=new Va(u),i=Cp(Va.prototype.request,l);return B.e... function VS (line 17) | function VS(u){const l=localStorage.getItem(u);if(!l)return null;try{ret... function ya (line 17) | async function ya(u){return window.electronAPI?.storeGet?window.electron... function Ya (line 17) | async function Ya(u,l){if(window.electronAPI?.storeSet)return window.ele... function gp (line 17) | async function gp(u){if(window.electronAPI?.storeDelete)return window.el... function ZS (line 17) | async function ZS(){if(window.electronAPI?.storeClear)return window.elec... function ls (line 17) | function ls(u){let l=String(u||"").trim();return l?(/^https?:\/\//i.test... function JS (line 17) | function JS(u){const l=u?.code,i=u?.message||"";return["DEPTH_ZERO_SELF_... function yn (line 17) | function yn(u){if(JS(u))return{ok:!1,code:"TLS",message:"SSL/TLS certifi... function FS (line 17) | function FS(u){return u&&typeof u=="object"&&u.api_version==="v1"&&typeo... class un (line 17) | class un{constructor(l,i=null,s={}){this.baseUrl=un.normalizeBaseUrl(l),... method constructor (line 17) | constructor(l,i=null,s={}){this.baseUrl=un.normalizeBaseUrl(l),this.to... method normalizeBaseUrl (line 17) | static normalizeBaseUrl(l){return String(l||"").trim().replace(/\/+$/,... method testPublicServerInfo (line 17) | static async testPublicServerInfo(l){const i=un.normalizeBaseUrl(ls(l)... method loginWithPassword (line 17) | static async loginWithPassword(l,i,s){const o=un.normalizeBaseUrl(ls(l... method validateSession (line 17) | async validateSession(){try{const l=await this.client.get("/api/v1/use... method unwrap (line 17) | async unwrap(l){return(await l).data} method getUsersMe (line 17) | getUsersMe(){return this.unwrap(this.client.get("/api/v1/users/me"))} method getTimerStatus (line 17) | getTimerStatus(){return this.unwrap(this.client.get("/api/v1/timer/sta... method startTimer (line 17) | startTimer(l){return this.unwrap(this.client.post("/api/v1/timer/start... method stopTimer (line 17) | stopTimer(){return this.unwrap(this.client.post("/api/v1/timer/stop"))} method getProjects (line 17) | getProjects(l={}){return this.unwrap(this.client.get("/api/v1/projects... method getTasks (line 17) | getTasks(l={}){return this.unwrap(this.client.get("/api/v1/tasks",{par... method getTimeEntries (line 17) | getTimeEntries(l={}){return this.unwrap(this.client.get("/api/v1/time-... method createTimeEntry (line 17) | createTimeEntry(l){return this.unwrap(this.client.post("/api/v1/time-e... method updateTimeEntry (line 17) | updateTimeEntry(l,i){return this.unwrap(this.client.put(`/api/v1/time-... method deleteTimeEntry (line 17) | deleteTimeEntry(l){return this.unwrap(this.client.delete(`/api/v1/time... method getInvoices (line 17) | getInvoices(l={}){return this.unwrap(this.client.get("/api/v1/invoices... method getExpenses (line 17) | getExpenses(l={}){return this.unwrap(this.client.get("/api/v1/expenses... method createExpense (line 17) | createExpense(l){return this.unwrap(this.client.post("/api/v1/expenses... method getCapacityReport (line 17) | getCapacityReport(l={}){return this.unwrap(this.client.get("/api/v1/re... method getTimesheetPeriods (line 17) | getTimesheetPeriods(l={}){return this.unwrap(this.client.get("/api/v1/... method getTimeOffRequests (line 17) | getTimeOffRequests(l={}){return this.unwrap(this.client.get("/api/v1/t... function Ll (line 17) | function Ll(u,l){const i=l?.code||"UNKNOWN",s=[];return u?s.push(`URL te... function Tt (line 17) | function Tt(u,l){return typeof l!="object"||ut(l).forEach((function(i){u... function Gt (line 17) | function Gt(u,l){return $S.call(u,l)} function Jl (line 17) | function Jl(u,l){typeof l=="function"&&(l=l(ui(u))),(typeof Reflect>"u"?... function kn (line 17) | function kn(u,l,i,s){tv(u,l,Tt(i&&Gt(i,"get")&&typeof i.get=="function"?... function Gl (line 17) | function Gl(u){return{from:function(l){return u.prototype=Object.create(... function Uf (line 17) | function Uf(u,l){let i;return WS(u,l)||(i=ui(u))&&Uf(i,l)} function us (line 17) | function us(u,l,i){return IS.call(u,l,i)} function nv (line 17) | function nv(u,l){return l(u)} function Wu (line 17) | function Wu(u){if(!u)throw new Error("Assertion Failed")} function av (line 17) | function av(u){Ge.setImmediate?setImmediate(u):setTimeout(u,0)} function lv (line 17) | function lv(u,l){return u.reduce(((i,s,o)=>{var f=l(s,o);return f&&(i[f[... function Yn (line 17) | function Yn(u,l){if(typeof l=="string"&&Gt(u,l))return u[l];if(!l)return... function rn (line 17) | function rn(u,l,i){if(u&&l!==void 0&&(!("isFrozen"in Object)||!Object.is... function uv (line 17) | function uv(u){var l={};for(var i in u)Gt(u,i)&&(l[i]=u[i]);return l} function iv (line 17) | function iv(u){return PS.apply([],u)} function vi (line 17) | function vi(u){va=typeof WeakMap<"u"&&new WeakMap;const l=nf(u);return v... function nf (line 17) | function nf(u){if(!u||typeof u!="object")return u;let l=va&&va.get(u);if... function af (line 17) | function af(u){return t1.call(u).slice(8,-1)} function Ln (line 17) | function Ln(u){var l,i,s,o;if(arguments.length===1){if(St(u))return u.sl... function sv (line 17) | function sv(u,l){pn=u,cv=l} function Pa (line 17) | function Pa(){if(a1)try{throw Pa.arguments,new Error}catch(u){return u}r... function uf (line 17) | function uf(u,l){var i=u.stack;return i?(l=l||0,i.indexOf(u.name)===0&&(... function Ql (line 20) | function Ql(u,l){this._e=Pa(),this.name=u,this.message=l} function fv (line 20) | function fv(u,l){return u+". Errors: "+Object.keys(l).map((i=>l[i].toStr... function is (line 21) | function is(u,l,i,s){this._e=Pa(),this.failures=l,this.failedKeys=s,this... function Pu (line 21) | function Pu(u,l){this._e=Pa(),this.name="BulkError",this.failures=Object... function s (line 21) | function s(o,f){this._e=Pa(),this.name=i,o?typeof o=="string"?(this.mess... function Ke (line 22) | function Ke(){} function ii (line 22) | function ii(u){return u} function i1 (line 22) | function i1(u,l){return u==null||u===ii?l:function(i){return l(u(i))}} function Wa (line 22) | function Wa(u,l){return function(){u.apply(this,arguments),l.apply(this,... function r1 (line 22) | function r1(u,l){return u===Ke?l:function(){var i=u.apply(this,arguments... function s1 (line 22) | function s1(u,l){return u===Ke?l:function(){u.apply(this,arguments);var ... function c1 (line 22) | function c1(u,l){return u===Ke?l:function(i){var s=u.apply(this,argument... function o1 (line 22) | function o1(u,l){return u===Ke?l:function(){return l.apply(this,argument... function Hf (line 22) | function Hf(u,l){return u===Ke?l:function(){var i=u.apply(this,arguments... function I (line 22) | function I(u){if(typeof this!="object")throw new TypeError("Promises mus... function i (line 22) | function i(s,o){var f=!u.global&&(u!==ie||l!==cs);const h=f&&!Gn();var m... function mv (line 22) | function mv(u,l,i,s,o){this.onFulfilled=typeof u=="function"?u:null,this... function yv (line 22) | function yv(u,l){try{l((i=>{if(u._state===null){if(i===u)throw new TypeE... function mf (line 22) | function mf(u,l){if(Wr.push(l),u._state===null){var i=u._lib&&gi();l=df(... function pv (line 22) | function pv(u){var l=u._listeners;u._listeners=[];for(var i=0,s=l.length... function Kf (line 22) | function Kf(u,l){if(u._state!==null){var i=u._state?l.onFulfilled:l.onRe... function d1 (line 22) | function d1(u,l,i){try{ff=l;var s,o=l._value;l._state?s=u(o):(Wr.length&... function vv (line 22) | function vv(u,l,i){if(l.length===i)return l;var s="";if(u._state===!1){v... function gv (line 22) | function gv(u,l){var i=l?l._numPrev+1:0;i<100&&(u._prev=l,u._numPrev=i)} function Lr (line 22) | function Lr(){gi()&&bi()} function gi (line 22) | function gi(){var u=of;return of=!1,ss=!1,u} function bi (line 22) | function bi(){var u,l,i;do for(;Iu.length>0;)for(u=Iu,Iu=[],i=u.length,l... function kf (line 22) | function kf(){var u=Za;Za=[],u.forEach((s=>{s._PSD.onunhandled.call(null... function Kr (line 22) | function Kr(u){return new I(ri,!1,u)} function Ve (line 22) | function Ve(u,l){var i=ie;return function(){var s=gi(),o=ie;try{return S... function v (line 23) | function v(){m(),Ir.splice(Ir.indexOf(v),1)} function ba (line 23) | function ba(u,l,i,s){var o=ie,f=Object.create(o);f.parent=o,f.ref=0,f.gl... function $l (line 23) | function $l(){return bt.id||(bt.id=++h1),++bt.awaits,bt.echoes+=dv,bt.id} function Gn (line 23) | function Gn(){return!!bt.awaits&&(--bt.awaits==0&&(bt.id=0),bt.echoes=bt... function kr (line 23) | function kr(u){return bt.echoes&&u&&u.constructor===$r?($l(),u.then((l=>... function y1 (line 23) | function y1(u){++cs,bt.echoes&&--bt.echoes!=0||(bt.echoes=bt.id=0),Pr.pu... function p1 (line 23) | function p1(){var u=Pr[Pr.length-1];Pr.pop(),Sa(u,!1)} function Sa (line 23) | function Sa(u,l){var i=ie;if((l?!bt.echoes||Qo++&&u===ie:!Qo||--Qo&&u===... function bv (line 23) | function bv(){var u=Ge.Promise;return Lf?{Promise:u,PromiseProp:Object.g... function Wl (line 23) | function Wl(u,l,i,s,o){var f=ie;try{return Sa(u,!0),l(i,s,o)}finally{Sa(... function Sv (line 23) | function Sv(u){hv.call(rf,u)} function os (line 23) | function os(u,l,i,s){return typeof u!="function"?u:function(){var o=ie;i... function Sp (line 23) | function Sp(u,l){return function(i,s){return u.call(this,os(i,l),os(s,l))}} function Ep (line 23) | function Ep(u,l){var i;try{i=l.onuncatched(u)}catch{}if(i!==!1)try{var s... function yf (line 23) | function yf(u,l,i,s){if(u.idbdb&&(u._state.openComplete||ie.letThrough||... function Ia (line 23) | function Ia(u,l){return u?l?function(){return u.apply(this,arguments)&&l... function Yr (line 23) | function Yr(u){return typeof u!="string"||/\./.test(u)?l=>l:l=>(l[u]===v... class b1 (line 23) | class b1{_trans(l,i,s){const o=this._tx||ie.trans,f=this.name;function h... method _trans (line 23) | _trans(l,i,s){const o=this._tx||ie.trans,f=this.name;function h(v,y,g)... method get (line 23) | get(l,i){return l&&l.constructor===Object?this.where(l).first(i):this.... method where (line 23) | where(l){if(typeof l=="string")return new this.db.WhereClause(this,l);... method filter (line 23) | filter(l){return this.toCollection().and(l)} method count (line 23) | count(l){return this.toCollection().count(l)} method offset (line 23) | offset(l){return this.toCollection().offset(l)} method limit (line 23) | limit(l){return this.toCollection().limit(l)} method each (line 23) | each(l){return this.toCollection().each(l)} method toArray (line 23) | toArray(l){return this.toCollection().toArray(l)} method toCollection (line 23) | toCollection(){return new this.db.Collection(new this.db.WhereClause(t... method orderBy (line 23) | orderBy(l){return new this.db.Collection(new this.db.WhereClause(this,... method reverse (line 23) | reverse(){return this.toCollection().reverse()} method mapToClass (line 23) | mapToClass(l){this.schema.mappedClass=l;const i=s=>{if(!s)return s;con... method defineClass (line 23) | defineClass(){return this.mapToClass((function(l){Tt(this,l)}))} method add (line 23) | add(l,i){const{auto:s,keyPath:o}=this.schema.primKey;let f=l;return o&... method update (line 23) | update(l,i){if(typeof l!="object"||St(l))return this.where(":id").equa... method put (line 23) | put(l,i){const{auto:s,keyPath:o}=this.schema.primKey;let f=l;return o&... method delete (line 23) | delete(l){return this._trans("readwrite",(i=>this.core.mutate({trans:i... method clear (line 23) | clear(){return this._trans("readwrite",(l=>this.core.mutate({trans:l,t... method bulkGet (line 23) | bulkGet(l){return this._trans("readonly",(i=>this.core.getMany({keys:l... method bulkAdd (line 23) | bulkAdd(l,i,s){const o=Array.isArray(i)?i:void 0,f=(s=s||(o?void 0:i))... method bulkPut (line 23) | bulkPut(l,i,s){const o=Array.isArray(i)?i:void 0,f=(s=s||(o?void 0:i))... method bulkDelete (line 23) | bulkDelete(l){const i=l.length;return this._trans("readwrite",(s=>this... function ni (line 23) | function ni(u){var l={},i=function(h,m){if(m){for(var v=arguments.length... function $u (line 23) | function $u(u,l){return Gl(l).from({prototype:u}),l} function Kl (line 23) | function Kl(u,l){return!(u.filter||u.algorithm||u.or)&&(l?u.justLimit:!u... function Zo (line 23) | function Zo(u,l){u.filter=Ia(u.filter,l)} function Jo (line 23) | function Jo(u,l,i){var s=u.replayFilter;u.replayFilter=s?()=>Ia(s(),l())... function es (line 23) | function es(u,l){if(u.isPrimKey)return l.primaryKey;const i=l.getIndexBy... function Ap (line 23) | function Ap(u,l,i){const s=es(u,l.schema);return l.openCursor({trans:i,v... function Gr (line 23) | function Gr(u,l,i,s){const o=u.replayFilter?Ia(u.filter,u.replayFilter()... function Op (line 23) | function Op(u,l,i,s){var o=Ve(s?(f,h,m)=>i(s(f),h,m):i);return u.then((f... function Et (line 23) | function Et(u,l){try{const i=wp(u),s=wp(l);if(i!==s)return i==="Array"?1... function wp (line 23) | function wp(u){const l=typeof u;if(l!=="object")return l;if(ArrayBuffer.... function xp (line 23) | function xp(u){return u instanceof Uint8Array?u:ArrayBuffer.isView(u)?ne... class S1 (line 23) | class S1{_read(l,i){var s=this._ctx;return s.error?s.table._trans(null,r... method _read (line 23) | _read(l,i){var s=this._ctx;return s.error?s.table._trans(null,rt.bind(... method _write (line 23) | _write(l){var i=this._ctx;return i.error?i.table._trans(null,rt.bind(n... method _addAlgorithm (line 23) | _addAlgorithm(l){var i=this._ctx;i.algorithm=Ia(i.algorithm,l)} method _iterate (line 23) | _iterate(l,i){return Gr(this._ctx,l,i,this._ctx.table.core)} method clone (line 23) | clone(l){var i=Object.create(this.constructor.prototype),s=Object.crea... method raw (line 23) | raw(){return this._ctx.valueMapper=null,this} method each (line 23) | each(l){var i=this._ctx;return this._read((s=>Gr(i,l,s,i.table.core)))} method count (line 23) | count(l){return this._read((i=>{const s=this._ctx,o=s.table.core;if(Kl... method sortBy (line 23) | sortBy(l,i){const s=l.split(".").reverse(),o=s[0],f=s.length-1;functio... method toArray (line 23) | toArray(l){return this._read((i=>{var s=this._ctx;if(s.dir==="next"&&K... method offset (line 23) | offset(l){var i=this._ctx;return l<=0||(i.offset+=l,Kl(i)?Jo(i,(()=>{v... method limit (line 23) | limit(l){return this._ctx.limit=Math.min(this._ctx.limit,l),Jo(this._c... method until (line 23) | until(l,i){return Zo(this._ctx,(function(s,o,f){return!l(s.value)||(o(... method first (line 23) | first(l){return this.limit(1).toArray((function(i){return i[0]})).then... method last (line 23) | last(l){return this.reverse().first(l)} method filter (line 23) | filter(l){var i,s;return Zo(this._ctx,(function(o){return l(o.value)})... method and (line 23) | and(l){return this.filter(l)} method or (line 23) | or(l){return new this.db.WhereClause(this._ctx.table,l,this)} method reverse (line 23) | reverse(){return this._ctx.dir=this._ctx.dir==="prev"?"next":"prev",th... method desc (line 23) | desc(){return this.reverse()} method eachKey (line 23) | eachKey(l){var i=this._ctx;return i.keysOnly=!i.isMatch,this.each((fun... method eachUniqueKey (line 23) | eachUniqueKey(l){return this._ctx.unique="unique",this.eachKey(l)} method eachPrimaryKey (line 23) | eachPrimaryKey(l){var i=this._ctx;return i.keysOnly=!i.isMatch,this.ea... method keys (line 23) | keys(l){var i=this._ctx;i.keysOnly=!i.isMatch;var s=[];return this.eac... method primaryKeys (line 23) | primaryKeys(l){var i=this._ctx;if(i.dir==="next"&&Kl(i,!0)&&i.limit>0)... method uniqueKeys (line 23) | uniqueKeys(l){return this._ctx.unique="unique",this.keys(l)} method firstKey (line 23) | firstKey(l){return this.limit(1).keys((function(i){return i[0]})).then... method lastKey (line 23) | lastKey(l){return this.reverse().firstKey(l)} method distinct (line 23) | distinct(){var l=this._ctx,i=l.index&&l.table.schema.idxByName[l.index... method modify (line 23) | modify(l){var i=this._ctx;return this._write((s=>{var o;if(typeof l=="... method delete (line 23) | delete(){var l=this._ctx,i=l.range;return Kl(l)&&(l.isPrimKey&&!g1||i.... function _1 (line 23) | function _1(u,l){return ul?-1:u===l?0:1} function Yt (line 23) | function Yt(u,l,i){var s=u instanceof Ov?new u.Collection(u):u;return s.... function kl (line 23) | function kl(u){return new u.Collection(u,(()=>Av(""))).limit(0)} function T1 (line 23) | function T1(u,l,i,s,o,f){for(var h=Math.min(u.length,s.length),m=-1,v=0;... function Qr (line 23) | function Qr(u,l,i,s){var o,f,h,m,v,y,g,b=i.length;if(!i.every((E=>typeof... function pa (line 23) | function pa(u,l,i,s){return{type:2,lower:u,upper:l,lowerOpen:i,upperOpen... function Av (line 23) | function Av(u){return{type:1,lower:u,upper:u}} class Ov (line 23) | class Ov{get Collection(){return this._ctx.table.db.Collection}between(l... method Collection (line 23) | get Collection(){return this._ctx.table.db.Collection} method between (line 23) | between(l,i,s,o){s=s!==!1,o=o===!0;try{return this._cmp(l,i)>0||this._... method equals (line 23) | equals(l){return l==null?Yt(this,qn):new this.Collection(this,(()=>Av(... method above (line 23) | above(l){return l==null?Yt(this,qn):new this.Collection(this,(()=>pa(l... method aboveOrEqual (line 23) | aboveOrEqual(l){return l==null?Yt(this,qn):new this.Collection(this,((... method below (line 23) | below(l){return l==null?Yt(this,qn):new this.Collection(this,(()=>pa(v... method belowOrEqual (line 23) | belowOrEqual(l){return l==null?Yt(this,qn):new this.Collection(this,((... method startsWith (line 23) | startsWith(l){return typeof l!="string"?Yt(this,_v):this.between(l,l+X... method startsWithIgnoreCase (line 23) | startsWithIgnoreCase(l){return l===""?this.startsWith(l):Qr(this,((i,s... method equalsIgnoreCase (line 23) | equalsIgnoreCase(l){return Qr(this,((i,s)=>i===s[0]),[l],"")} method anyOfIgnoreCase (line 23) | anyOfIgnoreCase(){var l=Ln.apply(Yl,arguments);return l.length===0?kl(... method startsWithAnyOfIgnoreCase (line 23) | startsWithAnyOfIgnoreCase(){var l=Ln.apply(Yl,arguments);return l.leng... method anyOf (line 23) | anyOf(){const l=Ln.apply(Yl,arguments);let i=this._cmp;try{l.sort(i)}c... method notEqual (line 23) | notEqual(l){return this.inAnyRange([[pf,l],[l,this.db._maxKey]],{inclu... method noneOf (line 23) | noneOf(){const l=Ln.apply(Yl,arguments);if(l.length===0)return new thi... method inAnyRange (line 23) | inAnyRange(l,i){const s=this._cmp,o=this._ascending,f=this._descending... method startsWithAnyOf (line 23) | startsWithAnyOf(){const l=Ln.apply(Yl,arguments);return l.every((i=>ty... function mn (line 23) | function mn(u){return Ve((function(l){return si(l),u(l.target.error),!1}))} function si (line 23) | function si(u){u.stopPropagation&&u.stopPropagation(),u.preventDefault&&... class A1 (line 23) | class A1{_lock(){return Wu(!ie.global),++this._reculock,this._reculock!=... method _lock (line 23) | _lock(){return Wu(!ie.global),++this._reculock,this._reculock!==1||ie.... method _unlock (line 23) | _unlock(){if(Wu(!ie.global),--this._reculock==0)for(ie.global||(ie.loc... method _locked (line 23) | _locked(){return this._reculock&&ie.lockOwnerFor!==this} method create (line 23) | create(l){if(!this.mode)return this;const i=this.db.idbdb,s=this.db._s... method _promise (line 23) | _promise(l,i,s){if(l==="readwrite"&&this.mode!=="readwrite")return rt(... method _root (line 23) | _root(){return this.parent?this.parent._root():this} method waitFor (line 23) | waitFor(l){var i=this._root();const s=I.resolve(l);if(i._waitingFor)i.... method abort (line 23) | abort(){this.active&&(this.active=!1,this.idbtrans&&this.idbtrans.abor... method table (line 23) | table(l){const i=this._memoizedTables||(this._memoizedTables={});if(Gt... function vf (line 23) | function vf(u,l,i,s,o,f,h){return{name:u,keyPath:l,unique:i,multi:s,auto... function wv (line 23) | function wv(u){return typeof u=="string"?u:u?"["+[].join.call(u,"+")+"]"... function xv (line 23) | function xv(u,l,i){return{name:u,primKey:l,indexes:i,mappedClass:null,id... function gf (line 23) | function gf(u){return u==null?()=>{}:typeof u=="string"?(function(l){ret... function Rp (line 23) | function Rp(u){return[].slice.call(u)} function ai (line 23) | function ai(u){return u==null?":id":typeof u=="string"?u:`[${u.join("+")... function w1 (line 23) | function w1(u,l,i){function s(v){if(v.type===3)return null;if(v.type===4... function bf (line 23) | function bf({_novip:u},l){const i=l.db,s=(function(o,f,{IDBKeyRange:h,in... function fs (line 23) | function fs({_novip:u},l,i,s){i.forEach((o=>{const f=s[o];l.forEach((h=>... function Sf (line 23) | function Sf({_novip:u},l){l.forEach((i=>{for(let s in i)i[s]instanceof u... function x1 (line 23) | function x1(u,l){return u._cfg.version-l._cfg.version} function R1 (line 23) | function R1(u,l,i,s){const o=u._dbSchema,f=u._createTransaction("readwri... function Rv (line 23) | function Rv(u,l){const i={del:[],add:[],change:[]};let s;for(s in u)l[s]... function $o (line 23) | function $o(u,l,i,s){const o=u.db.createObjectStore(l,i.keyPath?{keyPath... function _f (line 23) | function _f(u,l){u.createIndex(l.name,l.keyPath,{unique:l.unique,multiEn... function Ef (line 23) | function Ef(u,l,i){const s={};return us(l.objectStoreNames,0).forEach((o... function Tf (line 23) | function Tf({_novip:u},l,i){const s=i.db.objectStoreNames;for(let o=0;o<... class j1 (line 23) | class j1{_parseStoresSpec(l,i){ut(l).forEach((s=>{if(l[s]!==null){var o=... method _parseStoresSpec (line 23) | _parseStoresSpec(l,i){ut(l).forEach((s=>{if(l[s]!==null){var o=l[s].sp... method stores (line 23) | stores(l){const i=this.db;this._cfg.storesSource=this._cfg.storesSourc... method upgrade (line 23) | upgrade(l){return this._cfg.contentUpgrade=Hf(this._cfg.contentUpgrade... function Yf (line 23) | function Yf(u,l){let i=u._dbNamesDB;return i||(i=u._dbNamesDB=new Fa(bs,... function Gf (line 23) | function Gf(u){return u&&typeof u.databases=="function"} function Af (line 23) | function Af(u){return ba((function(){return ie.letThrough=!0,u()}))} function N1 (line 23) | function N1(){var u;return!navigator.userAgentData&&/Safari\//.test(navi... function D1 (line 23) | function D1(u){const l=u._state,{indexedDB:i}=u._deps;if(l.isBeingOpened... function Of (line 23) | function Of(u){var l=f=>u.next(f),i=o(l),s=o((f=>u.throw(f)));function o... function C1 (line 23) | function C1(u,l,i){var s=arguments.length;if(s<2)throw new oe.InvalidArg... function jv (line 23) | function jv(u,l,i,s,o){return I.resolve().then((()=>{const f=ie.transles... function Xr (line 23) | function Xr(u,l,i){const s=St(u)?u.slice():[u];for(let o=0;o{if(Gt(l,o... method table (line 23) | table(l){const i=u.table(l),{primaryKey:s}=i.schema;return{...i,mutate(f... function Nv (line 23) | function Nv(u,l,i){try{if(!l||l.keys.length0)throw Range... function ds (line 23) | function ds(u,l){Xf(l)||(function i(s,{from:o,to:f,l:h,r:m}){fi(s,o,f),h... function B1 (line 23) | function B1(u,l){const i=wf(l);let s=i.next();if(s.done)return!1;let o=s... function wf (line 23) | function wf(u){let l=Xf(u)?null:{s:0,n:u};return{next(i){const s=argumen... function jp (line 23) | function jp(u){var l,i;const s=(((l=u.r)===null||l===void 0?void 0:l.d)|... function Np (line 23) | function Np({r:u,l}){return(u?l?Math.max(u.d,l.d):u.d:l?l.d:0)+1} method add (line 23) | add(u){return ds(this,u),this} method addKey (line 23) | addKey(u){return fi(this,u,u),this} method addKeys (line 23) | addKeys(u){return u.forEach((l=>fi(this,l,l))),this} method [lf] (line 23) | [lf](){return wf(this)} function ye (line 23) | function ye(Oe){const de=le(Oe.name||"");function Qe(V){return V!=null?O... method get (line 23) | get(){const le=X.primaryKey;return j.addKey(le),le} class Fa (line 23) | class Fa{constructor(l,i){this._middlewares={},this.verno=0;const s=Fa.d... method constructor (line 23) | constructor(l,i){this._middlewares={},this.verno=0;const s=Fa.dependen... method version (line 23) | version(l){if(isNaN(l)||l<.1)throw new oe.Type("Given version is not a... method _whenReady (line 23) | _whenReady(l){return this.idbdb&&(this._state.openComplete||ie.letThro... method use (line 23) | use({stack:l,create:i,level:s,name:o}){o&&this.unuse({stack:l,name:o})... method unuse (line 23) | unuse({stack:l,name:i,create:s}){return l&&this._middlewares[l]&&(this... method open (line 23) | open(){return D1(this)} method _close (line 23) | _close(){const l=this._state,i=ti.indexOf(this);if(i>=0&&ti.splice(i,1... method close (line 23) | close(){this._close();const l=this._state;this._options.autoOpen=!1,l.... method delete (line 23) | delete(){const l=arguments.length>0,i=this._state;return new I(((s,o)=... method backendDB (line 23) | backendDB(){return this.idbdb} method isOpen (line 23) | isOpen(){return this.idbdb!==null} method hasBeenClosed (line 23) | hasBeenClosed(){const l=this._state.dbOpenError;return l&&l.name==="Da... method hasFailed (line 23) | hasFailed(){return this._state.dbOpenError!==null} method dynamicallyOpened (line 23) | dynamicallyOpened(){return this._state.autoSchema} method tables (line 23) | get tables(){return ut(this._allTables).map((l=>this._allTables[l]))} method transaction (line 23) | transaction(){const l=C1.apply(this,arguments);return this._transactio... method _transaction (line 23) | _transaction(l,i,s){let o=ie.trans;o&&o.db===this&&l.indexOf("!")===-1... method table (line 23) | table(l){if(!Gt(this._allTables,l))throw new oe.InvalidTable(`Table ${... class L1 (line 23) | class L1{constructor(l){this._subscribe=l}subscribe(l,i,s){return this._... method constructor (line 23) | constructor(l){this._subscribe=l} method subscribe (line 23) | subscribe(l,i,s){return this._subscribe(l&&typeof l!="function"?l:{nex... method [H1] (line 23) | [H1](){return this} function Dv (line 23) | function Dv(u,l){return ut(l).forEach((i=>{ds(u[i]||(u[i]=new Hn),l[i])}... function K1 (line 23) | function K1(u){let l,i=!1;const s=new L1((o=>{const f=Mf(u);let h=!1,m={... function ts (line 23) | function ts(u){let l=Kn;try{Kn=!0,_a.storagemutated.fire(u)}finally{Kn=l}} method getDatabaseNames (line 23) | getDatabaseNames(u){try{return(function({indexedDB:l,IDBKeyRange:i}){ret... function k1 (line 23) | async function k1(){return ze.queue.where("status").equals("pending").co... function Y1 (line 23) | function Y1({apiClient:u,settings:l,onStatus:i,onToast:s,onRefresh:o}){l... function Q1 (line 23) | function Q1(){const[u,l]=be.useState(!0),[i,s]=be.useState("server"),[o,... function X1 (line 23) | function X1(){return T.jsxs("div",{className:"loading-screen",children:[... function V1 (line 23) | function V1(u){const{step:l,setStep:i,serverUrl:s,setServerUrl:o,usernam... function Z1 (line 23) | function Z1({activeView:u,onChange:l}){return T.jsxs("aside",{className:... function J1 (line 23) | function J1({connection:u,user:l,syncStatus:i,theme:s,setTheme:o,onSyncN... function F1 (line 23) | function F1({data:u,loading:l,onRefresh:i,onStart:s,onStop:o,syncStatus:... function $1 (line 23) | function $1({projects:u,filter:l,setFilter:i,loading:s}){return T.jsxs("... function W1 (line 23) | function W1({entries:u,filter:l,setFilter:i,onNew:s,loading:o}){return T... function Dp (line 23) | function Dp({title:u,items:l,loading:i}){return T.jsxs("div",{className:... function I1 (line 23) | function I1({workforce:u,loading:l}){const i=u?.periods?.periods||u?.per... function P1 (line 23) | function P1(u){const{serverUrl:l,setServerUrl:i,username:s,setUsername:o... function e_ (line 23) | function e_({projects:u,tasks:l,onClose:i,onSubmit:s}){const[o,f]=be.use... function t_ (line 23) | function t_({projects:u,tasks:l,onClose:i,onSubmit:s}){const[o,f]=be.use... function Cv (line 23) | function Cv({title:u,children:l,onClose:i}){return be.useEffect(()=>{con... function n_ (line 23) | function n_({diagnostics:u}){return T.jsxs("details",{className:"diagnos... function zv (line 23) | function zv({entries:u}){return u?.length?T.jsx("div",{className:"list-c... function Si (line 23) | function Si({title:u,subtitle:l,action:i}){return T.jsxs("div",{classNam... function ns (line 23) | function ns({title:u,action:l,children:i}){return T.jsxs("section",{clas... function Vl (line 23) | function Vl({label:u,value:l}){return T.jsxs("div",{className:"stat-card... function Vf (line 23) | function Vf({title:u,text:l}){return T.jsxs("div",{className:"empty-stat... function Uv (line 23) | function Uv(){return T.jsx("div",{className:"card-grid",children:[1,2,3]... function Mv (line 23) | function Mv(){return T.jsx("div",{className:"list-card",children:[1,2,3,... function Bv (line 23) | function Bv({connection:u}){return T.jsx("span",{className:`connection-p... function Zf (line 23) | function Zf({theme:u,setTheme:l,expanded:i}){return T.jsxs("label",{clas... function a_ (line 23) | function a_({toast:u}){return T.jsx("div",{className:`toast ${u.type}`,r... function l_ (line 23) | function l_(u){const l=Math.floor(u/3600),i=Math.floor(u%3600/60),s=u%60... function u_ (line 23) | function u_(u){if(!u)return"0m";const l=Math.floor(u/60),i=u%60;return l... FILE: desktop/src/main/main.js function parseCommandLineArgs (line 9) | function parseCommandLineArgs(args = process.argv.slice(1)) { function isLocalOrPrivateHost (line 50) | function isLocalOrPrivateHost(hostname) { function isUsableWindow (line 82) | function isUsableWindow(win) { function sendToMainWindow (line 86) | function sendToMainWindow(channel, payload) { function focusMainWindow (line 92) | function focusMainWindow() { function attachTray (line 99) | function attachTray(win) { function createMainWindow (line 111) | function createMainWindow(options = {}) { function formatDuration (line 241) | function formatDuration(seconds) { constant ALLOWED_STORE_KEYS (line 255) | const ALLOWED_STORE_KEYS = new Set([ function isAllowedStoreKey (line 265) | function isAllowedStoreKey(key) { FILE: desktop/src/main/tray.js constant FALLBACK_TRAY_PNG (line 8) | const FALLBACK_TRAY_PNG = Buffer.from( function loadTrayNativeImage (line 18) | function loadTrayNativeImage() { function createTray (line 36) | function createTray(mainWindow) { function destroyTray (line 134) | function destroyTray() { FILE: desktop/src/main/window.js function loadWindowState (line 15) | function loadWindowState() { function saveWindowState (line 28) | function saveWindowState() { function createWindow (line 39) | function createWindow(options = {}) { FILE: desktop/src/renderer-react/src/main.jsx function App (line 26) | function App() { function LoadingScreen (line 516) | function LoadingScreen() { function AuthFlow (line 527) | function AuthFlow(props) { function Sidebar (line 611) | function Sidebar({ activeView, onChange }) { function TopBar (line 637) | function TopBar({ connection, user, syncStatus, theme, setTheme, onSyncN... function DashboardView (line 656) | function DashboardView({ data, loading, onRefresh, onStart, onStop, sync... function ProjectsView (line 687) | function ProjectsView({ projects, filter, setFilter, loading }) { function EntriesView (line 708) | function EntriesView({ entries, filter, setFilter, onNew, loading }) { function SimpleListView (line 718) | function SimpleListView({ title, items, loading }) { function WorkforceView (line 736) | function WorkforceView({ workforce, loading }) { function SettingsView (line 753) | function SettingsView(props) { function StartTimerDialog (line 797) | function StartTimerDialog({ projects, tasks, onClose, onSubmit }) { function TimeEntryDialog (line 812) | function TimeEntryDialog({ projects, tasks, onClose, onSubmit }) { function Dialog (line 833) | function Dialog({ title, children, onClose }) { function DiagnosticsPanel (line 849) | function DiagnosticsPanel({ diagnostics }) { function EntryList (line 859) | function EntryList({ entries }) { function ViewHeader (line 876) | function ViewHeader({ title, subtitle, action }) { function Panel (line 880) | function Panel({ title, action, children }) { function StatCard (line 884) | function StatCard({ label, value }) { function EmptyState (line 888) | function EmptyState({ title, text }) { function SkeletonGrid (line 892) | function SkeletonGrid() { function SkeletonList (line 896) | function SkeletonList() { function ConnectionPill (line 900) | function ConnectionPill({ connection }) { function ThemeSwitch (line 904) | function ThemeSwitch({ theme, setTheme, expanded }) { function Toast (line 917) | function Toast({ toast }) { function formatDuration (line 921) | function formatDuration(totalSeconds) { function formatMinutes (line 929) | function formatMinutes(minutes) { FILE: desktop/src/renderer-react/src/services/api.js function normalizeServerUrlInput (line 4) | function normalizeServerUrlInput(value) { function isTlsRelatedError (line 11) | function isTlsRelatedError(error) { function classifyAxiosError (line 27) | function classifyAxiosError(error) { function isInfoPayload (line 63) | function isInfoPayload(data) { class ApiClient (line 67) | class ApiClient { method constructor (line 68) | constructor(baseUrl, token = null, options = {}) { method normalizeBaseUrl (line 86) | static normalizeBaseUrl(url) { method testPublicServerInfo (line 90) | static async testPublicServerInfo(baseUrl) { method loginWithPassword (line 123) | static async loginWithPassword(baseUrl, username, password) { method validateSession (line 141) | async validateSession() { method unwrap (line 160) | async unwrap(promise) { method getUsersMe (line 165) | getUsersMe() { return this.unwrap(this.client.get('/api/v1/users/me')); } method getTimerStatus (line 166) | getTimerStatus() { return this.unwrap(this.client.get('/api/v1/timer/s... method startTimer (line 167) | startTimer(data) { return this.unwrap(this.client.post('/api/v1/timer/... method stopTimer (line 168) | stopTimer() { return this.unwrap(this.client.post('/api/v1/timer/stop'... method getProjects (line 169) | getProjects(params = {}) { return this.unwrap(this.client.get('/api/v1... method getTasks (line 170) | getTasks(params = {}) { return this.unwrap(this.client.get('/api/v1/ta... method getTimeEntries (line 171) | getTimeEntries(params = {}) { return this.unwrap(this.client.get('/api... method createTimeEntry (line 172) | createTimeEntry(data) { return this.unwrap(this.client.post('/api/v1/t... method updateTimeEntry (line 173) | updateTimeEntry(id, data) { return this.unwrap(this.client.put(`/api/v... method deleteTimeEntry (line 174) | deleteTimeEntry(id) { return this.unwrap(this.client.delete(`/api/v1/t... method getInvoices (line 175) | getInvoices(params = {}) { return this.unwrap(this.client.get('/api/v1... method getExpenses (line 176) | getExpenses(params = {}) { return this.unwrap(this.client.get('/api/v1... method createExpense (line 177) | createExpense(data) { return this.unwrap(this.client.post('/api/v1/exp... method getCapacityReport (line 178) | getCapacityReport(params = {}) { return this.unwrap(this.client.get('/... method getTimesheetPeriods (line 179) | getTimesheetPeriods(params = {}) { return this.unwrap(this.client.get(... method getTimeOffRequests (line 180) | getTimeOffRequests(params = {}) { return this.unwrap(this.client.get('... FILE: desktop/src/renderer-react/src/services/diagnostics.js function buildDiagnostics (line 1) | function buildDiagnostics(serverUrl, result) { FILE: desktop/src/renderer-react/src/services/store.js function readLocal (line 3) | function readLocal(key) { function storeGet (line 14) | async function storeGet(key) { function storeSet (line 20) | async function storeSet(key, value) { function storeDelete (line 27) | async function storeDelete(key) { function storeClear (line 34) | async function storeClear() { FILE: desktop/src/renderer-react/src/sync/syncEngine.js function getQueueDepth (line 13) | async function getQueueDepth() { function createSyncEngine (line 17) | function createSyncEngine({ apiClient, settings, onStatus, onToast, onRe... FILE: desktop/src/renderer/js/api/client.js function isTlsRelatedError (line 11) | function isTlsRelatedError(error) { function classifyAxiosError (line 33) | function classifyAxiosError(error) { function isTimeTrackerInfoPayload (line 109) | function isTimeTrackerInfoPayload(data) { class ApiClient (line 121) | class ApiClient { method constructor (line 126) | constructor(baseUrl, options = {}) { method setupInterceptors (line 144) | setupInterceptors() { method normalizeBaseUrl (line 186) | static normalizeBaseUrl(url) { method testPublicServerInfo (line 198) | static async testPublicServerInfo(baseUrl) { method loginWithPassword (line 261) | static async loginWithPassword(baseUrl, username, password) { method setAuthToken (line 292) | async setAuthToken(token) { method validateSession (line 301) | async validateSession() { method validateToken (line 349) | async validateToken() { method getUsersMe (line 354) | async getUsersMe() { method getTimerStatus (line 359) | async getTimerStatus() { method startTimer (line 363) | async startTimer({ projectId, taskId, notes }) { method stopTimer (line 371) | async stopTimer() { method getTimeEntries (line 375) | async getTimeEntries({ projectId, startDate, endDate, billable, page, ... method createTimeEntry (line 387) | async createTimeEntry(data) { method updateTimeEntry (line 391) | async updateTimeEntry(id, data) { method deleteTimeEntry (line 395) | async deleteTimeEntry(id) { method getProjects (line 399) | async getProjects({ status, clientId, page, perPage }) { method getProject (line 409) | async getProject(id) { method getClients (line 413) | async getClients({ status, page, perPage }) { method getTasks (line 421) | async getTasks({ projectId, status, page, perPage }) { method getTask (line 431) | async getTask(id) { method getTimeEntry (line 435) | async getTimeEntry(id) { method getInvoices (line 439) | async getInvoices({ status, clientId, projectId, page, perPage }) { method getInvoice (line 450) | async getInvoice(id) { method createInvoice (line 454) | async createInvoice(data) { method updateInvoice (line 458) | async updateInvoice(id, data) { method getExpenses (line 462) | async getExpenses({ projectId, category, startDate, endDate, page, per... method createExpense (line 474) | async createExpense(data) { method getCapacityReport (line 478) | async getCapacityReport({ startDate, endDate }) { method getTimesheetPeriods (line 484) | async getTimesheetPeriods({ status, startDate, endDate }) { method submitTimesheetPeriod (line 492) | async submitTimesheetPeriod(periodId) { method approveTimesheetPeriod (line 496) | async approveTimesheetPeriod(periodId, { comment } = {}) { method rejectTimesheetPeriod (line 502) | async rejectTimesheetPeriod(periodId, { reason } = {}) { method deleteTimesheetPeriod (line 508) | async deleteTimesheetPeriod(periodId) { method getLeaveTypes (line 512) | async getLeaveTypes() { method getTimeOffRequests (line 516) | async getTimeOffRequests({ status, startDate, endDate }) { method createTimeOffRequest (line 524) | async createTimeOffRequest({ leaveTypeId, startDate, endDate, requeste... method getTimeOffBalances (line 536) | async getTimeOffBalances({ userId } = {}) { method approveTimeOffRequest (line 542) | async approveTimeOffRequest(requestId, { comment } = {}) { method rejectTimeOffRequest (line 548) | async rejectTimeOffRequest(requestId, { comment } = {}) { method deleteTimeOffRequest (line 554) | async deleteTimeOffRequest(requestId) { FILE: desktop/src/renderer/js/app.js function truncateUrl (line 28) | function truncateUrl(url, maxLen) { function initApp (line 36) | async function initApp() { function loadInitialData (line 120) | async function loadInitialData() { function setupTrayListeners (line 133) | function setupTrayListeners() { function startConnectionCheck (line 148) | function startConnectionCheck() { function checkConnection (line 158) | async function checkConnection() { function loadCurrentUserProfile (line 193) | async function loadCurrentUserProfile() { function updateConnectionFromManager (line 214) | function updateConnectionFromManager() { function forceRelogin (line 270) | async function forceRelogin(message) { function showWizardWelcomeStep (line 285) | function showWizardWelcomeStep() { function showWizardServerStep (line 295) | function showWizardServerStep() { function showWizardTokenStep (line 305) | function showWizardTokenStep() { function resetLoginWizard (line 315) | function resetLoginWizard() { function clearLoginError (line 324) | function clearLoginError() { function setupEventListeners (line 328) | function setupEventListeners() { function handleLoginTestServer (line 432) | async function handleLoginTestServer() { function handleLoginWizardContinue (line 457) | async function handleLoginWizardContinue() { function handleLoginWizardBack (line 483) | function handleLoginWizardBack() { function handleLogin (line 496) | async function handleLogin(e) { function showLoginError (line 535) | function showLoginError(message) { function showLoginScreen (line 546) | function showLoginScreen(options = {}) { function showMainScreen (line 602) | function showMainScreen() { function switchView (line 608) | function switchView(view) { function loadDashboard (line 642) | async function loadDashboard() { function loadRecentEntries (line 673) | async function loadRecentEntries() { function loadProjects (line 703) | async function loadProjects() { function selectProject (line 730) | function selectProject(projectId) { function loadTimeEntries (line 744) | async function loadTimeEntries() { function editTimeEntry (line 787) | function editTimeEntry(entryId) { function deleteTimeEntry (line 791) | async function deleteTimeEntry(entryId) { function handleStartTimer (line 807) | async function handleStartTimer() { function showStartTimerDialog (line 835) | async function showStartTimerDialog() { function handleStopTimer (line 970) | async function handleStopTimer() { function startTimerPolling (line 996) | function startTimerPolling() { function stopTimerPolling (line 1027) | function stopTimerPolling() { function updateTimerDisplay (line 1034) | function updateTimerDisplay(timer) { function loadInvoices (line 1075) | async function loadInvoices() { function renderInvoicePager (line 1096) | function renderInvoicePager() { function changeInvoicePage (line 1111) | async function changeInvoicePage(delta) { function renderInvoices (line 1120) | function renderInvoices() { function loadMoreInvoices (line 1162) | function loadMoreInvoices() { function loadExpenses (line 1167) | async function loadExpenses() { function renderExpensePager (line 1188) | function renderExpensePager() { function changeExpensePage (line 1203) | async function changeExpensePage(delta) { function renderExpenses (line 1212) | function renderExpenses() { function loadMoreExpenses (line 1248) | function loadMoreExpenses() { function loadWorkforce (line 1253) | async function loadWorkforce() { function renderWorkforce (line 1286) | function renderWorkforce() { function renderPeriods (line 1293) | function renderPeriods() { function renderCapacity (line 1325) | function renderCapacity() { function renderTimeOffRequests (line 1350) | function renderTimeOffRequests() { function loadMoreTimeOffRequests (line 1395) | function loadMoreTimeOffRequests() { function renderBalances (line 1400) | function renderBalances() { function showCreateInvoiceDialog (line 1422) | async function showCreateInvoiceDialog() { function submitTimesheetPeriodAction (line 1500) | async function submitTimesheetPeriodAction(periodId) { function reviewTimesheetPeriodAction (line 1512) | async function reviewTimesheetPeriodAction(periodId, approve) { function deleteTimesheetPeriodAction (line 1528) | async function deleteTimesheetPeriodAction(periodId) { function showCreateTimeOffDialog (line 1540) | async function showCreateTimeOffDialog() { function showCreateExpenseDialog (line 1628) | async function showCreateExpenseDialog() { function updateInvoiceStatusAction (line 1693) | async function updateInvoiceStatusAction(invoiceId, status) { function markInvoicePaidAction (line 1704) | async function markInvoicePaidAction(invoiceId, totalAmount) { function reviewTimeOffRequestAction (line 1720) | async function reviewTimeOffRequestAction(requestId, approve) { function deleteTimeOffRequestAction (line 1736) | async function deleteTimeOffRequestAction(requestId) { function loadSettings (line 1748) | async function loadSettings() { function updateSyncIntervalState (line 1779) | function updateSyncIntervalState() { function handleSaveSettings (line 1786) | async function handleSaveSettings() { function handleTestConnection (line 1842) | async function handleTestConnection() { function showSettingsMessage (line 1889) | function showSettingsMessage(message, type = 'info') { function handleLogout (line 1905) | async function handleLogout() { function handleResetConfiguration (line 1915) | async function handleResetConfiguration() { function safeInitApp (line 1932) | async function safeInitApp() { function toggleFilters (line 1957) | function toggleFilters() { function applyFilters (line 1964) | async function applyFilters() { function clearFilters (line 1975) | function clearFilters() { function loadProjectsForFilter (line 1984) | async function loadProjectsForFilter() { function showTimeEntryForm (line 2007) | async function showTimeEntryForm(entryId = null) { FILE: desktop/src/renderer/js/bundle.js method "src/renderer/js/utils/helpers.js" (line 9) | "src/renderer/js/utils/helpers.js"(exports, module) { method "node_modules/axios/dist/browser/axios.cjs" (line 94) | "node_modules/axios/dist/browser/axios.cjs"(exports, module) { method "src/shared/config.js" (line 2735) | "src/shared/config.js"(exports, module) { method "src/renderer/js/connection/request_policy.js" (line 2782) | "src/renderer/js/connection/request_policy.js"(exports, module) { method "src/renderer/js/api/client.js" (line 2819) | "src/renderer/js/api/client.js"(exports, module) { method "src/renderer/js/connection/connection_state.js" (line 3310) | "src/renderer/js/connection/connection_state.js"(exports, module) { method "src/renderer/js/connection/connection_manager.js" (line 3324) | "src/renderer/js/connection/connection_manager.js"(exports, module) { method "src/renderer/js/connection/timer_operations.js" (line 3728) | "src/renderer/js/connection/timer_operations.js"(exports, module) { method "src/renderer/js/ui/notifications.js" (line 3791) | "src/renderer/js/ui/notifications.js"(exports, module) { method "src/renderer/js/state.js" (line 3832) | "src/renderer/js/state.js"(exports, module) { function truncateUrl (line 3883) | function truncateUrl(url, maxLen) { function initApp (line 3889) | async function initApp() { function loadInitialData (line 3960) | async function loadInitialData() { function setupTrayListeners (line 3972) | function setupTrayListeners() { function startConnectionCheck (line 3983) | function startConnectionCheck() { function checkConnection (line 3989) | async function checkConnection() { function loadCurrentUserProfile (line 4020) | async function loadCurrentUserProfile() { function updateConnectionFromManager (line 4040) | function updateConnectionFromManager() { function forceRelogin (line 4091) | async function forceRelogin(message) { function showWizardWelcomeStep (line 4105) | function showWizardWelcomeStep() { function showWizardServerStep (line 4114) | function showWizardServerStep() { function showWizardTokenStep (line 4123) | function showWizardTokenStep() { function resetLoginWizard (line 4132) | function resetLoginWizard() { function clearLoginError (line 4140) | function clearLoginError() { function setupEventListeners (line 4143) | function setupEventListeners() { function handleLoginTestServer (line 4230) | async function handleLoginTestServer() { function handleLoginWizardContinue (line 4254) | async function handleLoginWizardContinue() { function handleLoginWizardBack (line 4278) | function handleLoginWizardBack() { function handleLogin (line 4290) | async function handleLogin(e) { function showLoginError (line 4324) | function showLoginError(message) { function showLoginScreen (line 4334) | function showLoginScreen(options = {}) { function showMainScreen (line 4383) | function showMainScreen() { function switchView (line 4388) | function switchView(view) { function loadDashboard (line 4415) | async function loadDashboard() { function loadRecentEntries (line 4438) | async function loadRecentEntries() { function loadProjects (line 4464) | async function loadProjects() { function loadTimeEntries (line 4492) | async function loadTimeEntries() { function handleStartTimer (line 4530) | async function handleStartTimer() { function showStartTimerDialog (line 4554) | async function showStartTimerDialog() { function handleStopTimer (line 4671) | async function handleStopTimer() { function startTimerPolling (line 4693) | function startTimerPolling() { function stopTimerPolling (line 4721) | function stopTimerPolling() { function updateTimerDisplay (line 4727) | function updateTimerDisplay(timer) { function loadInvoices (line 4757) | async function loadInvoices() { function renderInvoicePager (line 4776) | function renderInvoicePager() { function changeInvoicePage (line 4790) | async function changeInvoicePage(delta) { function renderInvoices (line 4798) | function renderInvoices() { function loadExpenses (line 4835) | async function loadExpenses() { function renderExpensePager (line 4854) | function renderExpensePager() { function changeExpensePage (line 4868) | async function changeExpensePage(delta) { function renderExpenses (line 4876) | function renderExpenses() { function loadWorkforce (line 4907) | async function loadWorkforce() { function renderWorkforce (line 4935) | function renderWorkforce() { function renderPeriods (line 4941) | function renderPeriods() { function renderCapacity (line 4964) | function renderCapacity() { function renderTimeOffRequests (line 4988) | function renderTimeOffRequests() { function renderBalances (line 5026) | function renderBalances() { function showCreateInvoiceDialog (line 5047) | async function showCreateInvoiceDialog() { function showCreateTimeOffDialog (line 5122) | async function showCreateTimeOffDialog() { function showCreateExpenseDialog (line 5207) | async function showCreateExpenseDialog() { function loadSettings (line 5271) | async function loadSettings() { function updateSyncIntervalState (line 5298) | function updateSyncIntervalState() { function handleSaveSettings (line 5304) | async function handleSaveSettings() { function handleTestConnection (line 5353) | async function handleTestConnection() { function showSettingsMessage (line 5394) | function showSettingsMessage(message, type = "info") { function handleLogout (line 5406) | async function handleLogout() { function handleResetConfiguration (line 5415) | async function handleResetConfiguration() { function safeInitApp (line 5428) | async function safeInitApp() { function toggleFilters (line 5449) | function toggleFilters() { function applyFilters (line 5455) | async function applyFilters() { function clearFilters (line 5462) | function clearFilters() { function loadProjectsForFilter (line 5469) | async function loadProjectsForFilter() { function showTimeEntryForm (line 5488) | async function showTimeEntryForm(entryId = null) { FILE: desktop/src/renderer/js/connection/connection_manager.js constant STORE_SERVER (line 4) | const STORE_SERVER = 'server_url'; constant STORE_TOKEN (line 5) | const STORE_TOKEN = 'api_token'; constant STORE_TOKEN_SERVER (line 6) | const STORE_TOKEN_SERVER = 'api_token_server_url'; constant STORE_USERNAME (line 7) | const STORE_USERNAME = 'username'; function createConnectionManager (line 19) | function createConnectionManager(deps) { FILE: desktop/src/renderer/js/connection/connection_state.js constant CONNECTION_STATE (line 2) | const CONNECTION_STATE = { FILE: desktop/src/renderer/js/connection/request_policy.js constant SAFE_METHODS (line 6) | const SAFE_METHODS = new Set(['get', 'head']); function isRetryableTransportOrServer (line 8) | function isRetryableTransportOrServer(error) { function attachIdempotentRetryInterceptors (line 21) | function attachIdempotentRetryInterceptors(axiosInstance, options = {}) { FILE: desktop/src/renderer/js/connection/timer_operations.js function startTimerWithReconcile (line 13) | async function startTimerWithReconcile(apiClient, payload) { function stopTimerWithReconcile (line 46) | async function stopTimerWithReconcile(apiClient) { FILE: desktop/src/renderer/js/state.js function clearViewCaches (line 28) | function clearViewCaches() { FILE: desktop/src/renderer/js/storage/storage.js class TimeTrackerDB (line 6) | class TimeTrackerDB extends Dexie { method constructor (line 7) | constructor() { method saveTimeEntry (line 24) | async saveTimeEntry(entry) { method getTimeEntries (line 28) | async getTimeEntries(filters = {}) { method deleteTimeEntry (line 44) | async deleteTimeEntry(id) { method saveProject (line 49) | async saveProject(project) { method getProjects (line 53) | async getProjects(filters = {}) { method deleteProject (line 63) | async deleteProject(id) { method saveTask (line 68) | async saveTask(task) { method getTasks (line 72) | async getTasks(filters = {}) { method addToSyncQueue (line 86) | async addToSyncQueue(type, action, data) { method getSyncQueue (line 95) | async getSyncQueue() { method removeFromSyncQueue (line 99) | async removeFromSyncQueue(id) { method clearSyncQueue (line 103) | async clearSyncQueue() { method clearAll (line 108) | async clearAll() { FILE: desktop/src/renderer/js/ui/notifications.js function showError (line 5) | function showError(message) { function showSuccess (line 22) | function showSuccess(message) { FILE: desktop/src/renderer/js/utils/helpers.js function formatDuration (line 3) | function formatDuration(seconds) { function formatDurationLong (line 14) | function formatDurationLong(seconds) { function formatDate (line 22) | function formatDate(date) { function formatDateTime (line 29) | function formatDateTime(date) { function parseISODate (line 36) | function parseISODate(dateString) { function isValidUrl (line 40) | function isValidUrl(string) { function normalizeServerUrlInput (line 50) | function normalizeServerUrlInput(input) { function debounce (line 57) | function debounce(func, wait) { FILE: desktop/src/shared/config.js function readLocalStorageJson (line 6) | function readLocalStorageJson(key) { function initStore (line 19) | function initStore() { FILE: desktop/test/connection_manager.test.js function memoryStore (line 5) | function memoryStore() { FILE: desktop/test/timer_operations.test.js method startTimer (line 15) | async startTimer() { method getTimerStatus (line 20) | async getTimerStatus() { method stopTimer (line 32) | async stopTimer() { method stopTimer (line 44) | async stopTimer() { method getTimerStatus (line 49) | async getTimerStatus() { FILE: docker/entrypoint.py function log (line 15) | def log(message): function wait_for_database (line 21) | def wait_for_database(): function run_migrations (line 87) | def run_migrations(): function main (line 197) | def main(): FILE: docker/fix-all-column-issues.py function main (line 14) | def main(): FILE: docker/fix-all-issues.py function fix_database_schema (line 15) | def fix_database_schema(engine): function fix_file_permissions (line 102) | def fix_file_permissions(): function main (line 155) | def main(): FILE: docker/fix-column-name-mismatch.py function main (line 11) | def main(): FILE: docker/fix-docker-permissions.py function run_command (line 14) | def run_command(cmd, description): function get_user_info (line 44) | def get_user_info(): function fix_docker_permissions (line 62) | def fix_docker_permissions(): function main (line 205) | def main(): FILE: docker/fix-duplicate-columns.py function main (line 11) | def main(): FILE: docker/fix-invoice-tables.py function main (line 11) | def main(): FILE: docker/fix-invoices-now.py function main (line 11) | def main(): FILE: docker/fix-permissions-aggressive.py function run_command (line 13) | def run_command(cmd, description): function fix_permissions_aggressive (line 43) | def fix_permissions_aggressive(): function main (line 151) | def main(): FILE: docker/fix-schema.py function fix_schema (line 11) | def fix_schema(): FILE: docker/fix-settings-table.py function main (line 11) | def main(): FILE: docker/fix-upload-permissions.py function main (line 11) | def main(): FILE: docker/force-schema-update.py function wait_for_database (line 12) | def wait_for_database(url, max_attempts=30, delay=2): function force_schema_update (line 33) | def force_schema_update(engine): function main (line 98) | def main(): FILE: docker/init-database-enhanced.py function log (line 14) | def log(message, level="INFO"): function wait_for_database (line 26) | def wait_for_database(url, max_attempts=30, delay=2): function get_required_schema (line 47) | def get_required_schema(): function create_table_if_not_exists (line 232) | def create_table_if_not_exists(engine, table_name, table_schema): function create_indexes (line 284) | def create_indexes(engine, table_name, table_schema): function create_triggers (line 307) | def create_triggers(engine): function insert_initial_data (line 347) | def insert_initial_data(engine): function verify_database_schema (line 441) | def verify_database_schema(engine): function main (line 480) | def main(): FILE: docker/init-database-simple.py function wait_for_database (line 12) | def wait_for_database(url, max_attempts=30, delay=2): function ensure_correct_schema (line 33) | def ensure_correct_schema(engine): function main (line 98) | def main(): FILE: docker/init-database-sql.py function wait_for_database (line 12) | def wait_for_database(url, max_attempts=30, delay=2): function create_tables_sql (line 33) | def create_tables_sql(engine): function create_indexes (line 183) | def create_indexes(engine): function create_triggers (line 206) | def create_triggers(engine): function insert_initial_data (line 259) | def insert_initial_data(engine): function verify_tables (line 355) | def verify_tables(engine): function main (line 377) | def main(): FILE: docker/init-database.py function wait_for_database (line 15) | def wait_for_database(url, max_attempts=30, delay=2): function check_database_initialization (line 36) | def check_database_initialization(engine): function check_table_schema (line 83) | def check_table_schema(engine, table_name, required_columns): function ensure_correct_schema (line 102) | def ensure_correct_schema(engine): function initialize_database (line 124) | def initialize_database(engine): function main (line 226) | def main(): FILE: docker/init.sql type users (line 8) | CREATE TABLE IF NOT EXISTS users ( type projects (line 18) | CREATE TABLE IF NOT EXISTS projects ( type time_entries (line 33) | CREATE TABLE IF NOT EXISTS time_entries ( type settings (line 48) | CREATE TABLE IF NOT EXISTS settings ( type idx_time_entries_user_id (line 64) | CREATE INDEX IF NOT EXISTS idx_time_entries_user_id ON time_entries(user... type idx_time_entries_project_id (line 65) | CREATE INDEX IF NOT EXISTS idx_time_entries_project_id ON time_entries(p... type idx_time_entries_start_time (line 66) | CREATE INDEX IF NOT EXISTS idx_time_entries_start_time ON time_entries(s... function update_updated_at_column (line 87) | CREATE OR REPLACE FUNCTION update_updated_at_column() FILE: docker/migrate-add-company-branding.py function main (line 11) | def main(): function create_settings_table (line 47) | def create_settings_table(engine): function add_company_branding_fields (line 71) | def add_company_branding_fields(engine, existing_columns): function add_invoice_default_fields (line 95) | def add_invoice_default_fields(engine, existing_columns): FILE: docker/migrate-add-missing-settings-columns.py function wait_for_database (line 12) | def wait_for_database(url, max_attempts=30, delay=2): function add_missing_columns (line 33) | def add_missing_columns(engine): function verify_columns (line 70) | def verify_columns(engine): function update_existing_settings (line 100) | def update_existing_settings(engine): function main (line 134) | def main(): FILE: docker/migrate-add-project-costs.py function get_db_connection (line 15) | def get_db_connection(): function table_exists (line 25) | def table_exists(cursor, table_name): function migrate (line 36) | def migrate(): FILE: docker/migrate-add-task-columns.py function wait_for_database (line 12) | def wait_for_database(url, max_attempts=30, delay=2): function migrate_task_management (line 33) | def migrate_task_management(engine): function main (line 146) | def main(): FILE: docker/migrate-add-tasks.py function migrate_database (line 15) | def migrate_database(): FILE: docker/migrate-avatar-storage.py function get_old_avatar_dir (line 29) | def get_old_avatar_dir(): function get_new_avatar_dir (line 43) | def get_new_avatar_dir(): function ensure_directory (line 48) | def ensure_directory(path): function migrate_avatars (line 54) | def migrate_avatars(): function verify_migration (line 147) | def verify_migration(): FILE: docker/migrate-field-names.py function wait_for_database (line 11) | def wait_for_database(url, max_attempts=30, delay=2): function check_migration_needed (line 32) | def check_migration_needed(engine): function migrate_database (line 61) | def migrate_database(engine): function verify_migration (line 110) | def verify_migration(engine): function main (line 133) | def main(): FILE: docker/migrate-logo-upload.py function migrate_logo_system (line 11) | def migrate_logo_system(): function create_uploads_directories (line 170) | def create_uploads_directories(): FILE: docker/start-enhanced.py function wait_for_database (line 13) | def wait_for_database(): function run_script (line 18) | def run_script(script_path, description): function display_network_info (line 44) | def display_network_info(): function main (line 59) | def main(): FILE: docker/start-fixed.py function _truthy (line 15) | def _truthy(v: str) -> bool: function _sqlite_path_from_url (line 19) | def _sqlite_path_from_url(db_url: str): function wait_for_database (line 39) | def wait_for_database(): function detect_corrupted_database_state (line 106) | def detect_corrupted_database_state(app): function cleanup_corrupted_database_state (line 172) | def cleanup_corrupted_database_state(app): function run_migrations (line 255) | def run_migrations(): function verify_core_tables (line 399) | def verify_core_tables(app): function ensure_default_data (line 494) | def ensure_default_data(app): function display_network_info (line 570) | def display_network_info(): function log (line 590) | def log(message, level="INFO"): function main (line 602) | def main(): FILE: docker/start.py function main (line 12) | def main(): FILE: docker/startup_with_migration.py function wait_for_database (line 40) | def wait_for_database(db_url, max_retries=60, retry_delay=3): function detect_database_state (line 67) | def detect_database_state(db_url): function choose_migration_strategy (line 144) | def choose_migration_strategy(db_state, existing_tables): function execute_migration_strategy (line 164) | def execute_migration_strategy(strategy, db_url): function execute_fresh_init (line 182) | def execute_fresh_init(db_url): function execute_check_migrations (line 210) | def execute_check_migrations(db_url): function execute_comprehensive_migration (line 273) | def execute_comprehensive_migration(db_url): function execute_manual_migration (line 296) | def execute_manual_migration(db_url): function verify_database_integrity (line 323) | def verify_database_integrity(db_url): function main (line 385) | def main(): FILE: docker/test-database-complete.py function wait_for_database (line 12) | def wait_for_database(url, max_attempts=30, delay=2): function verify_table_exists (line 33) | def verify_table_exists(engine, table_name, description=""): function verify_table_schema (line 49) | def verify_table_schema(engine, table_name, required_columns): function main (line 71) | def main(): FILE: docker/test-db-simple.py function test_database_connection (line 11) | def test_database_connection(): FILE: docker/test-db.py function test_database (line 11) | def test_database(): FILE: docker/test-packages.py function check_package (line 11) | def check_package(package_name): function check_library (line 22) | def check_library(library_name): function main (line 33) | def main(): FILE: docker/test-pdf-generation.py function test_weasyprint (line 10) | def test_weasyprint(): function test_reportlab (line 23) | def test_reportlab(): function test_system_libraries (line 38) | def test_system_libraries(): function main (line 59) | def main(): FILE: docker/test-permissions.py function get_user_info (line 12) | def get_user_info(): function check_directory_permissions (line 31) | def check_directory_permissions(path, description): function main (line 94) | def main(): FILE: docker/test-routing.py function test_imports (line 13) | def test_imports(): function test_blueprint_routes (line 24) | def test_blueprint_routes(): function test_url_generation (line 62) | def test_url_generation(): function main (line 105) | def main(): FILE: docker/test-schema-fixed.py function test_schema (line 10) | def test_schema(): FILE: docker/test-schema.py function test_schema (line 10) | def test_schema(): FILE: docker/test_db_connection.py function test_postgresql_connection (line 13) | def test_postgresql_connection(db_url): function test_sqlite_connection (line 57) | def test_sqlite_connection(db_url): function main (line 99) | def main(): FILE: docker/verify-database.py function get_expected_schema (line 12) | def get_expected_schema(): function check_table_exists (line 59) | def check_table_exists(engine, table_name): function check_table_columns (line 69) | def check_table_columns(engine, table_name, expected_columns, required_c... function check_table_indexes (line 97) | def check_table_indexes(engine, table_name, expected_indexes): function check_foreign_keys (line 118) | def check_foreign_keys(engine, table_name, expected_fks): function check_data_integrity (line 139) | def check_data_integrity(engine): function main (line 171) | def main(): FILE: migrations/add_analytics_setting.py function migrate_sqlite (line 10) | def migrate_sqlite(): function migrate_postgres (line 40) | def migrate_postgres(): function main (line 77) | def main(): FILE: migrations/add_project_costs.sql type project_costs (line 7) | CREATE TABLE IF NOT EXISTS project_costs ( type ix_project_costs_project_id (line 26) | CREATE INDEX IF NOT EXISTS ix_project_costs_project_id ON project_costs(... type ix_project_costs_user_id (line 27) | CREATE INDEX IF NOT EXISTS ix_project_costs_user_id ON project_costs(use... type ix_project_costs_cost_date (line 28) | CREATE INDEX IF NOT EXISTS ix_project_costs_cost_date ON project_costs(c... type ix_project_costs_invoice_id (line 29) | CREATE INDEX IF NOT EXISTS ix_project_costs_invoice_id ON project_costs(... FILE: migrations/ensure_uploads_persistence.py function ensure_uploads_directories (line 18) | def ensure_uploads_directories(): function verify_docker_volume_config (line 113) | def verify_docker_volume_config(): function main (line 139) | def main(): FILE: migrations/env.py function run_migrations_offline (line 36) | def run_migrations_offline(): function run_migrations_online (line 57) | def run_migrations_online(): FILE: migrations/fix_invoice_currency.py function fix_invoice_currencies (line 16) | def fix_invoice_currencies(): FILE: migrations/fix_invoice_pdf_template_items_source.py function fix_invoice_pdf_templates (line 23) | def fix_invoice_pdf_templates(): FILE: migrations/legacy_schema_migration.py function migrate_legacy_schema (line 11) | def migrate_legacy_schema(): function migrate_projects_table (line 50) | def migrate_projects_table(db): function migrate_settings_table (line 112) | def migrate_settings_table(db): function create_migration_baseline (line 139) | def create_migration_baseline(): function main (line 179) | def main(): FILE: migrations/manage_migrations.py function run_command (line 13) | def run_command(command, description): function check_flask_migrate_installed (line 47) | def check_flask_migrate_installed(): function initialize_migrations (line 58) | def initialize_migrations(): function create_initial_migration (line 69) | def create_initial_migration(): function apply_migrations (line 80) | def apply_migrations(): function show_migration_status (line 84) | def show_migration_status(): function show_migration_history (line 88) | def show_migration_history(): function backup_database (line 92) | def backup_database(): function main (line 119) | def main(): FILE: migrations/migrate_existing_database.py function run_command (line 17) | def run_command(command, description, capture_output=True): function check_flask_migrate_installed (line 55) | def check_flask_migrate_installed(): function detect_database_type (line 66) | def detect_database_type(): function backup_database (line 83) | def backup_database(db_type, db_url): function analyze_existing_schema (line 130) | def analyze_existing_schema(db_type, db_url): function create_migration_strategy (line 208) | def create_migration_strategy(existing_tables, table_schemas): function initialize_flask_migrate (line 232) | def initialize_flask_migrate(): function create_initial_migration (line 243) | def create_initial_migration(): function stamp_database_with_current_revision (line 254) | def stamp_database_with_current_revision(): function apply_migrations (line 259) | def apply_migrations(): function verify_migration_success (line 263) | def verify_migration_success(): function create_data_migration_script (line 288) | def create_data_migration_script(existing_tables, table_schemas): function main (line 324) | def main(): FILE: migrations/migrate_to_client_model.py function migrate_to_client_model (line 22) | def migrate_to_client_model(): FILE: migrations/migration_019_kanban_columns.py function upgrade (line 12) | def upgrade(): function downgrade (line 68) | def downgrade(): FILE: migrations/test_migration_system.py function test_flask_migrate_installation (line 11) | def test_flask_migrate_installation(): function test_database_connection (line 21) | def test_database_connection(): function test_migration_files (line 36) | def test_migration_files(): function test_migration_commands (line 59) | def test_migration_commands(): function test_models_import (line 74) | def test_models_import(): function test_migration_scripts (line 84) | def test_migration_scripts(): function run_comprehensive_test (line 101) | def run_comprehensive_test(): function main (line 133) | def main(): FILE: migrations/versions/001_initial_schema.py function upgrade (line 19) | def upgrade(): function downgrade (line 178) | def downgrade(): FILE: migrations/versions/002_add_user_full_name.py function upgrade (line 18) | def upgrade(): function downgrade (line 46) | def downgrade(): FILE: migrations/versions/003_add_user_theme_preference.py function upgrade (line 11) | def upgrade(): function downgrade (line 16) | def downgrade(): FILE: migrations/versions/004_add_task_activities_table.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 74) | def downgrade() -> None: FILE: migrations/versions/005_add_missing_columns.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 47) | def downgrade() -> None: FILE: migrations/versions/006_add_logo_and_task_timestamps.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 43) | def downgrade() -> None: FILE: migrations/versions/007_add_invoice_and_more_settings_columns.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 55) | def downgrade() -> None: FILE: migrations/versions/008_align_invoices_and_settings_more.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 72) | def downgrade() -> None: FILE: migrations/versions/009_add_invoice_created_by.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 51) | def downgrade() -> None: FILE: migrations/versions/010_enforce_single_active_timer.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 63) | def downgrade() -> None: FILE: migrations/versions/011_add_user_preferred_language.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 30) | def downgrade() -> None: FILE: migrations/versions/012_add_pdf_template_fields.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 31) | def downgrade() -> None: FILE: migrations/versions/013_add_comments_table.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 69) | def downgrade() -> None: FILE: migrations/versions/014_add_payment_tracking.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 120) | def downgrade() -> None: FILE: migrations/versions/015_add_user_oidc_fields.py function _has_column (line 19) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_constraint (line 23) | def _has_constraint(inspector, table_name: str, constraint_name: str) ->... function upgrade (line 31) | def upgrade() -> None: function downgrade (line 66) | def downgrade() -> None: FILE: migrations/versions/016_add_focus_recurring_rates_filters_and_project_budget.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 113) | def downgrade() -> None: FILE: migrations/versions/017_reporting_invoicing_extensions.py function _has_table (line 19) | def _has_table(inspector, name: str) -> bool: function upgrade (line 26) | def upgrade() -> None: function downgrade (line 183) | def downgrade() -> None: FILE: migrations/versions/018_add_project_costs_table.py function _has_table (line 19) | def _has_table(inspector, name: str) -> bool: function upgrade (line 27) | def upgrade() -> None: function downgrade (line 113) | def downgrade() -> None: FILE: migrations/versions/019_add_kanban_columns_table.py function upgrade (line 19) | def upgrade(): function downgrade (line 56) | def downgrade(): FILE: migrations/versions/020_add_user_avatar.py function _has_column (line 19) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 23) | def upgrade() -> None: function downgrade (line 34) | def downgrade() -> None: FILE: migrations/versions/021_add_extra_goods_table.py function _has_table (line 19) | def _has_table(inspector, name: str) -> bool: function upgrade (line 27) | def upgrade() -> None: function downgrade (line 143) | def downgrade() -> None: FILE: migrations/versions/022_add_project_code_field.py function upgrade (line 19) | def upgrade(): function downgrade (line 65) | def downgrade(): FILE: migrations/versions/023_add_user_favorite_projects.py function upgrade (line 20) | def upgrade(): function downgrade (line 48) | def downgrade(): FILE: migrations/versions/024_add_client_notes_table.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 50) | def downgrade() -> None: FILE: migrations/versions/026_add_project_archiving_metadata.py function upgrade (line 20) | def upgrade(): function downgrade (line 73) | def downgrade(): FILE: migrations/versions/027_add_user_time_rounding_preferences.py function upgrade (line 19) | def upgrade(): function downgrade (line 51) | def downgrade(): FILE: migrations/versions/028_add_weekly_time_goals.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 58) | def downgrade() -> None: FILE: migrations/versions/029_add_expenses_table.py function _has_table (line 19) | def _has_table(inspector, name: str) -> bool: function upgrade (line 27) | def upgrade() -> None: function downgrade (line 161) | def downgrade() -> None: FILE: migrations/versions/030_add_permission_system.py function upgrade (line 21) | def upgrade(): function seed_permissions_and_roles (line 112) | def seed_permissions_and_roles(): function downgrade (line 374) | def downgrade(): FILE: migrations/versions/031_add_standard_hours_per_day.py function upgrade (line 18) | def upgrade(): function downgrade (line 48) | def downgrade(): FILE: migrations/versions/032_add_api_tokens.py function upgrade (line 19) | def upgrade(): function downgrade (line 75) | def downgrade(): FILE: migrations/versions/033_add_email_settings.py function upgrade (line 19) | def upgrade(): function downgrade (line 51) | def downgrade(): FILE: migrations/versions/034_add_calendar_events_table.py function upgrade (line 19) | def upgrade(): function downgrade (line 104) | def downgrade(): FILE: migrations/versions/035_enhance_payments_table.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 101) | def downgrade() -> None: FILE: migrations/versions/036_add_pdf_design_json.py function upgrade (line 19) | def upgrade() -> None: function downgrade (line 29) | def downgrade() -> None: FILE: migrations/versions/037_advanced_expenses.py function upgrade (line 19) | def upgrade(): function downgrade (line 275) | def downgrade(): FILE: migrations/versions/038_fix_advanced_expenses_schema.py function upgrade (line 19) | def upgrade(): function downgrade (line 286) | def downgrade(): FILE: migrations/versions/039_add_budget_alerts_table.py function upgrade (line 19) | def upgrade(): function downgrade (line 56) | def downgrade(): FILE: migrations/versions/040_add_import_export_tables.py function upgrade (line 20) | def upgrade(): function downgrade (line 81) | def downgrade(): FILE: migrations/versions/041_add_invoice_pdf_templates_table.py function upgrade (line 20) | def upgrade(): function downgrade (line 89) | def downgrade(): FILE: migrations/versions/042_client_prepaid_hours.py function upgrade (line 19) | def upgrade(): function downgrade (line 83) | def downgrade(): FILE: migrations/versions/043_add_project_id_to_kanban_columns.py function upgrade (line 20) | def upgrade(): function downgrade (line 101) | def downgrade(): FILE: migrations/versions/044_add_audit_logs_table.py function upgrade (line 20) | def upgrade(): function downgrade (line 92) | def downgrade(): FILE: migrations/versions/045_add_recurring_invoices_and_email_tracking.py function upgrade (line 20) | def upgrade(): function downgrade (line 123) | def downgrade(): FILE: migrations/versions/046_add_webhooks_system.py function upgrade (line 20) | def upgrade(): function downgrade (line 149) | def downgrade(): FILE: migrations/versions/047_add_client_portal_fields.py function upgrade (line 19) | def upgrade(): function downgrade (line 63) | def downgrade(): FILE: migrations/versions/048_add_client_portal_credentials.py function upgrade (line 19) | def upgrade(): function downgrade (line 70) | def downgrade(): FILE: migrations/versions/049_add_client_password_setup_token.py function upgrade (line 19) | def upgrade(): function downgrade (line 78) | def downgrade(): FILE: migrations/versions/050_add_offers_table.py function upgrade (line 19) | def upgrade(): function downgrade (line 116) | def downgrade(): FILE: migrations/versions/051_rename_offers_to_quotes_and_add_features.py function upgrade (line 19) | def upgrade(): function downgrade (line 300) | def downgrade(): FILE: migrations/versions/052_add_quote_discount_fields.py function upgrade (line 19) | def upgrade(): function downgrade (line 39) | def downgrade(): FILE: migrations/versions/053_add_quote_payment_terms.py function upgrade (line 18) | def upgrade(): function downgrade (line 48) | def downgrade(): FILE: migrations/versions/054_add_quote_comments.py function upgrade (line 18) | def upgrade(): function downgrade (line 58) | def downgrade(): FILE: migrations/versions/055_add_quote_attachments.py function upgrade (line 18) | def upgrade(): function downgrade (line 68) | def downgrade(): FILE: migrations/versions/056_add_quote_approval_workflow.py function column_exists (line 19) | def column_exists(table_name, column_name): function index_exists (line 27) | def index_exists(table_name, index_name): function constraint_exists (line 35) | def constraint_exists(table_name, constraint_name): function upgrade (line 43) | def upgrade(): function downgrade (line 100) | def downgrade(): FILE: migrations/versions/057_add_quote_templates.py function upgrade (line 18) | def upgrade(): function downgrade (line 74) | def downgrade(): FILE: migrations/versions/058_add_quote_versions.py function upgrade (line 18) | def upgrade(): function downgrade (line 68) | def downgrade(): FILE: migrations/versions/059_add_inventory_management.py function upgrade (line 19) | def upgrade(): function downgrade (line 255) | def downgrade(): FILE: migrations/versions/060_add_supplier_management.py function upgrade (line 19) | def upgrade(): function downgrade (line 72) | def downgrade(): FILE: migrations/versions/061_add_purchase_orders.py function upgrade (line 19) | def upgrade(): function downgrade (line 80) | def downgrade(): FILE: migrations/versions/062_add_performance_indexes.py function upgrade (line 23) | def upgrade(): function downgrade (line 135) | def downgrade(): FILE: migrations/versions/063_add_crm_features.py function upgrade (line 24) | def upgrade(): function downgrade (line 236) | def downgrade(): FILE: migrations/versions/064_add_kiosk_mode_settings.py function upgrade (line 19) | def upgrade(): function downgrade (line 56) | def downgrade(): FILE: migrations/versions/065_add_new_features.py function upgrade (line 24) | def upgrade(): function downgrade (line 252) | def downgrade(): FILE: migrations/versions/066_add_integration_framework.py function upgrade (line 19) | def upgrade(): function downgrade (line 72) | def downgrade(): FILE: migrations/versions/067_add_integration_credentials.py function upgrade (line 19) | def upgrade(): function downgrade (line 46) | def downgrade(): FILE: migrations/versions/067b_alias_067_add_integration_credentials.py function upgrade (line 23) | def upgrade(): function downgrade (line 28) | def downgrade(): FILE: migrations/versions/068_add_user_password_hash.py function _has_column (line 22) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 30) | def upgrade(): function downgrade (line 44) | def downgrade(): FILE: migrations/versions/069_add_workflow_automation.py function upgrade (line 18) | def upgrade(): function downgrade (line 69) | def downgrade(): FILE: migrations/versions/070_add_time_entry_approvals.py function upgrade (line 19) | def upgrade(): function downgrade (line 119) | def downgrade(): FILE: migrations/versions/071_add_recurring_tasks.py function upgrade (line 18) | def upgrade(): function downgrade (line 66) | def downgrade(): FILE: migrations/versions/072_add_client_portal_customization_and_team_chat.py function upgrade (line 18) | def upgrade(): function downgrade (line 193) | def downgrade(): FILE: migrations/versions/073_add_ai_features_and_gps_tracking.py function upgrade (line 18) | def upgrade(): function downgrade (line 152) | def downgrade(): FILE: migrations/versions/074_add_password_change_required.py function _has_column (line 19) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 27) | def upgrade(): function downgrade (line 41) | def downgrade(): FILE: migrations/versions/075_add_client_custom_fields_and_link_templates.py function _has_column (line 22) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_table (line 30) | def _has_table(inspector, table_name: str) -> bool: function _has_index (line 38) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function upgrade (line 46) | def upgrade(): function downgrade (line 94) | def downgrade(): FILE: migrations/versions/076_add_client_billing_to_time_entries.py function _has_column (line 24) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 32) | def upgrade(): function downgrade (line 121) | def downgrade(): FILE: migrations/versions/077_add_ui_feature_flags.py function upgrade (line 19) | def upgrade(): function downgrade (line 86) | def downgrade(): FILE: migrations/versions/078_add_system_ui_feature_flags.py function upgrade (line 19) | def upgrade(): function downgrade (line 105) | def downgrade(): FILE: migrations/versions/079_rename_user_badges_metadata_column.py function upgrade (line 22) | def upgrade(): function downgrade (line 76) | def downgrade(): FILE: migrations/versions/080_fix_metadata_column_names.py function upgrade (line 24) | def upgrade(): function downgrade (line 120) | def downgrade(): FILE: migrations/versions/081_add_all_integration_credentials.py function _has_table (line 28) | def _has_table(inspector, table_name: str) -> bool: function _has_column (line 35) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 42) | def upgrade(): function downgrade (line 147) | def downgrade(): FILE: migrations/versions/082_add_global_integrations.py function upgrade (line 19) | def upgrade(): function downgrade (line 99) | def downgrade(): FILE: migrations/versions/083_add_paid_status_to_time_entries.py function _has_column (line 22) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 30) | def upgrade(): function downgrade (line 53) | def downgrade(): FILE: migrations/versions/084_add_custom_field_definitions.py function upgrade (line 22) | def upgrade(): function downgrade (line 63) | def downgrade(): FILE: migrations/versions/085_add_project_custom_fields.py function _has_column (line 22) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 30) | def upgrade(): function downgrade (line 46) | def downgrade(): FILE: migrations/versions/086_add_project_and_client_attachments.py function upgrade (line 21) | def upgrade(): function downgrade (line 122) | def downgrade(): FILE: migrations/versions/087_add_salesman_email_mapping.py function upgrade (line 20) | def upgrade(): function downgrade (line 72) | def downgrade(): FILE: migrations/versions/088_add_salesman_splitting_to_reports.py function upgrade (line 21) | def upgrade(): function downgrade (line 61) | def downgrade(): FILE: migrations/versions/089_allow_auto_entries_without_project_or_client.py function upgrade (line 22) | def upgrade(): function downgrade (line 57) | def downgrade(): FILE: migrations/versions/089_fix_roles_permissions_sequences.py function upgrade (line 21) | def upgrade(): function downgrade (line 82) | def downgrade(): FILE: migrations/versions/090_add_push_subscriptions_table.py function upgrade (line 20) | def upgrade(): function downgrade (line 69) | def downgrade(): FILE: migrations/versions/090_enhance_report_builder_iteration.py function _has_column (line 23) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 31) | def upgrade(): function downgrade (line 71) | def downgrade(): FILE: migrations/versions/092_add_missing_module_visibility_flags.py function upgrade (line 21) | def upgrade(): function downgrade (line 122) | def downgrade(): FILE: migrations/versions/093_remove_ui_allow_module_flags.py function upgrade (line 19) | def upgrade(): function downgrade (line 113) | def downgrade(): FILE: migrations/versions/094_add_donation_interactions.py function upgrade (line 20) | def upgrade(): function downgrade (line 74) | def downgrade(): FILE: migrations/versions/095_add_missing_ui_show_issues.py function upgrade (line 21) | def upgrade(): function downgrade (line 53) | def downgrade(): FILE: migrations/versions/096_add_missing_portal_issues_enabled.py function _ensure_alembic_version_can_store_revision_ids (line 21) | def _ensure_alembic_version_can_store_revision_ids(bind, min_len: int = ... function upgrade (line 82) | def upgrade(): function downgrade (line 117) | def downgrade(): FILE: migrations/versions/097_add_stock_lots_for_devaluation.py function _has_table (line 26) | def _has_table(inspector, name: str) -> bool: function _has_index (line 33) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function upgrade (line 41) | def upgrade(): function downgrade (line 143) | def downgrade(): FILE: migrations/versions/098_add_invoice_peppol_transmissions.py function upgrade (line 19) | def upgrade(): function downgrade (line 79) | def downgrade(): FILE: migrations/versions/099_add_peppol_settings_columns.py function upgrade (line 18) | def upgrade(): function downgrade (line 58) | def downgrade(): FILE: migrations/versions/100_add_comment_attachments.py function upgrade (line 19) | def upgrade(): function downgrade (line 40) | def downgrade(): FILE: migrations/versions/100_add_gantt_colors_and_modules_disabled.py function upgrade (line 18) | def upgrade(): function downgrade (line 51) | def downgrade(): FILE: migrations/versions/101_add_issues_table.py function _has_table (line 21) | def _has_table(inspector, name: str) -> bool: function _has_column (line 29) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_index (line 37) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function upgrade (line 46) | def upgrade(): function downgrade (line 182) | def downgrade(): FILE: migrations/versions/102_add_missing_quotes_template_id.py function _has_table (line 23) | def _has_table(inspector, name: str) -> bool: function _has_column (line 31) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_index (line 39) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function _has_foreign_key (line 48) | def _has_foreign_key(inspector, table_name: str, fk_name: str) -> bool: function upgrade (line 57) | def upgrade(): function downgrade (line 164) | def downgrade(): FILE: migrations/versions/103_add_missing_quotes_quote_number.py function _has_table (line 23) | def _has_table(inspector, name: str) -> bool: function _has_column (line 31) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_index (line 39) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function upgrade (line 48) | def upgrade(): function downgrade (line 183) | def downgrade(): FILE: migrations/versions/104_add_missing_quotes_columns.py function _has_table (line 23) | def _has_table(inspector, name: str) -> bool: function _has_column (line 31) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_index (line 39) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function upgrade (line 48) | def upgrade(): function downgrade (line 199) | def downgrade(): FILE: migrations/versions/105_fix_client_notifications_cascade_delete.py function _has_table (line 22) | def _has_table(inspector, name: str) -> bool: function _has_foreign_key (line 30) | def _has_foreign_key(inspector, table_name: str, fk_name: str = None, co... function _get_foreign_key_name (line 43) | def _get_foreign_key_name(inspector, table_name: str, column_name: str) ... function _fix_foreign_key (line 55) | def _fix_foreign_key(table_name: str, column_name: str, fk_name_prefix: ... function upgrade (line 136) | def upgrade(): function downgrade (line 153) | def downgrade(): FILE: migrations/versions/106_add_reportlab_template_json.py function _has_table (line 23) | def _has_table(inspector, name: str) -> bool: function _has_column (line 31) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 40) | def upgrade(): function downgrade (line 66) | def downgrade(): FILE: migrations/versions/107_increase_invoice_prefix_length.py function upgrade (line 22) | def upgrade(): function downgrade (line 59) | def downgrade(): FILE: migrations/versions/108_add_decorative_images.py function upgrade (line 21) | def upgrade(): function downgrade (line 130) | def downgrade(): FILE: migrations/versions/109_add_pdf_template_date_format.py function upgrade (line 21) | def upgrade(): function downgrade (line 44) | def downgrade(): FILE: migrations/versions/110_add_disabled_module_ids.py function upgrade (line 21) | def upgrade(): function downgrade (line 43) | def downgrade(): FILE: migrations/versions/111_add_use_last_month_dates.py function _has_column (line 20) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 27) | def upgrade(): function downgrade (line 40) | def downgrade(): FILE: migrations/versions/112_add_invoices_peppol_compliant.py function upgrade (line 20) | def upgrade(): function downgrade (line 50) | def downgrade(): FILE: migrations/versions/113_add_invoice_buyer_reference.py function upgrade (line 19) | def upgrade(): function downgrade (line 43) | def downgrade(): FILE: migrations/versions/114_enhance_audit_logs_for_timeentry.py function upgrade (line 22) | def upgrade(): function downgrade (line 77) | def downgrade(): FILE: migrations/versions/115_add_exclude_weekends_to_weekly_goals.py function upgrade (line 21) | def upgrade(): function downgrade (line 46) | def downgrade(): FILE: migrations/versions/116_merge_three_heads.py function upgrade (line 22) | def upgrade(): function downgrade (line 27) | def downgrade(): FILE: migrations/versions/117_add_user_calendar_type_colors.py function upgrade (line 19) | def upgrade(): function downgrade (line 26) | def downgrade(): FILE: migrations/versions/118_add_locked_client_id.py function upgrade (line 19) | def upgrade(): function downgrade (line 37) | def downgrade(): FILE: migrations/versions/118_add_role_hidden_module_ids.py function upgrade (line 22) | def upgrade(): function downgrade (line 44) | def downgrade(): FILE: migrations/versions/119_add_settings_date_time_format.py function upgrade (line 21) | def upgrade(): function downgrade (line 54) | def downgrade(): FILE: migrations/versions/120_user_nullable_date_time_format.py function upgrade (line 20) | def upgrade(): function downgrade (line 41) | def downgrade(): FILE: migrations/versions/121_add_ui_show_donate_and_system_instance_id.py function upgrade (line 20) | def upgrade(): function downgrade (line 44) | def downgrade(): FILE: migrations/versions/122_add_settings_donate_ui_hidden.py function upgrade (line 19) | def upgrade(): function downgrade (line 35) | def downgrade(): FILE: migrations/versions/123_add_calendar_default_view.py function upgrade (line 19) | def upgrade(): function downgrade (line 26) | def downgrade(): FILE: migrations/versions/124_add_time_entry_requirements.py function upgrade (line 18) | def upgrade(): function downgrade (line 63) | def downgrade(): FILE: migrations/versions/125_add_default_daily_working_hours.py function upgrade (line 18) | def upgrade(): function downgrade (line 47) | def downgrade(): FILE: migrations/versions/126_add_overtime_include_weekends_to_users.py function upgrade (line 18) | def upgrade(): function downgrade (line 34) | def downgrade(): FILE: migrations/versions/127_add_user_clients_table.py function upgrade (line 18) | def upgrade(): function downgrade (line 41) | def downgrade(): FILE: migrations/versions/128_add_invoices_zugferd_pdf.py function upgrade (line 19) | def upgrade(): function downgrade (line 50) | def downgrade(): FILE: migrations/versions/129_add_task_tags.py function upgrade (line 18) | def upgrade(): function downgrade (line 32) | def downgrade(): FILE: migrations/versions/129_merge_118_128_heads.py function upgrade (line 18) | def upgrade(): function downgrade (line 23) | def downgrade(): FILE: migrations/versions/130_add_peppol_transport_mode_and_native.py function upgrade (line 21) | def upgrade(): function downgrade (line 44) | def downgrade(): FILE: migrations/versions/131_add_donation_interaction_variant.py function upgrade (line 19) | def upgrade(): function downgrade (line 33) | def downgrade(): FILE: migrations/versions/132_add_timesheet_governance_and_time_off.py function upgrade (line 18) | def upgrade(): function downgrade (line 123) | def downgrade(): FILE: migrations/versions/133_merge_132_and_129_task_tags_heads.py function upgrade (line 20) | def upgrade(): function downgrade (line 25) | def downgrade(): FILE: migrations/versions/134_add_overtime_weekly_mode.py function upgrade (line 19) | def upgrade(): function downgrade (line 45) | def downgrade(): FILE: migrations/versions/135_add_remind_to_log_settings.py function upgrade (line 19) | def upgrade(): function downgrade (line 45) | def downgrade(): FILE: migrations/versions/136_seed_overtime_leave_type.py function upgrade (line 20) | def upgrade(): function downgrade (line 44) | def downgrade(): FILE: migrations/versions/137_add_break_time_to_time_entries.py function upgrade (line 19) | def upgrade(): function downgrade (line 40) | def downgrade(): FILE: migrations/versions/138_add_default_break_rules_settings.py function upgrade (line 19) | def upgrade(): function downgrade (line 38) | def downgrade(): FILE: migrations/versions/139_add_keyboard_shortcuts_overrides.py function upgrade (line 19) | def upgrade(): function downgrade (line 35) | def downgrade(): FILE: migrations/versions/140_add_client_portal_dashboard_preferences.py function upgrade (line 18) | def upgrade(): function downgrade (line 55) | def downgrade(): FILE: migrations/versions/141_add_invoice_number_pattern.py function upgrade (line 18) | def upgrade(): function downgrade (line 34) | def downgrade(): FILE: migrations/versions/142_add_mail_test_recipient.py function upgrade (line 18) | def upgrade(): function downgrade (line 29) | def downgrade(): FILE: migrations/versions/143_add_task_custom_fields.py function _has_column (line 19) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 26) | def upgrade(): function downgrade (line 42) | def downgrade(): FILE: migrations/versions/144_api_idempotency_keys.py function upgrade (line 17) | def upgrade(): function downgrade (line 34) | def downgrade(): FILE: migrations/versions/145_add_quotes_requires_approval_columns.py function _has_table (line 20) | def _has_table(inspector, name: str) -> bool: function _has_column (line 27) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 34) | def upgrade(): function downgrade (line 56) | def downgrade(): FILE: migrations/versions/146_add_quote_item_position.py function _has_table (line 20) | def _has_table(inspector, name: str) -> bool: function _has_column (line 27) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 34) | def upgrade(): function downgrade (line 62) | def downgrade(): FILE: migrations/versions/147_add_quote_item_line_kind.py function _has_table (line 20) | def _has_table(inspector, name: str) -> bool: function _has_column (line 27) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 34) | def upgrade(): function downgrade (line 63) | def downgrade(): FILE: migrations/versions/148_add_user_dismissed_release_version.py function _has_column (line 18) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 25) | def upgrade(): function downgrade (line 34) | def downgrade(): FILE: migrations/versions/149_add_user_support_stats_reports_generated.py function _has_column (line 18) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 25) | def upgrade(): function downgrade (line 37) | def downgrade(): FILE: migrations/versions/150_add_smart_notifications.py function _has_column (line 18) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 25) | def upgrade(): function downgrade (line 80) | def downgrade(): FILE: migrations/versions/151_add_ai_helper_settings.py function _has_column (line 18) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 25) | def upgrade(): function downgrade (line 46) | def downgrade(): FILE: migrations/versions/152_add_user_totp_2fa.py function _has_column (line 18) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 25) | def upgrade(): function downgrade (line 45) | def downgrade(): FILE: migrations/versions/153_add_user_auth_provider.py function _has_column (line 18) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function upgrade (line 25) | def upgrade(): function downgrade (line 47) | def downgrade(): FILE: migrations/versions/20250127_000001_add_client_features.py function _has_table (line 18) | def _has_table(inspector, name: str) -> bool: function _has_column (line 25) | def _has_column(inspector, table_name: str, column_name: str) -> bool: function _has_fk (line 32) | def _has_fk(inspector, table_name: str, fk_name: str) -> bool: function _has_index (line 40) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function upgrade (line 48) | def upgrade(): function downgrade (line 156) | def downgrade(): FILE: migrations/versions/20251220_000001_add_integration_external_event_links.py function _has_table (line 19) | def _has_table(inspector, name: str) -> bool: function _has_index (line 27) | def _has_index(inspector, table_name: str, index_name: str) -> bool: function _ensure_alembic_version_can_store_revision_ids (line 39) | def _ensure_alembic_version_can_store_revision_ids(bind, min_len: int = ... function upgrade (line 100) | def upgrade(): function downgrade (line 150) | def downgrade(): FILE: migrations/versions/add_quick_wins_features.py function upgrade (line 19) | def upgrade(): function downgrade (line 147) | def downgrade(): FILE: mobile/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java class GeneratedPluginRegistrant (line 14) | @Keep method registerWith (line 17) | public static void registerWith(@NonNull FlutterEngine flutterEngine) { FILE: mobile/ios/Flutter/ephemeral/flutter_lldb_helper.py function handle_new_rx_page (line 7) | def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_d... function __lldb_init_module (line 24) | def __lldb_init_module(debugger: lldb.SBDebugger, _): FILE: mobile/lib/core/config/app_config.dart class AppConfig (line 5) | class AppConfig { method getServerUrl (line 50) | Future getServerUrl() method setServerUrl (line 56) | Future setServerUrl(String url) method clearServerUrl (line 62) | Future clearServerUrl() method getAutoSync (line 68) | Future getAutoSync() method setAutoSync (line 74) | Future setAutoSync(bool value) method getSyncInterval (line 80) | Future getSyncInterval() method setSyncInterval (line 86) | Future setSyncInterval(int value) method getThemeMode (line 92) | Future getThemeMode() method setThemeMode (line 98) | Future setThemeMode(String value) method getTrustedInsecureHosts (line 104) | Future> getTrustedInsecureHosts() method addTrustedInsecureHost (line 111) | Future addTrustedInsecureHost(String host) method clear (line 119) | Future clear() method clearAll (line 130) | Future clearAll() FILE: mobile/lib/core/constants/app_constants.dart class AppConstants (line 1) | class AppConstants { FILE: mobile/lib/core/telemetry/mobile_otel.dart function initMobileOpenTelemetry (line 11) | Future initMobileOpenTelemetry() function buildOtlpAuthHeader (line 56) | String buildOtlpAuthHeader(String token) function runMobileSpan (line 74) | Future runMobileSpan( FILE: mobile/lib/core/theme/app_theme.dart class AppColors (line 7) | class AppColors { class AppTheme (line 37) | class AppTheme { method _textTheme (line 38) | TextTheme _textTheme({ FILE: mobile/lib/core/theme/app_tokens.dart class AppSpacing (line 4) | class AppSpacing { class AppRadii (line 14) | class AppRadii { class AppDurations (line 26) | class AppDurations { FILE: mobile/lib/data/api/api_client.dart class ApiClient (line 5) | class ApiClient { method setAuthToken (line 32) | Future setAuthToken(String token) method validateTokenRaw (line 36) | Future> validateTokenRaw() method getUsersMe (line 40) | Future> getUsersMe() method getCurrentUser (line 46) | Future> getCurrentUser() method getTimerStatus (line 54) | Future> getTimerStatus() method startTimer (line 60) | Future> startTimer({ method stopTimer (line 77) | Future> stopTimer() method getTimeEntries (line 90) | Future> getTimeEntries({ method getTimeEntry (line 113) | Future> getTimeEntry(int entryId) method createTimeEntry (line 119) | Future> createTimeEntry({ method updateTimeEntry (line 149) | Future> updateTimeEntry( method deleteTimeEntry (line 175) | Future deleteTimeEntry(int entryId) method getProjects (line 180) | Future> getProjects({ method getProject (line 199) | Future> getProject(int projectId) method getTasks (line 205) | Future> getTasks({ method getTask (line 224) | Future> getTask(int taskId) method getClients (line 230) | Future> getClients({ method getInvoices (line 247) | Future> getInvoices({ method getExpenses (line 264) | Future> getExpenses({ method createExpense (line 279) | Future> createExpense(Map body) method createInvoice (line 285) | Future> createInvoice(Map body) method updateInvoice (line 291) | Future> updateInvoice(int invoiceId, Map> getTimesheetPeriods({ method getCapacityReport (line 314) | Future> getCapacityReport({ method getLeaveTypes (line 326) | Future> getLeaveTypes() method getTimeOffRequests (line 332) | Future> getTimeOffRequests() method getTimeOffBalances (line 338) | Future> getTimeOffBalances() method submitTimesheetPeriod (line 344) | Future submitTimesheetPeriod(int periodId) method approveTimesheetPeriod (line 349) | Future approveTimesheetPeriod(int periodId, {String? comment}) method rejectTimesheetPeriod (line 357) | Future rejectTimesheetPeriod(int periodId, {String? reason}) method deleteTimesheetPeriod (line 366) | Future deleteTimesheetPeriod(int periodId) method createTimeOffRequest (line 371) | Future> createTimeOffRequest({ method approveTimeOffRequest (line 390) | Future approveTimeOffRequest(int requestId, {String? comment}) method rejectTimeOffRequest (line 398) | Future rejectTimeOffRequest(int requestId, {String? comment}) method deleteTimeOffRequest (line 406) | Future deleteTimeOffRequest(int requestId) method _throwIfError (line 411) | void _throwIfError(Response res) FILE: mobile/lib/data/models/project.dart class Project (line 1) | class Project { method toJson (line 32) | Map toJson() method _parseDt (line 42) | DateTime? _parseDt(dynamic v) FILE: mobile/lib/data/models/task.dart class Task (line 1) | class Task { method toJson (line 35) | Map toJson() method _parseDt (line 46) | DateTime? _parseDt(dynamic v) FILE: mobile/lib/data/models/time_entry.dart class TimeEntry (line 1) | class TimeEntry { method toJson (line 53) | Map toJson() method _formatSeconds (line 82) | String _formatSeconds(int totalSeconds) method _parseDt (line 93) | DateTime? _parseDt(dynamic v) FILE: mobile/lib/data/models/time_entry_requirements.dart class TimeEntryRequirements (line 3) | @immutable FILE: mobile/lib/data/models/timer.dart class Timer (line 4) | @immutable method toJson (line 37) | Map toJson() FILE: mobile/lib/data/models/user_prefs.dart class UserPrefs (line 3) | @immutable FILE: mobile/lib/data/storage/local_storage.dart class LocalStorage (line 7) | class LocalStorage { method init (line 17) | Future init() method getTimer (line 30) | Future getTimer() method saveTimer (line 37) | Future saveTimer(tt.Timer timer) method clearTimer (line 41) | Future clearTimer() method getAllTimeEntries (line 45) | Future> getAllTimeEntries() method saveTimeEntry (line 54) | Future saveTimeEntry(TimeEntry entry) method deleteTimeEntry (line 65) | Future deleteTimeEntry(int entryId) method _persistEntries (line 71) | Future _persistEntries(List entries) method getSyncQueue (line 78) | Future>> getSyncQueue() method setSyncQueue (line 85) | Future setSyncQueue(List> queue) FILE: mobile/lib/data/storage/sync_service.dart function newSyncIdempotencyKey (line 10) | String newSyncIdempotencyKey() class SyncService (line 19) | class SyncService { method queueCreateTimeEntry (line 24) | Future queueCreateTimeEntry({ method queueDeleteTimeEntry (line 48) | Future queueDeleteTimeEntry(int entryId) method queueUpdateTimeEntry (line 58) | Future queueUpdateTimeEntry({ method syncAll (line 85) | Future syncAll() method processQueue (line 90) | Future processQueue() method syncFromServer (line 149) | Future syncFromServer() FILE: mobile/lib/domain/repositories/time_tracking_repository.dart class TimerAlreadyStoppedException (line 13) | class TimerAlreadyStoppedException implements Exception { method toString (line 17) | String toString() class TimeTrackingRepository (line 21) | class TimeTrackingRepository { method _isOnline (line 30) | Future _isOnline() method getTimerStatus (line 38) | Future getTimerStatus() method startTimer (line 65) | Future startTimer({ method stopTimer (line 117) | Future stopTimer() method getTimeEntries (line 151) | Future> getTimeEntries({ method getTimeEntry (line 213) | Future getTimeEntry(int entryId) method createTimeEntry (line 226) | Future createTimeEntry({ method updateTimeEntry (line 290) | Future updateTimeEntry( method deleteTimeEntry (line 321) | Future deleteTimeEntry(int entryId) method syncPending (line 344) | Future syncPending() method getProjects (line 356) | Future> getProjects({ method getProject (line 382) | Future getProject(int projectId) method getTasks (line 397) | Future> getTasks({ method getTask (line 423) | Future getTask(int taskId) FILE: mobile/lib/domain/usecases/sync_usecase.dart class SyncUseCase (line 10) | class SyncUseCase { method startPeriodicSync (line 20) | Future startPeriodicSync() method stopPeriodicSync (line 34) | void stopPeriodicSync() method _isOnline (line 40) | Future _isOnline() method sync (line 46) | Future sync() method onConnectionRestored (line 82) | Future onConnectionRestored() FILE: mobile/lib/main.dart function main (line 12) | void main() class TimeTrackerApp (line 23) | class TimeTrackerApp extends ConsumerWidget { method build (line 27) | Widget build(BuildContext context, WidgetRef ref) FILE: mobile/lib/presentation/providers/finance_workforce_providers.dart function _weekRange (line 5) | ({String start, String end}) _weekRange() FILE: mobile/lib/presentation/providers/projects_provider.dart class ProjectsState (line 7) | class ProjectsState { method copyWith (line 18) | ProjectsState copyWith({ class ProjectsNotifier (line 32) | class ProjectsNotifier extends StateNotifier { method loadProjects (line 41) | Future loadProjects({String? status}) method refresh (line 54) | Future refresh() FILE: mobile/lib/presentation/providers/tasks_provider.dart class TasksState (line 7) | class TasksState { method copyWith (line 18) | TasksState copyWith({ class TasksNotifier (line 32) | class TasksNotifier extends StateNotifier { method loadTasks (line 37) | Future loadTasks({int? projectId, String? status}) method refresh (line 53) | Future refresh() FILE: mobile/lib/presentation/providers/theme_mode_provider.dart class ThemeModeNotifier (line 7) | class ThemeModeNotifier extends StateNotifier { method _load (line 12) | void _load() method setMode (line 18) | Future setMode(String value) function themeModeFromString (line 28) | ThemeMode themeModeFromString(String value) FILE: mobile/lib/presentation/providers/time_entries_provider.dart class TimeEntriesFilter (line 7) | class TimeEntriesFilter { method copyWith (line 24) | TimeEntriesFilter copyWith({ class TimeEntriesState (line 44) | class TimeEntriesState { method copyWith (line 57) | TimeEntriesState copyWith({ class TimeEntriesNotifier (line 73) | class TimeEntriesNotifier extends StateNotifier { method loadEntries (line 82) | Future loadEntries({TimeEntriesFilter? filter}) method refresh (line 103) | Future refresh() method loadTimeEntries (line 107) | Future loadTimeEntries({ method setFilter (line 119) | Future setFilter(TimeEntriesFilter filter) method createEntry (line 123) | Future createEntry({ method updateEntry (line 154) | Future updateEntry( method deleteEntry (line 187) | Future deleteEntry(int entryId) FILE: mobile/lib/presentation/providers/timer_provider.dart class TimerState (line 17) | class TimerState { method copyWith (line 28) | TimerState copyWith({ class TimerNotifier (line 48) | class TimerNotifier extends StateNotifier { method _startPolling (line 59) | void _startPolling() method _loadTimerStatus (line 68) | Future _loadTimerStatus() method startTimer (line 80) | Future startTimer({ method stopTimer (line 105) | Future stopTimer() method refresh (line 122) | Future refresh() method getElapsedTime (line 127) | Duration getElapsedTime() method checkTimerStatus (line 134) | Future checkTimerStatus() FILE: mobile/lib/presentation/screens/finance_workforce_screen.dart class FinanceWorkforceScreen (line 7) | class FinanceWorkforceScreen extends ConsumerStatefulWidget { method createState (line 11) | ConsumerState createState() class _FinanceWorkforceScreenState (line 14) | class _FinanceWorkforceScreenState extends ConsumerState _load() method _refresh (line 107) | Future _refresh() method _changeInvoicePage (line 127) | Future _changeInvoicePage(int delta) method _changeExpensePage (line 138) | Future _changeExpensePage(int delta) method _submitPeriod (line 149) | Future _submitPeriod(int periodId) method _reviewPeriod (line 168) | Future _reviewPeriod({ method _deletePeriod (line 194) | Future _deletePeriod(int periodId) method _createExpense (line 212) | Future _createExpense({ method _openCreateExpenseDialog (line 249) | Future _openCreateExpenseDialog() method _createInvoice (line 346) | Future _createInvoice({ method _openCreateInvoiceDialog (line 374) | Future _openCreateInvoiceDialog(_FinanceWorkforceData data) method _createTimeOffRequest (line 495) | Future _createTimeOffRequest({ method _updateInvoiceStatus (line 536) | Future _updateInvoiceStatus({ method _reviewTimeOffRequest (line 561) | Future _reviewTimeOffRequest({ method _deleteTimeOffRequest (line 586) | Future _deleteTimeOffRequest(int requestId) method _openCreateTimeOffDialog (line 604) | Future _openCreateTimeOffDialog(_FinanceWorkforceData data) method build (line 739) | Widget build(BuildContext context) class _SectionCard (line 1160) | class _SectionCard extends StatelessWidget { method build (line 1172) | Widget build(BuildContext context) class _EmptyText (line 1191) | class _EmptyText extends StatelessWidget { method build (line 1196) | Widget build(BuildContext context) class _LoadMoreButton (line 1204) | class _LoadMoreButton extends StatelessWidget { method build (line 1209) | Widget build(BuildContext context) class _FinanceWorkforceData (line 1221) | class _FinanceWorkforceData { FILE: mobile/lib/presentation/screens/home_screen.dart class HomeScreen (line 18) | class HomeScreen extends StatefulWidget { method createState (line 22) | State createState() class _HomeScreenState (line 25) | class _HomeScreenState extends State { method build (line 37) | Widget build(BuildContext context) class DashboardTab (line 96) | class DashboardTab extends ConsumerStatefulWidget { method createState (line 100) | ConsumerState createState() class _DashboardTabState (line 103) | class _DashboardTabState extends ConsumerState { method initState (line 107) | void initState() method dispose (line 128) | void dispose() method _projectName (line 133) | String _projectName(int? projectId, List projects) method build (line 144) | Widget build(BuildContext context) method _formatTimer (line 309) | String _formatTimer(Duration duration) FILE: mobile/lib/presentation/screens/login_screen.dart class LoginScreen (line 14) | class LoginScreen extends ConsumerStatefulWidget { method createState (line 18) | ConsumerState createState() class _LoginScreenState (line 21) | class _LoginScreenState extends ConsumerState { method initState (line 32) | void initState() method _loadSavedCredentials (line 37) | Future _loadSavedCredentials() method dispose (line 45) | void dispose() method _isLikelyLocalOrEmulator (line 53) | bool _isLikelyLocalOrEmulator(String host) method _normalizeServerUrl (line 61) | String _normalizeServerUrl(String input) method _handleLogin (line 71) | Future _handleLogin() method _showDiagnostics (line 220) | Future _showDiagnostics(ConnectionDiagnostics diag) method build (line 306) | Widget build(BuildContext context) FILE: mobile/lib/presentation/screens/projects_screen.dart class ProjectsScreen (line 11) | class ProjectsScreen extends ConsumerStatefulWidget { method createState (line 15) | ConsumerState createState() class _ProjectsScreenState (line 18) | class _ProjectsScreenState extends ConsumerState { method initState (line 22) | void initState() method dispose (line 30) | void dispose() method _filterProjects (line 35) | List _filterProjects(List projects, String query) method _startTimerForProject (line 43) | Future _startTimerForProject(Project project) method build (line 57) | Widget build(BuildContext context) FILE: mobile/lib/presentation/screens/settings_screen.dart class SettingsScreen (line 12) | class SettingsScreen extends ConsumerStatefulWidget { method createState (line 16) | ConsumerState createState() class _SettingsScreenState (line 19) | class _SettingsScreenState extends ConsumerState { method initState (line 30) | void initState() method _loadConfig (line 35) | Future _loadConfig() method _runManualSync (line 59) | Future _runManualSync() method _showThemePicker (line 71) | void _showThemePicker() method _selectTheme (line 104) | void _selectTheme(String value) method _normalizeServerUrlForSettings (line 109) | String _normalizeServerUrlForSettings(String input) method _showEditServerUrlDialog (line 122) | Future _showEditServerUrlDialog() method _showEditApiTokenDialog (line 191) | Future _showEditApiTokenDialog() method _showSyncIntervalDialog (line 240) | Future _showSyncIntervalDialog() method _showAboutDialog (line 283) | void _showAboutDialog() method build (line 293) | Widget build(BuildContext context) method _sectionHeader (line 418) | Widget _sectionHeader(String title) class _ThemeOption (line 433) | class _ThemeOption extends StatelessWidget { method build (line 447) | Widget build(BuildContext context) FILE: mobile/lib/presentation/screens/splash_screen.dart class SplashScreen (line 7) | class SplashScreen extends ConsumerStatefulWidget { method createState (line 11) | ConsumerState createState() class _SplashScreenState (line 14) | class _SplashScreenState extends ConsumerState { method initState (line 16) | void initState() method _checkAuthStatus (line 21) | void _checkAuthStatus() method _continueAuthCheck (line 25) | Future _continueAuthCheck() method build (line 44) | Widget build(BuildContext context) FILE: mobile/lib/presentation/screens/time_entries_screen.dart class TimeEntriesScreen (line 13) | class TimeEntriesScreen extends ConsumerStatefulWidget { method createState (line 17) | ConsumerState createState() class _TimeEntriesScreenState (line 20) | class _TimeEntriesScreenState extends ConsumerState { method initState (line 22) | void initState() method build (line 30) | Widget build(BuildContext context) method _buildBody (line 60) | Widget _buildBody(TimeEntriesState state) method _showAddEntryDialog (line 95) | void _showAddEntryDialog() method _showEditEntryDialog (line 103) | void _showEditEntryDialog(int entryId) method _showDeleteConfirmation (line 111) | void _showDeleteConfirmation(int entryId) method _showFilterDialog (line 138) | void _showFilterDialog() FILE: mobile/lib/presentation/screens/time_entry_form_screen.dart class TimeEntryFormScreen (line 12) | class TimeEntryFormScreen extends ConsumerStatefulWidget { method createState (line 18) | ConsumerState createState() class _TimeEntryFormScreenState (line 22) | class _TimeEntryFormScreenState extends ConsumerState _loadEntry() method dispose (line 100) | void dispose() method _loadTasks (line 106) | Future _loadTasks(int projectId) method _selectDateTime (line 110) | Future _selectDateTime( method _handleSubmit (line 141) | Future _handleSubmit() method build (line 251) | Widget build(BuildContext context) FILE: mobile/lib/presentation/screens/timer_screen.dart class TimerScreen (line 10) | class TimerScreen extends ConsumerStatefulWidget { method createState (line 14) | ConsumerState createState() class _TimerScreenState (line 17) | class _TimerScreenState extends ConsumerState { method initState (line 19) | void initState() method build (line 27) | Widget build(BuildContext context) method _handleLogout (line 52) | Future _handleLogout() FILE: mobile/lib/presentation/widgets/empty_state.dart class EmptyState (line 5) | class EmptyState extends StatelessWidget { method build (line 20) | Widget build(BuildContext context) FILE: mobile/lib/presentation/widgets/error_view.dart class ErrorView (line 4) | class ErrorView extends StatelessWidget { method build (line 17) | Widget build(BuildContext context) FILE: mobile/lib/presentation/widgets/start_timer_sheet.dart function showStartTimerSheet (line 13) | Future showStartTimerSheet( class StartTimerSheet (line 25) | class StartTimerSheet extends ConsumerStatefulWidget { method createState (line 31) | ConsumerState createState() class _StartTimerSheetState (line 34) | class _StartTimerSheetState extends ConsumerState { method initState (line 42) | void initState() method dispose (line 57) | void dispose() method _tryApplyInitialProject (line 63) | void _tryApplyInitialProject(List projects) method _selectProject (line 74) | Future _selectProject(Project project) method _handleStart (line 83) | Future _handleStart() method build (line 135) | Widget build(BuildContext context) FILE: mobile/lib/presentation/widgets/time_entry_card.dart class TimeEntryCard (line 12) | class TimeEntryCard extends ConsumerWidget { method build (line 27) | Widget build(BuildContext context, WidgetRef ref) FILE: mobile/lib/presentation/widgets/timer_widget.dart class TimerWidget (line 14) | class TimerWidget extends ConsumerStatefulWidget { method createState (line 18) | ConsumerState createState() class _TimerWidgetState (line 21) | class _TimerWidgetState extends ConsumerState { method initState (line 25) | void initState() method dispose (line 36) | void dispose() method build (line 42) | Widget build(BuildContext context) FILE: mobile/lib/utils/auth/auth_service.dart class AuthService (line 3) | class AuthService { method storeToken (line 8) | Future storeToken(String token) method getToken (line 13) | Future getToken() method deleteToken (line 18) | Future deleteToken() method hasToken (line 23) | Future hasToken() FILE: mobile/lib/utils/date_format_utils.dart function dateFormatPatternFromKey (line 14) | String dateFormatPatternFromKey(String? key) function timeFormatPatternFromKey (line 29) | String timeFormatPatternFromKey(String? key) function formatDate (line 40) | String formatDate(DateTime? date, String? dateFormatKey) function formatTime (line 47) | String formatTime(DateTime? date, String? timeFormatKey) function formatDateTime (line 54) | String formatDateTime(DateTime? date, String? dateFormatKey, String? tim... function formatDateRange (line 62) | String formatDateRange(DateTime? start, DateTime? end, String? dateForma... FILE: mobile/lib/utils/network/connection_diagnostics_io.dart class ConnectionDiagnostics (line 5) | class ConnectionDiagnostics { function _looksLikeHttpsToHttpHandshake (line 23) | bool _looksLikeHttpsToHttpHandshake(Object? err) function _looksLikeHostnameMismatch (line 31) | bool _looksLikeHostnameMismatch(Object? err) function diagnoseDioFailure (line 36) | ConnectionDiagnostics diagnoseDioFailure( FILE: mobile/lib/utils/network/connection_diagnostics_stub.dart class ConnectionDiagnostics (line 3) | class ConnectionDiagnostics { function diagnoseDioFailure (line 21) | ConnectionDiagnostics diagnoseDioFailure( FILE: mobile/lib/utils/ssl/certificate_error_io.dart function isCertificateError (line 6) | bool isCertificateError(DioException e) FILE: mobile/lib/utils/ssl/certificate_error_stub.dart function isCertificateError (line 4) | bool isCertificateError(DioException e) FILE: mobile/lib/utils/ssl/ssl_utils.dart function configureDioTrustedHosts (line 8) | void configureDioTrustedHosts(Dio dio, Set trustedHosts) FILE: mobile/test/api_client_test.dart function main (line 4) | void main() FILE: mobile/test/models_test.dart function main (line 6) | void main() FILE: mobile/test/widget_test.dart function main (line 6) | void main() FILE: scripts/apply_migration.py function check_columns_exist (line 17) | def check_columns_exist(): function apply_migration (line 30) | def apply_migration(): FILE: scripts/audit_i18n.py function find_untranslated_in_templates (line 17) | def find_untranslated_in_templates(base_dir='app/templates'): function find_untranslated_flash_messages (line 79) | def find_untranslated_flash_messages(base_dir='app/routes'): function generate_report (line 111) | def generate_report(issues, output_file='i18n_audit_report.md'): function main (line 149) | def main(): FILE: scripts/audit_migrations_portability.py class Finding (line 24) | class Finding: function _iter_py_files (line 30) | def _iter_py_files(path: Path) -> Iterable[Path]: function _read_text (line 37) | def _read_text(p: Path) -> str: function _get_revision_id (line 41) | def _get_revision_id(tree: ast.AST) -> str | None: function _grep_lines (line 53) | def _grep_lines(text: str, pattern: re.Pattern[str], max_lines: int = 10... function audit_file (line 63) | def audit_file(path: Path) -> list[Finding]: function main (line 208) | def main() -> int: FILE: scripts/check_audit_logging.py function check_audit_setup (line 16) | def check_audit_setup(): FILE: scripts/check_audit_logs.py function check_audit_table (line 14) | def check_audit_table(): FILE: scripts/complete_all_translations.py function translate_text (line 41) | def translate_text(text, target_lang): function complete_translations_for_language (line 55) | def complete_translations_for_language(lang_code): function main (line 147) | def main(): FILE: scripts/complete_dutch_translations.py function translate_to_dutch (line 19) | def translate_to_dutch(text): function complete_dutch_translations (line 92) | def complete_dutch_translations(): FILE: scripts/complete_nl_translations.py function translate_message (line 439) | def translate_message(msgid): function complete_translations (line 444) | def complete_translations(): FILE: scripts/complete_spanish_translations.py function translate_string (line 18) | def translate_string(english_text): function complete_spanish_translations (line 160) | def complete_spanish_translations(): FILE: scripts/complete_spanish_translations_final.py function translate_po_file (line 11) | def translate_po_file(): FILE: scripts/extract_translations.py function run (line 5) | def run(cmd: list[str]) -> int: function main (line 13) | def main(): FILE: scripts/fill_po_argos.py function translate_text (line 23) | def translate_text(text: str, from_code: str, to_code: str) -> str: function main (line 32) | def main() -> int: FILE: scripts/fix_missing_columns.py function has_column (line 22) | def has_column(engine, table_name, column_name): function add_column_if_missing (line 32) | def add_column_if_missing(engine, table_name, column_name, column_type, ... function main (line 56) | def main(): FILE: scripts/fix_quotes_template_id.py function has_table (line 24) | def has_table(inspector, name: str) -> bool: function has_column (line 32) | def has_column(inspector, table_name: str, column_name: str) -> bool: function has_index (line 41) | def has_index(inspector, table_name: str, index_name: str) -> bool: function has_foreign_key (line 50) | def has_foreign_key(inspector, table_name: str, fk_name: str) -> bool: function main (line 59) | def main(): FILE: scripts/fix_translation_placeholders.py function extract_placeholders_from_msgid (line 18) | def extract_placeholders_from_msgid(msgid): function fix_placeholders_in_msgstr (line 27) | def fix_placeholders_in_msgstr(msgstr, original_placeholders): function fix_translation_file (line 60) | def fix_translation_file(po_file): function main (line 109) | def main(): FILE: scripts/generate-changelog.py class ChangelogGenerator (line 16) | class ChangelogGenerator: method __init__ (line 17) | def __init__(self, repo_path: str = "."): method _get_repo_url (line 22) | def _get_repo_url(self) -> Optional[str]: method _run_git_command (line 43) | def _run_git_command(self, command: List[str]) -> str: method get_latest_tag (line 58) | def get_latest_tag(self) -> str: method get_commits_since_tag (line 63) | def get_commits_since_tag(self, since_tag: str) -> List[Dict[str, str]]: method categorize_commits (line 88) | def categorize_commits(self, commits: List[Dict[str, str]]) -> Dict[st... method extract_breaking_changes (line 134) | def extract_breaking_changes(self, commits: List[Dict[str, str]]) -> L... method get_github_prs_and_issues (line 146) | def get_github_prs_and_issues(self, commits: List[Dict[str, str]]) -> ... method generate_changelog (line 202) | def generate_changelog(self, version: str, since_tag: str = None) -> str: method _format_changelog (line 232) | def _format_changelog( function main (line 346) | def main(): FILE: scripts/generate-icons.js function generateIcons (line 45) | async function generateIcons() { FILE: scripts/generate-mobile-icon.py function main (line 10) | def main(): FILE: scripts/generate_pwa_icons.py function build_icon (line 13) | def build_icon(size: int) -> Image.Image: function main (line 60) | def main() -> int: FILE: scripts/reset-dev-db.py function main (line 30) | def main(): FILE: scripts/sanitize_po_format_strings.py function _percent_keys (line 22) | def _percent_keys(msgid: str) -> list[str]: function _safe_percent (line 26) | def _safe_percent(msgid: str, msgstr: str) -> bool: function _brace_field_names (line 62) | def _brace_field_names(msgid: str) -> set[str]: function _safe_brace (line 74) | def _safe_brace(msgid: str, msgstr: str) -> bool: function main (line 90) | def main() -> int: FILE: scripts/seed-dev-data.py function main (line 37) | def main(): FILE: scripts/sync-desktop-version.py function get_version_from_setup (line 12) | def get_version_from_setup(): function update_package_json (line 39) | def update_package_json(version): function main (line 70) | def main(): FILE: scripts/sync-mobile-version.py function get_version_from_setup (line 11) | def get_version_from_setup(): function update_pubspec_yaml (line 38) | def update_pubspec_yaml(version): function update_android_build_gradle (line 81) | def update_android_build_gradle(version): function main (line 135) | def main(): FILE: scripts/sync_translations.py function read_po_catalog (line 21) | def read_po_catalog(filepath): function sync_translations (line 27) | def sync_translations(): FILE: scripts/translate_all_spanish.py function translate_po_file (line 697) | def translate_po_file(): FILE: scripts/translate_dutch.py function translate_text (line 11) | def translate_text(text): function translate_po_file (line 201) | def translate_po_file(): FILE: scripts/translate_spanish.py function translate_to_spanish (line 9) | def translate_to_spanish(english_text): function translate_po_file (line 154) | def translate_po_file(po_file_path): FILE: scripts/validate-setup.py class Colors (line 13) | class Colors: function print_header (line 23) | def print_header(text): function print_success (line 30) | def print_success(text): function print_error (line 35) | def print_error(text): function print_warning (line 40) | def print_warning(text): function print_info (line 45) | def print_info(text): function check_file_exists (line 50) | def check_file_exists(filepath, required=True): function check_python_package (line 64) | def check_python_package(package_name): function run_command (line 75) | def run_command(command, description): function main (line 116) | def main(): FILE: scripts/verify_and_fix_schema.py function get_sqlalchemy_type (line 22) | def get_sqlalchemy_type(column_type, dialect): function get_column_default (line 30) | def get_column_default(column, dialect): function has_column (line 65) | def has_column(inspector, table_name, column_name): function add_column_sql (line 74) | def add_column_sql(table_name, column, dialect): function verify_and_fix_table (line 93) | def verify_and_fix_table(engine, inspector, model_class, dialect): function main (line 151) | def main(): FILE: scripts/version-manager.py class VersionManager (line 15) | class VersionManager: method __init__ (line 16) | def __init__(self): method run_command (line 19) | def run_command(self, command, capture_output=True): method get_current_branch (line 54) | def get_current_branch(self): method get_latest_tag (line 58) | def get_latest_tag(self): method get_commit_count (line 66) | def get_commit_count(self): method get_commit_hash (line 76) | def get_commit_hash(self, short=True): method validate_version_format (line 83) | def validate_version_format(self, version): method suggest_next_version (line 102) | def suggest_next_version(self, current_version): method create_tag (line 126) | def create_tag(self, version, message=None, push=True): method create_build_tag (line 164) | def create_build_tag(self, build_number=None): method list_tags (line 176) | def list_tags(self): method show_tag_info (line 187) | def show_tag_info(self, tag): method show_status (line 215) | def show_status(self): function main (line 230) | def main(): FILE: tests/conftest.py function time_freezer (line 91) | def time_freezer(): function app_config (line 132) | def app_config(): function app (line 158) | def app(app_config): function client (line 313) | def client(app): function runner (line 319) | def runner(app): function db_session (line 330) | def db_session(app): function user (line 342) | def user(app): function admin_user (line 388) | def admin_user(app): function auth_user (line 435) | def auth_user(user): function multiple_users (line 441) | def multiple_users(app): function test_client (line 463) | def test_client(app, user): function multiple_clients (line 487) | def multiple_clients(app, user): function project (line 511) | def project(app, test_client): function multiple_projects (line 547) | def multiple_projects(app, test_client): function time_entry (line 593) | def time_entry(app, user, project): function multiple_time_entries (line 622) | def multiple_time_entries(app, user, project): function active_timer (line 653) | def active_timer(app, user, project): function task (line 676) | def task(app, project, user): function invoice (line 699) | def invoice(app, user, project, test_client): function invoice_with_items (line 721) | def invoice_with_items(app, invoice): function authenticated_client (line 754) | def authenticated_client(client, user): function admin_authenticated_client (line 784) | def admin_authenticated_client(client, admin_user): function auth_headers (line 814) | def auth_headers(user): function api_token (line 829) | def api_token(app, user): function client_with_token (line 844) | def client_with_token(app, api_token): function scope_restricted_user (line 853) | def scope_restricted_user(app, test_client): function scope_restricted_authenticated_client (line 890) | def scope_restricted_authenticated_client(client, scope_restricted_user): function regular_user (line 909) | def regular_user(user): function temp_file (line 920) | def temp_file(): function temp_dir (line 929) | def temp_dir(): function test_client_obj (line 944) | def test_client_obj(test_client): function test_user (line 950) | def test_user(user): function auth_user (line 956) | def auth_user(user): function test_project (line 962) | def test_project(project): function test_task (line 968) | def test_task(task): function installation_config (line 979) | def installation_config(temp_dir): function _reset_opentelemetry_after_test (line 1002) | def _reset_opentelemetry_after_test(): function pytest_configure (line 1017) | def pytest_configure(config): FILE: tests/factories.py class _SessionFactory (line 28) | class _SessionFactory(SQLAlchemyModelFactory): class Meta (line 31) | class Meta: class UserFactory (line 37) | class UserFactory(_SessionFactory): class Meta (line 38) | class Meta: class ClientFactory (line 46) | class ClientFactory(_SessionFactory): class Meta (line 47) | class Meta: class ProjectFactory (line 55) | class ProjectFactory(_SessionFactory): class Meta (line 56) | class Meta: method client_id (line 62) | def client_id(self): class UserTaskFactory (line 74) | class UserTaskFactory(_SessionFactory): class Meta (line 75) | class Meta: class TimeEntryFactory (line 85) | class TimeEntryFactory(_SessionFactory): class Meta (line 86) | class Meta: class InvoiceFactory (line 101) | class InvoiceFactory(_SessionFactory): class Meta (line 102) | class Meta: class InvoiceItemFactory (line 123) | class InvoiceItemFactory(_SessionFactory): class Meta (line 124) | class Meta: class ExpenseFactory (line 134) | class ExpenseFactory(_SessionFactory): class Meta (line 135) | class Meta: class PaymentFactory (line 151) | class PaymentFactory(_SessionFactory): class Meta (line 152) | class Meta: class ExpenseCategoryFactory (line 166) | class ExpenseCategoryFactory(_SessionFactory): class Meta (line 167) | class Meta: class ApiTokenFactory (line 181) | class ApiTokenFactory: method create (line 189) | def create( class RecurringInvoiceFactory (line 209) | class RecurringInvoiceFactory(_SessionFactory): class Meta (line 210) | class Meta: FILE: tests/models/test_import_export_models.py function app (line 15) | def app(): class TestDataImportModel (line 36) | class TestDataImportModel: method test_create_import (line 39) | def test_create_import(self, app): method test_import_lifecycle (line 57) | def test_import_lifecycle(self, app): method test_import_complete (line 81) | def test_import_complete(self, app): method test_import_fail (line 96) | def test_import_fail(self, app): method test_import_add_error (line 111) | def test_import_add_error(self, app): method test_import_set_summary (line 128) | def test_import_set_summary(self, app): method test_import_to_dict (line 145) | def test_import_to_dict(self, app): class TestDataExportModel (line 165) | class TestDataExportModel: method test_create_export (line 168) | def test_create_export(self, app): method test_export_lifecycle (line 182) | def test_export_lifecycle(self, app): method test_export_fail (line 204) | def test_export_fail(self, app): method test_export_with_filters (line 219) | def test_export_with_filters(self, app): method test_export_expiration (line 235) | def test_export_expiration(self, app): method test_export_to_dict (line 256) | def test_export_to_dict(self, app): FILE: tests/smoke_test_email.py class TestEmailSmokeTests (line 13) | class TestEmailSmokeTests: method test_email_support_page_loads (line 16) | def test_email_support_page_loads(self, admin_authenticated_client): method check_email_configuration_status_api (line 28) | def check_email_configuration_status_api(self, admin_authenticated_cli... method test_admin_dashboard_integration (line 46) | def test_admin_dashboard_integration(self, admin_authenticated_client): method test_email_utilities_importable (line 56) | def test_email_utilities_importable(self): method test_email_routes_registered (line 72) | def test_email_routes_registered(self, app): method test_email_template_exists (line 90) | def test_email_template_exists(self, app): method check_email_configuration_with_environment (line 120) | def check_email_configuration_with_environment(self, app, monkeypatch): class TestEmailFeatureIntegrity (line 142) | class TestEmailFeatureIntegrity: method test_all_email_functions_have_docstrings (line 145) | def test_all_email_functions_have_docstrings(self): method test_email_routes_have_proper_decorators (line 157) | def test_email_routes_have_proper_decorators(self): FILE: tests/smoke_test_prepaid_hours.py function test_prepaid_hours_summary_display (line 11) | def test_prepaid_hours_summary_display(app, client, user): FILE: tests/smoke_test_project_dashboard.py function app (line 15) | def app(): function client (line 27) | def client(app): function user (line 33) | def user(app): function test_client_obj (line 44) | def test_client_obj(app): function project_with_data (line 54) | def project_with_data(app, test_client_obj, user): function login (line 123) | def login(client, username="testuser", password="testpass123"): class TestProjectDashboardSmoke (line 129) | class TestProjectDashboardSmoke: method test_dashboard_page_loads (line 132) | def test_dashboard_page_loads(self, client, user, project_with_data): method test_dashboard_requires_authentication (line 141) | def test_dashboard_requires_authentication(self, client, project_with_... method test_dashboard_shows_project_name (line 146) | def test_dashboard_shows_project_name(self, client, user, project_with... method test_dashboard_shows_key_metrics (line 155) | def test_dashboard_shows_key_metrics(self, client, user, project_with_... method test_dashboard_shows_charts (line 169) | def test_dashboard_shows_charts(self, client, user, project_with_data): method test_dashboard_shows_budget_visualization (line 180) | def test_dashboard_shows_budget_visualization(self, client, user, proj... method test_dashboard_shows_task_statistics (line 189) | def test_dashboard_shows_task_statistics(self, client, user, project_w... method test_dashboard_shows_team_contributions (line 200) | def test_dashboard_shows_team_contributions(self, client, user, projec... method test_dashboard_shows_recent_activity (line 209) | def test_dashboard_shows_recent_activity(self, client, user, project_w... method test_dashboard_has_back_link (line 218) | def test_dashboard_has_back_link(self, client, user, project_with_data): method test_dashboard_period_filter_works (line 228) | def test_dashboard_period_filter_works(self, client, user, project_wit... method test_dashboard_period_filter_dropdown (line 238) | def test_dashboard_period_filter_dropdown(self, client, user, project_... method test_project_view_has_dashboard_link (line 247) | def test_project_view_has_dashboard_link(self, client, user, project_w... method test_dashboard_handles_no_data_gracefully (line 258) | def test_dashboard_handles_no_data_gracefully(self, client, user, test... method test_dashboard_shows_hours_worked (line 271) | def test_dashboard_shows_hours_worked(self, client, user, project_with... method test_dashboard_shows_budget_amount (line 281) | def test_dashboard_shows_budget_amount(self, client, user, project_wit... method test_dashboard_calculates_completion_rate (line 291) | def test_dashboard_calculates_completion_rate(self, client, user, proj... method test_dashboard_shows_team_member_name (line 301) | def test_dashboard_shows_team_member_name(self, client, user, project_... method test_dashboard_handles_invalid_period (line 310) | def test_dashboard_handles_invalid_period(self, client, user, project_... method test_dashboard_404_for_nonexistent_project (line 318) | def test_dashboard_404_for_nonexistent_project(self, client, user): method test_dashboard_chart_js_loaded (line 326) | def test_dashboard_chart_js_loaded(self, client, user, project_with_da... method test_dashboard_responsive_layout (line 335) | def test_dashboard_responsive_layout(self, client, user, project_with_... method test_dashboard_dark_mode_compatible (line 345) | def test_dashboard_dark_mode_compatible(self, client, user, project_wi... FILE: tests/smoke_test_user_settings.py class TestUserSettingsSmokeTests (line 13) | class TestUserSettingsSmokeTests: method test_settings_page_accessible (line 16) | def test_settings_page_accessible(self, client, user): method test_can_update_basic_profile (line 24) | def test_can_update_basic_profile(self, client, user): method test_can_toggle_notifications (line 41) | def test_can_toggle_notifications(self, client, user): method test_can_change_theme (line 66) | def test_can_change_theme(self, client, user): method test_can_change_timezone (line 78) | def test_can_change_timezone(self, client, user): method test_can_change_date_format (line 89) | def test_can_change_date_format(self, client, user): method test_can_enable_time_rounding (line 100) | def test_can_enable_time_rounding(self, client, user): method test_can_set_standard_hours (line 117) | def test_can_set_standard_hours(self, client, user): method test_theme_api_works (line 128) | def test_theme_api_works(self, client, user): method test_preferences_api_works (line 142) | def test_preferences_api_works(self, client, user): method test_settings_page_has_required_forms (line 156) | def test_settings_page_has_required_forms(self, client, user): method test_invalid_timezone_rejected (line 175) | def test_invalid_timezone_rejected(self, client, user): method test_invalid_hours_rejected (line 186) | def test_invalid_hours_rejected(self, client, user): method test_settings_persist_after_save (line 199) | def test_settings_persist_after_save(self, client, user): FILE: tests/test_activity_feed.py class TestActivityModel (line 9) | class TestActivityModel: method test_activity_creation (line 12) | def test_activity_creation(self, app, test_user, test_project): method test_activity_log_method (line 33) | def test_activity_log_method(self, app, test_user, test_project): method test_activity_get_recent (line 54) | def test_activity_get_recent(self, app, test_user, test_project): method test_activity_filter_by_entity_type (line 74) | def test_activity_filter_by_entity_type(self, app, test_user, test_pro... method test_activity_to_dict (line 106) | def test_activity_to_dict(self, app, test_user, test_project): method test_activity_get_icon (line 129) | def test_activity_get_icon(self, app, test_user, test_project): class TestActivityAPIEndpoints (line 151) | class TestActivityAPIEndpoints: method test_get_activities (line 154) | def test_get_activities(self, authenticated_client, test_user, test_pr... method test_get_activities_with_entity_type_filter (line 177) | def test_get_activities_with_entity_type_filter(self, authenticated_cl... method test_get_activities_with_pagination (line 205) | def test_get_activities_with_pagination(self, authenticated_client, te... method test_get_activity_stats (line 234) | def test_get_activity_stats(self, authenticated_client, test_user, tes... class TestActivityIntegration (line 275) | class TestActivityIntegration: method test_project_create_logs_activity (line 278) | def test_project_create_logs_activity(self, admin_authenticated_client... method test_task_create_logs_activity (line 305) | def test_task_create_logs_activity(self, authenticated_client, test_pr... method test_timer_start_logs_activity (line 330) | def test_timer_start_logs_activity(self, authenticated_client, test_pr... method test_timer_stop_logs_activity (line 348) | def test_timer_stop_logs_activity(self, authenticated_client, test_use... class TestActivityFeedDateParams (line 372) | class TestActivityFeedDateParams: method test_api_activity_valid_date_params (line 377) | def test_api_activity_valid_date_params(self, app, client, user, test_... method test_api_activity_invalid_start_date_returns_400 (line 397) | def test_api_activity_invalid_start_date_returns_400(self, app, client... method test_api_activity_invalid_end_date_returns_400 (line 408) | def test_api_activity_invalid_end_date_returns_400(self, app, client, ... method test_web_activity_invalid_date_filter_skipped_no_crash (line 418) | def test_web_activity_invalid_date_filter_skipped_no_crash(self, app, ... class TestActivityWidget (line 428) | class TestActivityWidget: method test_dashboard_includes_activities (line 431) | def test_dashboard_includes_activities(self, authenticated_client, tes... FILE: tests/test_admin_dashboard_charts.py function test_admin_dashboard_returns_chart_data_with_30_days (line 8) | def test_admin_dashboard_returns_chart_data_with_30_days(client, app, ad... FILE: tests/test_admin_email_routes.py class TestAdminEmailRoutes (line 10) | class TestAdminEmailRoutes: method test_email_support_page_requires_login (line 13) | def test_email_support_page_requires_login(self, client): method test_email_support_page_requires_admin (line 18) | def test_email_support_page_requires_admin(self, client, regular_user): method test_email_support_page_admin_access (line 31) | def test_email_support_page_admin_access(self, client, admin_user): method test_email_support_shows_configuration_status (line 45) | def test_email_support_shows_configuration_status(self, mock_test_conf... method test_test_email_endpoint_requires_login (line 74) | def test_test_email_endpoint_requires_login(self, client): method test_send_email_template_test_requires_login (line 79) | def test_send_email_template_test_requires_login(self, client): method test_send_test_email_success (line 86) | def test_send_test_email_success(self, mock_send, client, admin_user): method test_send_test_email_failure (line 107) | def test_send_test_email_failure(self, mock_send, client, admin_user): method test_send_test_email_no_recipient (line 127) | def test_send_test_email_no_recipient(self, client, admin_user): method test_email_config_status_endpoint (line 143) | def test_email_config_status_endpoint(self, client, admin_user): method test_rate_limiting_on_test_email (line 160) | def test_rate_limiting_on_test_email(self, client, admin_user): function regular_user (line 181) | def regular_user(app): function admin_user (line 197) | def admin_user(app): FILE: tests/test_admin_settings_logo.py function admin_user (line 13) | def admin_user(app): function authenticated_admin_client (line 26) | def authenticated_admin_client(admin_authenticated_client): function sample_logo_image (line 32) | def sample_logo_image(): function cleanup_logos (line 43) | def cleanup_logos(app): function test_settings_has_logo_no_filename (line 64) | def test_settings_has_logo_no_filename(app): function test_settings_has_logo_file_not_exists (line 76) | def test_settings_has_logo_file_not_exists(app): function test_settings_get_logo_url (line 88) | def test_settings_get_logo_url(app): function test_settings_get_logo_url_no_filename (line 100) | def test_settings_get_logo_url_no_filename(app): function test_settings_get_logo_path (line 112) | def test_settings_get_logo_path(app): function test_admin_settings_page_accessible (line 133) | def test_admin_settings_page_accessible(admin_authenticated_client): function test_admin_settings_requires_authentication (line 143) | def test_admin_settings_requires_authentication(client): function test_logo_upload_successful (line 150) | def test_logo_upload_successful(authenticated_admin_client, sample_logo_... function test_logo_upload_no_file (line 176) | def test_logo_upload_no_file(authenticated_admin_client, app): function test_logo_upload_invalid_file_type (line 186) | def test_logo_upload_invalid_file_type(authenticated_admin_client, app): function test_logo_upload_replaces_old_logo (line 205) | def test_logo_upload_replaces_old_logo(authenticated_admin_client, clean... function test_remove_logo_successful (line 251) | def test_remove_logo_successful(authenticated_admin_client, sample_logo_... function test_remove_logo_when_none_exists (line 282) | def test_remove_logo_when_none_exists(authenticated_admin_client, app): function test_serve_uploaded_logo (line 296) | def test_serve_uploaded_logo(authenticated_admin_client, sample_logo_ima... function test_logo_upload_requires_admin (line 321) | def test_logo_upload_requires_admin(client, app): function test_remove_logo_requires_admin (line 351) | def test_remove_logo_requires_admin(client, app): function test_logo_display_in_settings_page_no_logo (line 375) | def test_logo_display_in_settings_page_no_logo(admin_authenticated_client): function test_logo_display_in_settings_page_with_logo (line 385) | def test_logo_display_in_settings_page_with_logo(admin_authenticated_cli... FILE: tests/test_admin_users.py class TestAdminUserList (line 19) | class TestAdminUserList: method test_list_users_as_admin (line 22) | def test_list_users_as_admin(self, client, admin_user): method test_list_users_as_regular_user_denied (line 32) | def test_list_users_as_regular_user_denied(self, client, user): method test_list_users_unauthenticated (line 41) | def test_list_users_unauthenticated(self, client): class TestAdminUserCreation (line 47) | class TestAdminUserCreation: method test_create_user_get_form (line 50) | def test_create_user_get_form(self, client, admin_user): method test_create_user_success (line 59) | def test_create_user_success(self, client, admin_user, app): method test_create_user_duplicate_username (line 78) | def test_create_user_duplicate_username(self, client, admin_user, user): method test_create_user_missing_username (line 93) | def test_create_user_missing_username(self, client, admin_user): class TestAdminUserEditing (line 105) | class TestAdminUserEditing: method test_edit_user_get_form (line 108) | def test_edit_user_get_form(self, client, admin_user, user): method test_edit_user_success (line 118) | def test_edit_user_success(self, client, admin_user, user, app): method test_edit_user_deactivate (line 139) | def test_edit_user_deactivate(self, client, admin_user, user, app): class TestAdminUserPasswordReset (line 163) | class TestAdminUserPasswordReset: method test_reset_password_success (line 166) | def test_reset_password_success(self, client, admin_user, user, app): method test_reset_password_with_force_change (line 201) | def test_reset_password_with_force_change(self, client, admin_user, us... method test_reset_password_password_too_short (line 233) | def test_reset_password_password_too_short(self, client, admin_user, u... method test_reset_password_passwords_dont_match (line 255) | def test_reset_password_passwords_dont_match(self, client, admin_user,... method test_reset_password_optional (line 277) | def test_reset_password_optional(self, client, admin_user, user, app): method test_reset_password_form_fields_present (line 306) | def test_reset_password_form_fields_present(self, client, admin_user, ... class TestAdminUserDeletion (line 320) | class TestAdminUserDeletion: method test_delete_user_success (line 323) | def test_delete_user_success(self, client, admin_user, app): method test_delete_user_with_time_entries_fails (line 349) | def test_delete_user_with_time_entries_fails(self, client, admin_user,... method test_delete_last_admin_fails (line 385) | def test_delete_last_admin_fails(self, client, admin_user, app): method test_delete_admin_with_multiple_admins_success (line 402) | def test_delete_admin_with_multiple_admins_success(self, client, admin... method test_delete_user_as_regular_user_denied (line 429) | def test_delete_user_as_regular_user_denied(self, client, user, app): method test_delete_nonexistent_user_404 (line 455) | def test_delete_nonexistent_user_404(self, client, admin_user): method test_delete_user_unauthenticated (line 465) | def test_delete_user_unauthenticated(self, client, user): method test_delete_inactive_admin_with_one_active_admin_fails (line 471) | def test_delete_inactive_admin_with_one_active_admin_fails(self, clien... class TestAdminUserDeletionCascading (line 494) | class TestAdminUserDeletionCascading: method test_delete_user_cascades_to_project_costs (line 497) | def test_delete_user_cascades_to_project_costs(self, client, admin_use... method test_user_list_shows_delete_button_for_other_users (line 538) | def test_user_list_shows_delete_button_for_other_users(self, client, a... method test_user_list_hides_delete_button_for_current_user (line 550) | def test_user_list_hides_delete_button_for_current_user(self, client, ... class TestUserDeletionSmokeTests (line 567) | class TestUserDeletionSmokeTests: method test_admin_can_delete_user_without_data (line 571) | def test_admin_can_delete_user_without_data(self, client, admin_user, ... method test_cannot_delete_user_with_time_entries (line 598) | def test_cannot_delete_user_with_time_entries(self, client, admin_user... method test_cannot_delete_last_admin (line 634) | def test_cannot_delete_last_admin(self, client, admin_user, app): method test_user_list_accessible_to_admin (line 651) | def test_user_list_accessible_to_admin(self, client, admin_user): method test_regular_user_cannot_access_user_deletion (line 663) | def test_regular_user_cannot_access_user_deletion(self, client, user, ... method test_delete_button_appears_in_ui (line 686) | def test_delete_button_appears_in_ui(self, client, admin_user, user): method test_complete_user_deletion_workflow (line 699) | def test_complete_user_deletion_workflow(self, client, admin_user, app): method test_admin_can_reset_user_password (line 734) | def test_admin_can_reset_user_password(self, client, admin_user, user,... method test_password_reset_form_accessible (line 782) | def test_password_reset_form_accessible(self, client, admin_user, user): FILE: tests/test_analytics.py function app (line 14) | def app(): function client (line 32) | def client(app): class TestLogEvent (line 37) | class TestLogEvent: method test_log_event_basic (line 40) | def test_log_event_basic(self, app): method test_log_event_without_request_context (line 48) | def test_log_event_without_request_context(self, app): method test_log_event_with_extra_data (line 54) | def test_log_event_with_extra_data(self, app): class TestTrackEvent (line 62) | class TestTrackEvent: method test_track_event_when_enabled (line 67) | def test_track_event_when_enabled(self, mock_send, _mock_enabled, app): method test_track_event_when_disabled (line 79) | def test_track_event_when_disabled(self, mock_send, _mock_enabled, app): method test_track_event_handles_errors_gracefully (line 87) | def test_track_event_handles_errors_gracefully(self, mock_send, _mock_... method test_track_event_with_none_properties (line 94) | def test_track_event_with_none_properties(self, app): class TestPrometheusMetrics (line 105) | class TestPrometheusMetrics: method test_metrics_endpoint_exists (line 108) | def test_metrics_endpoint_exists(self, client): method test_metrics_endpoint_format (line 114) | def test_metrics_endpoint_format(self, client): method test_metrics_are_incremented (line 123) | def test_metrics_are_incremented(self, client): class TestAnalyticsIntegration (line 137) | class TestAnalyticsIntegration: method test_login_analytics (line 142) | def test_login_analytics(self, mock_track, mock_log, authenticated_cli... method test_timer_analytics_integration (line 155) | def test_timer_analytics_integration(self, mock_track, mock_log, app, ... class TestSentryIntegration (line 164) | class TestSentryIntegration: method test_sentry_initializes_when_dsn_set (line 168) | def test_sentry_initializes_when_dsn_set(self, mock_init): method test_sentry_not_initialized_without_dsn (line 178) | def test_sentry_not_initialized_without_dsn(self): class TestRequestIDAttachment (line 187) | class TestRequestIDAttachment: method test_request_id_attached (line 190) | def test_request_id_attached(self, app, client): class TestAnalyticsEventSchema (line 201) | class TestAnalyticsEventSchema: method test_event_naming_convention (line 204) | def test_event_naming_convention(self): class TestAnalyticsPrivacy (line 224) | class TestAnalyticsPrivacy: method test_no_pii_in_standard_events (line 227) | def test_no_pii_in_standard_events(self, app): method test_telemetry_uses_internal_ids (line 245) | def test_telemetry_uses_internal_ids(self, mock_send, _mock_enabled, a... class TestAnalyticsPerformance (line 255) | class TestAnalyticsPerformance: method test_analytics_dont_block_requests (line 258) | def test_analytics_dont_block_requests(self, client): method test_analytics_errors_dont_break_app (line 271) | def test_analytics_errors_dont_break_app(self, mock_send, app, client): FILE: tests/test_api_audit_activities_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function admin_user (line 31) | def admin_user(app): function admin_token (line 40) | def admin_token(app, admin_user): function _auth (line 47) | def _auth(t): function test_audit_and_activities_list (line 51) | def test_audit_and_activities_list(client, admin_token): FILE: tests/test_api_budget_alerts_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function admin_user (line 31) | def admin_user(app): function api_token (line 40) | def api_token(app, admin_user): function project (line 50) | def project(app): function _auth (line 57) | def _auth(t): function test_budget_alerts (line 61) | def test_budget_alerts(client, api_token, project): FILE: tests/test_api_calendar_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function _auth (line 49) | def _auth(t): function test_calendar_crud (line 53) | def test_calendar_crud(client, api_token): FILE: tests/test_api_client_notes_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function user (line 31) | def user(app): function api_token (line 40) | def api_token(app, user): function client_model (line 48) | def client_model(app): function _auth (line 55) | def _auth(t): function test_client_notes_crud (line 59) | def test_client_notes_crud(client, api_token, client_model): FILE: tests/test_api_comments_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function user (line 31) | def user(app): function api_token (line 40) | def api_token(app, user): function project (line 48) | def project(app): function _auth (line 55) | def _auth(t): function test_comments_crud_project (line 59) | def test_comments_crud_project(client, api_token, project): FILE: tests/test_api_comprehensive.py function test_start_timer_api (line 19) | def test_start_timer_api(authenticated_client, project): function test_get_timer_status (line 31) | def test_get_timer_status(authenticated_client): function test_get_projects_list (line 46) | def test_get_projects_list(authenticated_client): function test_get_project_details (line 56) | def test_get_project_details(authenticated_client, project): function test_get_time_entries (line 71) | def test_get_time_entries(authenticated_client): function test_get_time_entry_details (line 81) | def test_get_time_entry_details(authenticated_client, time_entry): function test_get_clients_list (line 96) | def test_get_clients_list(authenticated_client): function test_get_client_details (line 106) | def test_get_client_details(authenticated_client, test_client): function test_get_invoices_list (line 121) | def test_get_invoices_list(authenticated_client): function test_get_invoice_details (line 131) | def test_get_invoice_details(authenticated_client, invoice): function test_get_time_report (line 146) | def test_get_time_report(authenticated_client): function test_get_project_report (line 158) | def test_get_project_report(authenticated_client, project): function test_get_tasks_list (line 175) | def test_get_tasks_list(authenticated_client): function test_get_task_details (line 185) | def test_get_task_details(authenticated_client, task): function test_get_project_tasks_includes_all_statuses (line 195) | def test_get_project_tasks_includes_all_statuses(authenticated_client, p... function test_get_settings (line 236) | def test_get_settings(authenticated_client): function test_get_dashboard_stats (line 251) | def test_get_dashboard_stats(authenticated_client): function test_search_api (line 266) | def test_search_api(authenticated_client): function test_export_time_entries (line 281) | def test_export_time_entries(authenticated_client): FILE: tests/test_api_contract.py function contract_user_id (line 18) | def contract_user_id(app): function api_token_read_only (line 30) | def api_token_read_only(app, contract_user_id): function api_token_time_entries_only (line 42) | def api_token_time_entries_only(app, contract_user_id): function api_token_full (line 56) | def api_token_full(app, contract_user_id): function test_project (line 70) | def test_project(app, contract_user_id): class TestErrorResponseContract (line 85) | class TestErrorResponseContract: method test_401_includes_error_message_and_error_code (line 88) | def test_401_includes_error_message_and_error_code(self, client): method test_403_scope_includes_error_message_and_error_code (line 96) | def test_403_scope_includes_error_message_and_error_code(self, client,... method test_403_get_projects_with_time_entries_only_token (line 112) | def test_403_get_projects_with_time_entries_only_token(self, client, a... method test_400_validation_includes_error_code_and_errors (line 123) | def test_400_validation_includes_error_code_and_errors(self, client, a... method test_404_not_found_includes_error_code (line 140) | def test_404_not_found_includes_error_code(self, client, api_token_full): class TestPaginationContract (line 150) | class TestPaginationContract: method test_projects_list_has_projects_and_pagination (line 153) | def test_projects_list_has_projects_and_pagination(self, client, api_t... method test_pagination_default_per_page (line 164) | def test_pagination_default_per_page(self, client, api_token_full): FILE: tests/test_api_credit_notes_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function setup_invoice (line 50) | def setup_invoice(app, user): function _auth (line 70) | def _auth(t): function test_credit_notes_crud (line 74) | def test_credit_notes_crud(client, api_token, setup_invoice): FILE: tests/test_api_deprecation_headers.py function test_legacy_health_deprecation_header (line 8) | def test_legacy_health_deprecation_header(client): function test_legacy_search_deprecation_header (line 16) | def test_legacy_search_deprecation_header(authenticated_client, project): function test_legacy_timer_status_deprecation_header (line 25) | def test_legacy_timer_status_deprecation_header(authenticated_client): function test_legacy_projects_list_deprecation_header (line 32) | def test_legacy_projects_list_deprecation_header(authenticated_client): FILE: tests/test_api_expenses_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function _auth (line 49) | def _auth(token): function test_expenses_crud (line 53) | def test_expenses_crud(client, api_token): FILE: tests/test_api_favorites_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function user (line 31) | def user(app): function api_token (line 40) | def api_token(app, user): function project (line 48) | def project(app): function _auth (line 58) | def _auth(t): function test_favorites_flow (line 62) | def test_favorites_flow(client, api_token, project): FILE: tests/test_api_invoice_templates_api_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function admin_user (line 31) | def admin_user(app): function admin_token (line 40) | def admin_token(app, admin_user): function _auth (line 47) | def _auth(t): function test_invoice_pdf_templates_list_and_get (line 51) | def test_invoice_pdf_templates_list_and_get(client, admin_token): FILE: tests/test_api_invoice_templates_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function admin_user (line 31) | def admin_user(app): function admin_token (line 40) | def admin_token(app, admin_user): function _auth (line 47) | def _auth(t): function test_invoice_templates_crud (line 51) | def test_invoice_templates_crud(client, admin_token): FILE: tests/test_api_invoices_v1.py function app (line 13) | def app(): function client (line 29) | def client(app): function user (line 34) | def user(app): function api_token (line 43) | def api_token(app, user): function client_model (line 53) | def client_model(app): function project (line 61) | def project(app, client_model): function _auth_header (line 68) | def _auth_header(token): function test_list_invoices_empty (line 72) | def test_list_invoices_empty(client, api_token): function test_create_get_update_cancel_invoice (line 81) | def test_create_get_update_cancel_invoice(client, api_token, user, proje... FILE: tests/test_api_kanban_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function user (line 31) | def user(app): function api_token (line 40) | def api_token(app, user): function _auth (line 47) | def _auth(t): function test_kanban_columns (line 51) | def test_kanban_columns(client, api_token): FILE: tests/test_api_mileage_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function _auth (line 49) | def _auth(t): function test_mileage_crud (line 53) | def test_mileage_crud(client, api_token): FILE: tests/test_api_payments_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function setup_invoice (line 52) | def setup_invoice(app, user): function _auth (line 72) | def _auth(t): function test_payments_crud (line 76) | def test_payments_crud(client, api_token, setup_invoice): FILE: tests/test_api_per_diem_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function _auth (line 49) | def _auth(t): function test_per_diem_crud (line 53) | def test_per_diem_crud(client, api_token): FILE: tests/test_api_project_costs_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function project (line 52) | def project(app): function _auth (line 62) | def _auth(t): function test_project_costs_crud (line 66) | def test_project_costs_crud(client, api_token, project): FILE: tests/test_api_purchase_orders_v1.py function api_token (line 17) | def api_token(db_session, test_user): function _auth_headers (line 29) | def _auth_headers(token): function test_supplier (line 34) | def test_supplier(db_session, test_user): class TestPurchaseOrderCreateAPI (line 41) | class TestPurchaseOrderCreateAPI: method test_create_purchase_order_first_record (line 42) | def test_create_purchase_order_first_record(self, client, api_token, t... method test_create_purchase_order_rejects_invalid_item (line 58) | def test_create_purchase_order_rejects_invalid_item(self, client, api_... method test_create_purchase_order_conflict_maps_to_409 (line 70) | def test_create_purchase_order_conflict_maps_to_409(self, client, api_... FILE: tests/test_api_recurring_invoices_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function user (line 33) | def user(app): function api_token (line 42) | def api_token(app, user): function setup_project_client (line 54) | def setup_project_client(app): function _auth (line 64) | def _auth(t): function test_recurring_invoices_crud_and_generate (line 68) | def test_recurring_invoices_crud_and_generate(client, api_token, user, s... FILE: tests/test_api_route_contract.py function test_contract_routes_registered (line 23) | def test_contract_routes_registered(app): function test_openapi_info_version_matches_app_version (line 36) | def test_openapi_info_version_matches_app_version(app, client): FILE: tests/test_api_saved_filters_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function user (line 31) | def user(app): function api_token (line 40) | def api_token(app, user): function _auth (line 47) | def _auth(t): function test_saved_filters_crud (line 51) | def test_saved_filters_crud(client, api_token): FILE: tests/test_api_tax_currency_v1.py function app (line 12) | def app(): function client (line 28) | def client(app): function admin_user (line 33) | def admin_user(app): function admin_token (line 42) | def admin_token(app, admin_user): function _auth (line 49) | def _auth(t): function test_tax_currency_flow (line 53) | def test_tax_currency_flow(client, admin_token): FILE: tests/test_api_time_entry_templates_v1.py function app (line 10) | def app(): function client (line 26) | def client(app): function user (line 31) | def user(app): function api_token (line 40) | def api_token(app, user): function _auth (line 49) | def _auth(t): function test_templates_crud (line 53) | def test_templates_crud(client, api_token): FILE: tests/test_api_v1.py function app (line 19) | def app(): function client (line 59) | def client(app): function test_user (line 65) | def test_user(app): function admin_user (line 78) | def admin_user(app): function api_token (line 89) | def api_token(app, test_user): function test_project (line 104) | def test_project(app, test_user, test_client_model): function test_client_model (line 119) | def test_client_model(app): class TestAPIAuthentication (line 127) | class TestAPIAuthentication: method test_no_token (line 130) | def test_no_token(self, client): method test_invalid_token (line 137) | def test_invalid_token(self, client): method test_valid_bearer_token (line 143) | def test_valid_bearer_token(self, client, api_token): method test_valid_api_key_header (line 149) | def test_valid_api_key_header(self, client, api_token): method test_insufficient_scope (line 155) | def test_insufficient_scope(self, app, client, test_user, test_client_... class TestAIHelperAPI (line 181) | class TestAIHelperAPI: method test_ai_context_preview_uses_token_auth (line 184) | def test_ai_context_preview_uses_token_auth(self, client, api_token, t... method test_ai_chat_returns_disabled_error_when_not_enabled (line 194) | def test_ai_chat_returns_disabled_error_when_not_enabled(self, client,... class TestProjects (line 203) | class TestProjects: method test_list_projects (line 206) | def test_list_projects(self, client, api_token, test_project): method test_get_project (line 218) | def test_get_project(self, client, api_token, test_project): method test_create_project (line 228) | def test_create_project(self, client, api_token, test_client_model): method test_update_project (line 245) | def test_update_project(self, client, api_token, test_project): method test_delete_project (line 257) | def test_delete_project(self, client, api_token, test_project): class TestTimeEntries (line 271) | class TestTimeEntries: method test_list_time_entries (line 274) | def test_list_time_entries(self, client, api_token, test_user, test_pr... method test_create_time_entry (line 295) | def test_create_time_entry(self, client, api_token, test_project): method test_update_time_entry (line 313) | def test_update_time_entry(self, client, api_token, test_user, test_pr... class TestTimer (line 339) | class TestTimer: method test_get_timer_status_no_active (line 342) | def test_get_timer_status_no_active(self, client, api_token): method test_start_timer (line 352) | def test_start_timer(self, client, api_token, test_project): method test_stop_timer (line 364) | def test_stop_timer(self, client, api_token, test_user, test_project): class TestTasks (line 386) | class TestTasks: method test_list_tasks (line 389) | def test_list_tasks(self, client, api_token, test_user, test_project): method test_create_task (line 409) | def test_create_task(self, client, api_token, test_project): class TestClients (line 428) | class TestClients: method test_list_clients (line 431) | def test_list_clients(self, client, api_token, test_client_model): method test_create_client (line 441) | def test_create_client(self, client, api_token): class TestReports (line 454) | class TestReports: method test_summary_report (line 457) | def test_summary_report(self, client, api_token, test_user, test_proje... class TestPagination (line 488) | class TestPagination: method test_pagination_params (line 491) | def test_pagination_params(self, client, api_token, test_project, test... class TestSystemEndpoints (line 518) | class TestSystemEndpoints: method test_api_info (line 521) | def test_api_info(self, client): method test_health_check (line 531) | def test_health_check(self, client): FILE: tests/test_api_v1_inventory_movements.py function api_token (line 23) | def api_token(db_session, test_user): function test_warehouse (line 37) | def test_warehouse(db_session, test_user): function test_stock_item_trackable (line 46) | def test_stock_item_trackable(db_session, test_user): class TestInventoryMovementsAPI (line 61) | class TestInventoryMovementsAPI: method test_create_return_with_devaluation (line 64) | def test_create_return_with_devaluation( method test_create_waste_with_devaluation (line 107) | def test_create_waste_with_devaluation( FILE: tests/test_audit_log_model.py class TestAuditLogModel (line 9) | class TestAuditLogModel: method test_audit_log_creation (line 12) | def test_audit_log_creation(self, app, test_user, test_project): method test_audit_log_log_change_method (line 33) | def test_audit_log_log_change_method(self, app, test_user, test_project): method test_audit_log_value_encoding (line 58) | def test_audit_log_value_encoding(self, app, test_user, test_project): method test_audit_log_get_for_entity (line 88) | def test_audit_log_get_for_entity(self, app, test_user, test_project): method test_audit_log_get_for_user (line 111) | def test_audit_log_get_for_user(self, app, test_user, test_project): method test_audit_log_get_recent (line 133) | def test_audit_log_get_recent(self, app, test_user, test_project): method test_audit_log_to_dict (line 171) | def test_audit_log_to_dict(self, app, test_user, test_project): method test_audit_log_icons_and_colors (line 196) | def test_audit_log_icons_and_colors(self, app, test_user, test_project): FILE: tests/test_audit_log_routes.py class TestAuditLogRoutes (line 9) | class TestAuditLogRoutes: method test_list_audit_logs_requires_auth (line 12) | def test_list_audit_logs_requires_auth(self, app, client): method test_list_audit_logs_requires_permission (line 19) | def test_list_audit_logs_requires_permission(self, app, client, test_u... method test_list_audit_logs_as_admin (line 31) | def test_list_audit_logs_as_admin(self, app, client, admin_user): method test_view_audit_log_detail (line 53) | def test_view_audit_log_detail(self, app, client, admin_user, test_pro... method test_entity_history_route (line 75) | def test_entity_history_route(self, app, client, admin_user, test_proj... method test_api_audit_logs_endpoint (line 98) | def test_api_audit_logs_endpoint(self, app, client, admin_user, test_p... method test_filter_audit_logs_by_entity_type (line 122) | def test_filter_audit_logs_by_entity_type(self, app, client, admin_use... method test_filter_audit_logs_by_action (line 141) | def test_filter_audit_logs_by_action(self, app, client, admin_user, te... method test_filter_audit_logs_by_user (line 160) | def test_filter_audit_logs_by_user(self, app, client, admin_user, test... FILE: tests/test_audit_logging.py class TestAuditLoggingUtility (line 10) | class TestAuditLoggingUtility: method test_should_track_model (line 13) | def test_should_track_model(self, app, test_project): method test_should_track_field (line 24) | def test_should_track_field(self): method test_serialize_value (line 34) | def test_serialize_value(self): method test_get_entity_name (line 59) | def test_get_entity_name(self, app, test_project, test_user): method test_get_entity_type (line 68) | def test_get_entity_type(self, app, test_project): class TestAuditLoggingIntegration (line 74) | class TestAuditLoggingIntegration: method test_audit_logging_on_create (line 77) | def test_audit_logging_on_create(self, app, test_user, test_client): method test_audit_logging_on_update (line 89) | def test_audit_logging_on_update(self, app, test_user, test_project): method test_audit_logging_on_delete (line 104) | def test_audit_logging_on_delete(self, app, test_user, test_project): FILE: tests/test_audit_trail_smoke.py class TestAuditTrailSmoke (line 10) | class TestAuditTrailSmoke: method test_audit_log_creation_smoke (line 13) | def test_audit_log_creation_smoke(self, app, test_user, test_project): method test_audit_log_field_change_tracking_smoke (line 34) | def test_audit_log_field_change_tracking_smoke(self, app, test_user, t... method test_audit_log_entity_history_smoke (line 58) | def test_audit_log_entity_history_smoke(self, app, test_user, test_pro... method test_audit_log_user_activity_smoke (line 83) | def test_audit_log_user_activity_smoke(self, app, test_user, test_proj... method test_audit_log_filtering_smoke (line 105) | def test_audit_log_filtering_smoke(self, app, test_user, test_project): method test_audit_log_value_serialization_smoke (line 150) | def test_audit_log_value_serialization_smoke(self, app, test_user, tes... FILE: tests/test_basic.py function test_app_creation (line 14) | def test_app_creation(app): function test_database_creation (line 22) | def test_database_creation(app): function test_user_creation (line 38) | def test_user_creation(app): function test_admin_user (line 53) | def test_admin_user(app): function test_project_creation (line 65) | def test_project_creation(app): function test_time_entry_creation (line 92) | def test_time_entry_creation(app, user, project): function test_active_timer (line 116) | def test_active_timer(app, user, project): function test_user_active_timer_property (line 137) | def test_user_active_timer_property(app, user, project): function test_project_totals (line 159) | def test_project_totals(app, user, project): function test_settings_singleton (line 194) | def test_settings_singleton(app): function test_health_check (line 207) | def test_health_check(client): function test_login_page (line 217) | def test_login_page(client): function test_protected_route_redirect (line 225) | def test_protected_route_redirect(client): function test_testing_config_respects_database_url (line 234) | def test_testing_config_respects_database_url(): FILE: tests/test_budget_alert_model.py function client_obj (line 11) | def client_obj(app): function project_with_budget (line 20) | def project_with_budget(app, client_obj): function test_user (line 37) | def test_user(app): function test_budget_alert_creation (line 46) | def test_budget_alert_creation(app, project_with_budget): function test_budget_alert_acknowledge (line 71) | def test_budget_alert_acknowledge(app, project_with_budget, test_user): function test_budget_alert_to_dict (line 95) | def test_budget_alert_to_dict(app, project_with_budget): function test_get_active_alerts (line 126) | def test_get_active_alerts(app, project_with_budget): function test_get_active_alerts_by_project (line 160) | def test_get_active_alerts_by_project(app, project_with_budget, client_o... function test_create_alert_method (line 206) | def test_create_alert_method(app, project_with_budget): function test_create_alert_critical_type (line 224) | def test_create_alert_critical_type(app, project_with_budget): function test_create_alert_over_budget (line 238) | def test_create_alert_over_budget(app, project_with_budget): function test_create_alert_no_duplicates (line 253) | def test_create_alert_no_duplicates(app, project_with_budget): function test_get_alert_summary (line 281) | def test_get_alert_summary(app, project_with_budget, client_obj): function test_get_alert_summary_by_project (line 328) | def test_get_alert_summary_by_project(app, project_with_budget, client_o... function test_alert_repr (line 374) | def test_alert_repr(app, project_with_budget): function test_alert_message_generation (line 395) | def test_alert_message_generation(app, project_with_budget): function test_acknowledged_alerts_filter (line 429) | def test_acknowledged_alerts_filter(app, project_with_budget, test_user): FILE: tests/test_budget_alerts_smoke.py function admin_user (line 12) | def admin_user(app): function regular_user (line 22) | def regular_user(app): function client_obj (line 32) | def client_obj(app): function project_with_budget (line 41) | def project_with_budget(app, client_obj): function test_budget_dashboard_loads (line 58) | def test_budget_dashboard_loads(client, app, admin_user, project_with_bu... function test_project_budget_detail_loads (line 69) | def test_project_budget_detail_loads(client, app, admin_user, project_wi... function test_burn_rate_api_endpoint (line 80) | def test_burn_rate_api_endpoint(client, app, admin_user, project_with_bu... function test_completion_estimate_api_endpoint (line 109) | def test_completion_estimate_api_endpoint(client, app, admin_user, proje... function test_resource_allocation_api_endpoint (line 123) | def test_resource_allocation_api_endpoint(client, app, admin_user, proje... function test_cost_trends_api_endpoint (line 151) | def test_cost_trends_api_endpoint(client, app, admin_user, project_with_... function test_budget_status_api_endpoint (line 180) | def test_budget_status_api_endpoint(client, app, admin_user, project_wit... function test_alerts_api_endpoint (line 196) | def test_alerts_api_endpoint(client, app, admin_user, project_with_budget): function test_acknowledge_alert_api_endpoint (line 224) | def test_acknowledge_alert_api_endpoint(client, app, admin_user, project... function test_check_alerts_api_endpoint (line 256) | def test_check_alerts_api_endpoint(client, app, admin_user, project_with... function test_budget_summary_api_endpoint (line 283) | def test_budget_summary_api_endpoint(client, app, admin_user, project_wi... function test_non_admin_cannot_check_alerts (line 303) | def test_non_admin_cannot_check_alerts(client, app, regular_user, projec... function test_budget_alert_model_integration (line 312) | def test_budget_alert_model_integration(app, project_with_budget): function test_scheduled_task_integration (line 339) | def test_scheduled_task_integration(app, project_with_budget, regular_us... function test_budget_forecasting_utilities_integration (line 365) | def test_budget_forecasting_utilities_integration(app, project_with_budg... function test_project_without_budget_handling (line 411) | def test_project_without_budget_handling(client, app, admin_user, client... function test_end_to_end_budget_workflow (line 430) | def test_end_to_end_budget_workflow(client, app, admin_user, project_wit... FILE: tests/test_budget_forecasting.py function client_obj (line 23) | def client_obj(app): function project_with_budget (line 33) | def project_with_budget(app, client_obj): function test_user (line 50) | def test_user(app): function time_entries_last_30_days (line 60) | def time_entries_last_30_days(app, project_with_budget, test_user): function test_calculate_burn_rate_no_data (line 82) | def test_calculate_burn_rate_no_data(app, project_with_budget): function test_calculate_burn_rate_with_data (line 94) | def test_calculate_burn_rate_with_data(app, project_with_budget, time_en... function test_calculate_burn_rate_invalid_project (line 109) | def test_calculate_burn_rate_invalid_project(app): function test_estimate_completion_date_no_budget (line 115) | def test_estimate_completion_date_no_budget(app, client_obj): function test_estimate_completion_date_no_activity (line 131) | def test_estimate_completion_date_no_activity(app, project_with_budget): function test_estimate_completion_date_with_activity (line 142) | def test_estimate_completion_date_with_activity(app, project_with_budget... function test_analyze_resource_allocation_no_data (line 154) | def test_analyze_resource_allocation_no_data(app, project_with_budget): function test_analyze_resource_allocation_with_data (line 164) | def test_analyze_resource_allocation_with_data(app, project_with_budget,... function test_analyze_cost_trends_no_data (line 184) | def test_analyze_cost_trends_no_data(app, project_with_budget): function test_analyze_cost_trends_with_data (line 194) | def test_analyze_cost_trends_with_data(app, project_with_budget, time_en... function test_analyze_cost_trends_different_granularities (line 205) | def test_analyze_cost_trends_different_granularities(app, project_with_b... function test_get_budget_status_no_budget (line 220) | def test_get_budget_status_no_budget(app, client_obj): function test_get_budget_status_healthy (line 232) | def test_get_budget_status_healthy(app, project_with_budget): function test_get_budget_status_warning (line 245) | def test_get_budget_status_warning(app, project_with_budget, test_user): function test_get_budget_status_critical (line 271) | def test_get_budget_status_critical(app, project_with_budget, test_user): function test_get_budget_status_over_budget (line 297) | def test_get_budget_status_over_budget(app, project_with_budget, test_us... function test_check_budget_alerts_no_alerts_needed (line 322) | def test_check_budget_alerts_no_alerts_needed(app, project_with_budget): function test_check_budget_alerts_warning_alert (line 330) | def test_check_budget_alerts_warning_alert(app, project_with_budget, tes... function test_check_budget_alerts_over_budget (line 353) | def test_check_budget_alerts_over_budget(app, project_with_budget, test_... function test_check_budget_alerts_invalid_project (line 376) | def test_check_budget_alerts_invalid_project(app): function test_resource_allocation_multiple_users (line 383) | def test_resource_allocation_multiple_users(app, project_with_budget, cl... FILE: tests/test_bulk_task_operations.py function tasks_for_bulk (line 19) | def tasks_for_bulk(app, user, admin_user, project): function second_project (line 45) | def second_project(app): function test_bulk_delete_no_tasks_selected (line 75) | def test_bulk_delete_no_tasks_selected(authenticated_client): function test_bulk_delete_multiple_tasks (line 85) | def test_bulk_delete_multiple_tasks(authenticated_client, app, tasks_for... function test_bulk_delete_with_time_entries_skips_task (line 103) | def test_bulk_delete_with_time_entries_skips_task(authenticated_client, ... function test_bulk_delete_permission_check (line 139) | def test_bulk_delete_permission_check(client, app, admin_user, user, pro... function test_bulk_status_no_tasks_selected (line 168) | def test_bulk_status_no_tasks_selected(authenticated_client): function test_bulk_status_change_multiple_tasks (line 180) | def test_bulk_status_change_multiple_tasks(authenticated_client, app, ta... function test_bulk_status_invalid_status (line 201) | def test_bulk_status_invalid_status(authenticated_client, app, tasks_for... function test_bulk_status_reopen_from_done (line 216) | def test_bulk_status_reopen_from_done(authenticated_client, app, tasks_f... function test_bulk_assign_no_tasks_selected (line 249) | def test_bulk_assign_no_tasks_selected(authenticated_client, user): function test_bulk_assign_multiple_tasks (line 261) | def test_bulk_assign_multiple_tasks(authenticated_client, app, tasks_for... function test_bulk_assign_no_user_selected (line 282) | def test_bulk_assign_no_user_selected(authenticated_client, app, tasks_f... function test_bulk_assign_invalid_user (line 295) | def test_bulk_assign_invalid_user(authenticated_client, app, tasks_for_b... function test_bulk_move_project_no_tasks_selected (line 317) | def test_bulk_move_project_no_tasks_selected(authenticated_client, proje... function test_bulk_move_project_multiple_tasks (line 329) | def test_bulk_move_project_multiple_tasks(authenticated_client, app, tas... function test_bulk_move_project_updates_time_entries (line 354) | def test_bulk_move_project_updates_time_entries(authenticated_client, ap... function test_bulk_move_project_no_project_selected (line 394) | def test_bulk_move_project_no_project_selected(authenticated_client, app... function test_bulk_move_project_invalid_project (line 409) | def test_bulk_move_project_invalid_project(authenticated_client, app, ta... function test_bulk_move_project_logs_activity (line 426) | def test_bulk_move_project_logs_activity(authenticated_client, app, task... function test_bulk_operations_routes_exist (line 453) | def test_bulk_operations_routes_exist(authenticated_client): function test_bulk_update_due_date_route (line 492) | def test_bulk_update_due_date_route(authenticated_client, app, tasks_for... function test_bulk_update_priority_route (line 506) | def test_bulk_update_priority_route(authenticated_client, app, tasks_for... function test_task_list_has_checkboxes (line 520) | def test_task_list_has_checkboxes(authenticated_client): function test_export_tasks_csv (line 535) | def test_export_tasks_csv(authenticated_client, app, tasks_for_bulk): function test_export_tasks_with_filters (line 557) | def test_export_tasks_with_filters(authenticated_client, app, tasks_for_... function test_export_button_exists (line 581) | def test_export_button_exists(authenticated_client): FILE: tests/test_calendar_event_model.py function test_calendar_event_creation (line 21) | def test_calendar_event_creation(app, user, project): function test_calendar_event_all_day (line 118) | def test_calendar_event_all_day(app, user): function test_calendar_event_with_project (line 135) | def test_calendar_event_with_project(app, user, project): function test_calendar_event_with_task (line 160) | def test_calendar_event_with_task(app, user, project): function test_calendar_event_with_client (line 190) | def test_calendar_event_with_client(app, user, test_client): function test_calendar_event_recurring (line 214) | def test_calendar_event_recurring(app, user): function test_calendar_event_with_reminder (line 241) | def test_calendar_event_with_reminder(app, user): function test_calendar_event_with_color (line 263) | def test_calendar_event_with_color(app, user): function test_calendar_event_private (line 285) | def test_calendar_event_private(app, user): function test_calendar_event_duration_hours (line 307) | def test_calendar_event_duration_hours(app, user): function test_calendar_event_to_dict (line 324) | def test_calendar_event_to_dict(app, user, project): function test_calendar_event_user_relationship (line 373) | def test_calendar_event_user_relationship(app, user): function test_calendar_event_parent_child_relationship (line 395) | def test_calendar_event_parent_child_relationship(app, user): function test_get_events_in_range (line 438) | def test_get_events_in_range(app, user): function test_get_events_in_range_with_tasks (line 474) | def test_get_events_in_range_with_tasks(app, user, project): function test_get_events_in_range_with_time_entries (line 510) | def test_get_events_in_range_with_time_entries(app, user, project): function test_calendar_event_repr (line 545) | def test_calendar_event_repr(app, user): function test_calendar_event_cascade_delete_with_user (line 564) | def test_calendar_event_cascade_delete_with_user(app, user): function test_calendar_event_cascade_delete_with_parent (line 594) | def test_calendar_event_cascade_delete_with_parent(app, user): function test_calendar_event_different_types (line 639) | def test_calendar_event_different_types(app, user): function test_calendar_event_user_has_events_relationship (line 665) | def test_calendar_event_user_has_events_relationship(app, user): FILE: tests/test_calendar_routes.py function test_calendar_view_accessible (line 20) | def test_calendar_view_accessible(authenticated_client): function test_calendar_view_requires_authentication (line 28) | def test_calendar_view_requires_authentication(client): function test_calendar_day_view (line 36) | def test_calendar_day_view(authenticated_client): function test_calendar_week_view (line 43) | def test_calendar_week_view(authenticated_client): function test_calendar_month_view (line 50) | def test_calendar_month_view(authenticated_client): function test_calendar_with_date_parameter (line 57) | def test_calendar_with_date_parameter(authenticated_client): function test_calendar_default_view_no_param_uses_month_or_session (line 65) | def test_calendar_default_view_no_param_uses_month_or_session(authentica... function test_calendar_url_view_param_stores_in_session_and_used (line 76) | def test_calendar_url_view_param_stores_in_session_and_used(authenticate... function test_calendar_user_default_view_used_when_no_url_param (line 88) | def test_calendar_user_default_view_used_when_no_url_param(authenticated... function test_get_calendar_events_api (line 106) | def test_get_calendar_events_api(authenticated_client, user, app): function test_get_calendar_events_missing_dates (line 132) | def test_get_calendar_events_missing_dates(authenticated_client): function test_create_calendar_event_api (line 142) | def test_create_calendar_event_api(authenticated_client, app): function test_create_calendar_event_missing_required_fields (line 176) | def test_create_calendar_event_missing_required_fields(authenticated_cli... function test_get_single_event_api (line 191) | def test_get_single_event_api(authenticated_client, user, app): function test_get_nonexistent_event (line 212) | def test_get_nonexistent_event(authenticated_client): function test_update_calendar_event_api (line 220) | def test_update_calendar_event_api(authenticated_client, user, app): function test_update_event_permission_denied (line 251) | def test_update_event_permission_denied(authenticated_client, admin_user... function test_delete_calendar_event_api (line 275) | def test_delete_calendar_event_api(authenticated_client, user, app): function test_delete_event_permission_denied (line 300) | def test_delete_event_permission_denied(authenticated_client, admin_user... function test_move_calendar_event_api (line 321) | def test_move_calendar_event_api(authenticated_client, user, app): function test_resize_calendar_event_api (line 353) | def test_resize_calendar_event_api(authenticated_client, user, app): function test_new_event_form_accessible (line 388) | def test_new_event_form_accessible(authenticated_client): function test_edit_event_form_accessible (line 396) | def test_edit_event_form_accessible(authenticated_client, user, app): function test_edit_event_form_permission_denied (line 414) | def test_edit_event_form_permission_denied(authenticated_client, admin_u... function test_view_event_detail (line 431) | def test_view_event_detail(authenticated_client, user, app): function test_calendar_shows_tasks (line 462) | def test_calendar_shows_tasks(authenticated_client, user, project, app): function test_calendar_with_project_filter (line 495) | def test_calendar_with_project_filter(authenticated_client, user, projec... function test_calendar_event_creation_workflow (line 520) | def test_calendar_event_creation_workflow(authenticated_client, user, app): FILE: tests/test_cii_invoice.py function _make_invoice (line 12) | def _make_invoice(**overrides): function _make_seller (line 40) | def _make_seller(**overrides): function _make_buyer (line 57) | def _make_buyer(**overrides): function test_build_cii_produces_valid_xml (line 72) | def test_build_cii_produces_valid_xml(): function test_build_cii_passes_en16931_validation (line 83) | def test_build_cii_passes_en16931_validation(): function test_cii_contains_guideline_id (line 93) | def test_cii_contains_guideline_id(): function test_cii_contains_invoice_number (line 100) | def test_cii_contains_invoice_number(): function test_cii_contains_type_code_380 (line 107) | def test_cii_contains_type_code_380(): function test_cii_contains_issue_date_format_102 (line 113) | def test_cii_contains_issue_date_format_102(): function test_cii_contains_seller_and_buyer (line 121) | def test_cii_contains_seller_and_buyer(): function test_cii_contains_tax_info (line 132) | def test_cii_contains_tax_info(): function test_cii_contains_monetary_totals (line 144) | def test_cii_contains_monetary_totals(): function test_cii_contains_line_items (line 157) | def test_cii_contains_line_items(): function test_cii_adds_placeholder_line_when_no_items (line 171) | def test_cii_adds_placeholder_line_when_no_items(): function test_cii_includes_buyer_reference (line 178) | def test_cii_includes_buyer_reference(): function test_cii_includes_notes (line 186) | def test_cii_includes_notes(): function test_cii_includes_due_date (line 194) | def test_cii_includes_due_date(): function test_cii_includes_seller_tax_registration (line 202) | def test_cii_includes_seller_tax_registration(): function test_cii_includes_seller_legal_organization (line 211) | def test_cii_includes_seller_legal_organization(): function test_cii_sha256_changes_with_content (line 219) | def test_cii_sha256_changes_with_content(): function test_cii_handles_zero_tax (line 228) | def test_cii_handles_zero_tax(): function test_cii_monetary_elements_have_currency_id (line 242) | def test_cii_monetary_elements_have_currency_id(): FILE: tests/test_client_note_model.py function test_client_note_creation (line 20) | def test_client_note_creation(app, user, test_client): function test_client_note_requires_client (line 40) | def test_client_note_requires_client(app, user): function test_client_note_requires_content (line 49) | def test_client_note_requires_content(app, user, test_client): function test_client_note_strips_content (line 58) | def test_client_note_strips_content(app, user, test_client): function test_client_note_author_relationship (line 70) | def test_client_note_author_relationship(app, user, test_client): function test_client_note_client_relationship (line 85) | def test_client_note_client_relationship(app, user, test_client): function test_client_has_notes_relationship (line 100) | def test_client_has_notes_relationship(app, user, test_client): function test_client_note_author_name_property (line 119) | def test_client_note_author_name_property(app, test_client): function test_client_note_client_name_property (line 152) | def test_client_note_client_name_property(app, user, test_client): function test_client_note_can_edit (line 165) | def test_client_note_can_edit(app, user, admin_user, test_client): function test_client_note_can_delete (line 189) | def test_client_note_can_delete(app, user, admin_user, test_client): function test_client_note_edit_content (line 213) | def test_client_note_edit_content(app, user, test_client): function test_client_note_edit_content_permission_denied (line 230) | def test_client_note_edit_content_permission_denied(app, user, test_clie... function test_client_note_edit_content_empty_fails (line 250) | def test_client_note_edit_content_empty_fails(app, user, test_client): function test_client_note_to_dict (line 264) | def test_client_note_to_dict(app, user, test_client): function test_get_client_notes (line 291) | def test_get_client_notes(app, user, test_client): function test_get_important_notes (line 314) | def test_get_important_notes(app, user, test_client): function test_get_user_notes (line 336) | def test_get_user_notes(app, user, test_client): function test_get_recent_notes (line 366) | def test_get_recent_notes(app, user, test_client): function test_client_note_repr (line 386) | def test_client_note_repr(app, user, test_client): function test_client_note_cascade_delete (line 402) | def test_client_note_cascade_delete(app, user, test_client): FILE: tests/test_client_notes_routes.py function test_create_client_note (line 20) | def test_create_client_note(authenticated_client, test_client, user, app): function test_create_important_client_note (line 42) | def test_create_important_client_note(authenticated_client, test_client,... function test_create_note_empty_content_fails (line 62) | def test_create_note_empty_content_fails(authenticated_client, test_clie... function test_create_note_invalid_client_fails (line 81) | def test_create_note_invalid_client_fails(authenticated_client, app): function test_edit_client_note_page (line 96) | def test_edit_client_note_page(authenticated_client, test_client, user, ... function test_edit_client_note_submit (line 114) | def test_edit_client_note_submit(authenticated_client, test_client, user... function test_edit_note_permission_denied (line 141) | def test_edit_note_permission_denied(authenticated_client, test_client, ... function test_delete_client_note (line 162) | def test_delete_client_note(authenticated_client, test_client, user, app): function test_delete_nonexistent_note_fails (line 186) | def test_delete_nonexistent_note_fails(authenticated_client, test_client... function test_toggle_important_note (line 198) | def test_toggle_important_note(authenticated_client, test_client, user, ... function test_list_client_notes_api (line 239) | def test_list_client_notes_api(authenticated_client, test_client, user, ... function test_list_client_notes_api_ordered_by_important (line 260) | def test_list_client_notes_api_ordered_by_important(authenticated_client... function test_get_single_note_api (line 282) | def test_get_single_note_api(authenticated_client, test_client, user, app): function test_get_important_notes_api (line 304) | def test_get_important_notes_api(authenticated_client, test_client, user... function test_get_recent_notes_api (line 327) | def test_get_recent_notes_api(authenticated_client, test_client, user, a... function test_get_user_notes_api (line 348) | def test_get_user_notes_api(authenticated_client, test_client, user, app): function test_client_view_shows_notes (line 373) | def test_client_view_shows_notes(authenticated_client, test_client, user... function test_unauthenticated_user_cannot_access_notes (line 391) | def test_unauthenticated_user_cannot_access_notes(client, test_client, a... FILE: tests/test_client_portal.py function safe_commit_with_retry (line 19) | def safe_commit_with_retry(max_retries=3): function safe_get_user (line 52) | def safe_get_user(user_id): class TestClientPortalUserModel (line 77) | class TestClientPortalUserModel: method test_user_client_portal_enabled_field (line 80) | def test_user_client_portal_enabled_field(self, app, user): method test_user_client_id_field (line 85) | def test_user_client_id_field(self, app, user): method test_is_client_portal_user_property (line 90) | def test_is_client_portal_user_property(self, app, user, test_client): method test_get_client_portal_data (line 104) | def test_get_client_portal_data(self, app, user, test_client): method test_get_client_portal_data_with_projects (line 124) | def test_get_client_portal_data_with_projects(self, app, user, test_cl... method test_get_client_portal_data_with_invoices (line 143) | def test_get_client_portal_data_with_invoices(self, app, user, test_cl... method test_get_client_portal_data_with_time_entries (line 203) | def test_get_client_portal_data_with_time_entries(self, app, user, tes... class TestClientPortalRoutes (line 266) | class TestClientPortalRoutes: method test_client_portal_dashboard_requires_access (line 269) | def test_client_portal_dashboard_requires_access(self, app, client, us... method test_client_portal_dashboard_with_access (line 281) | def test_client_portal_dashboard_with_access(self, app, client, user, ... method test_client_portal_dashboard_customize_save_has_loading_state (line 307) | def test_client_portal_dashboard_customize_save_has_loading_state(self... method test_client_portal_projects_route (line 325) | def test_client_portal_projects_route(self, app, client, user, test_cl... method test_client_portal_invoices_route (line 349) | def test_client_portal_invoices_route(self, app, client, user, test_cl... method test_client_portal_time_entries_route (line 373) | def test_client_portal_time_entries_route(self, app, client, user, tes... method test_view_invoice_belongs_to_client (line 397) | def test_view_invoice_belongs_to_client(self, app, client, user, test_... method test_view_invoice_other_clients_invoice_returns_404_with_flash (line 445) | def test_view_invoice_other_clients_invoice_returns_404_with_flash( method test_view_quote_other_clients_quote_returns_404_with_flash (line 487) | def test_view_quote_other_clients_quote_returns_404_with_flash( class TestAdminClientPortalManagement (line 530) | class TestAdminClientPortalManagement: method test_admin_can_enable_client_portal (line 533) | def test_admin_can_enable_client_portal(self, app, admin_authenticated... method test_admin_can_disable_client_portal (line 586) | def test_admin_can_disable_client_portal(self, app, admin_authenticate... function test_client_portal_smoke (line 661) | def test_client_portal_smoke(app, user, test_client): class TestClientPortalDashboardPreferences (line 685) | class TestClientPortalDashboardPreferences: method test_dashboard_preferences_get_default (line 688) | def test_dashboard_preferences_get_default(self, app, client, user, te... method test_dashboard_preferences_post_and_get (line 704) | def test_dashboard_preferences_post_and_get(self, app, client, user, t... method test_dashboard_preferences_reject_invalid_widget_id (line 724) | def test_dashboard_preferences_reject_invalid_widget_id(self, app, cli... method test_dashboard_preferences_require_auth (line 740) | def test_dashboard_preferences_require_auth(self, app, client): method test_dashboard_preferences_post_non_json_returns_400 (line 745) | def test_dashboard_preferences_post_non_json_returns_400(self, app, cl... method test_dashboard_preferences_post_widget_ids_not_list_returns_400 (line 761) | def test_dashboard_preferences_post_widget_ids_not_list_returns_400( class TestClientPortalReportsVisibility (line 789) | class TestClientPortalReportsVisibility: method test_reports_only_show_authenticated_client_data (line 792) | def test_reports_only_show_authenticated_client_data(self, app, client... method test_reports_date_range_days_param (line 814) | def test_reports_date_range_days_param(self, app, client, user, test_c... method test_reports_csv_export (line 828) | def test_reports_csv_export(self, app, client, user, test_client): method test_reports_csv_export_requires_access (line 845) | def test_reports_csv_export_requires_access(self, app, client): class TestClientPortalActivityFeed (line 858) | class TestClientPortalActivityFeed: method test_activity_feed_requires_auth (line 861) | def test_activity_feed_requires_auth(self, app, client): method test_activity_feed_returns_feed_items (line 866) | def test_activity_feed_returns_feed_items(self, app, client, user, tes... method test_activity_feed_service_only_client_projects (line 880) | def test_activity_feed_service_only_client_projects(self, app, test_cl... function test_get_client_id_from_session_client_portal_id (line 906) | def test_get_client_id_from_session_client_portal_id(app): function test_get_client_id_from_session_user_portal (line 917) | def test_get_client_id_from_session_user_portal(app, user, test_client): function test_get_client_id_from_session_returns_none_without_portal (line 931) | def test_get_client_id_from_session_returns_none_without_portal(app, user): function test_create_notification_emits_to_client_room (line 942) | def test_create_notification_emits_to_client_room(app, test_client): FILE: tests/test_client_prepaid_model.py function test_client_prepaid_properties_and_consumption (line 12) | def test_client_prepaid_properties_and_consumption(app): FILE: tests/test_client_single_simplification.py function test_manual_entry_shows_single_client_prefilled (line 16) | def test_manual_entry_shows_single_client_prefilled(authenticated_client... function test_manual_entry_shows_select_when_multiple_clients (line 38) | def test_manual_entry_shows_select_when_multiple_clients(authenticated_c... FILE: tests/test_comprehensive_tracking.py function mock_tracking (line 11) | def mock_tracking(): class TestClientEventTracking (line 17) | class TestClientEventTracking: method test_client_creation_tracking (line 20) | def test_client_creation_tracking(self, admin_authenticated_client, ad... method test_client_update_tracking (line 35) | def test_client_update_tracking(self, client, admin_user, test_client_... method test_client_archive_tracking (line 51) | def test_client_archive_tracking(self, client, admin_user, test_client... class TestTaskEventTracking (line 64) | class TestTaskEventTracking: method test_task_creation_tracking (line 67) | def test_task_creation_tracking(self, client, auth_user, test_project,... method test_task_status_change_tracking (line 83) | def test_task_status_change_tracking(self, client, auth_user, test_tas... method test_task_update_tracking (line 94) | def test_task_update_tracking(self, client, auth_user, test_task, mock... class TestCommentEventTracking (line 115) | class TestCommentEventTracking: method test_comment_creation_tracking (line 118) | def test_comment_creation_tracking(self, client, auth_user, test_proje... class TestAdminTelemetryDashboard (line 132) | class TestAdminTelemetryDashboard: method test_telemetry_dashboard_access (line 135) | def test_telemetry_dashboard_access(self, client, admin_user): method test_telemetry_toggle (line 145) | def test_telemetry_toggle(self, client, admin_user, installation_config): method test_non_admin_cannot_access_telemetry (line 161) | def test_non_admin_cannot_access_telemetry(self, client, auth_user): FILE: tests/test_config_priority.py class TestConfigPriority (line 14) | class TestConfigPriority: method test_settings_priority_over_env (line 17) | def test_settings_priority_over_env(self, app): method test_env_used_as_initial_value (line 39) | def test_env_used_as_initial_value(self, app): method test_config_manager_priority_order (line 66) | def test_config_manager_priority_order(self, app): method test_env_fallback_when_settings_not_set (line 92) | def test_env_fallback_when_settings_not_set(self, app): method test_settings_initialization_from_env_types (line 112) | def test_settings_initialization_from_env_types(self, app): method test_webui_changes_persist (line 139) | def test_webui_changes_persist(self, app): FILE: tests/test_currency_display.py function app (line 21) | def app(): function admin_user (line 134) | def admin_user(app): function test_client_with_auth (line 146) | def test_client_with_auth(app, client, admin_user): function usd_settings (line 158) | def usd_settings(app): function sample_client (line 174) | def sample_client(app): function sample_project (line 182) | def sample_project(app, sample_client): function sample_invoice (line 193) | def sample_invoice(app, sample_project, admin_user, sample_client): function sample_payment (line 219) | def sample_payment(app, sample_invoice): function sample_expense (line 236) | def sample_expense(app, admin_user, sample_project): function test_currency_symbol_filter_usd (line 254) | def test_currency_symbol_filter_usd(app): function test_currency_symbol_filter_eur (line 268) | def test_currency_symbol_filter_eur(app): function test_currency_symbol_filter_gbp (line 282) | def test_currency_symbol_filter_gbp(app): function test_currency_symbol_filter_fallback (line 296) | def test_currency_symbol_filter_fallback(app): function test_currency_icon_filter_usd (line 310) | def test_currency_icon_filter_usd(app): function test_currency_icon_filter_eur (line 324) | def test_currency_icon_filter_eur(app): function test_currency_injected_in_template_context (line 339) | def test_currency_injected_in_template_context(app, usd_settings): function test_reports_page_displays_usd (line 357) | def test_reports_page_displays_usd(test_client_with_auth, admin_user, us... function test_payments_page_displays_usd (line 380) | def test_payments_page_displays_usd(test_client_with_auth, admin_user, u... function test_expenses_list_page_displays_usd (line 398) | def test_expenses_list_page_displays_usd(test_client_with_auth, admin_us... function test_expenses_dashboard_displays_usd (line 416) | def test_expenses_dashboard_displays_usd(test_client_with_auth, admin_us... function test_settings_default_currency (line 434) | def test_settings_default_currency(app): function test_settings_currency_can_be_changed (line 448) | def test_settings_currency_can_be_changed(app): function test_currency_consistency_across_pages (line 470) | def test_currency_consistency_across_pages( function test_payments_with_different_currencies (line 490) | def test_payments_with_different_currencies(app, test_client_with_auth, ... FILE: tests/test_custom_field_definitions.py function test_custom_field_definition_creation (line 20) | def test_custom_field_definition_creation(app, admin_user): function test_count_clients_with_value_no_clients (line 47) | def test_count_clients_with_value_no_clients(app, admin_user): function test_count_clients_with_value_with_clients (line 64) | def test_count_clients_with_value_with_clients(app, admin_user, test_cli... function test_count_clients_with_value_ignores_empty (line 95) | def test_count_clients_with_value_ignores_empty(app, admin_user, test_cl... function test_count_clients_with_value_ignores_other_fields (line 132) | def test_count_clients_with_value_ignores_other_fields(app, admin_user, ... function test_delete_custom_field_removes_from_clients (line 167) | def test_delete_custom_field_removes_from_clients(app, admin_user, test_... function test_delete_custom_field_multiple_clients (line 206) | def test_delete_custom_field_multiple_clients(app, admin_user, test_clie... function test_delete_custom_field_no_clients_affected (line 248) | def test_delete_custom_field_no_clients_affected(app, admin_user, admin_... function test_delete_custom_field_preserves_other_fields (line 275) | def test_delete_custom_field_preserves_other_fields(app, admin_user, tes... FILE: tests/test_delete_actions.py function test_task_view_shows_delete_button (line 6) | def test_task_view_shows_delete_button(authenticated_client, task, app): function test_client_view_shows_delete_button (line 16) | def test_client_view_shows_delete_button(admin_authenticated_client, tes... function test_project_view_shows_delete_button (line 26) | def test_project_view_shows_delete_button(admin_authenticated_client, pr... function test_delete_task_flow (line 36) | def test_delete_task_flow(authenticated_client, task, app): function test_delete_client_flow_blocked_when_projects_exist (line 48) | def test_delete_client_flow_blocked_when_projects_exist(admin_authentica... function test_delete_project_flow (line 58) | def test_delete_project_flow(admin_authenticated_client, project, app): FILE: tests/test_demo_mode_and_safe_templates.py function test_render_sandboxed_string_allows_invoice_variables (line 17) | def test_render_sandboxed_string_allows_invoice_variables(): function test_render_sandboxed_string_blocks_typical_ssti (line 30) | def test_render_sandboxed_string_blocks_typical_ssti(): function test_demo_mode_init_creates_non_admin_user (line 37) | def test_demo_mode_init_creates_non_admin_user(app_config): function test_demo_mode_init_downgrades_legacy_admin_demo_user (line 70) | def test_demo_mode_init_downgrades_legacy_admin_demo_user(app_config): FILE: tests/test_email.py class TestEmailConfiguration (line 14) | class TestEmailConfiguration: method test_init_mail (line 17) | def test_init_mail(self, app): method test_email_config_status_not_configured (line 26) | def test_email_config_status_not_configured(self, app): method test_email_config_status_configured (line 42) | def test_email_config_status_configured(self, app): method test_email_config_warns_about_default_sender (line 63) | def test_email_config_warns_about_default_sender(self, app): method test_email_config_errors_on_both_tls_and_ssl (line 74) | def test_email_config_errors_on_both_tls_and_ssl(self, app): class TestSendEmail (line 87) | class TestSendEmail: method test_send_email_success (line 92) | def test_send_email_success(self, mock_thread, mock_send, app): method test_send_email_no_server (line 107) | def test_send_email_no_server(self, app): method test_send_email_no_recipients (line 118) | def test_send_email_no_recipients(self, app): method test_send_test_email_success (line 130) | def test_send_test_email_success(self, mock_send, app): method test_send_test_email_invalid_recipient (line 142) | def test_send_test_email_invalid_recipient(self, app): method test_send_test_email_no_server (line 150) | def test_send_test_email_no_server(self, app): method test_send_test_email_exception (line 161) | def test_send_test_email_exception(self, mock_send, app): class TestEmailIntegration (line 176) | class TestEmailIntegration: method check_email_configuration_in_app_context (line 179) | def check_email_configuration_in_app_context(self, app): method test_email_settings_from_environment (line 188) | def test_email_settings_from_environment(self, app, monkeypatch): class TestDatabaseEmailConfiguration (line 204) | class TestDatabaseEmailConfiguration: method test_get_mail_config_when_disabled (line 207) | def test_get_mail_config_when_disabled(self, app): method test_get_mail_config_when_enabled (line 219) | def test_get_mail_config_when_enabled(self, app): method test_init_mail_uses_database_config (line 245) | def test_init_mail_uses_database_config(self, app): method test_reload_mail_config (line 264) | def test_reload_mail_config(self, app): method test_check_email_configuration_shows_source (line 283) | def test_check_email_configuration_shows_source(self, app): function mock_mail_send (line 311) | def mock_mail_send(): FILE: tests/test_enhanced_ui.py class TestEnhancedUI (line 9) | class TestEnhancedUI: method test_enhanced_css_loaded (line 12) | def test_enhanced_css_loaded(self, authenticated_client): method test_enhanced_js_loaded (line 18) | def test_enhanced_js_loaded(self, authenticated_client): method test_charts_js_loaded (line 24) | def test_charts_js_loaded(self, authenticated_client): method test_onboarding_js_loaded (line 30) | def test_onboarding_js_loaded(self, authenticated_client): method test_toast_notifications_js_loaded (line 36) | def test_toast_notifications_js_loaded(self, authenticated_client): method test_set_submit_button_loading_available (line 42) | def test_set_submit_button_loading_available(self, authenticated_client): method test_filter_ajax_error_toast_message_in_enhanced_ui (line 49) | def test_filter_ajax_error_toast_message_in_enhanced_ui(self, authenti... class TestComponentLibrary (line 57) | class TestComponentLibrary: method test_ui_components_file_exists (line 60) | def test_ui_components_file_exists(self): method test_page_header_component (line 67) | def test_page_header_component(self, app): method test_stat_card_component (line 82) | def test_stat_card_component(self, app): method test_breadcrumb_component (line 97) | def test_breadcrumb_component(self, app): method test_button_component (line 111) | def test_button_component(self, app): method test_empty_state_component (line 126) | def test_empty_state_component(self, app): method test_loading_spinner_component (line 141) | def test_loading_spinner_component(self, app): method test_progress_bar_component (line 154) | def test_progress_bar_component(self, app): method test_badge_component (line 168) | def test_badge_component(self, app): method test_alert_component (line 182) | def test_alert_component(self, app): class TestEnhancedTables (line 196) | class TestEnhancedTables: method test_projects_table_enhanced (line 199) | def test_projects_table_enhanced(self, authenticated_client): method test_tasks_table_enhanced (line 205) | def test_tasks_table_enhanced(self, authenticated_client): class TestPWA (line 212) | class TestPWA: method test_service_worker_exists (line 215) | def test_service_worker_exists(self): method test_manifest_exists (line 222) | def test_manifest_exists(self): method test_manifest_linked_in_base (line 229) | def test_manifest_linked_in_base(self, authenticated_client): method test_pwa_meta_tags (line 235) | def test_pwa_meta_tags(self, authenticated_client): class TestAccessibility (line 243) | class TestAccessibility: method test_skip_link_present (line 246) | def test_skip_link_present(self, authenticated_client): method test_aria_labels_present (line 252) | def test_aria_labels_present(self, authenticated_client): class TestChartJS (line 260) | class TestChartJS: method test_chartjs_loaded (line 263) | def test_chartjs_loaded(self, authenticated_client): method test_chart_manager_loaded (line 269) | def test_chart_manager_loaded(self, authenticated_client): class TestFilterSystem (line 276) | class TestFilterSystem: method test_filter_form_attribute (line 279) | def test_filter_form_attribute(self, authenticated_client): class TestBreadcrumbs (line 286) | class TestBreadcrumbs: method test_breadcrumbs_in_projects (line 289) | def test_breadcrumbs_in_projects(self, authenticated_client): method test_breadcrumbs_in_tasks (line 296) | def test_breadcrumbs_in_tasks(self, authenticated_client): class TestResponsiveDesign (line 303) | class TestResponsiveDesign: method test_viewport_meta_tag (line 306) | def test_viewport_meta_tag(self, authenticated_client): method test_mobile_navigation_button (line 313) | def test_mobile_navigation_button(self, authenticated_client): class TestStaticFiles (line 320) | class TestStaticFiles: method test_enhanced_ui_css_exists (line 323) | def test_enhanced_ui_css_exists(self): method test_enhanced_ui_js_exists (line 329) | def test_enhanced_ui_js_exists(self): method test_charts_js_exists (line 335) | def test_charts_js_exists(self): method test_onboarding_js_exists (line 341) | def test_onboarding_js_exists(self): method test_service_worker_js_exists (line 347) | def test_service_worker_js_exists(self): FILE: tests/test_error_handling.py function test_user_friendly_message_404 (line 18) | def test_user_friendly_message_404(): function test_user_friendly_message_500 (line 31) | def test_user_friendly_message_500(): function test_user_friendly_message_401 (line 41) | def test_user_friendly_message_401(): function test_user_friendly_message_403 (line 51) | def test_user_friendly_message_403(): function test_user_friendly_message_unknown_status (line 61) | def test_user_friendly_message_unknown_status(): function test_user_friendly_message_with_description (line 72) | def test_user_friendly_message_with_description(): function test_recovery_options_include_dashboard (line 81) | def test_recovery_options_include_dashboard(): function test_error_handling_enhanced_file_exists (line 89) | def test_error_handling_enhanced_file_exists(): function test_error_handling_retry_functionality (line 99) | def test_error_handling_retry_functionality(): function test_offline_queue_functionality (line 113) | def test_offline_queue_functionality(): function test_graceful_degradation (line 130) | def test_graceful_degradation(): function test_error_handling_js_loaded (line 144) | def test_error_handling_js_loaded(authenticated_client): function test_api_health_endpoint (line 154) | def test_api_health_endpoint(client): function test_error_handlers_registered (line 166) | def test_error_handlers_registered(app): function test_error_template_updates (line 178) | def test_error_template_updates(client): function test_error_handling_network_monitoring (line 190) | def test_error_handling_network_monitoring(): function test_error_handling_offline_indicator (line 204) | def test_error_handling_offline_indicator(): function test_error_handling_recovery_options (line 218) | def test_error_handling_recovery_options(): FILE: tests/test_excel_export.py function test_create_time_entries_excel_with_client (line 13) | def test_create_time_entries_excel_with_client(app, user, project, test_... function test_create_time_entries_excel_with_task (line 56) | def test_create_time_entries_excel_with_task(app, user, project, task): function test_create_time_entries_excel_multiple_entries (line 92) | def test_create_time_entries_excel_multiple_entries(app, multiple_time_e... function test_project_report_excel_export (line 111) | def test_project_report_excel_export(app, time_entry): FILE: tests/test_expenses.py function app (line 22) | def app(): function client_fixture (line 34) | def client_fixture(app): function test_user (line 40) | def test_user(app): function test_admin (line 50) | def test_admin(app): function test_client (line 60) | def test_client(app): function test_project (line 70) | def test_project(app, test_client): function test_invoice (line 86) | def test_invoice(app, test_client, test_project, test_user): class TestExpenseModel (line 107) | class TestExpenseModel: method test_create_expense (line 110) | def test_create_expense(self, app, test_user): method test_create_expense_with_all_fields (line 132) | def test_create_expense_with_all_fields(self, app, test_user, test_pro... method test_expense_str_representation (line 164) | def test_expense_str_representation(self, app, test_user): method test_expense_timestamps (line 180) | def test_expense_timestamps(self, app, test_user): class TestExpenseProperties (line 199) | class TestExpenseProperties: method test_total_amount_property (line 202) | def test_total_amount_property(self, app, test_user): method test_tag_list_property (line 218) | def test_tag_list_property(self, app, test_user): method test_is_approved_property (line 238) | def test_is_approved_property(self, app, test_user, test_admin): method test_is_reimbursed_property (line 260) | def test_is_reimbursed_property(self, app, test_user): class TestExpenseRelationships (line 281) | class TestExpenseRelationships: method test_user_relationship (line 284) | def test_user_relationship(self, app, test_user): method test_project_relationship (line 304) | def test_project_relationship(self, app, test_user, test_project): method test_client_relationship (line 325) | def test_client_relationship(self, app, test_user, test_client): class TestExpenseMethods (line 347) | class TestExpenseMethods: method test_approve_method (line 350) | def test_approve_method(self, app, test_user, test_admin): method test_reject_method (line 370) | def test_reject_method(self, app, test_user, test_admin): method test_mark_as_reimbursed (line 390) | def test_mark_as_reimbursed(self, app, test_user, test_admin): method test_mark_as_invoiced (line 415) | def test_mark_as_invoiced(self, app, test_user, test_invoice): method test_to_dict (line 435) | def test_to_dict(self, app, test_user): class TestExpenseQueries (line 463) | class TestExpenseQueries: method test_get_expenses (line 466) | def test_get_expenses(self, app, test_user): method test_get_expenses_by_status (line 488) | def test_get_expenses_by_status(self, app, test_user, test_admin): method test_get_total_expenses (line 520) | def test_get_total_expenses(self, app, test_user): method test_get_expenses_by_category (line 544) | def test_get_expenses_by_category(self, app, test_user): method test_get_pending_approvals (line 567) | def test_get_pending_approvals(self, app, test_user): method test_get_uninvoiced_expenses (line 592) | def test_get_uninvoiced_expenses(self, app, test_user, test_admin, tes... class TestExpenseConstraints (line 626) | class TestExpenseConstraints: method test_cannot_create_expense_without_user (line 629) | def test_cannot_create_expense_without_user(self, app): class TestExpenseSmokeTests (line 650) | class TestExpenseSmokeTests: method test_expense_creation_smoke (line 653) | def test_expense_creation_smoke(self, app, test_user): method test_expense_query_smoke (line 668) | def test_expense_query_smoke(self, app, test_user): method test_expense_workflow_smoke (line 684) | def test_expense_workflow_smoke(self, app, test_user, test_admin): FILE: tests/test_extra_good_model.py class TestExtraGoodModel (line 12) | class TestExtraGoodModel: method test_create_extra_good_for_project (line 15) | def test_create_extra_good_for_project(self, app, db_session): method test_create_extra_good_for_invoice (line 56) | def test_create_extra_good_for_invoice(self, app, db_session): method test_update_total (line 99) | def test_update_total(self, app, db_session): method test_to_dict (line 122) | def test_to_dict(self, app, db_session): method test_get_project_goods (line 151) | def test_get_project_goods(self, app, db_session): method test_get_total_amount (line 187) | def test_get_total_amount(self, app, db_session): method test_get_goods_by_category (line 220) | def test_get_goods_by_category(self, app, db_session): FILE: tests/test_factories_smoke.py function test_project_and_client_factory_persist (line 25) | def test_project_and_client_factory_persist(app): function test_timeentry_factory_and_duration (line 37) | def test_timeentry_factory_and_duration(app): function test_invoice_and_items_factories (line 51) | def test_invoice_and_items_factories(app): function test_expense_factory (line 63) | def test_expense_factory(app): function test_payment_factory (line 75) | def test_payment_factory(app): function test_expense_category_factory (line 86) | def test_expense_category_factory(app): FILE: tests/test_favorite_projects.py function app (line 20) | def app(): function client_fixture (line 42) | def client_fixture(app): function test_user (line 48) | def test_user(app): function test_admin (line 58) | def test_admin(app): function test_client (line 68) | def test_client(app): function test_project (line 78) | def test_project(app, test_client): function test_project_2 (line 94) | def test_project_2(app, test_client): class TestUserFavoriteProjectModel (line 112) | class TestUserFavoriteProjectModel: method test_create_favorite (line 115) | def test_create_favorite(self, app, test_user, test_project): method test_favorite_unique_constraint (line 131) | def test_favorite_unique_constraint(self, app, test_user, test_project): method test_favorite_to_dict (line 151) | def test_favorite_to_dict(self, app, test_user, test_project): class TestUserFavoriteProjectMethods (line 169) | class TestUserFavoriteProjectMethods: method test_add_favorite_project (line 172) | def test_add_favorite_project(self, app, test_user, test_project): method test_add_favorite_project_idempotent (line 185) | def test_add_favorite_project_idempotent(self, app, test_user, test_pr... method test_remove_favorite_project (line 199) | def test_remove_favorite_project(self, app, test_user, test_project): method test_is_project_favorite_with_id (line 212) | def test_is_project_favorite_with_id(self, app, test_user, test_project): method test_get_favorite_projects (line 227) | def test_get_favorite_projects(self, app, test_user, test_project, tes... method test_get_favorite_projects_filtered_by_status (line 244) | def test_get_favorite_projects_filtered_by_status(self, app, test_user... class TestProjectFavoriteMethods (line 267) | class TestProjectFavoriteMethods: method test_is_favorited_by_user (line 270) | def test_is_favorited_by_user(self, app, test_user, test_project): method test_is_favorited_by_user_id (line 285) | def test_is_favorited_by_user_id(self, app, test_user, test_project): method test_project_to_dict_with_favorite_status (line 297) | def test_project_to_dict_with_favorite_status(self, app, test_user, te... class TestFavoriteProjectRoutes (line 323) | class TestFavoriteProjectRoutes: method test_favorite_project_route (line 326) | def test_favorite_project_route(self, app, client_fixture, test_user, ... method test_unfavorite_project_route (line 346) | def test_unfavorite_project_route(self, app, client_fixture, test_user... method test_favorite_nonexistent_project (line 371) | def test_favorite_nonexistent_project(self, app, client_fixture, test_... method test_favorite_project_requires_login (line 380) | def test_favorite_project_requires_login(self, app, client_fixture, te... class TestFavoriteProjectFiltering (line 388) | class TestFavoriteProjectFiltering: method test_list_projects_with_favorites_filter (line 391) | def test_list_projects_with_favorites_filter(self, app, client_fixture... method test_list_all_projects_without_filter (line 410) | def test_list_all_projects_without_filter(self, app, client_fixture, t... class TestFavoriteProjectRelationships (line 433) | class TestFavoriteProjectRelationships: method test_delete_user_cascades_favorites (line 436) | def test_delete_user_cascades_favorites(self, app, test_user, test_pro... method test_delete_project_cascades_favorites (line 457) | def test_delete_project_cascades_favorites(self, app, test_user, test_... method test_multiple_users_favorite_same_project (line 478) | def test_multiple_users_favorite_same_project(self, app, test_user, te... class TestFavoriteProjectsSmoke (line 501) | class TestFavoriteProjectsSmoke: method test_complete_favorite_workflow (line 504) | def test_complete_favorite_workflow(self, app, test_user, test_project): method test_favorite_with_archived_projects (line 530) | def test_favorite_with_archived_projects(self, app, test_user, test_pr... FILE: tests/test_i18n.py class TestI18nConfiguration (line 13) | class TestI18nConfiguration: method test_supported_languages_configured (line 16) | def test_supported_languages_configured(self, client): method test_rtl_languages_configured (line 40) | def test_rtl_languages_configured(self, client): method test_default_locale_is_english (line 54) | def test_default_locale_is_english(self, client): class TestLocaleSelection (line 61) | class TestLocaleSelection: method test_locale_from_user_preference (line 64) | def test_locale_from_user_preference(self, client, test_user): method test_locale_from_session (line 84) | def test_locale_from_session(self, client): method test_locale_fallback_to_default (line 98) | def test_locale_fallback_to_default(self, client): class TestLanguageSwitching (line 108) | class TestLanguageSwitching: method test_set_language_direct_route (line 111) | def test_set_language_direct_route(self, client, test_user): method test_set_language_api_endpoint (line 131) | def test_set_language_api_endpoint(self, client, test_user): method test_set_invalid_language (line 149) | def test_set_invalid_language(self, client, test_user): method test_language_persists_across_sessions (line 162) | def test_language_persists_across_sessions(self, client, test_user): class TestRTLSupport (line 181) | class TestRTLSupport: method test_rtl_detection_for_arabic (line 184) | def test_rtl_detection_for_arabic(self, client, test_user): method test_rtl_detection_for_hebrew (line 201) | def test_rtl_detection_for_hebrew(self, client, test_user): method test_ltr_for_english (line 218) | def test_ltr_for_english(self, client, test_user): class TestTranslations (line 236) | class TestTranslations: method test_english_translations (line 239) | def test_english_translations(self, client): method test_translation_files_exist (line 249) | def test_translation_files_exist(self, client): class TestLanguageSelectorUI (line 260) | class TestLanguageSelectorUI: method test_language_selector_in_header (line 263) | def test_language_selector_in_header(self, client, test_user): method test_language_list_contains_all_languages (line 277) | def test_language_list_contains_all_languages(self, client, test_user): class TestUserSettingsLanguage (line 294) | class TestUserSettingsLanguage: method test_language_setting_in_user_settings (line 297) | def test_language_setting_in_user_settings(self, client, test_user): method test_save_language_in_user_settings (line 310) | def test_save_language_in_user_settings(self, client, test_user): function test_user (line 334) | def test_user(client): FILE: tests/test_import_export.py function app (line 19) | def app(): function client_fixture (line 73) | def client_fixture(app): function auth_headers (line 79) | def auth_headers(app, client_fixture): function admin_auth_headers (line 93) | def admin_auth_headers(app, client_fixture): class TestCSVImport (line 106) | class TestCSVImport: method test_csv_import_success (line 109) | def test_csv_import_success(self, app, client_fixture, auth_headers): method test_csv_import_no_file (line 126) | def test_csv_import_no_file(self, app, client_fixture, auth_headers): method test_csv_import_wrong_extension (line 134) | def test_csv_import_wrong_extension(self, app, client_fixture, auth_he... class TestGDPRExport (line 147) | class TestGDPRExport: method test_gdpr_export_json (line 150) | def test_gdpr_export_json(self, app, client_fixture, auth_headers): method test_gdpr_export_zip (line 160) | def test_gdpr_export_zip(self, app, client_fixture, auth_headers): method test_gdpr_export_invalid_format (line 169) | def test_gdpr_export_invalid_format(self, app, client_fixture, auth_he... class TestFilteredExport (line 178) | class TestFilteredExport: method test_filtered_export_json (line 181) | def test_filtered_export_json(self, app, client_fixture, auth_headers): method test_filtered_export_csv (line 194) | def test_filtered_export_csv(self, app, client_fixture, auth_headers): class TestBackupRestore (line 207) | class TestBackupRestore: method test_create_backup_admin_only (line 210) | def test_create_backup_admin_only(self, app, client_fixture, auth_head... method test_create_backup_success (line 218) | def test_create_backup_success(self, app, client_fixture, admin_auth_h... class TestImportHistory (line 229) | class TestImportHistory: method test_import_history (line 232) | def test_import_history(self, app, client_fixture, auth_headers): class TestExportHistory (line 242) | class TestExportHistory: method test_export_history (line 245) | def test_export_history(self, app, client_fixture, auth_headers): class TestDownloadExport (line 255) | class TestDownloadExport: method test_download_nonexistent_export (line 258) | def test_download_nonexistent_export(self, app, client_fixture, auth_h... class TestCSVTemplate (line 265) | class TestCSVTemplate: method test_download_csv_template (line 268) | def test_download_csv_template(self, app, client_fixture, auth_headers): class TestDataImportModel (line 277) | class TestDataImportModel: method test_create_import_record (line 280) | def test_create_import_record(self, app): method test_import_record_progress (line 293) | def test_import_record_progress(self, app): class TestDataExportModel (line 315) | class TestDataExportModel: method test_create_export_record (line 318) | def test_create_export_record(self, app): method test_export_record_completion (line 330) | def test_export_record_completion(self, app): method test_export_expiration (line 350) | def test_export_expiration(self, app): FILE: tests/test_installation_config.py function temp_config_dir (line 14) | def temp_config_dir(tmp_path): function installation_config (line 22) | def installation_config(temp_config_dir, monkeypatch): class TestInstallationConfig (line 30) | class TestInstallationConfig: method test_installation_salt_generation (line 33) | def test_installation_salt_generation(self, installation_config): method test_installation_id_generation (line 44) | def test_installation_id_generation(self, installation_config): method test_install_id_uuid_format (line 54) | def test_install_id_uuid_format(self, installation_config): method test_installation_id_uniqueness (line 63) | def test_installation_id_uniqueness(self, temp_config_dir, monkeypatch): method test_setup_completion (line 77) | def test_setup_completion(self, installation_config): method test_telemetry_preference (line 92) | def test_telemetry_preference(self, installation_config): method test_config_persistence (line 105) | def test_config_persistence(self, installation_config, temp_config_dir): method test_get_all_config (line 124) | def test_get_all_config(self, installation_config): method test_initial_data_seeding_tracking (line 138) | def test_initial_data_seeding_tracking(self, installation_config): method test_initial_data_seeding_persistence (line 151) | def test_initial_data_seeding_persistence(self, installation_config, t... method test_initial_data_seeding_default_value (line 166) | def test_initial_data_seeding_default_value(self, installation_config): method test_set_telemetry_preference_does_not_remove_setup_complete (line 171) | def test_set_telemetry_preference_does_not_remove_setup_complete(self,... method test_get_telemetry_bad_load_does_not_poison_then_wipe_setup_complete (line 186) | def test_get_telemetry_bad_load_does_not_poison_then_wipe_setup_complete( class TestSetupRoutes (line 207) | class TestSetupRoutes: method test_setup_page_redirects_if_complete (line 210) | def test_setup_page_redirects_if_complete(self, client, installation_c... method test_setup_completion_flow (line 219) | def test_setup_completion_flow(self, client, installation_config): method test_setup_without_telemetry (line 242) | def test_setup_without_telemetry(self, client, installation_config): FILE: tests/test_integration/test_activitywatch_integration.py function test_user (line 18) | def test_user(db_session): function test_project (line 28) | def test_project(db_session, test_user): function activitywatch_integration (line 43) | def activitywatch_integration(db_session, test_user, test_project): class TestActivityWatchConnector (line 62) | class TestActivityWatchConnector: method test_provider_name (line 65) | def test_provider_name(self, activitywatch_integration): method test_test_connection_success (line 71) | def test_test_connection_success(self, mock_get, activitywatch_integra... method test_test_connection_failure (line 89) | def test_test_connection_failure(self, mock_get, activitywatch_integra... method test_sync_data_imports_events (line 100) | def test_sync_data_imports_events(self, mock_get, db_session, activity... method test_sync_data_skips_duplicates (line 135) | def test_sync_data_skips_duplicates(self, mock_get, db_session, activi... method test_get_config_schema (line 189) | def test_get_config_schema(self, activitywatch_integration): FILE: tests/test_integration/test_caldav_integration.py function test_user (line 20) | def test_user(db_session): function test_project (line 30) | def test_project(db_session, test_user): function caldav_integration (line 45) | def caldav_integration(db_session, test_user, test_project): class TestCalDAVClient (line 79) | class TestCalDAVClient: method test_client_initialization (line 82) | def test_client_initialization(self): method test_discover_calendars (line 90) | def test_discover_calendars(self, mock_request): class TestCalDAVConnector (line 150) | class TestCalDAVConnector: method test_provider_name (line 153) | def test_provider_name(self, caldav_integration): method test_get_basic_creds (line 159) | def test_get_basic_creds(self, caldav_integration): method test_get_basic_creds_missing (line 167) | def test_get_basic_creds_missing(self, caldav_integration): method test_test_connection (line 174) | def test_test_connection(self, mock_client_class, caldav_integration): method test_sync_data_imports_events (line 192) | def test_sync_data_imports_events(self, mock_client_class, db_session,... method test_sync_data_skips_duplicates (line 231) | def test_sync_data_skips_duplicates(self, mock_client_class, db_sessio... class TestCalDAVRoutes (line 280) | class TestCalDAVRoutes: method test_caldav_setup_get (line 283) | def test_caldav_setup_get(self, authenticated_client, test_user, test_... method test_caldav_setup_post (line 289) | def test_caldav_setup_post(self, authenticated_client, test_user, test... class TestIntegrationExternalEventLink (line 322) | class TestIntegrationExternalEventLink: method test_link_creation (line 325) | def test_link_creation(self, db_session, caldav_integration, test_proj... method test_link_unique_constraint (line 351) | def test_link_unique_constraint(self, db_session, caldav_integration, ... FILE: tests/test_integration/test_inventory_integration.py function test_user (line 28) | def test_user(db_session): function test_client (line 38) | def test_client(db_session): function test_warehouse (line 47) | def test_warehouse(db_session, test_user): function test_stock_item (line 56) | def test_stock_item(db_session, test_user): function test_stock_with_quantity (line 72) | def test_stock_with_quantity(db_session, test_stock_item, test_warehouse): class TestQuoteInventoryIntegration (line 82) | class TestQuoteInventoryIntegration: method test_quote_with_stock_item (line 85) | def test_quote_with_stock_item( method test_quote_create_expense_and_good_lines (line 125) | def test_quote_create_expense_and_good_lines(self, client, test_user, ... method test_quote_send_reserves_stock (line 166) | def test_quote_send_reserves_stock( class TestInvoiceInventoryIntegration (line 206) | class TestInvoiceInventoryIntegration: method test_invoice_with_stock_item (line 209) | def test_invoice_with_stock_item( method test_invoice_sent_reduces_stock (line 257) | def test_invoice_sent_reduces_stock( method test_invoice_sent_twice_does_not_double_reduce_stock (line 311) | def test_invoice_sent_twice_does_not_double_reduce_stock( class TestStockReservationLifecycle (line 369) | class TestStockReservationLifecycle: method test_reservation_fulfillment (line 372) | def test_reservation_fulfillment( method test_reservation_cancellation (line 397) | def test_reservation_cancellation( FILE: tests/test_integration/test_jira_integration.py function test_user (line 19) | def test_user(db_session): function jira_integration (line 29) | def jira_integration(db_session, test_user): function jira_integration_no_auto_sync (line 48) | def jira_integration_no_auto_sync(db_session, test_user): function jira_integration_with_webhook_secret (line 67) | def jira_integration_with_webhook_secret(db_session, test_user): function _jira_webhook_signature (line 86) | def _jira_webhook_signature(secret: str, body: bytes) -> str: class TestJiraIssueKeyPattern (line 92) | class TestJiraIssueKeyPattern: method test_valid_keys (line 95) | def test_valid_keys(self): method test_invalid_keys (line 101) | def test_invalid_keys(self): class TestJiraHandleWebhook (line 109) | class TestJiraHandleWebhook: method test_handle_webhook_valid_issue_updated_triggers_sync (line 112) | def test_handle_webhook_valid_issue_updated_triggers_sync( method test_handle_webhook_valid_issue_created_triggers_sync (line 131) | def test_handle_webhook_valid_issue_created_triggers_sync( method test_handle_webhook_malformed_payload_not_dict (line 146) | def test_handle_webhook_malformed_payload_not_dict(self, jira_integrat... method test_handle_webhook_malformed_payload_issue_not_dict (line 156) | def test_handle_webhook_malformed_payload_issue_not_dict( method test_handle_webhook_malformed_payload_missing_issue_key (line 169) | def test_handle_webhook_malformed_payload_missing_issue_key( method test_handle_webhook_malformed_payload_invalid_key_format (line 190) | def test_handle_webhook_malformed_payload_invalid_key_format( method test_handle_webhook_unsupported_event_type (line 206) | def test_handle_webhook_unsupported_event_type(self, jira_integration): method test_handle_webhook_sync_failure (line 220) | def test_handle_webhook_sync_failure(self, jira_integration): method test_handle_webhook_auto_sync_disabled_ack_only (line 238) | def test_handle_webhook_auto_sync_disabled_ack_only( method test_handle_webhook_duplicate_idempotent (line 254) | def test_handle_webhook_duplicate_idempotent(self, jira_integration): class TestJiraWebhookVerification (line 271) | class TestJiraWebhookVerification: method test_handle_webhook_with_secret_and_valid_signature_accepted (line 274) | def test_handle_webhook_with_secret_and_valid_signature_accepted( method test_handle_webhook_with_secret_and_missing_signature_rejected (line 294) | def test_handle_webhook_with_secret_and_missing_signature_rejected( method test_handle_webhook_with_secret_and_wrong_signature_rejected (line 310) | def test_handle_webhook_with_secret_and_wrong_signature_rejected( method test_handle_webhook_without_secret_no_verification (line 329) | def test_handle_webhook_without_secret_no_verification(self, jira_inte... class TestJiraSyncIssue (line 343) | class TestJiraSyncIssue: method test_sync_issue_success (line 346) | def test_sync_issue_success(self, jira_integration): method test_sync_issue_not_found (line 374) | def test_sync_issue_not_found(self, jira_integration): method test_sync_issue_invalid_key_empty (line 386) | def test_sync_issue_invalid_key_empty(self, jira_integration): method test_sync_issue_invalid_key_format (line 395) | def test_sync_issue_invalid_key_format(self, jira_integration): method test_sync_issue_no_token (line 405) | def test_sync_issue_no_token(self, jira_integration): class TestJiraWebhookRoute (line 417) | class TestJiraWebhookRoute: method test_post_webhook_unknown_provider_returns_404 (line 420) | def test_post_webhook_unknown_provider_returns_404(self, app, client): method test_post_jira_webhook_malformed_body_returns_500 (line 431) | def test_post_jira_webhook_malformed_body_returns_500( method test_post_jira_webhook_valid_payload_returns_200 (line 447) | def test_post_jira_webhook_valid_payload_returns_200( FILE: tests/test_invoice_currency_fix.py function app (line 16) | def app(): function client_fixture (line 45) | def client_fixture(app): function test_user (line 51) | def test_user(app): function test_client_model (line 62) | def test_client_model(app, test_user): function test_project (line 75) | def test_project(app, test_user, test_client_model): class TestInvoiceCurrencyFix (line 90) | class TestInvoiceCurrencyFix: method test_new_invoice_uses_settings_currency (line 93) | def test_new_invoice_uses_settings_currency(self, app, test_user, test... method test_invoice_creation_via_route (line 117) | def test_invoice_creation_via_route(self, app, client_fixture, test_us... method test_invoice_with_different_currency_setting (line 145) | def test_invoice_with_different_currency_setting(self, app, test_user,... method test_invoice_duplicate_preserves_currency (line 170) | def test_invoice_duplicate_preserves_currency(self, app, test_user, te... method test_invoice_items_display_with_currency (line 204) | def test_invoice_items_display_with_currency(self, app, test_user, tes... method test_settings_currency_default (line 235) | def test_settings_currency_default(self, app): method test_invoice_model_init_with_currency_kwarg (line 249) | def test_invoice_model_init_with_currency_kwarg(self, app, test_user, ... method test_invoice_to_dict_includes_currency (line 266) | def test_invoice_to_dict_includes_currency(self, app, test_user, test_... FILE: tests/test_invoice_currency_smoke.py function app (line 15) | def app(): function test_invoice_currency_smoke (line 37) | def test_invoice_currency_smoke(app): function test_pdf_generator_uses_settings_currency (line 84) | def test_pdf_generator_uses_settings_currency(app): FILE: tests/test_invoice_email.py function test_user (line 17) | def test_user(app): function test_client (line 26) | def test_client(app): function test_project (line 34) | def test_project(app, test_client): function test_invoice (line 44) | def test_invoice(app, test_user, test_project, test_client): function mock_pdf_generator (line 77) | def mock_pdf_generator(): function mock_mail_send (line 87) | def mock_mail_send(): class TestSendInvoiceEmail (line 93) | class TestSendInvoiceEmail: method test_send_invoice_email_success (line 96) | def test_send_invoice_email_success(self, app, test_invoice, test_user... method test_send_invoice_email_with_custom_message (line 120) | def test_send_invoice_email_with_custom_message( method test_send_invoice_email_pdf_generation_failure (line 141) | def test_send_invoice_email_pdf_generation_failure(self, app, test_inv... method test_send_invoice_email_no_mail_server (line 167) | def test_send_invoice_email_no_mail_server(self, app, test_invoice, te... method test_send_invoice_email_creates_tracking_record (line 180) | def test_send_invoice_email_creates_tracking_record( method test_send_invoice_email_updates_draft_status (line 206) | def test_send_invoice_email_updates_draft_status( method test_send_invoice_email_does_not_update_non_draft_status (line 228) | def test_send_invoice_email_does_not_update_non_draft_status( method test_send_invoice_email_with_email_template (line 250) | def test_send_invoice_email_with_email_template( method test_send_invoice_email_failure_creates_failed_record (line 280) | def test_send_invoice_email_failure_creates_failed_record(self, app, t... class TestInvoiceEmailRoutes (line 301) | class TestInvoiceEmailRoutes: method test_send_invoice_email_route_success (line 304) | def test_send_invoice_email_route_success( method test_get_invoice_email_history (line 320) | def test_get_invoice_email_history(self, client, test_user, test_invoi... method test_resend_invoice_email_route (line 341) | def test_resend_invoice_email_route(self, client, test_user, test_invo... class TestInvoiceEmailModel (line 369) | class TestInvoiceEmailModel: method test_invoice_email_creation (line 372) | def test_invoice_email_creation(self, app, test_invoice, test_user): method test_invoice_email_mark_opened (line 390) | def test_invoice_email_mark_opened(self, app, test_invoice, test_user): method test_invoice_email_mark_failed (line 409) | def test_invoice_email_mark_failed(self, app, test_invoice, test_user): method test_invoice_email_to_dict (line 428) | def test_invoice_email_to_dict(self, app, test_invoice, test_user): class TestSendInvoiceTemplateTestEmail (line 451) | class TestSendInvoiceTemplateTestEmail: method test_send_invoice_template_test_email_success (line 455) | def test_send_invoice_template_test_email_success( method test_send_invoice_template_test_email_no_mail_server (line 479) | def test_send_invoice_template_test_email_no_mail_server(self, app, te... method test_send_invoice_template_test_email_template_missing (line 494) | def test_send_invoice_template_test_email_template_missing(self, app, ... FILE: tests/test_invoice_expenses.py function test_user (line 14) | def test_user(app): function test_client (line 27) | def test_client(app): function test_project (line 36) | def test_project(app, test_client): function test_invoice (line 47) | def test_invoice(app, test_user, test_project, test_client): function test_expense (line 63) | def test_expense(app, test_user, test_project): class TestInvoiceExpenseIntegration (line 83) | class TestInvoiceExpenseIntegration: method test_link_expense_to_invoice (line 86) | def test_link_expense_to_invoice(self, app, test_invoice, test_expense): method test_unlink_expense_from_invoice (line 100) | def test_unlink_expense_from_invoice(self, app, test_invoice, test_exp... method test_calculate_totals_with_expenses (line 115) | def test_calculate_totals_with_expenses(self, app, test_invoice, test_... method test_uninvoiced_expenses_query (line 145) | def test_uninvoiced_expenses_query(self, app, test_expense, test_proje... method test_uninvoiced_expenses_excludes_invoiced (line 153) | def test_uninvoiced_expenses_excludes_invoiced(self, app, test_invoice... method test_expense_in_pdf_export (line 165) | def test_expense_in_pdf_export(self, app, test_invoice, test_expense): method test_multiple_expenses_on_invoice (line 176) | def test_multiple_expenses_on_invoice(self, app, test_invoice, test_us... class TestExpenseProperties (line 228) | class TestExpenseProperties: method test_expense_total_amount_includes_tax (line 231) | def test_expense_total_amount_includes_tax(self, app, test_expense): method test_expense_is_invoiced_property (line 236) | def test_expense_is_invoiced_property(self, app, test_invoice, test_ex... FILE: tests/test_invoice_numbering.py function test_validate_invoice_pattern_rejects_missing_seq (line 11) | def test_validate_invoice_pattern_rejects_missing_seq(): function test_validate_invoice_pattern_rejects_unknown_token (line 18) | def test_validate_invoice_pattern_rejects_unknown_token(): function test_invoice_sequence_increments_for_same_pattern (line 25) | def test_invoice_sequence_increments_for_same_pattern(app, user, project... FILE: tests/test_invoice_pdf_postprocess.py function test_postprocess_noop_when_zugferd_disabled (line 16) | def test_postprocess_noop_when_zugferd_disabled(app): function test_postprocess_embeds_when_zugferd_enabled (line 28) | def test_postprocess_embeds_when_zugferd_enabled(app): function test_postprocess_returns_embed_error_on_invalid_pdf (line 100) | def test_postprocess_returns_embed_error_on_invalid_pdf(app): function test_build_invoice_email_payload_calls_postprocess (line 139) | def test_build_invoice_email_payload_calls_postprocess(mock_pp, mock_ige... FILE: tests/test_invoice_validators.py function test_validate_ubl_wellformed_accepts_valid_invoice (line 15) | def test_validate_ubl_wellformed_accepts_valid_invoice(): function test_validate_ubl_wellformed_rejects_invalid_xml (line 23) | def test_validate_ubl_wellformed_rejects_invalid_xml(): function test_validate_ubl_wellformed_rejects_non_invoice_root (line 30) | def test_validate_ubl_wellformed_rejects_non_invoice_root(): function _minimal_peppol_ubl (line 39) | def _minimal_peppol_ubl() -> str: function test_validate_ubl_peppol_bis3_accepts_valid (line 80) | def test_validate_ubl_peppol_bis3_accepts_valid(): function test_validate_ubl_peppol_bis3_detects_missing_buyer_reference (line 87) | def test_validate_ubl_peppol_bis3_detects_missing_buyer_reference(): function test_validate_ubl_peppol_bis3_detects_missing_endpoint (line 97) | def test_validate_ubl_peppol_bis3_detects_missing_endpoint(): function test_validate_ubl_peppol_bis3_detects_missing_lines (line 109) | def test_validate_ubl_peppol_bis3_detects_missing_lines(): function test_validate_ubl_peppol_bis3_detects_missing_unitcode (line 121) | def test_validate_ubl_peppol_bis3_detects_missing_unitcode(): function test_validate_cii_wellformed_accepts_valid (line 131) | def test_validate_cii_wellformed_accepts_valid(): function test_validate_cii_wellformed_rejects_ubl (line 138) | def test_validate_cii_wellformed_rejects_ubl(): function test_validate_cii_wellformed_rejects_invalid_xml (line 146) | def test_validate_cii_wellformed_rejects_invalid_xml(): function _minimal_cii_en16931 (line 153) | def _minimal_cii_en16931() -> str: function test_validate_cii_en16931_accepts_valid (line 233) | def test_validate_cii_en16931_accepts_valid(): function test_validate_cii_en16931_detects_missing_seller (line 239) | def test_validate_cii_en16931_detects_missing_seller(): function test_validate_cii_en16931_detects_missing_document_id (line 250) | def test_validate_cii_en16931_detects_missing_document_id(): function test_validate_cii_en16931_detects_missing_line_items (line 258) | def test_validate_cii_en16931_detects_missing_line_items(): function test_validate_cii_en16931_detects_missing_grand_total (line 271) | def test_validate_cii_en16931_detects_missing_grand_total(): FILE: tests/test_invoices.py function sample_user (line 13) | def sample_user(app): function sample_project (line 22) | def sample_project(app): function sample_invoice (line 38) | def sample_invoice(app, sample_user, sample_project): function test_invoice_creation (line 61) | def test_invoice_creation(app, sample_user, sample_project): function test_invoice_item_creation (line 92) | def test_invoice_item_creation(app, sample_invoice): function test_invoice_totals_calculation (line 109) | def test_invoice_totals_calculation(app, sample_invoice): function test_invoice_with_tax (line 135) | def test_invoice_with_tax(app, sample_user, sample_project): function test_invoice_number_generation (line 170) | def test_invoice_number_generation(app): function test_invoice_number_generation_with_custom_pattern (line 183) | def test_invoice_number_generation_with_custom_pattern(app): function test_invoice_number_generation_with_empty_pattern_uses_sequence (line 196) | def test_invoice_number_generation_with_empty_pattern_uses_sequence(app): function test_invoice_overdue_status (line 208) | def test_invoice_overdue_status(app, sample_user, sample_project): function test_create_invoice_template_has_client_data_attributes (line 245) | def test_create_invoice_template_has_client_data_attributes(app, client,... function test_invoice_to_dict (line 271) | def test_invoice_to_dict(app, sample_invoice): function test_invoice_item_to_dict (line 283) | def test_invoice_item_to_dict(app, sample_invoice): function test_edit_invoice_template_has_expected_fields (line 300) | def test_edit_invoice_template_has_expected_fields(app, client, user, pr... function test_generate_from_time_page_renders_lists (line 350) | def test_generate_from_time_page_renders_lists(app, client, user, project): function test_generate_from_time_applies_prepaid_hours (line 408) | def test_generate_from_time_applies_prepaid_hours(app, client, user): function test_invoice_payment_status_initialization (line 481) | def test_invoice_payment_status_initialization(app, sample_user, sample_... function test_record_full_payment (line 515) | def test_record_full_payment(app, sample_invoice): function test_record_partial_payment (line 563) | def test_record_partial_payment(app, sample_invoice): function test_record_overpayment (line 600) | def test_record_overpayment(app, sample_invoice): function test_multiple_payments (line 631) | def test_multiple_payments(app, sample_invoice): function test_update_payment_status_method (line 672) | def test_update_payment_status_method(app, sample_invoice): function test_invoice_to_dict_includes_payment_fields (line 708) | def test_invoice_to_dict_includes_payment_fields(app, sample_invoice): function test_invoice_sorted_payments_property (line 747) | def test_invoice_sorted_payments_property(app, sample_invoice, sample_us... function test_invoice_sorted_payments_with_same_date (line 793) | def test_invoice_sorted_payments_with_same_date(app, sample_invoice, sam... function test_invoice_sorted_payments_empty (line 835) | def test_invoice_sorted_payments_empty(app, sample_invoice): function test_invoice_with_extra_goods (line 852) | def test_invoice_with_extra_goods(app, sample_invoice, sample_user): function test_pdf_generator_includes_extra_goods (line 878) | def test_pdf_generator_includes_extra_goods(app, sample_invoice, sample_... function test_pdf_generator_extra_goods_formatting (line 931) | def test_pdf_generator_extra_goods_formatting(app, sample_invoice, sampl... function test_pdf_fallback_generator_includes_extra_goods (line 997) | def test_pdf_fallback_generator_includes_extra_goods(app, sample_invoice... function test_pdf_export_with_extra_goods_smoke (line 1043) | def test_pdf_export_with_extra_goods_smoke(app, sample_invoice, sample_u... function test_pdf_reportlab_generator_includes_extra_goods (line 1106) | def test_pdf_reportlab_generator_includes_extra_goods(app, sample_invoic... function test_pdf_export_fallback_with_extra_goods_smoke (line 1154) | def test_pdf_export_fallback_with_extra_goods_smoke(app, sample_invoice,... function test_invoice_deletion_basic (line 1200) | def test_invoice_deletion_basic(app, sample_invoice): function test_invoice_deletion_cascades_to_items (line 1218) | def test_invoice_deletion_cascades_to_items(app, sample_invoice): function test_invoice_deletion_cascades_to_extra_goods (line 1262) | def test_invoice_deletion_cascades_to_extra_goods(app, sample_invoice, s... function test_invoice_deletion_cascades_to_payments (line 1310) | def test_invoice_deletion_cascades_to_payments(app, sample_invoice, samp... function test_invoice_deletion_with_all_related_data (line 1356) | def test_invoice_deletion_with_all_related_data(app, sample_invoice, sam... function test_delete_invoice_route_success (line 1416) | def test_delete_invoice_route_success(app, client, user, project): function test_delete_invoice_route_permission_denied (line 1458) | def test_delete_invoice_route_permission_denied(app, client, user, proje... function test_delete_invoice_route_admin_can_delete_any (line 1501) | def test_delete_invoice_route_admin_can_delete_any(app, client, user, pr... function test_delete_invoice_route_not_found (line 1547) | def test_delete_invoice_route_not_found(app, client, user): function test_invoice_view_has_delete_button (line 1563) | def test_invoice_view_has_delete_button(app, client, user, project): function test_invoice_view_peppol_check_exception_shows_generic_warning (line 1603) | def test_invoice_view_peppol_check_exception_shows_generic_warning(app, ... function test_invoice_list_has_delete_buttons (line 1644) | def test_invoice_list_has_delete_buttons(app, client, admin_user, project): function test_delete_invoice_with_complex_data_smoke (line 1703) | def test_delete_invoice_with_complex_data_smoke(app, client, user, proje... FILE: tests/test_keyboard_shortcuts.py class TestKeyboardShortcutsRoutes (line 14) | class TestKeyboardShortcutsRoutes: method setup (line 18) | def setup(self, authenticated_client, auth_user): method test_keyboard_shortcuts_settings_page (line 23) | def test_keyboard_shortcuts_settings_page(self): method test_keyboard_shortcuts_settings_requires_auth (line 31) | def test_keyboard_shortcuts_settings_requires_auth(self, app): method test_settings_index_loads (line 39) | def test_settings_index_loads(self): method test_keyboard_shortcuts_css_exists (line 44) | def test_keyboard_shortcuts_css_exists(self): method test_keyboard_shortcuts_js_exists (line 50) | def test_keyboard_shortcuts_js_exists(self): class TestKeyboardShortcutsIntegration (line 57) | class TestKeyboardShortcutsIntegration: method setup (line 61) | def setup(self, authenticated_client, auth_user): method test_keyboard_shortcuts_in_base_template (line 66) | def test_keyboard_shortcuts_in_base_template(self): method test_command_palette_in_base_template (line 73) | def test_command_palette_in_base_template(self): method test_cheat_sheet_elements_in_page (line 80) | def test_cheat_sheet_elements_in_page(self): method test_navigation_shortcuts_documented (line 89) | def test_navigation_shortcuts_documented(self): method test_statistics_elements_present (line 96) | def test_statistics_elements_present(self): class TestKeyboardShortcutsAccessibility (line 105) | class TestKeyboardShortcutsAccessibility: method setup (line 109) | def setup(self, authenticated_client, auth_user): method test_skip_to_main_content_link (line 114) | def test_skip_to_main_content_link(self): method test_aria_labels_in_shortcuts_page (line 121) | def test_aria_labels_in_shortcuts_page(self): method test_keyboard_navigation_styles (line 128) | def test_keyboard_navigation_styles(self): class TestKeyboardShortcutsDocumentation (line 137) | class TestKeyboardShortcutsDocumentation: method test_documentation_exists (line 140) | def test_documentation_exists(self): method test_documentation_has_content (line 147) | def test_documentation_has_content(self): function app (line 165) | def app(): function client (line 187) | def client(app): function runner (line 193) | def runner(app): function auth_user (line 199) | def auth_user(app): function authenticated_client (line 211) | def authenticated_client(client, auth_user): function admin_user (line 220) | def admin_user(app): function test_keyboard_shortcuts_module_imports (line 234) | def test_keyboard_shortcuts_module_imports(): function test_settings_route_registered (line 240) | def test_settings_route_registered(app): function test_keyboard_shortcuts_route_registered (line 248) | def test_keyboard_shortcuts_route_registered(app): class TestKeyboardShortcutsData (line 258) | class TestKeyboardShortcutsData: method setup (line 262) | def setup(self, authenticated_client, auth_user): method test_shortcuts_data_structure (line 267) | def test_shortcuts_data_structure(self): method test_statistics_tracking (line 280) | def test_statistics_tracking(self): class TestKeyboardShortcutsPerformance (line 293) | class TestKeyboardShortcutsPerformance: method setup (line 297) | def setup(self, authenticated_client, auth_user): method test_settings_page_loads_quickly (line 302) | def test_settings_page_loads_quickly(self): method test_css_file_size_reasonable (line 313) | def test_css_file_size_reasonable(self): method test_js_file_size_reasonable (line 320) | def test_js_file_size_reasonable(self): class TestKeyboardShortcutsSecurity (line 331) | class TestKeyboardShortcutsSecurity: method setup (line 335) | def setup(self, authenticated_client, auth_user): method test_settings_requires_authentication (line 340) | def test_settings_requires_authentication(self, app): method test_no_xss_in_shortcuts_page (line 348) | def test_no_xss_in_shortcuts_page(self): method test_csrf_protection_enabled (line 356) | def test_csrf_protection_enabled(self, app): class TestKeyboardShortcutsEdgeCases (line 364) | class TestKeyboardShortcutsEdgeCases: method setup (line 368) | def setup(self, authenticated_client, auth_user): method test_settings_page_with_no_shortcuts (line 373) | def test_settings_page_with_no_shortcuts(self): method test_settings_page_with_special_characters (line 379) | def test_settings_page_with_special_characters(self): method test_multiple_concurrent_requests (line 384) | def test_multiple_concurrent_requests(self): class TestKeyboardShortcutsRegression (line 398) | class TestKeyboardShortcutsRegression: method setup (line 402) | def setup(self, authenticated_client, auth_user): method test_base_template_not_broken (line 407) | def test_base_template_not_broken(self): method test_other_pages_not_affected (line 413) | def test_other_pages_not_affected(self): method test_sidebar_navigation_still_works (line 425) | def test_sidebar_navigation_still_works(self): FILE: tests/test_keyboard_shortcuts_api.py function api_authenticated_client (line 19) | def api_authenticated_client(client, user): class TestKeyboardShortcutsAPI (line 27) | class TestKeyboardShortcutsAPI: method test_get_requires_auth (line 30) | def test_get_requires_auth(self, app, client): method test_get_returns_config_when_authenticated (line 36) | def test_get_returns_config_when_authenticated(self, api_authenticated... method test_get_returns_defaults_when_no_overrides (line 52) | def test_get_returns_defaults_when_no_overrides(self, api_authenticate... method test_post_save_valid_overrides (line 62) | def test_post_save_valid_overrides(self, api_authenticated_client): method test_post_reject_conflict (line 83) | def test_post_reject_conflict(self, api_authenticated_client): method test_post_reject_forbidden_key (line 96) | def test_post_reject_forbidden_key(self, api_authenticated_client): method test_post_reset_clears_overrides (line 110) | def test_post_reset_clears_overrides(self, api_authenticated_client, u... method test_post_invalid_body (line 126) | def test_post_invalid_body(self, api_authenticated_client): method test_post_non_json_body_returns_400_or_415 (line 135) | def test_post_non_json_body_returns_400_or_415(self, api_authenticated... method test_reset_requires_auth (line 149) | def test_reset_requires_auth(self, app, client): class TestKeyboardShortcutsValidation (line 159) | class TestKeyboardShortcutsValidation: method test_normalize_key (line 162) | def test_normalize_key(self): method test_merge_overrides_empty (line 167) | def test_merge_overrides_empty(self): method test_merge_overrides_applied (line 173) | def test_merge_overrides_applied(self): method test_validate_overrides_success (line 179) | def test_validate_overrides_success(self): method test_validate_overrides_conflict (line 189) | def test_validate_overrides_conflict(self): method test_validate_overrides_forbidden (line 196) | def test_validate_overrides_forbidden(self): method test_validate_overrides_unknown_id (line 204) | def test_validate_overrides_unknown_id(self): FILE: tests/test_keyboard_shortcuts_input_fix.py class TestKeyboardShortcutsInputFix (line 14) | class TestKeyboardShortcutsInputFix: method setup (line 18) | def setup(self, admin_authenticated_client, admin_user, test_client): method test_create_project_page_loads (line 24) | def test_create_project_page_loads(self): method test_create_project_with_gr_in_name (line 30) | def test_create_project_with_gr_in_name(self): method test_create_task_with_trigger_in_name (line 53) | def test_create_task_with_trigger_in_name(self): method test_project_name_with_multiple_triggers (line 75) | def test_project_name_with_multiple_triggers(self): method test_keyboard_shortcuts_js_loaded (line 101) | def test_keyboard_shortcuts_js_loaded(self): class TestKeyboardShortcutsJavaScriptLogic (line 112) | class TestKeyboardShortcutsJavaScriptLogic: method test_istyping_method_exists (line 115) | def test_istyping_method_exists(self): method test_input_check_before_sequences (line 140) | def test_input_check_before_sequences(self): method test_sequence_cleared_when_typing (line 153) | def test_sequence_cleared_when_typing(self): method test_allowed_shortcuts_in_inputs (line 165) | def test_allowed_shortcuts_in_inputs(self): method test_contenteditable_check (line 179) | def test_contenteditable_check(self): method test_rich_text_editor_detection (line 190) | def test_rich_text_editor_detection(self): class TestKeyboardShortcutsBugScenarios (line 217) | class TestKeyboardShortcutsBugScenarios: method setup (line 221) | def setup(self, admin_authenticated_client, admin_user, test_client): method test_reported_bug_typing_program (line 227) | def test_reported_bug_typing_program(self): method test_all_shortcut_triggers_in_text (line 259) | def test_all_shortcut_triggers_in_text(self): function test_smoke_keyboard_shortcuts_on_multiple_pages (line 291) | def test_smoke_keyboard_shortcuts_on_multiple_pages(admin_authenticated_... FILE: tests/test_ldap_auth.py function ldap_app_config (line 17) | def ldap_app_config(app_config): function ldap_app (line 44) | def ldap_app(ldap_app_config): function _mock_ldap_entry (line 64) | def _mock_ldap_entry(dn: str, uid: str, mail: str, given: str = "A", sn:... function test_ldap_authenticate_success (line 78) | def test_ldap_authenticate_success(mock_conn_cls, mock_svc, ldap_app): function test_ldap_authenticate_wrong_password (line 99) | def test_ldap_authenticate_wrong_password(mock_conn_cls, mock_svc, ldap_... function test_ldap_required_group_blocks_non_member (line 118) | def test_ldap_required_group_blocks_non_member(mock_conn_cls, mock_svc, ... function test_ldap_admin_group_grants_admin (line 135) | def test_ldap_admin_group_grants_admin(mock_conn_cls, mock_svc, ldap_app): function test_ldap_syncs_attributes_on_relogin (line 157) | def test_ldap_syncs_attributes_on_relogin(mock_conn_cls, mock_svc, ldap_... function test_ldap_exception_returns_none (line 183) | def test_ldap_exception_returns_none(mock_svc, ldap_app): function test_login_route_ldap_success (line 194) | def test_login_route_ldap_success(client, app): function test_login_route_ldap_failure_generic_message (line 230) | def test_login_route_ldap_failure_generic_message(client, app): FILE: tests/test_ldap_setup_wizard.py function test_ldap_setup_wizard_requires_login (line 8) | def test_ldap_setup_wizard_requires_login(client): function test_ldap_setup_wizard_get_as_admin (line 13) | def test_ldap_setup_wizard_get_as_admin(admin_authenticated_client): function test_ldap_wizard_validate_missing_host (line 19) | def test_ldap_wizard_validate_missing_host(admin_authenticated_client): function test_ldap_wizard_validate_invalid_auth_method (line 31) | def test_ldap_wizard_validate_invalid_auth_method(admin_authenticated_cl... function test_ldap_wizard_validate_ok (line 49) | def test_ldap_wizard_validate_ok(admin_authenticated_client): function test_ldap_wizard_generate_rejects_non_ldap_auth (line 68) | def test_ldap_wizard_generate_rejects_non_ldap_auth(admin_authenticated_... function test_ldap_wizard_generate_success (line 83) | def test_ldap_wizard_generate_success(admin_authenticated_client): function test_ldap_wizard_generate_requires_host (line 123) | def test_ldap_wizard_generate_requires_host(admin_authenticated_client): function test_ldap_wizard_test_connection_uses_service (line 138) | def test_ldap_wizard_test_connection_uses_service(admin_authenticated_cl... function test_ldap_service_test_connection_accepts_cfg (line 160) | def test_ldap_service_test_connection_accepts_cfg(app): FILE: tests/test_logo_pdf.py function test_logo_setup (line 17) | def test_logo_setup(): function test_pdf_generation (line 92) | def test_pdf_generation(): function main (line 147) | def main(): FILE: tests/test_models/test_expense_category.py function user (line 17) | def user(client): function category (line 28) | def category(client): function test_create_expense_category (line 46) | def test_create_expense_category(client): function test_category_budget_utilization (line 62) | def test_category_budget_utilization(client, category, user): function test_category_over_budget_threshold (line 89) | def test_category_over_budget_threshold(client, category, user): function test_get_active_categories (line 109) | def test_get_active_categories(client, category): function test_category_to_dict (line 124) | def test_category_to_dict(client, category): function test_category_unique_name (line 140) | def test_category_unique_name(client, category): function test_category_quarterly_budget (line 149) | def test_category_quarterly_budget(client, category, user): function test_get_categories_over_budget (line 172) | def test_get_categories_over_budget(client, category, user): FILE: tests/test_models/test_inventory_models.py function test_user (line 24) | def test_user(db_session): function test_warehouse (line 33) | def test_warehouse(db_session, test_user): function test_stock_item (line 42) | def test_stock_item(db_session, test_user): class TestWarehouse (line 58) | class TestWarehouse: method test_create_warehouse (line 61) | def test_create_warehouse(self, db_session, test_user): method test_warehouse_code_uppercase (line 79) | def test_warehouse_code_uppercase(self, db_session, test_user): method test_warehouse_to_dict (line 84) | def test_warehouse_to_dict(self, db_session, test_user): class TestStockItem (line 96) | class TestStockItem: method test_create_stock_item (line 99) | def test_create_stock_item(self, db_session, test_user): method test_sku_uppercase (line 117) | def test_sku_uppercase(self, db_session, test_user): method test_total_quantity_on_hand (line 122) | def test_total_quantity_on_hand(self, db_session, test_user, test_stoc... method test_is_low_stock (line 136) | def test_is_low_stock(self, db_session, test_user, test_stock_item, te... class TestWarehouseStock (line 157) | class TestWarehouseStock: method test_create_warehouse_stock (line 160) | def test_create_warehouse_stock(self, db_session, test_stock_item, tes... method test_reserve_quantity (line 176) | def test_reserve_quantity(self, db_session, test_stock_item, test_ware... method test_reserve_insufficient_stock (line 190) | def test_reserve_insufficient_stock(self, db_session, test_stock_item,... method test_release_reservation (line 204) | def test_release_reservation(self, db_session, test_stock_item, test_w... method test_adjust_on_hand (line 221) | def test_adjust_on_hand(self, db_session, test_stock_item, test_wareho... class TestStockMovement (line 238) | class TestStockMovement: method test_record_movement (line 241) | def test_record_movement(self, db_session, test_user, test_stock_item,... method test_movement_updates_stock (line 259) | def test_movement_updates_stock(self, db_session, test_user, test_stoc... method test_return_can_be_devalued_into_lot (line 281) | def test_return_can_be_devalued_into_lot(self, db_session, test_user, ... method test_waste_with_devaluation_flow (line 301) | def test_waste_with_devaluation_flow(self, db_session, test_user, test... method test_first_inbound_with_no_lots_matches_warehouse_stock (line 345) | def test_first_inbound_with_no_lots_matches_warehouse_stock(self, db_s... method test_first_outbound_with_no_lots_matches_warehouse_stock (line 371) | def test_first_outbound_with_no_lots_matches_warehouse_stock(self, db_... class TestStockReservation (line 405) | class TestStockReservation: method test_create_reservation (line 408) | def test_create_reservation(self, db_session, test_user, test_stock_it... method test_reservation_insufficient_stock (line 433) | def test_reservation_insufficient_stock(self, db_session, test_user, t... method test_fulfill_reservation (line 451) | def test_fulfill_reservation(self, db_session, test_user, test_stock_i... method test_cancel_reservation (line 481) | def test_cancel_reservation(self, db_session, test_user, test_stock_it... method test_expired_reservation (line 511) | def test_expired_reservation(self, db_session, test_user, test_stock_i... class TestProjectStockAllocation (line 528) | class TestProjectStockAllocation: method test_create_allocation (line 531) | def test_create_allocation(self, db_session, test_user, test_stock_ite... method test_record_usage (line 552) | def test_record_usage(self, db_session, test_user, test_stock_item, te... method test_record_usage_exceeds_allocation (line 574) | def test_record_usage_exceeds_allocation(self, db_session, test_user, ... FILE: tests/test_models/test_mileage.py function user (line 16) | def user(client): function project (line 26) | def project(client): function test_create_mileage (line 38) | def test_create_mileage(client, user): function test_mileage_round_trip (line 62) | def test_mileage_round_trip(client, user): function test_mileage_approval (line 83) | def test_mileage_approval(client, user): function test_mileage_rejection (line 113) | def test_mileage_rejection(client, user): function test_mileage_create_expense (line 142) | def test_mileage_create_expense(client, user, project): function test_mileage_to_dict (line 170) | def test_mileage_to_dict(client, user): function test_get_total_distance (line 198) | def test_get_total_distance(client, user): function test_mileage_default_rates (line 234) | def test_mileage_default_rates(client): function test_mileage_reimbursement (line 247) | def test_mileage_reimbursement(client, user): FILE: tests/test_models/test_per_diem.py function user (line 16) | def user(client): function rate (line 26) | def rate(client): function test_create_per_diem_rate (line 45) | def test_create_per_diem_rate(client): function test_get_rate_for_location (line 62) | def test_get_rate_for_location(client, rate): function test_get_rate_falls_back_to_country (line 71) | def test_get_rate_falls_back_to_country(client): function test_create_per_diem_claim (line 92) | def test_create_per_diem_claim(client, user, rate): function test_per_diem_calculation (line 120) | def test_per_diem_calculation(client, user, rate): function test_per_diem_with_meal_deductions (line 146) | def test_per_diem_with_meal_deductions(client, user, rate): function test_calculate_days_from_dates_single_day (line 175) | def test_calculate_days_from_dates_single_day(client): function test_calculate_days_from_dates_multi_day (line 188) | def test_calculate_days_from_dates_multi_day(client): function test_calculate_days_with_half_days (line 205) | def test_calculate_days_with_half_days(client): function test_per_diem_approval (line 222) | def test_per_diem_approval(client, user): function test_per_diem_to_dict (line 253) | def test_per_diem_to_dict(client, user, rate): function test_per_diem_recalculate (line 283) | def test_per_diem_recalculate(client, user): function test_per_diem_create_expense (line 311) | def test_per_diem_create_expense(client, user): FILE: tests/test_models/test_purchase_order.py function test_user (line 14) | def test_user(db_session): function test_supplier (line 23) | def test_supplier(db_session, test_user): function test_warehouse (line 32) | def test_warehouse(db_session, test_user): function test_stock_item (line 41) | def test_stock_item(db_session, test_user): function test_purchase_order (line 50) | def test_purchase_order(db_session, test_supplier, test_user): class TestPurchaseOrder (line 64) | class TestPurchaseOrder: method test_create_purchase_order (line 67) | def test_create_purchase_order(self, db_session, test_supplier, test_u... method test_purchase_order_with_items (line 84) | def test_purchase_order_with_items(self, db_session, test_purchase_ord... method test_purchase_order_receive (line 101) | def test_purchase_order_receive(self, db_session, test_purchase_order,... method test_purchase_order_cancel (line 123) | def test_purchase_order_cancel(self, db_session, test_purchase_order): method test_purchase_order_to_dict (line 130) | def test_purchase_order_to_dict(self, db_session, test_purchase_order): method test_purchase_order_none_safe_normalization (line 138) | def test_purchase_order_none_safe_normalization(self, db_session, test... method test_purchase_order_item_description_required (line 149) | def test_purchase_order_item_description_required(self, db_session, te... FILE: tests/test_models/test_supplier.py function test_user (line 13) | def test_user(db_session): function test_supplier (line 22) | def test_supplier(db_session, test_user): function test_stock_item (line 37) | def test_stock_item(db_session, test_user): class TestSupplier (line 50) | class TestSupplier: method test_create_supplier (line 53) | def test_create_supplier(self, db_session, test_user): method test_supplier_code_uppercase (line 69) | def test_supplier_code_uppercase(self, db_session, test_user): method test_supplier_to_dict (line 74) | def test_supplier_to_dict(self, db_session, test_supplier): method test_supplier_stock_items_relationship (line 81) | def test_supplier_stock_items_relationship(self, db_session, test_supp... method test_supplier_deactivation (line 95) | def test_supplier_deactivation(self, db_session, test_supplier): FILE: tests/test_models/test_webhook.py function test_user (line 14) | def test_user(db_session): function test_webhook (line 23) | def test_webhook(db_session, test_user): class TestWebhook (line 38) | class TestWebhook: method test_create_webhook (line 41) | def test_create_webhook(self, db_session, test_user): method test_webhook_subscribes_to (line 57) | def test_webhook_subscribes_to(self, test_webhook): method test_webhook_wildcard_subscription (line 63) | def test_webhook_wildcard_subscription(self, db_session, test_user): method test_webhook_signature_generation (line 72) | def test_webhook_signature_generation(self, test_webhook): method test_webhook_signature_verification (line 81) | def test_webhook_signature_verification(self, test_webhook): method test_webhook_to_dict (line 89) | def test_webhook_to_dict(self, test_webhook): method test_webhook_to_dict_with_secret (line 100) | def test_webhook_to_dict_with_secret(self, test_webhook): class TestWebhookDelivery (line 108) | class TestWebhookDelivery: method test_create_delivery (line 111) | def test_create_delivery(self, db_session, test_webhook): method test_delivery_mark_success (line 124) | def test_delivery_mark_success(self, db_session, test_webhook): method test_delivery_mark_failed (line 140) | def test_delivery_mark_failed(self, db_session, test_webhook): method test_delivery_mark_retrying (line 155) | def test_delivery_mark_retrying(self, db_session, test_webhook): method test_delivery_hash_payload (line 171) | def test_delivery_hash_payload(self): method test_delivery_to_dict (line 180) | def test_delivery_to_dict(self, db_session, test_webhook): FILE: tests/test_models_comprehensive.py function test_user_creation (line 23) | def test_user_creation(app, user): function test_user_is_admin_property (line 33) | def test_user_is_admin_property(app, admin_user): function test_user_active_timer (line 40) | def test_user_active_timer(app, user, active_timer): function test_user_time_entries_relationship (line 50) | def test_user_time_entries_relationship(app, user, multiple_time_entries): function test_user_to_dict (line 58) | def test_user_to_dict(app, user): function test_client_creation (line 76) | def test_client_creation(app, test_client): function test_client_projects_relationship (line 86) | def test_client_projects_relationship(app, test_client, multiple_projects): function test_client_total_projects_property (line 94) | def test_client_total_projects_property(app, test_client, multiple_proje... function test_client_archive_activate (line 102) | def test_client_archive_activate(app, test_client): function test_client_get_active_clients (line 119) | def test_client_get_active_clients(app, multiple_clients): function test_client_to_dict (line 127) | def test_client_to_dict(app, test_client): function test_project_creation (line 143) | def test_project_creation(app, project): function test_project_client_relationship (line 153) | def test_project_client_relationship(app, project, test_client): function test_project_time_entries_relationship (line 165) | def test_project_time_entries_relationship(app, project, multiple_time_e... function test_project_total_hours (line 173) | def test_project_total_hours(app, project, multiple_time_entries): function test_project_estimated_cost (line 182) | def test_project_estimated_cost(app, project, multiple_time_entries): function test_project_archive (line 194) | def test_project_archive(app, project): function test_time_entry_creation (line 210) | def test_time_entry_creation(app, time_entry): function test_time_entry_duration (line 219) | def test_time_entry_duration(app, time_entry): function test_active_timer_is_active (line 229) | def test_active_timer_is_active(app, active_timer): function test_stop_timer (line 238) | def test_stop_timer(app, active_timer): function test_time_entry_tag_list (line 252) | def test_time_entry_tag_list(app, test_client): function test_task_creation (line 287) | def test_task_creation(app, task): function test_task_project_relationship (line 297) | def test_task_project_relationship(app, task, project): function test_task_status_transitions (line 306) | def test_task_status_transitions(app, task): function test_invoice_creation (line 329) | def test_invoice_creation(app, invoice): function test_invoice_number_generation (line 339) | def test_invoice_number_generation(app): function test_invoice_calculate_totals (line 348) | def test_invoice_calculate_totals(app, invoice_with_items): function test_invoice_payment_tracking (line 365) | def test_invoice_payment_tracking(app, invoice_with_items): function test_invoice_overdue_status (line 396) | def test_invoice_overdue_status(app, user, project, test_client): function test_settings_singleton (line 425) | def test_settings_singleton(app): function test_settings_default_values (line 435) | def test_settings_default_values(app): function test_cascade_delete_user_time_entries (line 452) | def test_cascade_delete_user_time_entries(app, user, multiple_time_entri... function test_project_client_relationship_integrity (line 474) | def test_project_client_relationship_integrity(app, project, test_client): function test_project_requires_name (line 492) | def test_project_requires_name(app, test_client): function test_time_entry_requires_start_time (line 502) | def test_time_entry_requires_start_time(app, user, project): function test_user_deletion_without_relationships (line 522) | def test_user_deletion_without_relationships(app): function test_user_deletion_cascades_project_costs (line 543) | def test_user_deletion_cascades_project_costs(app, test_client): function test_user_deletion_cascades_time_entries (line 588) | def test_user_deletion_cascades_time_entries(app, test_client): function test_user_deletion_removes_from_favorite_projects (line 629) | def test_user_deletion_removes_from_favorite_projects(app, test_client): function test_user_deletion_preserves_tasks_assigned_to_them (line 669) | def test_user_deletion_preserves_tasks_assigned_to_them(app, test_client): function test_user_cannot_be_deleted_if_has_created_tasks (line 713) | def test_user_cannot_be_deleted_if_has_created_tasks(app, test_client): function test_user_deletion_count_check (line 748) | def test_user_deletion_count_check(app): FILE: tests/test_models_extended.py function test_user_display_name (line 18) | def test_user_display_name(app): function test_user_total_hours (line 32) | def test_user_total_hours(user): function test_user_repr (line 40) | def test_user_repr(user): function test_user_projects_through_time_entries (line 47) | def test_user_projects_through_time_entries(app, user, project): function test_client_status_property (line 77) | def test_client_status_property(test_client): function test_client_repr (line 86) | def test_client_repr(test_client): function test_client_with_multiple_projects (line 93) | def test_client_with_multiple_projects(app, test_client): function test_client_archive_activate_methods (line 111) | def test_client_archive_activate_methods(app, test_client): function test_project_status (line 140) | def test_project_status(project): function test_project_billable_hours (line 148) | def test_project_billable_hours(project): function test_project_with_no_time_entries (line 157) | def test_project_with_no_time_entries(app, test_client): function test_project_hourly_rate (line 171) | def test_project_hourly_rate(app, test_client): function test_project_non_billable (line 186) | def test_project_non_billable(app, test_client): function test_project_to_dict (line 201) | def test_project_to_dict(app, project): function test_time_entry_str_representation (line 221) | def test_time_entry_str_representation(time_entry): function test_time_entry_with_notes (line 229) | def test_time_entry_with_notes(app, user, project): function test_time_entry_with_tags (line 253) | def test_time_entry_with_tags(app, user, project): function test_time_entry_billable_calculation (line 279) | def test_time_entry_billable_calculation(app, user, project): function test_time_entry_long_duration (line 306) | def test_time_entry_long_duration(app, user, project): function test_task_str_representation (line 334) | def test_task_str_representation(task): function test_task_repr (line 342) | def test_task_repr(task): function test_task_with_priority (line 350) | def test_task_with_priority(app, project, user): function test_task_with_due_date (line 375) | def test_task_with_due_date(app, project, user): function test_task_completion (line 396) | def test_task_completion(app, task): function test_invoice_str_representation (line 417) | def test_invoice_str_representation(invoice): function test_invoice_repr (line 425) | def test_invoice_repr(invoice): function test_invoice_with_multiple_items (line 433) | def test_invoice_with_multiple_items(app, test_client, project, user): function test_invoice_with_discount (line 465) | def test_invoice_with_discount(app, invoice): function test_invoice_status_transitions (line 480) | def test_invoice_status_transitions(app, test_client, project, user): function test_comment_creation (line 518) | def test_comment_creation(app, user, task): function test_comment_str_representation (line 536) | def test_comment_str_representation(app, user, task): function test_settings_update (line 557) | def test_settings_update(app): function test_settings_currency (line 574) | def test_settings_currency(app): function test_settings_timezone_validation (line 590) | def test_settings_timezone_validation(app): function test_settings_str_representation (line 605) | def test_settings_str_representation(app): function test_user_client_relationship_through_projects (line 620) | def test_user_client_relationship_through_projects(app, user, test_client): function test_task_comment_relationship (line 650) | def test_task_comment_relationship(app, user, project): FILE: tests/test_multiselect_filters.py function test_parse_ids (line 21) | def test_parse_ids(): function test_sqlalchemy_in_filter (line 66) | def test_sqlalchemy_in_filter(): function test_url_parameter_generation (line 104) | def test_url_parameter_generation(): function test_backward_compatibility (line 134) | def test_backward_compatibility(): function main (line 172) | def main(): FILE: tests/test_new_features.py function test_burndown_endpoint_available (line 8) | def test_burndown_endpoint_available(client, app): function test_saved_filter_model_roundtrip (line 25) | def test_saved_filter_model_roundtrip(app): function test_inline_client_creation_json_flow (line 38) | def test_inline_client_creation_json_flow(admin_authenticated_client): function test_inline_task_creation_json_flow (line 55) | def test_inline_task_creation_json_flow(authenticated_client, project, u... function test_start_timer_with_new_task_creation (line 87) | def test_start_timer_with_new_task_creation(authenticated_client, projec... FILE: tests/test_oidc_logout.py function oidc_user (line 13) | def oidc_user(app): function oidc_authenticated_client (line 28) | def oidc_authenticated_client(client, oidc_user): function test_logout_without_post_logout_uri_config (line 45) | def test_logout_without_post_logout_uri_config(oidc_authenticated_client... function test_logout_with_post_logout_uri_config (line 77) | def test_logout_with_post_logout_uri_config(oidc_authenticated_client, a... function test_logout_oidc_provider_has_revocation_endpoint_only (line 107) | def test_logout_oidc_provider_has_revocation_endpoint_only(oidc_authenti... function test_logout_local_auth_method (line 132) | def test_logout_local_auth_method(authenticated_client, app): function test_logout_clears_oidc_id_token_from_session (line 150) | def test_logout_clears_oidc_id_token_from_session(oidc_authenticated_cli... function test_logout_uses_cached_oidc_id_token_hint_when_present (line 172) | def test_logout_uses_cached_oidc_id_token_hint_when_present(oidc_authent... function test_logout_with_both_auth_method_no_post_logout_uri (line 210) | def test_logout_with_both_auth_method_no_post_logout_uri(oidc_authentica... function test_logout_provider_metadata_load_fails_gracefully (line 231) | def test_logout_provider_metadata_load_fails_gracefully(oidc_authenticat... function test_logout_endpoint_exists (line 256) | def test_logout_endpoint_exists(client): function test_logout_configuration_keys_valid (line 264) | def test_logout_configuration_keys_valid(app): FILE: tests/test_oidc_session_cookie_bloat.py function test_oidc_callback_does_not_store_id_token_in_cookie_session (line 15) | def test_oidc_callback_does_not_store_id_token_in_cookie_session(app, cl... FILE: tests/test_onboarding.py function test_onboarding_manager_exists (line 12) | def test_onboarding_manager_exists(): function test_onboarding_js_loaded (line 25) | def test_onboarding_js_loaded(authenticated_client): function test_contextual_help_system (line 35) | def test_contextual_help_system(): function test_tooltip_system (line 51) | def test_tooltip_system(): function test_feature_discovery (line 67) | def test_feature_discovery(): function test_enhanced_tour_steps (line 83) | def test_enhanced_tour_steps(): function test_onboarding_files_exist (line 99) | def test_onboarding_files_exist(): function test_onboarding_base_template_integration (line 114) | def test_onboarding_base_template_integration(authenticated_client): FILE: tests/test_otel_integration.py function otel_app (line 10) | def otel_app(app_config, monkeypatch, tmp_path): function otel_client (line 33) | def otel_client(otel_app): function test_health_request_emits_span (line 37) | def test_health_request_emits_span(otel_client): function test_otlp_log_payload_has_trace_and_event_category (line 48) | def test_otlp_log_payload_has_trace_and_event_category(): function test_record_background_job_noop_without_metrics (line 66) | def test_record_background_job_noop_without_metrics(): function test_http_server_metrics_record_does_not_raise_when_otel_inactive (line 73) | def test_http_server_metrics_record_does_not_raise_when_otel_inactive(ot... FILE: tests/test_overtime.py class TestOvertimeCalculations (line 22) | class TestOvertimeCalculations: method test_calculate_daily_overtime_no_overtime (line 25) | def test_calculate_daily_overtime_no_overtime(self): method test_calculate_daily_overtime_exact_standard (line 30) | def test_calculate_daily_overtime_exact_standard(self): method test_calculate_daily_overtime_with_overtime (line 35) | def test_calculate_daily_overtime_with_overtime(self): method test_calculate_daily_overtime_large_overtime (line 40) | def test_calculate_daily_overtime_large_overtime(self): class TestPeriodOvertime (line 46) | class TestPeriodOvertime: method test_user (line 50) | def test_user(self, app): method test_client_obj (line 59) | def test_client_obj(self, app): method test_project (line 66) | def test_project(self, app, test_client_obj): method test_period_overtime_no_entries (line 72) | def test_period_overtime_no_entries(self, app, test_user): method test_period_overtime_all_regular (line 84) | def test_period_overtime_all_regular(self, app, test_user, test_project): method test_period_overtime_with_overtime (line 111) | def test_period_overtime_with_overtime(self, app, test_user, test_proj... method test_period_overtime_multiple_entries_same_day (line 150) | def test_period_overtime_multiple_entries_same_day(self, app, test_use... class TestDailyBreakdown (line 177) | class TestDailyBreakdown: method test_user_daily (line 181) | def test_user_daily(self, app): method test_project_daily (line 190) | def test_project_daily(self, app, test_client_obj): method test_client_obj (line 197) | def test_client_obj(self, app): method test_daily_breakdown_empty (line 203) | def test_daily_breakdown_empty(self, app, test_user_daily): method test_daily_breakdown_with_entries (line 212) | def test_daily_breakdown_with_entries(self, app, test_user_daily, test... class TestOvertimeStatistics (line 251) | class TestOvertimeStatistics: method test_user_stats (line 255) | def test_user_stats(self, app): method test_project_stats (line 264) | def test_project_stats(self, app, test_client_obj): method test_client_obj (line 271) | def test_client_obj(self, app): method test_overtime_statistics_comprehensive (line 277) | def test_overtime_statistics_comprehensive(self, app, test_user_stats,... class TestUserModel (line 320) | class TestUserModel: method test_user_has_standard_hours_field (line 323) | def test_user_has_standard_hours_field(self, app): method test_user_can_set_custom_standard_hours (line 333) | def test_user_can_set_custom_standard_hours(self, app): method test_user_standard_hours_validation_min (line 344) | def test_user_standard_hours_validation_min(self, app): method test_user_standard_hours_validation_max (line 353) | def test_user_standard_hours_validation_max(self, app): class TestWeeklyOvertimeSummary (line 363) | class TestWeeklyOvertimeSummary: method test_user_weekly (line 367) | def test_user_weekly(self, app): method test_project_weekly (line 376) | def test_project_weekly(self, app, test_client_obj): method test_client_obj (line 384) | def test_client_obj(self, app): method test_weekly_summary_empty (line 391) | def test_weekly_summary_empty(self, app, test_user_weekly): method test_weekly_summary_with_data (line 396) | def test_weekly_summary_with_data(self, app, test_user_weekly, test_pr... class TestWeeklyOvertimeMode (line 430) | class TestWeeklyOvertimeMode: method user_weekly (line 434) | def user_weekly(self, app): method client_and_project (line 446) | def client_and_project(self, app): method test_week_start_for_date_monday (line 455) | def test_week_start_for_date_monday(self, app, user_weekly): method test_period_overtime_weekly_no_overtime (line 462) | def test_period_overtime_weekly_no_overtime(self, app, user_weekly, cl... method test_period_overtime_weekly_with_overtime (line 484) | def test_period_overtime_weekly_with_overtime(self, app, user_weekly, ... class TestOvertimeYTD (line 507) | class TestOvertimeYTD: method ytd_user (line 511) | def ytd_user(self, app): method ytd_client_project (line 519) | def ytd_client_project(self, app): method test_get_overtime_ytd_returns_dict (line 526) | def test_get_overtime_ytd_returns_dict(self, app, ytd_user): method test_get_overtime_ytd_no_entries (line 535) | def test_get_overtime_ytd_no_entries(self, app, ytd_user): method test_get_overtime_ytd_with_entries (line 542) | def test_get_overtime_ytd_with_entries(self, app, ytd_user, ytd_client... method test_get_overtime_last_12_months_returns_dict (line 561) | def test_get_overtime_last_12_months_returns_dict(self, app, ytd_user): FILE: tests/test_overtime_leave.py function overtime_leave_type (line 19) | def overtime_leave_type(app): function user_with_ytd_overtime (line 37) | def user_with_ytd_overtime(app, overtime_leave_type): function test_overtime_leave_request_within_ytd_succeeds (line 59) | def test_overtime_leave_request_within_ytd_succeeds(app, user_with_ytd_o... function test_overtime_leave_request_exceeding_ytd_fails (line 82) | def test_overtime_leave_request_exceeding_ytd_fails(app, user_with_ytd_o... FILE: tests/test_overtime_smoke.py class TestOvertimeSmoke (line 15) | class TestOvertimeSmoke: method test_overtime_utils_import (line 18) | def test_overtime_utils_import(self): method test_user_model_has_standard_hours (line 29) | def test_user_model_has_standard_hours(self, app): method test_basic_overtime_calculation (line 35) | def test_basic_overtime_calculation(self): method test_no_overtime_calculation (line 41) | def test_no_overtime_calculation(self): method test_period_overtime_basic (line 46) | def test_period_overtime_basic(self, app): method test_settings_route_accessible (line 67) | def test_settings_route_accessible(self, app): method test_user_report_route_exists (line 74) | def test_user_report_route_exists(self, app): method test_analytics_overtime_route_exists (line 80) | def test_analytics_overtime_route_exists(self, app): method test_overtime_calculation_with_real_entry (line 86) | def test_overtime_calculation_with_real_entry(self, app): method test_migration_file_exists (line 117) | def test_migration_file_exists(self): method test_overtime_template_fields (line 124) | def test_overtime_template_fields(self, app): class TestOvertimeIntegration (line 137) | class TestOvertimeIntegration: method test_full_overtime_workflow (line 140) | def test_full_overtime_workflow(self, app): method test_different_standard_hours_between_users (line 196) | def test_different_standard_hours_between_users(self, app): FILE: tests/test_payment_model.py function app (line 13) | def app(): function test_user (line 49) | def test_user(app): function test_client (line 57) | def test_client(app): function test_project (line 65) | def test_project(app, test_client, test_user): function test_invoice (line 73) | def test_invoice(app, test_project, test_user, test_client): class TestPaymentModel (line 93) | class TestPaymentModel: method test_create_payment (line 96) | def test_create_payment(self, app, test_invoice, test_user): method test_payment_calculate_net_amount_without_fee (line 125) | def test_payment_calculate_net_amount_without_fee(self, app, test_invo... method test_payment_calculate_net_amount_with_fee (line 142) | def test_payment_calculate_net_amount_with_fee(self, app, test_invoice): method test_payment_to_dict (line 158) | def test_payment_to_dict(self, app, test_invoice, test_user): method test_payment_relationship_with_invoice (line 194) | def test_payment_relationship_with_invoice(self, app, test_invoice): method test_payment_relationship_with_user (line 224) | def test_payment_relationship_with_user(self, app, test_invoice, test_... method test_payment_repr (line 255) | def test_payment_repr(self, app, test_invoice): method test_multiple_payments_for_invoice (line 271) | def test_multiple_payments_for_invoice(self, app, test_invoice): method test_payment_status_values (line 309) | def test_payment_status_values(self, app, test_invoice): class TestPaymentIntegration (line 333) | class TestPaymentIntegration: method test_invoice_updates_with_payment (line 336) | def test_invoice_updates_with_payment(self, app, test_invoice): method test_invoice_fully_paid_with_payments (line 370) | def test_invoice_fully_paid_with_payments(self, app, test_invoice): FILE: tests/test_payment_routes.py function app (line 14) | def app(): function test_user (line 49) | def test_user(app): function test_admin (line 57) | def test_admin(app): function test_client (line 67) | def test_client(app): function test_project (line 75) | def test_project(app, test_client, test_user): function test_invoice (line 83) | def test_invoice(app, test_project, test_user, test_client): function test_payment (line 103) | def test_payment(app, test_invoice, test_user): class TestPaymentRoutes (line 121) | class TestPaymentRoutes: method test_list_payments_requires_login (line 124) | def test_list_payments_requires_login(self, client): method test_list_payments_as_user (line 129) | def test_list_payments_as_user(self, client, test_user, test_payment): method test_list_payments_as_admin (line 139) | def test_list_payments_as_admin(self, client, test_admin, test_payment): method test_view_payment_requires_login (line 149) | def test_view_payment_requires_login(self, client, test_payment): method test_view_payment (line 154) | def test_view_payment(self, client, test_user, test_payment): method test_create_payment_get_requires_login (line 164) | def test_create_payment_get_requires_login(self, client): method test_create_payment_get (line 169) | def test_create_payment_get(self, client, test_user): method test_create_payment_post (line 179) | def test_create_payment_post(self, client, test_user, test_invoice, app): method test_create_payment_with_gateway_fee (line 213) | def test_create_payment_with_gateway_fee(self, client, test_user, test... method test_edit_payment_get (line 244) | def test_edit_payment_get(self, client, test_user, test_payment): method test_edit_payment_post (line 254) | def test_edit_payment_post(self, client, test_user, test_payment, app): method test_delete_payment (line 281) | def test_delete_payment(self, client, test_user, test_payment, app): method test_payment_stats_api (line 297) | def test_payment_stats_api(self, client, test_user, test_payment): method test_create_payment_invalid_amount (line 313) | def test_create_payment_invalid_amount(self, client, test_user, test_i... method test_create_payment_without_invoice (line 332) | def test_create_payment_without_invoice(self, client, test_user): class TestPaymentFilteringAndSearch (line 351) | class TestPaymentFilteringAndSearch: method test_filter_payments_by_status (line 354) | def test_filter_payments_by_status(self, client, test_user, test_payme... method test_filter_payments_by_method (line 364) | def test_filter_payments_by_method(self, client, test_user, test_payme... method test_filter_payments_by_date_range (line 374) | def test_filter_payments_by_date_range(self, client, test_user, test_p... method test_filter_payments_by_invoice (line 386) | def test_filter_payments_by_invoice(self, client, test_user, test_invo... FILE: tests/test_payment_smoke.py function setup_payment_test_data (line 12) | def setup_payment_test_data(app): class TestPaymentSmokeTests (line 57) | class TestPaymentSmokeTests: method test_payment_model_exists (line 60) | def test_payment_model_exists(self): method test_payment_blueprint_registered (line 66) | def test_payment_blueprint_registered(self, app): method test_payment_routes_exist (line 71) | def test_payment_routes_exist(self, app): method test_payment_database_table_exists (line 79) | def test_payment_database_table_exists(self, app): method test_payment_model_columns (line 88) | def test_payment_model_columns(self, app): method test_create_and_retrieve_payment (line 118) | def test_create_and_retrieve_payment(self, app, setup_payment_test_data): method test_payment_invoice_relationship (line 149) | def test_payment_invoice_relationship(self, app, setup_payment_test_da... method test_payment_list_page_loads (line 183) | def test_payment_list_page_loads(self, client, setup_payment_test_data): method test_payment_create_page_loads (line 199) | def test_payment_create_page_loads(self, client, setup_payment_test_da... method test_payment_workflow_end_to_end (line 215) | def test_payment_workflow_end_to_end(self, client, app, setup_payment_... method test_payment_templates_exist (line 256) | def test_payment_templates_exist(self, app): method test_payment_model_methods (line 268) | def test_payment_model_methods(self, app, setup_payment_test_data): method test_payment_filter_functionality (line 294) | def test_payment_filter_functionality(self, client, app, setup_payment... method test_invoice_shows_payment_history (line 342) | def test_invoice_shows_payment_history(self, client, app, setup_paymen... class TestPaymentFeatureCompleteness (line 377) | class TestPaymentFeatureCompleteness: method test_migration_exists (line 380) | def test_migration_exists(self): method test_payment_api_endpoint_exists (line 391) | def test_payment_api_endpoint_exists(self, app): method test_all_crud_operations_work (line 397) | def test_all_crud_operations_work(self, client, app, setup_payment_tes... FILE: tests/test_pdf_layout.py function admin_user (line 15) | def admin_user(app): function regular_user (line 26) | def regular_user(app): function sample_invoice (line 37) | def sample_invoice(app, admin_user): function test_pdf_layout_page_requires_admin (line 81) | def test_pdf_layout_page_requires_admin(client, regular_user): function test_pdf_layout_page_accessible_to_admin (line 96) | def test_pdf_layout_page_accessible_to_admin(admin_authenticated_client): function test_pdf_layout_save_custom_template (line 107) | def test_pdf_layout_save_custom_template(admin_authenticated_client, app): function test_pdf_layout_reset_to_defaults (line 137) | def test_pdf_layout_reset_to_defaults(admin_authenticated_client, app): function test_pdf_layout_get_defaults (line 158) | def test_pdf_layout_get_defaults(admin_authenticated_client): function test_pdf_layout_preview (line 173) | def test_pdf_layout_preview(admin_authenticated_client, sample_invoice): function test_pdf_layout_preview_prefers_form_template_json_over_database (line 202) | def test_pdf_layout_preview_prefers_form_template_json_over_database( function test_pdf_layout_preview_with_mock_invoice (line 270) | def test_pdf_layout_preview_with_mock_invoice(admin_authenticated_client... function test_settings_pdf_template_fields_exist (line 286) | def test_settings_pdf_template_fields_exist(app): function test_settings_pdf_template_defaults (line 295) | def test_settings_pdf_template_defaults(app): function test_pdf_generation_with_custom_template (line 307) | def test_pdf_generation_with_custom_template(app, sample_invoice): function test_pdf_generation_with_default_template (line 337) | def test_pdf_generation_with_default_template(app, sample_invoice): function test_pdf_layout_navigation_link_exists (line 361) | def test_pdf_layout_navigation_link_exists(admin_authenticated_client, a... function test_pdf_layout_form_csrf_protection (line 387) | def test_pdf_layout_form_csrf_protection(admin_authenticated_client): function test_pdf_layout_jinja_variable_rendering (line 398) | def test_pdf_layout_jinja_variable_rendering(app, sample_invoice): function test_pdf_layout_rate_limiting (line 425) | def test_pdf_layout_rate_limiting(admin_authenticated_client): function test_pdf_layout_with_invoice_items_loop (line 440) | def test_pdf_layout_with_invoice_items_loop(app, sample_invoice): function test_pdf_layout_save_and_restore_tables (line 483) | def test_pdf_layout_save_and_restore_tables(app): FILE: tests/test_pdfa3.py function test_convert_to_pdfa3_adds_identification (line 15) | def test_convert_to_pdfa3_adds_identification(app): function test_convert_to_pdfa3_adds_output_intent (line 41) | def test_convert_to_pdfa3_adds_output_intent(app): function test_convert_to_pdfa3_icc_profile_is_valid (line 69) | def test_convert_to_pdfa3_icc_profile_is_valid(app): function test_convert_to_pdfa3_preserves_existing_xmp (line 106) | def test_convert_to_pdfa3_preserves_existing_xmp(app): function test_convert_to_pdfa3_returns_error_on_invalid_pdf (line 139) | def test_convert_to_pdfa3_returns_error_on_invalid_pdf(app): function test_bundled_srgb_icc_file_present (line 148) | def test_bundled_srgb_icc_file_present(): function test_verapdf_when_invoice_verapdf_path_configured (line 157) | def test_verapdf_when_invoice_verapdf_path_configured(app): FILE: tests/test_peppol_identifiers.py function test_validate_scheme_id_accepts_numeric (line 13) | def test_validate_scheme_id_accepts_numeric(): function test_validate_scheme_id_rejects_empty (line 20) | def test_validate_scheme_id_rejects_empty(): function test_validate_endpoint_id_accepts_valid (line 29) | def test_validate_endpoint_id_accepts_valid(): function test_validate_endpoint_id_rejects_empty (line 36) | def test_validate_endpoint_id_rejects_empty(): function test_validate_participant_identifiers_roundtrip (line 43) | def test_validate_participant_identifiers_roundtrip(): function test_validate_participant_identifiers_rejects_invalid_sender (line 54) | def test_validate_participant_identifiers_rejects_invalid_sender(): FILE: tests/test_peppol_service.py class _FakeResponse (line 10) | class _FakeResponse: method __init__ (line 11) | def __init__(self, status_code=200, json_data=None, text="", content_t... method json (line 17) | def json(self): function test_peppol_service_disabled_returns_error (line 22) | def test_peppol_service_disabled_returns_error(app): function test_peppol_service_requires_client_endpoint (line 34) | def test_peppol_service_requires_client_endpoint(app, monkeypatch): function test_peppol_service_success_creates_transmission (line 75) | def test_peppol_service_success_creates_transmission(app, monkeypatch): function test_peppol_service_generic_transport_uses_identifier_validation (line 151) | def test_peppol_service_generic_transport_uses_identifier_validation(app... function test_as4_message_payload_is_gzip_compressed (line 169) | def test_as4_message_payload_is_gzip_compressed(): function test_native_transport_marked_experimental (line 191) | def test_native_transport_marked_experimental(): FILE: tests/test_permissions.py function test_permission_creation (line 10) | def test_permission_creation(app): function test_role_creation (line 25) | def test_role_creation(app): function test_role_permission_assignment (line 40) | def test_role_permission_assignment(app): function test_role_permission_removal (line 66) | def test_role_permission_removal(app): function test_user_role_assignment (line 88) | def test_user_role_assignment(app): function test_user_permission_check (line 108) | def test_user_permission_check(app): function test_user_has_any_permission (line 142) | def test_user_has_any_permission(app): function test_user_has_all_permissions (line 168) | def test_user_has_all_permissions(app): function test_user_get_all_permissions (line 196) | def test_user_get_all_permissions(app): function test_legacy_admin_user_permissions (line 236) | def test_legacy_admin_user_permissions(app): function test_admin_role_user (line 253) | def test_admin_role_user(app): function test_super_admin_role_user (line 277) | def test_super_admin_role_user(app): function test_role_get_permission_names (line 298) | def test_role_get_permission_names(app): function test_user_get_role_names (line 321) | def test_user_get_role_names(app): function test_permission_to_dict (line 344) | def test_permission_to_dict(app): function test_role_to_dict (line 360) | def test_role_to_dict(app): function test_role_to_dict_with_permissions (line 376) | def test_role_to_dict_with_permissions(app): FILE: tests/test_permissions_routes.py function test_roles_list_page (line 9) | def test_roles_list_page(client, admin_user): function test_create_role_page (line 21) | def test_create_role_page(client, admin_user): function test_permissions_list_page (line 31) | def test_permissions_list_page(client, admin_user): function test_create_role_flow (line 41) | def test_create_role_flow(app, client, admin_user): function test_view_role_page (line 71) | def test_view_role_page(app, client, admin_user): function test_edit_role_flow (line 90) | def test_edit_role_flow(app, client, admin_user): function test_delete_role_flow (line 119) | def test_delete_role_flow(app, client, admin_user): function test_cannot_delete_system_role (line 141) | def test_cannot_delete_system_role(app, client, admin_user): function test_cannot_edit_system_role (line 164) | def test_cannot_edit_system_role(app, client, admin_user): function test_manage_user_roles_page (line 193) | def test_manage_user_roles_page(app, client, admin_user): function test_assign_roles_to_user (line 212) | def test_assign_roles_to_user(app, client, admin_user): function test_api_get_user_permissions (line 239) | def test_api_get_user_permissions(app, client, admin_user): function test_api_get_role_permissions (line 268) | def test_api_get_role_permissions(app, client, admin_user): function test_non_admin_cannot_access_roles (line 295) | def test_non_admin_cannot_access_roles(authenticated_client): FILE: tests/test_prepaid_allocator.py function test_prepaid_allocator_partial_allocation (line 13) | def test_prepaid_allocator_partial_allocation(app, user): FILE: tests/test_profile_avatar.py function _make_test_image_bytes (line 7) | def _make_test_image_bytes(fmt="PNG", size=(10, 10), color=(255, 0, 0, 2... function avatar_test_app (line 16) | def avatar_test_app(app, temp_dir): function test_upload_avatar (line 26) | def test_upload_avatar(app, temp_dir, user): function test_remove_avatar (line 59) | def test_remove_avatar(app, temp_dir, user): FILE: tests/test_project_archiving.py class TestProjectArchivingModel (line 8) | class TestProjectArchivingModel: method test_project_archive_with_metadata (line 12) | def test_project_archive_with_metadata(self, app, project, admin_user): method test_project_archive_without_reason (line 27) | def test_project_archive_without_reason(self, app, project, admin_user): method test_project_unarchive_clears_metadata (line 41) | def test_project_unarchive_clears_metadata(self, app, project, admin_u... method test_project_archived_by_user_property (line 61) | def test_project_archived_by_user_property(self, app, project, admin_u... method test_project_to_dict_includes_archive_metadata (line 74) | def test_project_to_dict_includes_archive_metadata(self, app, project,... method test_archived_at_timestamp_accuracy (line 90) | def test_archived_at_timestamp_accuracy(self, app, project, admin_user): class TestProjectArchivingRoutes (line 103) | class TestProjectArchivingRoutes: method test_archive_project_route_get (line 107) | def test_archive_project_route_get(self, admin_authenticated_client, a... method test_archive_project_route_post_with_reason (line 119) | def test_archive_project_route_post_with_reason(self, admin_authentica... method test_archive_project_route_post_without_reason (line 138) | def test_archive_project_route_post_without_reason(self, admin_authent... method test_unarchive_project_clears_metadata (line 153) | def test_unarchive_project_clears_metadata(self, admin_authenticated_c... method test_bulk_archive_with_reason (line 174) | def test_bulk_archive_with_reason(self, admin_authenticated_client, ap... method test_filter_archived_projects (line 203) | def test_filter_archived_projects(self, admin_authenticated_client, ap... method test_non_admin_cannot_archive (line 224) | def test_non_admin_cannot_archive(self, authenticated_client, app, pro... class TestArchivedProjectValidation (line 236) | class TestArchivedProjectValidation: method test_cannot_start_timer_on_archived_project (line 240) | def test_cannot_start_timer_on_archived_project(self, authenticated_cl... method test_cannot_create_manual_entry_on_archived_project (line 256) | def test_cannot_create_manual_entry_on_archived_project(self, authenti... method test_cannot_create_bulk_entry_on_archived_project (line 283) | def test_cannot_create_bulk_entry_on_archived_project(self, authentica... method test_archived_projects_not_in_active_list (line 310) | def test_archived_projects_not_in_active_list(self, authenticated_clie... class TestArchivingActivityLogs (line 334) | class TestArchivingActivityLogs: method test_archive_creates_activity_log (line 338) | def test_archive_creates_activity_log(self, admin_authenticated_client... method test_unarchive_creates_activity_log (line 358) | def test_unarchive_creates_activity_log(self, admin_authenticated_clie... class TestArchivingUI (line 378) | class TestArchivingUI: method test_project_view_shows_archive_metadata (line 382) | def test_project_view_shows_archive_metadata(self, admin_authenticated... method test_project_list_shows_archived_status_badge (line 404) | def test_project_list_shows_archived_status_badge(self, admin_authenti... method test_archive_form_has_quick_select_buttons (line 424) | def test_archive_form_has_quick_select_buttons(self, admin_authenticat... class TestArchivingSmokeTests (line 440) | class TestArchivingSmokeTests: method test_complete_archive_unarchive_workflow (line 443) | def test_complete_archive_unarchive_workflow(self, admin_authenticated... FILE: tests/test_project_archiving_models.py class TestProjectArchivingFields (line 9) | class TestProjectArchivingFields: method test_archived_at_field_exists (line 12) | def test_archived_at_field_exists(self, app, project): method test_archived_by_field_exists (line 24) | def test_archived_by_field_exists(self, app, project, admin_user): method test_archived_reason_field_exists (line 34) | def test_archived_reason_field_exists(self, app, project): method test_archived_at_is_nullable (line 45) | def test_archived_at_is_nullable(self, app, test_client): method test_archived_by_is_nullable (line 55) | def test_archived_by_is_nullable(self, app, test_client): method test_archived_reason_is_nullable (line 65) | def test_archived_reason_is_nullable(self, app, test_client): class TestProjectArchiveMethod (line 77) | class TestProjectArchiveMethod: method test_archive_sets_status (line 80) | def test_archive_sets_status(self, app, project): method test_archive_sets_timestamp (line 89) | def test_archive_sets_timestamp(self, app, project): method test_archive_with_user_id (line 101) | def test_archive_with_user_id(self, app, project, admin_user): method test_archive_with_reason (line 110) | def test_archive_with_reason(self, app, project): method test_archive_with_all_parameters (line 120) | def test_archive_with_all_parameters(self, app, project, admin_user): method test_archive_without_parameters (line 133) | def test_archive_without_parameters(self, app, project): method test_archive_updates_updated_at (line 145) | def test_archive_updates_updated_at(self, app, project): method test_archive_can_be_called_multiple_times (line 160) | def test_archive_can_be_called_multiple_times(self, app, project, admi... class TestProjectUnarchiveMethod (line 183) | class TestProjectUnarchiveMethod: method test_unarchive_sets_status_to_active (line 186) | def test_unarchive_sets_status_to_active(self, app, project, admin_user): method test_unarchive_clears_archived_at (line 198) | def test_unarchive_clears_archived_at(self, app, project, admin_user): method test_unarchive_clears_archived_by (line 211) | def test_unarchive_clears_archived_by(self, app, project, admin_user): method test_unarchive_clears_archived_reason (line 224) | def test_unarchive_clears_archived_reason(self, app, project, admin_us... method test_unarchive_updates_updated_at (line 237) | def test_unarchive_updates_updated_at(self, app, project, admin_user): class TestProjectArchiveProperties (line 256) | class TestProjectArchiveProperties: method test_is_archived_property_when_archived (line 259) | def test_is_archived_property_when_archived(self, app, project, admin_... method test_is_archived_property_when_active (line 268) | def test_is_archived_property_when_active(self, app, project): method test_is_archived_property_when_inactive (line 272) | def test_is_archived_property_when_inactive(self, app, project): method test_archived_by_user_property_returns_user (line 281) | def test_archived_by_user_property_returns_user(self, app, project, ad... method test_archived_by_user_property_returns_none_when_not_archived (line 293) | def test_archived_by_user_property_returns_none_when_not_archived(self... method test_archived_by_user_property_returns_none_when_user_deleted (line 297) | def test_archived_by_user_property_returns_none_when_user_deleted(self... class TestProjectToDictArchiveFields (line 323) | class TestProjectToDictArchiveFields: method test_to_dict_includes_is_archived (line 326) | def test_to_dict_includes_is_archived(self, app, project): method test_to_dict_includes_archived_at (line 333) | def test_to_dict_includes_archived_at(self, app, project, admin_user): method test_to_dict_includes_archived_by (line 347) | def test_to_dict_includes_archived_by(self, app, project, admin_user): method test_to_dict_includes_archived_reason (line 359) | def test_to_dict_includes_archived_reason(self, app, project, admin_us... method test_to_dict_archive_fields_null_when_not_archived (line 372) | def test_to_dict_archive_fields_null_when_not_archived(self, app, proj... class TestProjectArchiveEdgeCases (line 383) | class TestProjectArchiveEdgeCases: method test_archive_with_empty_string_reason (line 386) | def test_archive_with_empty_string_reason(self, app, project): method test_archive_with_very_long_reason (line 396) | def test_archive_with_very_long_reason(self, app, project): method test_archive_with_special_characters_in_reason (line 408) | def test_archive_with_special_characters_in_reason(self, app, project): method test_archive_with_invalid_user_id (line 419) | def test_archive_with_invalid_user_id(self, app, project): FILE: tests/test_project_costs.py function app (line 23) | def app(): function client_fixture (line 35) | def client_fixture(app): function test_user (line 41) | def test_user(app): function test_admin (line 51) | def test_admin(app): function test_client (line 61) | def test_client(app): function test_project (line 71) | def test_project(app, test_client): function test_invoice (line 87) | def test_invoice(app, test_client, test_project, test_user): class TestProjectCostModel (line 109) | class TestProjectCostModel: method test_create_project_cost (line 112) | def test_create_project_cost(self, app, test_project, test_user): method test_create_project_cost_with_all_fields (line 135) | def test_create_project_cost_with_all_fields(self, app, test_project, ... method test_project_cost_str_representation (line 158) | def test_project_cost_str_representation(self, app, test_project, test... method test_project_cost_timestamps (line 176) | def test_project_cost_timestamps(self, app, test_project, test_user): class TestProjectCostRelationships (line 196) | class TestProjectCostRelationships: method test_project_relationship (line 199) | def test_project_relationship(self, app, test_project, test_user): method test_user_relationship (line 221) | def test_user_relationship(self, app, test_project, test_user): method test_invoice_relationship (line 243) | def test_invoice_relationship(self, app, test_project, test_user, test... class TestProjectCostMethods (line 268) | class TestProjectCostMethods: method test_is_invoiced_property (line 271) | def test_is_invoiced_property(self, app, test_project, test_user, test... method test_mark_as_invoiced (line 294) | def test_mark_as_invoiced(self, app, test_project, test_user, test_inv... method test_unmark_as_invoiced (line 327) | def test_unmark_as_invoiced(self, app, test_project, test_user, test_i... method test_to_dict (line 353) | def test_to_dict(self, app, test_project, test_user): class TestProjectCostQueries (line 386) | class TestProjectCostQueries: method test_get_project_costs (line 389) | def test_get_project_costs(self, app, test_project, test_user): method test_get_project_costs_with_date_filter (line 414) | def test_get_project_costs_with_date_filter(self, app, test_project, t... method test_get_project_costs_billable_only (line 441) | def test_get_project_costs_billable_only(self, app, test_project, test... method test_get_total_costs (line 465) | def test_get_total_costs(self, app, test_project, test_user): method test_get_uninvoiced_costs (line 489) | def test_get_uninvoiced_costs(self, app, test_project, test_user, test... method test_get_costs_by_category (line 533) | def test_get_costs_by_category(self, app, test_project, test_user): class TestProjectCostConstraints (line 566) | class TestProjectCostConstraints: method test_cannot_create_cost_without_project (line 569) | def test_cannot_create_cost_without_project(self, app, test_user): method test_cannot_create_cost_without_user (line 587) | def test_cannot_create_cost_without_user(self, app, test_project): method test_cascade_delete_with_project (line 605) | def test_cascade_delete_with_project(self, app, test_client, test_user): class TestProjectCostSmokeTests (line 638) | class TestProjectCostSmokeTests: method test_project_cost_creation_smoke (line 641) | def test_project_cost_creation_smoke(self, app, test_project, test_user): method test_project_cost_query_smoke (line 657) | def test_project_cost_query_smoke(self, app, test_project, test_user): method test_project_cost_relationship_smoke (line 674) | def test_project_cost_relationship_smoke(self, app, test_project, test... FILE: tests/test_project_dashboard.py function app (line 25) | def app(): function client_fixture (line 37) | def client_fixture(app): function test_user (line 43) | def test_user(app): function test_user2 (line 54) | def test_user2(app): function test_admin (line 65) | def test_admin(app): function test_client (line 76) | def test_client(app): function test_project (line 86) | def test_project(app, test_client): function test_project_with_data (line 104) | def test_project_with_data(app, test_project, test_user, test_user2): function login (line 231) | def login(client, username="testuser", password="testpass123"): class TestProjectDashboardAccess (line 236) | class TestProjectDashboardAccess: method test_dashboard_requires_login (line 239) | def test_dashboard_requires_login(self, app, client_fixture, test_proj... method test_dashboard_accessible_when_logged_in (line 245) | def test_dashboard_accessible_when_logged_in(self, app, client_fixture... method test_dashboard_404_for_nonexistent_project (line 252) | def test_dashboard_404_for_nonexistent_project(self, app, client_fixtu... class TestDashboardData (line 260) | class TestDashboardData: method test_budget_data_calculation (line 263) | def test_budget_data_calculation(self, app, client_fixture, test_proje... method test_task_statistics (line 278) | def test_task_statistics(self, app, client_fixture, test_project_with_... method test_team_contributions (line 300) | def test_team_contributions(self, app, client_fixture, test_project_wi... method test_recent_activity (line 320) | def test_recent_activity(self, app, client_fixture, test_project_with_... method test_overdue_tasks_warning (line 335) | def test_overdue_tasks_warning(self, app, client_fixture, test_project... class TestDashboardPeriodFiltering (line 346) | class TestDashboardPeriodFiltering: method test_period_filter_all_time (line 349) | def test_period_filter_all_time(self, app, client_fixture, test_projec... method test_period_filter_week (line 357) | def test_period_filter_week(self, app, client_fixture, test_project_wi... method test_period_filter_month (line 364) | def test_period_filter_month(self, app, client_fixture, test_project_w... method test_period_filter_three_months (line 371) | def test_period_filter_three_months(self, app, client_fixture, test_pr... method test_period_filter_year (line 378) | def test_period_filter_year(self, app, client_fixture, test_project_wi... class TestDashboardWithNoData (line 386) | class TestDashboardWithNoData: method test_dashboard_with_no_budget (line 389) | def test_dashboard_with_no_budget(self, app, client_fixture, test_clie... method test_dashboard_with_no_tasks (line 402) | def test_dashboard_with_no_tasks(self, app, client_fixture, test_proje... method test_dashboard_with_no_time_entries (line 410) | def test_dashboard_with_no_time_entries(self, app, client_fixture, tes... method test_dashboard_with_no_activity (line 420) | def test_dashboard_with_no_activity(self, app, client_fixture, test_pr... class TestDashboardBudgetThreshold (line 429) | class TestDashboardBudgetThreshold: method test_budget_threshold_exceeded_warning (line 432) | def test_budget_threshold_exceeded_warning(self, app, client_fixture, ... class TestDashboardNavigation (line 470) | class TestDashboardNavigation: method test_back_to_project_link (line 473) | def test_back_to_project_link(self, app, client_fixture, test_project,... method test_dashboard_link_in_project_view (line 482) | def test_dashboard_link_in_project_view(self, app, client_fixture, tes... FILE: tests/test_project_inactive_status.py class TestProjectInactiveStatus (line 7) | class TestProjectInactiveStatus: method test_project_default_status (line 11) | def test_project_default_status(self, app, test_client): method test_project_deactivate (line 23) | def test_project_deactivate(self, app, project): method test_project_activate_from_inactive (line 34) | def test_project_activate_from_inactive(self, app, project): method test_project_archive_from_inactive (line 48) | def test_project_archive_from_inactive(self, app, project): method test_project_unarchive_to_active (line 61) | def test_project_unarchive_to_active(self, app, project): method test_project_status_transitions (line 74) | def test_project_status_transitions(self, app, project): class TestProjectInactiveRoutes (line 102) | class TestProjectInactiveRoutes: method test_deactivate_project_route (line 106) | def test_deactivate_project_route(self, admin_authenticated_client, ap... method test_activate_project_route (line 120) | def test_activate_project_route(self, admin_authenticated_client, app,... method test_filter_inactive_projects (line 136) | def test_filter_inactive_projects(self, admin_authenticated_client, ap... class TestTaskDeletion (line 160) | class TestTaskDeletion: method test_task_list_has_bulk_delete_features (line 164) | def test_task_list_has_bulk_delete_features(self, admin_authenticated_... FILE: tests/test_quick_wins.py function test_imports (line 15) | def test_imports(): function test_model_attributes (line 45) | def test_model_attributes(): function test_model_methods (line 92) | def test_model_methods(): function test_blueprint_registration (line 120) | def test_blueprint_registration(): function test_utility_functions (line 144) | def test_utility_functions(): function test_template_files (line 171) | def test_template_files(): function test_migration_file (line 204) | def test_migration_file(): function main (line 240) | def main(): FILE: tests/test_reports_task_report.py function test_task_report_returns_correct_hours_and_entries (line 8) | def test_task_report_returns_correct_hours_and_entries(client, app, admi... function test_task_report_excel_export_returns_correct_hours (line 68) | def test_task_report_excel_export_returns_correct_hours(client, app, adm... function test_time_entry_repository_get_task_aggregates (line 126) | def test_time_entry_repository_get_task_aggregates(app, project, task, u... FILE: tests/test_repositories/test_base_repository.py function test_get_by_id_success (line 12) | def test_get_by_id_success(app, test_project): function test_get_by_id_not_found (line 23) | def test_get_by_id_not_found(app): function test_find_by (line 32) | def test_find_by(app, test_client_model): function test_find_one_by (line 48) | def test_find_one_by(app, test_client_model): function test_create (line 64) | def test_create(app, test_client_model): function test_update (line 79) | def test_update(app, test_project): function test_count (line 91) | def test_count(app, test_client_model): function test_exists (line 111) | def test_exists(app, test_project): FILE: tests/test_repositories/test_time_entry_repository.py function repository (line 17) | def repository(): function sample_user (line 23) | def sample_user(db_session): function sample_project (line 32) | def sample_project(db_session, sample_user): class TestTimeEntryRepository (line 46) | class TestTimeEntryRepository: method test_create_timer (line 49) | def test_create_timer(self, repository, db_session, sample_user, sampl... method test_get_active_timer (line 61) | def test_get_active_timer(self, repository, db_session, sample_user, s... method test_stop_timer (line 74) | def test_stop_timer(self, repository, db_session, sample_user, sample_... method test_get_by_user (line 89) | def test_get_by_user(self, repository, db_session, sample_user, sample... method test_get_by_date_range (line 109) | def test_get_by_date_range(self, repository, db_session, sample_user, ... method test_get_distinct_project_ids_for_user (line 140) | def test_get_distinct_project_ids_for_user(self, repository, db_sessio... FILE: tests/test_role_module_visibility.py function test_module_registry_hides_module_if_all_roles_hide (line 9) | def test_module_registry_hides_module_if_all_roles_hide(app, user): function test_module_registry_allows_module_if_any_role_allows (line 25) | def test_module_registry_allows_module_if_any_role_allows(app, user): function test_module_enabled_decorator_blocks_hidden_module_route (line 43) | def test_module_enabled_decorator_blocks_hidden_module_route(app, user): FILE: tests/test_routes.py function test_health_check (line 18) | def test_health_check(client): function test_login_page_accessible (line 28) | def test_login_page_accessible(client): function test_static_files_accessible (line 36) | def test_static_files_accessible(client): function test_protected_route_redirects_to_login (line 51) | def test_protected_route_redirects_to_login(client): function test_dashboard_accessible_when_authenticated (line 60) | def test_dashboard_accessible_when_authenticated(authenticated_client): function test_logout_route (line 68) | def test_logout_route(authenticated_client): function test_start_timer_api (line 82) | def test_start_timer_api(authenticated_client, project, app): function test_stop_timer_api (line 94) | def test_stop_timer_api(authenticated_client, active_timer, app): function test_get_active_timer (line 106) | def test_get_active_timer(authenticated_client, active_timer, app): function test_projects_list_page (line 123) | def test_projects_list_page(authenticated_client): function test_projects_create_page_contains_client_modal_trigger (line 131) | def test_projects_create_page_contains_client_modal_trigger(admin_authen... function test_create_project_post_does_not_500_and_logs_activity (line 141) | def test_create_project_post_does_not_500_and_logs_activity(admin_authen... function test_project_create_page (line 184) | def test_project_create_page(admin_authenticated_client): function test_project_detail_page (line 192) | def test_project_detail_page(authenticated_client, project, app): function test_create_project_api (line 202) | def test_create_project_api(client_with_token, test_client, app): function test_edit_project_description (line 221) | def test_edit_project_description(admin_authenticated_client, project, a... function test_project_edit_page_has_markdown_editor (line 267) | def test_project_edit_page_has_markdown_editor(admin_authenticated_clien... function test_clients_list_page (line 295) | def test_clients_list_page(authenticated_client): function test_client_detail_page (line 303) | def test_client_detail_page(authenticated_client, test_client, app): function test_edit_client_updates_prepaid_fields (line 312) | def test_edit_client_updates_prepaid_fields(admin_authenticated_client, ... function test_edit_client_rejects_negative_prepaid_hours (line 348) | def test_edit_client_rejects_negative_prepaid_hours(admin_authenticated_... function test_reports_page (line 395) | def test_reports_page(authenticated_client): function test_time_report_api (line 404) | def test_time_report_api(authenticated_client, multiple_time_entries, app): function test_analytics_page (line 422) | def test_analytics_page(authenticated_client): function test_dashboard_contains_start_timer_modal (line 430) | def test_dashboard_contains_start_timer_modal(authenticated_client): function test_base_layout_has_sidebar_toggle (line 441) | def test_base_layout_has_sidebar_toggle(authenticated_client): function test_hours_by_day_api (line 453) | def test_hours_by_day_api(authenticated_client, multiple_time_entries, a... function test_hours_by_project_api (line 467) | def test_hours_by_project_api(authenticated_client, multiple_time_entrie... function test_invoices_list_page (line 485) | def test_invoices_list_page(authenticated_client): function test_invoice_detail_page (line 493) | def test_invoice_detail_page(authenticated_client, invoice, app): function test_invoice_create_page (line 502) | def test_invoice_create_page(authenticated_client): function test_admin_page_requires_admin (line 515) | def test_admin_page_requires_admin(authenticated_client): function test_admin_page_accessible_by_admin (line 524) | def test_admin_page_accessible_by_admin(admin_authenticated_client): function test_admin_users_list (line 532) | def test_admin_users_list(admin_authenticated_client): function test_404_error_page (line 545) | def test_404_error_page(client): function test_api_requires_authentication (line 558) | def test_api_requires_authentication(client): function test_api_invalid_json (line 566) | def test_api_invalid_json(authenticated_client): function test_settings_page (line 580) | def test_settings_page(authenticated_client): function test_tasks_list_page (line 594) | def test_tasks_list_page(authenticated_client): function test_task_create_page (line 602) | def test_task_create_page(authenticated_client, project, app): function test_task_detail_page (line 611) | def test_task_detail_page(authenticated_client, task, app): function test_create_task_api (line 621) | def test_create_task_api(authenticated_client, project, app): function test_update_task_status_api_put (line 642) | def test_update_task_status_api_put(authenticated_client, task, app): function test_add_comment_api (line 661) | def test_add_comment_api(authenticated_client, task, app): function test_time_entries_page (line 676) | def test_time_entries_page(authenticated_client): function test_create_time_entry_api (line 686) | def test_create_time_entry_api(authenticated_client, project, user, app): function test_update_time_entry_api (line 709) | def test_update_time_entry_api(authenticated_client, time_entry, app): function test_delete_time_entry_api (line 719) | def test_delete_time_entry_api(authenticated_client, time_entry, app): function test_user_profile_page (line 733) | def test_user_profile_page(authenticated_client): function test_user_settings_page (line 742) | def test_user_settings_page(authenticated_client): function test_export_time_entries_csv (line 756) | def test_export_time_entries_csv(authenticated_client, multiple_time_ent... function test_export_invoice_pdf (line 773) | def test_export_invoice_pdf(authenticated_client, invoice_with_items, app): FILE: tests/test_routes/test_api_search.py class _FailingProjectQuery (line 13) | class _FailingProjectQuery: method filter (line 16) | def filter(self, *args, **kwargs): method limit (line 19) | def limit(self, *args, **kwargs): method order_by (line 22) | def order_by(self, *args, **kwargs): method all (line 25) | def all(self): function out_of_scope_entities (line 36) | def out_of_scope_entities(app, user): class TestLegacySearchAPI (line 76) | class TestLegacySearchAPI: method test_search_with_valid_query (line 79) | def test_search_with_valid_query(self, authenticated_client, project): method test_search_with_short_query (line 92) | def test_search_with_short_query(self, authenticated_client): method test_search_with_empty_query (line 103) | def test_search_with_empty_query(self, authenticated_client): method test_search_partial_when_projects_domain_db_error (line 113) | def test_search_partial_when_projects_domain_db_error(self, authentica... method test_search_with_limit (line 125) | def test_search_with_limit(self, authenticated_client, project): method test_search_with_types_filter (line 133) | def test_search_with_types_filter(self, authenticated_client, project): method test_search_projects (line 143) | def test_search_projects(self, authenticated_client, project): method test_search_requires_authentication (line 153) | def test_search_requires_authentication(self, client): method test_search_scope_restricted_excludes_other_client_entities (line 159) | def test_search_scope_restricted_excludes_other_client_entities( method test_search_scope_restricted_still_finds_assigned_project_and_task (line 176) | def test_search_scope_restricted_still_finds_assigned_project_and_task( method test_search_admin_sees_out_of_scope_project (line 194) | def test_search_admin_sees_out_of_scope_project( class TestV1SearchAPI (line 205) | class TestV1SearchAPI: method api_token (line 209) | def api_token(self, app, user): method api_client (line 221) | def api_client(self, app, api_token): method test_search_with_valid_query (line 228) | def test_search_with_valid_query(self, api_client, project): method test_search_with_short_query (line 241) | def test_search_with_short_query(self, api_client): method test_search_with_empty_query (line 252) | def test_search_with_empty_query(self, api_client): method test_v1_search_partial_when_projects_domain_db_error (line 261) | def test_v1_search_partial_when_projects_domain_db_error(self, api_cli... method test_search_requires_authentication (line 272) | def test_search_requires_authentication(self, app): method test_search_requires_read_projects_scope (line 281) | def test_search_requires_read_projects_scope(self, app, user): method test_search_with_limit (line 302) | def test_search_with_limit(self, api_client, project): method test_search_with_types_filter (line 311) | def test_search_with_types_filter(self, api_client, project): method test_search_projects (line 321) | def test_search_projects(self, api_client, project): method test_search_time_entries_respects_user_permissions (line 331) | def test_search_time_entries_respects_user_permissions(self, app, user... method test_search_clients (line 364) | def test_search_clients(self, api_client, test_client): method test_search_tasks (line 374) | def test_search_tasks(self, api_client, task): method test_v1_search_scope_restricted_excludes_other_client_entities (line 384) | def test_v1_search_scope_restricted_excludes_other_client_entities( FILE: tests/test_routes/test_api_smart_notifications.py function test_notifications_requires_login (line 11) | def test_notifications_requires_login(client): function test_notifications_dismiss_requires_login (line 17) | def test_notifications_dismiss_requires_login(client): function test_notifications_get_json (line 23) | def test_notifications_get_json(authenticated_client, user, app): function test_notifications_dismiss_invalid_kind (line 37) | def test_notifications_dismiss_invalid_kind(authenticated_client, app, u... FILE: tests/test_routes/test_api_v1_calendar_templates_refactored.py class TestAPICalendarTemplatesRefactored (line 13) | class TestAPICalendarTemplatesRefactored: method api_token (line 17) | def api_token(self, app, user): method client_with_token (line 31) | def client_with_token(self, app, api_token): method test_list_calendar_events_uses_eager_loading (line 38) | def test_list_calendar_events_uses_eager_loading(self, app, client_wit... method test_get_calendar_event_uses_eager_loading (line 58) | def test_get_calendar_event_uses_eager_loading(self, app, client_with_... method test_list_time_entry_templates_uses_eager_loading (line 78) | def test_list_time_entry_templates_uses_eager_loading(self, app, clien... method test_get_time_entry_template_uses_eager_loading (line 87) | def test_get_time_entry_template_uses_eager_loading(self, app, client_... FILE: tests/test_routes/test_api_v1_expenses_complete.py class TestAPIExpensesComplete (line 14) | class TestAPIExpensesComplete: method api_token (line 18) | def api_token(self, app, user): method client_with_token (line 30) | def client_with_token(self, app, api_token): method test_list_expenses_with_filters (line 37) | def test_list_expenses_with_filters(self, app, client_with_token, user... method test_get_expense_uses_eager_loading (line 46) | def test_get_expense_uses_eager_loading(self, app, client_with_token, ... method test_create_expense_all_fields (line 54) | def test_create_expense_all_fields(self, app, client_with_token, proje... method test_update_expense_uses_service_layer (line 83) | def test_update_expense_uses_service_layer(self, app, client_with_toke... method test_delete_expense_uses_service_layer (line 96) | def test_delete_expense_uses_service_layer(self, app, client_with_toke... method test_expense_permissions (line 110) | def test_expense_permissions(self, app, user, project): FILE: tests/test_routes/test_api_v1_inventory_reports.py function api_token (line 20) | def api_token(db_session, test_user): function warehouse (line 34) | def warehouse(db_session, test_user): function stock_item_with_cost (line 43) | def stock_item_with_cost(db_session, test_user): function _auth_headers (line 60) | def _auth_headers(token): class TestInventoryScopes (line 64) | class TestInventoryScopes: method test_read_inventory_only_can_access_inventory (line 67) | def test_read_inventory_only_can_access_inventory(self, client, db_ses... method test_read_inventory_only_cannot_access_projects (line 77) | def test_read_inventory_only_cannot_access_projects(self, client, db_s... method test_read_projects_still_grants_inventory (line 87) | def test_read_projects_still_grants_inventory(self, client, api_token): class TestValuationReportAPI (line 93) | class TestValuationReportAPI: method test_valuation_report_empty (line 96) | def test_valuation_report_empty(self, client, api_token): method test_valuation_report_with_stock (line 107) | def test_valuation_report_with_stock( method test_valuation_report_filter_warehouse (line 132) | def test_valuation_report_filter_warehouse( method test_valuation_unauthorized (line 155) | def test_valuation_unauthorized(self, client): method test_valuation_invalid_warehouse_id (line 160) | def test_valuation_invalid_warehouse_id(self, client, api_token): class TestMovementHistoryReportAPI (line 173) | class TestMovementHistoryReportAPI: method test_movement_history_empty (line 176) | def test_movement_history_empty(self, client, api_token): method test_movement_history_with_data (line 188) | def test_movement_history_with_data( method test_movement_history_paginated (line 218) | def test_movement_history_paginated(self, client, api_token): method test_movement_history_unauthorized (line 231) | def test_movement_history_unauthorized(self, client): method test_movement_history_invalid_pagination (line 236) | def test_movement_history_invalid_pagination(self, client, api_token): class TestTurnoverReportAPI (line 249) | class TestTurnoverReportAPI: method test_turnover_report_structure (line 252) | def test_turnover_report_structure(self, client, api_token): method test_turnover_report_with_dates (line 262) | def test_turnover_report_with_dates(self, client, api_token): method test_turnover_unauthorized (line 273) | def test_turnover_unauthorized(self, client): method test_turnover_invalid_dates (line 278) | def test_turnover_invalid_dates(self, client, api_token): class TestLowStockReportAPI (line 292) | class TestLowStockReportAPI: method test_low_stock_report_empty (line 295) | def test_low_stock_report_empty(self, client, api_token): method test_low_stock_report_with_reorder (line 303) | def test_low_stock_report_with_reorder( method test_low_stock_filter_warehouse (line 331) | def test_low_stock_filter_warehouse( method test_low_stock_unauthorized (line 355) | def test_low_stock_unauthorized(self, client): method test_low_stock_invalid_warehouse_id (line 360) | def test_low_stock_invalid_warehouse_id(self, client, api_token): FILE: tests/test_routes/test_api_v1_inventory_transfers.py function api_token (line 22) | def api_token(db_session, test_user): function token_read_only (line 36) | def token_read_only(db_session, test_user): function warehouse_from (line 50) | def warehouse_from(db_session, test_user): function warehouse_to (line 59) | def warehouse_to(db_session, test_user): function stock_item_trackable (line 68) | def stock_item_trackable(db_session, test_user): function _auth_headers (line 83) | def _auth_headers(token): class TestListTransfersAPI (line 87) | class TestListTransfersAPI: method test_list_transfers_empty (line 90) | def test_list_transfers_empty(self, client, api_token): method test_list_transfers_after_create (line 100) | def test_list_transfers_after_create( method test_list_transfers_unauthorized (line 143) | def test_list_transfers_unauthorized(self, client): class TestCreateTransferAPI (line 149) | class TestCreateTransferAPI: method test_create_transfer_success (line 152) | def test_create_transfer_success( method test_create_transfer_missing_fields (line 206) | def test_create_transfer_missing_fields(self, client, api_token): method test_create_transfer_invalid_json_returns_400 (line 217) | def test_create_transfer_invalid_json_returns_400(self, client, api_to... method test_create_transfer_invalid_id_types (line 226) | def test_create_transfer_invalid_id_types( method test_create_transfer_same_warehouse (line 255) | def test_create_transfer_same_warehouse( method test_create_transfer_insufficient_stock (line 282) | def test_create_transfer_insufficient_stock( method test_create_transfer_forbidden_without_write_scope (line 299) | def test_create_transfer_forbidden_without_write_scope( method test_create_transfer_unauthorized (line 325) | def test_create_transfer_unauthorized(self, client, stock_item_trackab... class TestGetTransferAPI (line 339) | class TestGetTransferAPI: method test_get_transfer_success (line 342) | def test_get_transfer_success( method test_get_transfer_not_found (line 380) | def test_get_transfer_not_found(self, client, api_token): method test_get_transfer_non_integer_reference_id_returns_404 (line 385) | def test_get_transfer_non_integer_reference_id_returns_404(self, clien... FILE: tests/test_routes/test_api_v1_invoices_tasks_expenses_refactored.py class TestAPIInvoicesRefactored (line 14) | class TestAPIInvoicesRefactored: method api_token (line 18) | def api_token(self, app, user): method client_with_token (line 30) | def client_with_token(self, app, api_token): method test_list_invoices_uses_service_layer (line 37) | def test_list_invoices_uses_service_layer(self, app, client_with_token... method test_get_invoice_uses_eager_loading (line 46) | def test_get_invoice_uses_eager_loading(self, app, client_with_token, ... method test_create_invoice_uses_service_layer (line 55) | def test_create_invoice_uses_service_layer(self, app, client_with_toke... class TestAPITasksRefactored (line 75) | class TestAPITasksRefactored: method api_token (line 79) | def api_token(self, app, user): method client_with_token (line 91) | def client_with_token(self, app, api_token): method test_list_tasks_uses_service_layer (line 98) | def test_list_tasks_uses_service_layer(self, app, client_with_token, t... method test_get_task_uses_eager_loading (line 107) | def test_get_task_uses_eager_loading(self, app, client_with_token, task): method test_create_task_uses_service_layer (line 116) | def test_create_task_uses_service_layer(self, app, client_with_token, ... class TestAPIExpensesRefactored (line 130) | class TestAPIExpensesRefactored: method api_token (line 134) | def api_token(self, app, user): method client_with_token (line 146) | def client_with_token(self, app, api_token): method test_list_expenses_uses_service_layer (line 153) | def test_list_expenses_uses_service_layer(self, app, client_with_token... method test_get_expense_uses_eager_loading (line 162) | def test_get_expense_uses_eager_loading(self, app, client_with_token, ... method test_create_expense_uses_service_layer (line 171) | def test_create_expense_uses_service_layer(self, app, client_with_toke... FILE: tests/test_routes/test_api_v1_mileage_refactored.py class TestAPIMileageRefactored (line 14) | class TestAPIMileageRefactored: method api_token (line 18) | def api_token(self, app, user): method client_with_token (line 30) | def client_with_token(self, app, api_token): method test_list_mileage_uses_eager_loading (line 37) | def test_list_mileage_uses_eager_loading(self, app, client_with_token,... method test_get_mileage_uses_eager_loading (line 46) | def test_get_mileage_uses_eager_loading(self, app, client_with_token, ... method test_create_mileage (line 55) | def test_create_mileage(self, app, client_with_token, user, project): method test_update_mileage (line 77) | def test_update_mileage(self, app, client_with_token, mileage): method test_delete_mileage (line 90) | def test_delete_mileage(self, app, client_with_token, mileage): method test_list_mileage_with_filters (line 104) | def test_list_mileage_with_filters(self, app, client_with_token, user,... FILE: tests/test_routes/test_api_v1_payments_refactored.py class TestAPIPaymentsRefactored (line 14) | class TestAPIPaymentsRefactored: method api_token (line 18) | def api_token(self, app, user): method client_with_token (line 30) | def client_with_token(self, app, api_token): method test_list_payments_uses_eager_loading (line 37) | def test_list_payments_uses_eager_loading(self, app, client_with_token... method test_get_payment_uses_eager_loading (line 46) | def test_get_payment_uses_eager_loading(self, app, client_with_token, ... method test_create_payment_uses_service_layer (line 55) | def test_create_payment_uses_service_layer(self, app, client_with_toke... method test_update_payment_uses_service_layer (line 75) | def test_update_payment_uses_service_layer(self, app, client_with_toke... method test_delete_payment_uses_service_layer (line 88) | def test_delete_payment_uses_service_layer(self, app, client_with_toke... FILE: tests/test_routes/test_api_v1_projects_refactored.py class TestAPIProjectsRefactored (line 12) | class TestAPIProjectsRefactored: method api_token (line 16) | def api_token(self, app, user): method client_with_token (line 28) | def client_with_token(self, app, client, api_token): method test_list_projects_uses_service_layer (line 35) | def test_list_projects_uses_service_layer(self, app, client_with_token... method test_get_project_uses_eager_loading (line 45) | def test_get_project_uses_eager_loading(self, app, client_with_token, ... method test_create_project_uses_service_layer (line 54) | def test_create_project_uses_service_layer(self, app, client_with_toke... method test_update_project_uses_service_layer (line 73) | def test_update_project_uses_service_layer(self, app, client_with_toke... method test_delete_project_uses_service_layer (line 92) | def test_delete_project_uses_service_layer(self, app, client_with_toke... method test_list_projects_with_filters (line 106) | def test_list_projects_with_filters(self, app, client_with_token, proj... FILE: tests/test_routes/test_api_v1_quotes_refactored.py class TestAPIQuotesRefactored (line 12) | class TestAPIQuotesRefactored: method api_token (line 16) | def api_token(self, app, user): method client_with_token (line 28) | def client_with_token(self, app, api_token): method test_list_quotes_uses_service_layer (line 35) | def test_list_quotes_uses_service_layer(self, app, client_with_token, ... method test_get_quote_uses_service_layer (line 44) | def test_get_quote_uses_service_layer(self, app, client_with_token, qu... method test_create_quote_uses_service_layer (line 53) | def test_create_quote_uses_service_layer(self, app, client_with_token,... method test_update_quote_uses_service_layer (line 72) | def test_update_quote_uses_service_layer(self, app, client_with_token,... FILE: tests/test_routes/test_api_v1_recurring_invoices_credit_notes.py class TestAPIRecurringInvoicesCreditNotes (line 13) | class TestAPIRecurringInvoicesCreditNotes: method api_token (line 17) | def api_token(self, app, user): method client_with_token (line 31) | def client_with_token(self, app, api_token): method test_list_recurring_invoices_uses_eager_loading (line 38) | def test_list_recurring_invoices_uses_eager_loading(self, app, client_... method test_get_recurring_invoice_uses_eager_loading (line 47) | def test_get_recurring_invoice_uses_eager_loading(self, app, client_wi... method test_list_credit_notes_uses_eager_loading (line 56) | def test_list_credit_notes_uses_eager_loading(self, app, client_with_t... method test_get_credit_note_uses_eager_loading (line 73) | def test_get_credit_note_uses_eager_loading(self, app, client_with_tok... FILE: tests/test_routes/test_api_v1_reports_refactored.py class TestAPIReportsRefactored (line 13) | class TestAPIReportsRefactored: method api_token (line 17) | def api_token(self, app, user): method client_with_token (line 27) | def client_with_token(self, app, api_token): method test_report_summary_uses_eager_loading (line 34) | def test_report_summary_uses_eager_loading(self, app, client_with_toke... method test_report_summary_with_filters (line 48) | def test_report_summary_with_filters(self, app, client_with_token, use... FILE: tests/test_routes/test_api_v1_time_entries_complete.py class TestAPITimeEntriesComplete (line 13) | class TestAPITimeEntriesComplete: method api_token (line 17) | def api_token(self, app, user): method client_with_token (line 29) | def client_with_token(self, app, api_token): method test_update_time_entry_uses_service_layer (line 36) | def test_update_time_entry_uses_service_layer(self, app, client_with_t... method test_delete_time_entry_uses_service_layer (line 49) | def test_delete_time_entry_uses_service_layer(self, app, client_with_t... method test_start_timer_uses_service_layer (line 63) | def test_start_timer_uses_service_layer(self, app, client_with_token, ... method test_stop_timer_uses_service_layer (line 76) | def test_stop_timer_uses_service_layer(self, app, client_with_token, u... FILE: tests/test_routes/test_api_v1_time_entries_refactored.py class TestAPITimeEntriesRefactored (line 13) | class TestAPITimeEntriesRefactored: method api_token (line 17) | def api_token(self, app, user): method client_with_token (line 29) | def client_with_token(self, app, api_token): method test_list_time_entries_uses_eager_loading (line 36) | def test_list_time_entries_uses_eager_loading(self, app, client_with_t... method test_get_time_entry_uses_eager_loading (line 50) | def test_get_time_entry_uses_eager_loading(self, app, client_with_toke... method test_create_time_entry_uses_service_layer (line 59) | def test_create_time_entry_uses_service_layer(self, app, client_with_t... method test_list_time_entries_with_filters (line 87) | def test_list_time_entries_with_filters(self, app, client_with_token, ... method test_list_time_entries_pagination (line 100) | def test_list_time_entries_pagination(self, app, client_with_token, us... method test_list_time_entries_same_day_date_filter_includes_midday_entries (line 126) | def test_list_time_entries_same_day_date_filter_includes_midday_entries( FILE: tests/test_routes/test_api_version_check.py function version_payload (line 12) | def version_payload(): class TestApiVersionCheckAuth (line 23) | class TestApiVersionCheckAuth: method test_unauthenticated_returns_401 (line 24) | def test_unauthenticated_returns_401(self, client): method test_regular_user_forbidden (line 28) | def test_regular_user_forbidden(self, client, user): method test_admin_ok (line 37) | def test_admin_ok(self, client, admin_user, version_payload): class TestApiVersionDismiss (line 52) | class TestApiVersionDismiss: method test_dismiss_persists (line 53) | def test_dismiss_persists(self, app, client, admin_user): method test_dismiss_invalid_version_400 (line 69) | def test_dismiss_invalid_version_400(self, client, admin_user): FILE: tests/test_routes/test_auth.py function test_login_page_returns_200 (line 10) | def test_login_page_returns_200(client): function test_login_success_redirects (line 18) | def test_login_success_redirects(client, user): function test_login_wrong_password_returns_200_with_message (line 33) | def test_login_wrong_password_returns_200_with_message(client, user): FILE: tests/test_routes/test_inventory_routes.py function test_user (line 14) | def test_user(db_session): function test_warehouse (line 24) | def test_warehouse(db_session, test_user): function test_stock_item (line 33) | def test_stock_item(db_session, test_user): class TestStockItemsRoutes (line 48) | class TestStockItemsRoutes: method test_list_stock_items (line 51) | def test_list_stock_items(self, client, test_user, test_stock_item): method test_create_stock_item (line 61) | def test_create_stock_item(self, client, test_user): method test_view_stock_item (line 85) | def test_view_stock_item(self, client, test_user, test_stock_item): method test_edit_stock_item (line 95) | def test_edit_stock_item(self, client, test_user, test_stock_item): class TestWarehousesRoutes (line 118) | class TestWarehousesRoutes: method test_list_warehouses (line 121) | def test_list_warehouses(self, client, test_user, test_warehouse): method test_create_warehouse (line 131) | def test_create_warehouse(self, client, test_user): method test_view_warehouse (line 147) | def test_view_warehouse(self, client, test_user, test_warehouse): class TestStockLevelsRoutes (line 158) | class TestStockLevelsRoutes: method test_view_stock_levels (line 161) | def test_view_stock_levels(self, client, test_user, test_stock_item, t... class TestStockMovementsRoutes (line 178) | class TestStockMovementsRoutes: method test_list_movements (line 181) | def test_list_movements(self, client, test_user): method test_create_movement (line 190) | def test_create_movement(self, client, test_user, test_stock_item, tes... method test_create_return_with_devaluation (line 213) | def test_create_return_with_devaluation(self, client, test_user, test_... method test_create_waste_with_devaluation (line 251) | def test_create_waste_with_devaluation(self, client, test_user, test_s... FILE: tests/test_routes/test_main_dashboard_cached.py class TestDashboardCaching (line 13) | class TestDashboardCaching: method test_dashboard_uses_cache (line 16) | def test_dashboard_uses_cache(self, authenticated_client, app, user, p... method test_dashboard_cache_ttl (line 35) | def test_dashboard_cache_ttl(self, authenticated_client, app, user): method test_dashboard_cache_invalidation (line 50) | def test_dashboard_cache_invalidation(self, authenticated_client, app,... FILE: tests/test_routes/test_purchase_order_routes.py function test_user (line 16) | def test_user(db_session): function test_supplier (line 26) | def test_supplier(db_session, test_user): function test_warehouse (line 35) | def test_warehouse(db_session, test_user): function test_stock_item (line 44) | def test_stock_item(db_session, test_user): function test_purchase_order (line 53) | def test_purchase_order(db_session, test_supplier, test_user): class TestPurchaseOrderRoutes (line 67) | class TestPurchaseOrderRoutes: method test_list_purchase_orders (line 70) | def test_list_purchase_orders(self, client, test_user, test_purchase_o... method test_create_purchase_order (line 80) | def test_create_purchase_order(self, client, test_user, test_supplier,... method test_view_purchase_order (line 106) | def test_view_purchase_order(self, client, test_user, test_purchase_or... method test_view_purchase_order_with_line_items (line 115) | def test_view_purchase_order_with_line_items(self, client, test_user, ... method test_edit_purchase_order (line 137) | def test_edit_purchase_order(self, client, test_user, test_purchase_or... method test_receive_purchase_order (line 157) | def test_receive_purchase_order(self, client, test_user, test_purchase... method test_cancel_purchase_order (line 186) | def test_cancel_purchase_order(self, client, test_user, test_purchase_... method test_delete_purchase_order (line 201) | def test_delete_purchase_order(self, client, test_user, test_purchase_... method test_create_purchase_order_safe_commit_failure (line 216) | def test_create_purchase_order_safe_commit_failure(self, client, test_... FILE: tests/test_routes/test_quotes_web.py function test_create_quote_redirect_then_view_returns_200 (line 9) | def test_create_quote_redirect_then_view_returns_200(admin_authenticated... function test_edit_quote_by_user_with_edit_quotes_redirect_then_view_returns_200 (line 33) | def test_edit_quote_by_user_with_edit_quotes_redirect_then_view_returns_... FILE: tests/test_routes/test_reports_scope.py function test_project_report_lists_only_allowed_projects (line 12) | def test_project_report_lists_only_allowed_projects( FILE: tests/test_routes/test_supplier_routes.py function test_user (line 13) | def test_user(db_session): function test_supplier (line 23) | def test_supplier(db_session, test_user): class TestSupplierRoutes (line 31) | class TestSupplierRoutes: method test_list_suppliers (line 34) | def test_list_suppliers(self, client, test_user, test_supplier): method test_create_supplier (line 44) | def test_create_supplier(self, client, test_user): method test_create_supplier_duplicate_code (line 66) | def test_create_supplier_duplicate_code(self, client, test_user, test_... method test_view_supplier (line 85) | def test_view_supplier(self, client, test_user, test_supplier): method test_edit_supplier (line 95) | def test_edit_supplier(self, client, test_user, test_supplier): method test_delete_supplier (line 116) | def test_delete_supplier(self, client, test_user, test_supplier): FILE: tests/test_routes/test_timer_scope.py function test_timer_start_denied_for_disallowed_project (line 12) | def test_timer_start_denied_for_disallowed_project( function test_timer_start_allowed_for_assigned_project (line 52) | def test_timer_start_allowed_for_assigned_project( FILE: tests/test_security.py function test_unauthenticated_cannot_access_dashboard (line 19) | def test_unauthenticated_cannot_access_dashboard(client): function test_unauthenticated_cannot_access_api (line 27) | def test_unauthenticated_cannot_access_api(client): function test_session_cookie_httponly (line 34) | def test_session_cookie_httponly(client, user): function test_regular_user_cannot_access_admin_pages (line 56) | def test_regular_user_cannot_access_admin_pages(authenticated_client): function test_admin_can_access_admin_pages (line 64) | def test_admin_can_access_admin_pages(admin_authenticated_client): function test_user_cannot_access_other_users_data (line 72) | def test_user_cannot_access_other_users_data(app, user, multiple_users, ... function test_user_cannot_edit_other_users_time_entries (line 85) | def test_user_cannot_edit_other_users_time_entries(app, authenticated_cl... function test_csrf_token_required_for_forms (line 127) | def test_csrf_token_required_for_forms(client, user): function test_sql_injection_in_search (line 148) | def test_sql_injection_in_search(authenticated_client): function test_sql_injection_in_filter (line 160) | def test_sql_injection_in_filter(authenticated_client): function test_xss_in_project_name (line 176) | def test_xss_in_project_name(app, authenticated_client, test_client): function test_xss_in_notes (line 193) | def test_xss_in_notes(app, authenticated_client, project): function test_path_traversal_in_file_download (line 213) | def test_path_traversal_in_file_download(authenticated_client): function test_api_rate_limiting (line 236) | def test_api_rate_limiting(client): function test_password_not_exposed_in_api (line 256) | def test_password_not_exposed_in_api(app, user): function test_logout_invalidates_session (line 274) | def test_logout_invalidates_session(client, user): function test_session_fixation_protection (line 294) | def test_session_fixation_protection(client, user): function test_security_headers_present (line 318) | def test_security_headers_present(client): function test_oversized_input_rejection (line 344) | def test_oversized_input_rejection(authenticated_client, project): function test_invalid_email_format (line 357) | def test_invalid_email_format(app): function test_cannot_create_negative_time_entries (line 385) | def test_cannot_create_negative_time_entries(app, authenticated_client, ... function test_cannot_create_invoice_with_negative_amount (line 410) | def test_cannot_create_invoice_with_negative_amount(app, authenticated_c... FILE: tests/test_service_worker.py function test_service_worker_serves_sw_js (line 1) | def test_service_worker_serves_sw_js(client): function test_manifest_legacy_redirect (line 9) | def test_manifest_legacy_redirect(client): function test_offline_page_public (line 15) | def test_offline_page_public(client): FILE: tests/test_services/test_api_token_service.py function test_create_token_success (line 17) | def test_create_token_success(app, test_user): function test_create_token_invalid_user (line 37) | def test_create_token_invalid_user(app): function test_validate_scopes_valid (line 48) | def test_validate_scopes_valid(app): function test_validate_scopes_invalid (line 58) | def test_validate_scopes_invalid(app): function test_rotate_token (line 68) | def test_rotate_token(app, test_user): FILE: tests/test_services/test_comment_service.py class TestCommentService (line 11) | class TestCommentService: method test_create_comment_success (line 14) | def test_create_comment_success(self, db_session, sample_project, samp... method test_create_comment_empty_content (line 27) | def test_create_comment_empty_content(self, db_session, sample_project... method test_create_comment_no_target (line 36) | def test_create_comment_no_target(self, db_session, sample_user): method test_create_comment_invalid_project (line 45) | def test_create_comment_invalid_project(self, db_session, sample_user): method test_get_project_comments (line 54) | def test_get_project_comments(self, db_session, sample_project, sample... method test_delete_comment_success (line 68) | def test_delete_comment_success(self, db_session, sample_project, samp... FILE: tests/test_services/test_export_service.py class TestExportService (line 13) | class TestExportService: method test_export_time_entries_csv (line 16) | def test_export_time_entries_csv(self, db_session, sample_project, sam... method test_export_projects_csv (line 36) | def test_export_projects_csv(self, db_session, sample_project): method test_export_invoices_csv (line 56) | def test_export_invoices_csv(self, db_session, sample_invoice): FILE: tests/test_services/test_invoice_service.py function test_list_invoices_with_eager_loading (line 15) | def test_list_invoices_with_eager_loading(app, test_project, test_user): function test_list_invoices_filtering (line 46) | def test_list_invoices_filtering(app, test_project, test_user): function test_get_invoice_with_details (line 85) | def test_get_invoice_with_details(app, test_project, test_user): function test_create_invoice_from_time_entries_with_tax (line 114) | def test_create_invoice_from_time_entries_with_tax(app, test_project, te... function test_create_invoice_from_time_entries_no_billable (line 157) | def test_create_invoice_from_time_entries_no_billable(app, test_project,... function test_create_invoice_from_time_entries_invalid_project (line 185) | def test_create_invoice_from_time_entries_invalid_project(app, test_user): function test_mark_invoice_as_sent_updates_time_entries (line 200) | def test_mark_invoice_as_sent_updates_time_entries(app, test_project, te... function test_update_invoice_status (line 241) | def test_update_invoice_status(app, test_project, test_user): function test_create_client_unbilled_invoice_two_projects (line 274) | def test_create_client_unbilled_invoice_two_projects(app, test_user, tes... FILE: tests/test_services/test_notification_service.py function _commit_user_prefs (line 22) | def _commit_user_prefs(user_id: int, **values): function _insert_time_entry (line 27) | def _insert_time_entry(**kwargs): function test_parse_hhmm (line 51) | def test_parse_hhmm(): function test_build_disabled_returns_empty (line 59) | def test_build_disabled_returns_empty(app, user): function test_long_timer_notification (line 69) | def test_long_timer_notification(app, user, project): function test_no_tracking_in_slot (line 96) | def test_no_tracking_in_slot(app, user, project): function test_no_tracking_suppressed_when_timer_active (line 118) | def test_no_tracking_suppressed_when_timer_active(app, user, project): function test_dismissal_hides_kind (line 147) | def test_dismissal_hides_kind(app, user, project): function test_max_per_day_truncates (line 182) | def test_max_per_day_truncates(app, user, project): function test_get_today_summary_for_user (line 213) | def test_get_today_summary_for_user(app, user, project): FILE: tests/test_services/test_payment_service.py class TestPaymentService (line 13) | class TestPaymentService: method test_create_payment_success (line 16) | def test_create_payment_success(self, db_session, sample_invoice, samp... method test_create_payment_invalid_invoice (line 34) | def test_create_payment_invalid_invoice(self, db_session, sample_user): method test_create_payment_invalid_amount (line 45) | def test_create_payment_invalid_amount(self, db_session, sample_invoic... method test_get_invoice_payments (line 56) | def test_get_invoice_payments(self, db_session, sample_invoice, sample... method test_get_total_paid (line 74) | def test_get_total_paid(self, db_session, sample_invoice, sample_user): FILE: tests/test_services/test_payment_service_complete.py class TestPaymentServiceComplete (line 12) | class TestPaymentServiceComplete: method test_update_payment_success (line 15) | def test_update_payment_success(self, app, invoice, payment): method test_update_payment_not_found (line 27) | def test_update_payment_not_found(self, app): method test_delete_payment_success (line 36) | def test_delete_payment_success(self, app, invoice, payment): method test_delete_payment_updates_invoice_status (line 44) | def test_delete_payment_updates_invoice_status(self, app, invoice, pay... FILE: tests/test_services/test_project_service.py function test_create_project_success (line 13) | def test_create_project_success(app, test_client_model, test_user): function test_create_project_invalid_client (line 32) | def test_create_project_invalid_client(app, test_user): function test_list_projects_with_eager_loading (line 45) | def test_list_projects_with_eager_loading(app, test_client_model, test_u... function test_get_project_with_details (line 68) | def test_get_project_with_details(app, test_client_model, test_user): function test_list_projects_filtering (line 89) | def test_list_projects_filtering(app, test_client_model, test_user): FILE: tests/test_services/test_recurring_invoice_service.py class TestRecurringInvoiceService (line 13) | class TestRecurringInvoiceService: method test_generate_invoice_returns_none_when_should_not_generate (line 16) | def test_generate_invoice_returns_none_when_should_not_generate(self): FILE: tests/test_services/test_reporting_service.py function test_get_reports_summary (line 13) | def test_get_reports_summary(app, test_user, test_project): function test_get_time_summary (line 40) | def test_get_time_summary(app, test_user, test_project): function test_get_project_summary (line 65) | def test_get_project_summary(app, test_project, test_user): FILE: tests/test_services/test_stats_service.py function _add_entry (line 14) | def _add_entry(user_id, project_id, start, end, duration_seconds): function test_value_dashboard_basic_math (line 31) | def test_value_dashboard_basic_math(app, user, project): function test_value_dashboard_active_days_two_dates (line 44) | def test_value_dashboard_active_days_two_dates(app, user, project): function test_value_dashboard_week_and_month_windows (line 56) | def test_value_dashboard_week_and_month_windows(app, user, project): function test_value_dashboard_last_7_days_shape_and_sum (line 99) | def test_value_dashboard_last_7_days_shape_and_sum(app, user, project): function test_value_dashboard_most_productive_day (line 126) | def test_value_dashboard_most_productive_day(app, user, project): function test_value_dashboard_estimated_value (line 149) | def test_value_dashboard_estimated_value(app, user, project): function test_value_dashboard_excludes_active_timer (line 167) | def test_value_dashboard_excludes_active_timer(app, user, project): function test_value_dashboard_no_entries (line 194) | def test_value_dashboard_no_entries(app, user): function test_value_dashboard_cache_read_through (line 206) | def test_value_dashboard_cache_read_through(app, user, project, monkeypa... FILE: tests/test_services/test_task_service.py function test_create_task_success (line 13) | def test_create_task_success(app, test_project, test_user): function test_create_task_invalid_project (line 32) | def test_create_task_invalid_project(app, test_user): function test_list_tasks_with_eager_loading (line 43) | def test_list_tasks_with_eager_loading(app, test_project, test_user): function test_get_task_with_details (line 65) | def test_get_task_with_details(app, test_project, test_user): FILE: tests/test_services/test_time_entry_bulk_service.py function test_bulk_all_active_entries_returns_400 (line 12) | def test_bulk_all_active_entries_returns_400(mock_db, mock_safe_commit): FILE: tests/test_services/test_time_tracking_service.py function mock_time_entry_repo (line 15) | def mock_time_entry_repo(): function mock_project_repo (line 21) | def mock_project_repo(): function service (line 27) | def service(mock_time_entry_repo, mock_project_repo): function sample_project (line 36) | def sample_project(): class TestStartTimer (line 45) | class TestStartTimer: method test_start_timer_success (line 48) | def test_start_timer_success(self, service, mock_time_entry_repo, mock... method test_start_timer_already_running (line 68) | def test_start_timer_already_running(self, service, mock_time_entry_re... method test_start_timer_invalid_project (line 82) | def test_start_timer_invalid_project(self, service, mock_time_entry_re... method test_start_timer_archived_project (line 95) | def test_start_timer_archived_project(self, service, mock_time_entry_r... class TestStopTimer (line 112) | class TestStopTimer: method test_stop_timer_success (line 115) | def test_stop_timer_success(self, service, mock_time_entry_repo): method test_stop_timer_no_active_timer (line 135) | def test_stop_timer_no_active_timer(self, service, mock_time_entry_repo): class TestCreateManualEntry (line 148) | class TestCreateManualEntry: method test_create_manual_entry_success (line 151) | def test_create_manual_entry_success(self, service, mock_time_entry_re... method test_create_manual_entry_invalid_time_range (line 173) | def test_create_manual_entry_invalid_time_range(self, service, mock_pr... FILE: tests/test_services/test_time_tracking_service_complete.py class TestTimeTrackingServiceComplete (line 11) | class TestTimeTrackingServiceComplete: method test_update_entry_success (line 14) | def test_update_entry_success(self, app, user, project, time_entry): method test_update_entry_recalculates_duration_when_start_end_edited (line 26) | def test_update_entry_recalculates_duration_when_start_end_edited(self... method test_update_entry_not_found (line 51) | def test_update_entry_not_found(self, app, user): method test_update_entry_access_denied (line 60) | def test_update_entry_access_denied(self, app, user, other_user, time_... method test_delete_entry_success (line 69) | def test_delete_entry_success(self, app, user, time_entry): method test_delete_entry_active_timer (line 83) | def test_delete_entry_active_timer(self, app, user, time_entry): FILE: tests/test_services/test_version_service.py class TestParseReleaseObject (line 11) | class TestParseReleaseObject: method test_parses_tag_and_fields (line 12) | def test_parses_tag_and_fields(self, app): method test_invalid_tag_returns_none (line 28) | def test_invalid_tag_returns_none(self, app): class TestVersionServiceBuildResponse (line 34) | class TestVersionServiceBuildResponse: method test_upgrade_when_newer_remote (line 35) | def test_upgrade_when_newer_remote(self, app, admin_user): method test_respects_dismissed_version (line 54) | def test_respects_dismissed_version(self, app, admin_user): method test_no_update_when_current_not_semver (line 71) | def test_no_update_when_current_not_semver(self, app, admin_user): class TestVersionServiceCache (line 89) | class TestVersionServiceCache: method test_uses_hot_cache_without_http_second_call (line 90) | def test_uses_hot_cache_without_http_second_call(self, app): function test_github_fetch_uses_stale_on_failure (line 111) | def test_github_fetch_uses_stale_on_failure(app): function test_version_check_bearer_admin (line 137) | def test_version_check_bearer_admin(app, client, admin_user): FILE: tests/test_silent_exception_fixes.py function test_safe_log_does_not_raise (line 17) | def test_safe_log_does_not_raise(): function test_safe_file_remove_nonexistent_returns_true (line 28) | def test_safe_file_remove_nonexistent_returns_true(): function test_safe_file_remove_with_logger (line 36) | def test_safe_file_remove_with_logger(): function test_api_v1_per_diem_patch_invalid_full_days_returns_400 (line 54) | def test_api_v1_per_diem_patch_invalid_full_days_returns_400(app, client): function test_team_chat_api_message_invalid_attachment_size_returns_400 (line 98) | def test_team_chat_api_message_invalid_attachment_size_returns_400(app, ... function test_expenses_bulk_update_invalid_payload_returns_error (line 154) | def test_expenses_bulk_update_invalid_payload_returns_error(app, client): function test_backup_get_alembic_revision_returns_none_on_error (line 192) | def test_backup_get_alembic_revision_returns_none_on_error(app): FILE: tests/test_single_active_timer_setting.py function _api_headers (line 15) | def _api_headers(plain_token: str) -> dict: function _second_project (line 19) | def _second_project(client_id: int) -> Project: function test_single_timer_enforced_when_setting_on (line 33) | def test_single_timer_enforced_when_setting_on(app, client, user, projec... function test_multiple_timers_allowed_when_setting_off (line 65) | def test_multiple_timers_allowed_when_setting_off(app, client, user, pro... function test_setting_read_from_db_not_env (line 86) | def test_setting_read_from_db_not_env(app, client, user, project, api_to... function test_both_web_and_api_routes_respect_setting (line 118) | def test_both_web_and_api_routes_respect_setting(app, authenticated_clie... FILE: tests/test_support_services.py function test_usage_stats_service_shape (line 7) | def test_usage_stats_service_shape(app, test_user): function test_consume_layout_prompt_sets_consumed (line 16) | def test_consume_layout_prompt_sets_consumed(): function test_support_prompt_suppressed_for_supporter (line 30) | def test_support_prompt_suppressed_for_supporter(): function test_support_prompt_respects_ui_show_donate (line 41) | def test_support_prompt_respects_ui_show_donate(): function test_pick_dashboard_skips_when_after_report_pending (line 52) | def test_pick_dashboard_skips_when_after_report_pending(): FILE: tests/test_system_ui_flags.py class TestSystemUiFlags (line 8) | class TestSystemUiFlags: method test_calendar_hidden_when_system_disabled (line 9) | def test_calendar_hidden_when_system_disabled(self, client, user): FILE: tests/test_task_edit_project.py function test_edit_task_changes_project_and_updates_time_entries (line 11) | def test_edit_task_changes_project_and_updates_time_entries(authenticate... FILE: tests/test_tasks_filters_ui.py function test_task_view_renders_markdown (line 5) | def test_task_view_renders_markdown(app, client, task, authenticated_cli... function test_project_view_renders_markdown (line 23) | def test_project_view_renders_markdown(app, client, project, admin_authe... function test_tasks_filters_collapsible_ui (line 42) | def test_tasks_filters_collapsible_ui(authenticated_client): FILE: tests/test_tasks_templates.py function test_create_task_page_has_tips (line 9) | def test_create_task_page_has_tips(client, app): function test_edit_task_page_has_tips (line 29) | def test_edit_task_page_has_tips(client, app): function test_kanban_board_aria_and_dnd (line 53) | def test_kanban_board_aria_and_dnd(authenticated_client, app): function test_kanban_card_shows_project_code_and_no_status_dropdown (line 80) | def test_kanban_card_shows_project_code_and_no_status_dropdown(authentic... FILE: tests/test_telemetry.py class TestTelemetryFingerprint (line 23) | class TestTelemetryFingerprint: method test_fingerprint_is_consistent (line 26) | def test_fingerprint_is_consistent(self): method test_fingerprint_changes_with_salt (line 33) | def test_fingerprint_changes_with_salt(self): method test_fingerprint_is_sha256_hash (line 47) | def test_fingerprint_is_sha256_hash(self): class TestTelemetryEnabled (line 54) | class TestTelemetryEnabled: method test_telemetry_enabled_values (line 74) | def test_telemetry_enabled_values(self, value, expected): method test_telemetry_disabled_by_default (line 82) | def test_telemetry_disabled_by_default(self): class TestSendTelemetryPing (line 91) | class TestSendTelemetryPing: method test_send_ping_when_enabled (line 95) | def test_send_ping_when_enabled(self, mock_send): method test_no_ping_when_disabled (line 117) | def test_no_ping_when_disabled(self, mock_send): method test_no_ping_when_no_sink_config (line 125) | def test_no_ping_when_no_sink_config(self, mock_send): method test_ping_forwards_extra_data (line 135) | def test_ping_forwards_extra_data(self, mock_send): method test_ping_handles_network_errors_gracefully (line 154) | def test_ping_handles_network_errors_gracefully(self, mock_send): class TestTelemetryEventTypes (line 170) | class TestTelemetryEventTypes: method test_send_install_ping (line 174) | def test_send_install_ping(self, mock_send): method test_send_update_ping (line 180) | def test_send_update_ping(self, mock_send): method test_send_health_ping (line 190) | def test_send_health_ping(self, mock_send): class TestTelemetryMarker (line 196) | class TestTelemetryMarker: method test_should_send_when_no_marker (line 199) | def test_should_send_when_no_marker(self): method test_should_not_send_when_marker_exists (line 206) | def test_should_not_send_when_marker_exists(self): method test_mark_telemetry_sent_creates_file (line 219) | def test_mark_telemetry_sent_creates_file(self): class TestCheckAndSendTelemetry (line 234) | class TestCheckAndSendTelemetry: method test_check_and_send_when_appropriate (line 239) | def test_check_and_send_when_appropriate(self, mock_mark, mock_send): method test_no_send_when_disabled (line 252) | def test_no_send_when_disabled(self, mock_send): method test_no_send_when_already_sent (line 263) | def test_no_send_when_already_sent(self, mock_send): FILE: tests/test_telemetry_consent_and_base.py class TestConsentGate (line 11) | class TestConsentGate: method test_send_analytics_event_no_capture_when_opt_out (line 15) | def test_send_analytics_event_no_capture_when_opt_out(self, mock_send): method test_send_analytics_event_capture_when_opt_in (line 24) | def test_send_analytics_event_capture_when_opt_in(self, mock_send): class TestBaseTelemetry (line 47) | class TestBaseTelemetry: method test_send_base_first_seen_idempotent (line 50) | def test_send_base_first_seen_idempotent(self): method test_send_base_heartbeat_calls_telemetry_with_schema (line 73) | def test_send_base_heartbeat_calls_telemetry_with_schema(self): method test_base_payload_includes_telemetry_fingerprint (line 104) | def test_base_payload_includes_telemetry_fingerprint(self): class TestInstallIdInPayloads (line 121) | class TestInstallIdInPayloads: method test_install_id_stable_across_calls (line 124) | def test_install_id_stable_across_calls(self, tmp_path, monkeypatch): FILE: tests/test_time_entry_duplication.py function time_entry_with_all_fields (line 21) | def time_entry_with_all_fields(app, user, project, task): function time_entry_minimal (line 44) | def time_entry_minimal(app, user, project): function test_duplicate_route_exists (line 70) | def test_duplicate_route_exists(authenticated_client, time_entry_with_al... function test_duplicate_route_requires_authentication (line 79) | def test_duplicate_route_requires_authentication(client, time_entry_with... function test_duplicate_nonexistent_entry_returns_404 (line 89) | def test_duplicate_nonexistent_entry_returns_404(authenticated_client): function test_duplicate_entry_renders_manual_entry_form (line 102) | def test_duplicate_entry_renders_manual_entry_form(authenticated_client,... function test_duplicate_prefills_project (line 116) | def test_duplicate_prefills_project(authenticated_client, time_entry_wit... function test_duplicate_prefills_task (line 129) | def test_duplicate_prefills_task(authenticated_client, time_entry_with_a... function test_duplicate_prefills_notes (line 143) | def test_duplicate_prefills_notes(authenticated_client, time_entry_with_... function test_duplicate_prefills_tags (line 156) | def test_duplicate_prefills_tags(authenticated_client, time_entry_with_a... function test_duplicate_prefills_billable_status (line 169) | def test_duplicate_prefills_billable_status(authenticated_client, time_e... function test_duplicate_minimal_entry (line 183) | def test_duplicate_minimal_entry(authenticated_client, time_entry_minima... function test_duplicate_shows_original_entry_info (line 196) | def test_duplicate_shows_original_entry_info(authenticated_client, time_... function test_duplicate_own_entry_only (line 214) | def test_duplicate_own_entry_only(app, user, project, authenticated_clie... function test_admin_can_duplicate_any_entry (line 242) | def test_admin_can_duplicate_any_entry(admin_authenticated_client, user,... function test_duplicate_button_on_dashboard (line 273) | def test_duplicate_button_on_dashboard(authenticated_client, time_entry_... function test_duplicate_button_on_edit_page (line 294) | def test_duplicate_button_on_edit_page(authenticated_client, time_entry_... function test_time_entry_has_all_duplicatable_fields (line 312) | def test_time_entry_has_all_duplicatable_fields(app, user, project): function test_duplicated_entry_can_be_created (line 342) | def test_duplicated_entry_can_be_created(app, user, project, time_entry_... function test_duplicate_entry_without_task (line 389) | def test_duplicate_entry_without_task(authenticated_client, time_entry_m... function test_duplicate_entry_without_notes (line 402) | def test_duplicate_entry_without_notes(authenticated_client, time_entry_... function test_duplicate_entry_without_tags (line 415) | def test_duplicate_entry_without_tags(authenticated_client, time_entry_m... function test_duplicate_entry_from_inactive_project (line 428) | def test_duplicate_entry_from_inactive_project(app, user, authenticated_... function test_duplicate_with_task_not_overridden_by_template_code (line 462) | def test_duplicate_with_task_not_overridden_by_template_code( FILE: tests/test_time_entry_freeze.py function test_active_timer_duration_without_real_time (line 13) | def test_active_timer_duration_without_real_time(app, time_freezer): FILE: tests/test_time_entry_resume.py function test_resume_timer_properties (line 15) | def test_resume_timer_properties(app, user, project): function test_resume_timer_with_task (line 61) | def test_resume_timer_with_task(app, user, project): function test_resume_timer_without_task (line 106) | def test_resume_timer_without_task(app, user, project): function test_resume_timer_route (line 143) | def test_resume_timer_route(client, user, project): function test_resume_timer_blocks_if_active_timer_exists (line 183) | def test_resume_timer_blocks_if_active_timer_exists(client, user, project): function test_resume_timer_fails_for_archived_project (line 225) | def test_resume_timer_fails_for_archived_project(client, user, project): function test_resume_timer_permission_check (line 263) | def test_resume_timer_permission_check(client, user, project): function test_resume_timer_handles_deleted_task (line 301) | def test_resume_timer_handles_deleted_task(client, user, project): function test_resume_timer_smoke (line 349) | def test_resume_timer_smoke(client, user, project): function test_resume_preserves_billable_status (line 383) | def test_resume_preserves_billable_status(app, user, project): function test_resume_preserves_tags (line 419) | def test_resume_preserves_tags(app, user, project): FILE: tests/test_time_entry_templates.py class TestTimeEntryTemplateModel (line 23) | class TestTimeEntryTemplateModel: method test_create_template_with_all_fields (line 26) | def test_create_template_with_all_fields(self, app, user, project, task): method test_create_template_minimal_fields (line 58) | def test_create_template_minimal_fields(self, app, user): method test_template_default_duration_property (line 75) | def test_template_default_duration_property(self, app, user): method test_template_record_usage (line 94) | def test_template_record_usage(self, app, user): method test_template_increment_usage (line 112) | def test_template_increment_usage(self, app, user): method test_template_to_dict (line 130) | def test_template_to_dict(self, app, user, project, task): method test_template_relationships (line 166) | def test_template_relationships(self, app, user, project, task): method test_template_repr (line 193) | def test_template_repr(self, app, user): class TestTimeEntryTemplateRoutes (line 209) | class TestTimeEntryTemplateRoutes: method test_list_templates_authenticated (line 212) | def test_list_templates_authenticated(self, authenticated_client, user): method test_list_templates_unauthenticated (line 218) | def test_list_templates_unauthenticated(self, client): method test_list_templates_with_usage_data (line 224) | def test_list_templates_with_usage_data(self, authenticated_client, us... method test_create_template_page_get (line 249) | def test_create_template_page_get(self, authenticated_client): method test_create_template_success (line 256) | def test_create_template_success(self, authenticated_client, user, pro... method test_create_template_without_name (line 281) | def test_create_template_without_name(self, authenticated_client): method test_create_template_duplicate_name (line 290) | def test_create_template_duplicate_name(self, authenticated_client, us... method test_edit_template_page_get (line 305) | def test_edit_template_page_get(self, authenticated_client, user): method test_edit_template_success (line 316) | def test_edit_template_success(self, authenticated_client, user): method test_delete_template_success (line 339) | def test_delete_template_success(self, authenticated_client, user): class TestTimeEntryTemplateAPI (line 380) | class TestTimeEntryTemplateAPI: method test_get_templates_api (line 383) | def test_get_templates_api(self, authenticated_client, user): method test_get_single_template_api (line 397) | def test_get_single_template_api(self, authenticated_client, user): method test_use_template_api (line 409) | def test_use_template_api(self, authenticated_client, user): class TestTimeEntryTemplatesSmoke (line 433) | class TestTimeEntryTemplatesSmoke: method test_templates_page_renders (line 436) | def test_templates_page_renders(self, authenticated_client): method test_create_template_page_renders (line 442) | def test_create_template_page_renders(self, authenticated_client): method test_template_crud_workflow (line 448) | def test_template_crud_workflow(self, authenticated_client, user, proj... class TestTimeEntryTemplateIntegration (line 485) | class TestTimeEntryTemplateIntegration: method test_start_timer_from_template (line 488) | def test_start_timer_from_template(self, authenticated_client, user, p... method test_start_timer_from_template_without_project (line 519) | def test_start_timer_from_template_without_project(self, authenticated... method test_start_timer_from_template_with_active_timer (line 530) | def test_start_timer_from_template_with_active_timer(self, authenticat... method test_manual_entry_with_template_prefill (line 552) | def test_manual_entry_with_template_prefill(self, authenticated_client... method test_start_timer_with_template_id (line 572) | def test_start_timer_with_template_id(self, authenticated_client, user... method test_template_with_project_and_task (line 592) | def test_template_with_project_and_task(self, app, user, project, task): method test_template_usage_tracking_over_time (line 605) | def test_template_usage_tracking_over_time(self, app, user): method test_multiple_users_separate_templates (line 623) | def test_multiple_users_separate_templates(self, app): FILE: tests/test_time_rounding.py class TestRoundTimeDuration (line 14) | class TestRoundTimeDuration: method test_no_rounding_when_interval_is_one (line 17) | def test_no_rounding_when_interval_is_one(self): method test_round_to_nearest_5_minutes (line 23) | def test_round_to_nearest_5_minutes(self): method test_round_to_nearest_15_minutes (line 34) | def test_round_to_nearest_15_minutes(self): method test_round_up (line 45) | def test_round_up(self): method test_round_down (line 56) | def test_round_down(self): method test_round_to_hour (line 65) | def test_round_to_hour(self): method test_invalid_rounding_method_defaults_to_nearest (line 74) | def test_invalid_rounding_method_defaults_to_nearest(self): method test_zero_duration (line 80) | def test_zero_duration(self): method test_very_small_durations (line 86) | def test_very_small_durations(self): method test_very_large_durations (line 93) | def test_very_large_durations(self): class TestApplyUserRounding (line 103) | class TestApplyUserRounding: method test_with_rounding_disabled (line 106) | def test_with_rounding_disabled(self): method test_with_rounding_enabled (line 117) | def test_with_rounding_enabled(self): method test_different_user_preferences (line 129) | def test_different_user_preferences(self): method test_get_user_rounding_settings (line 150) | def test_get_user_rounding_settings(self): method test_get_user_rounding_settings_with_defaults (line 163) | def test_get_user_rounding_settings_with_defaults(self): class TestFormattingFunctions (line 175) | class TestFormattingFunctions: method test_format_rounding_interval (line 178) | def test_format_rounding_interval(self): method test_get_available_rounding_intervals (line 187) | def test_get_available_rounding_intervals(self): method test_get_available_rounding_methods (line 195) | def test_get_available_rounding_methods(self): FILE: tests/test_time_rounding_param.py function test_round_time_duration_parametrized (line 26) | def test_round_time_duration_parametrized(seconds, interval, method, exp... FILE: tests/test_timer_edit_own_time_entries.py function _ensure_edit_own_permission (line 11) | def _ensure_edit_own_permission(user): function test_edit_timer_page_shows_schedule_fields_with_edit_own_permission (line 35) | def test_edit_timer_page_shows_schedule_fields_with_edit_own_permission(... function test_edit_timer_post_updates_times_with_edit_own_permission (line 61) | def test_edit_timer_post_updates_times_with_edit_own_permission(app, aut... function test_api_entry_put_updates_times_with_edit_own_permission (line 107) | def test_api_entry_put_updates_times_with_edit_own_permission(app, authe... FILE: tests/test_timezone.py function app (line 20) | def app(): function client (line 39) | def client(app): function user (line 45) | def user(app): function project (line 55) | def project(app): function test_timezone_default_from_environment (line 64) | def test_timezone_default_from_environment(app): function test_timezone_from_database_settings (line 76) | def test_timezone_from_database_settings(app): function test_timezone_change_affects_display (line 90) | def test_timezone_change_affects_display(app, user, project): function test_timezone_aware_current_time (line 135) | def test_timezone_aware_current_time(app): function test_timezone_conversion_utc_to_local (line 159) | def test_timezone_conversion_utc_to_local(app): function test_timezone_conversion_local_to_utc (line 182) | def test_timezone_conversion_local_to_utc(app): function test_invalid_timezone_fallback (line 205) | def test_invalid_timezone_fallback(app): function test_timezone_settings_update (line 224) | def test_timezone_settings_update(app): function test_get_available_timezones_matches_pytz_common (line 251) | def test_get_available_timezones_matches_pytz_common(): function test_convert_app_datetime_to_user_respects_user_timezone (line 259) | def test_convert_app_datetime_to_user_respects_user_timezone(app, user): function test_convert_app_datetime_to_user_falls_back_to_app_timezone (line 282) | def test_convert_app_datetime_to_user_falls_back_to_app_timezone(app, us... function test_update_preferences_allows_clearing_user_timezone (line 302) | def test_update_preferences_allows_clearing_user_timezone(app, user): FILE: tests/test_ui_quick_wins.py function test_base_layout_has_skip_link (line 6) | def test_base_layout_has_skip_link(authenticated_client): function test_login_has_primary_button_and_user_icon (line 17) | def test_login_has_primary_button_and_user_icon(client): function test_tasks_table_has_sticky_and_zebra (line 28) | def test_tasks_table_has_sticky_and_zebra(authenticated_client): FILE: tests/test_uploads_persistence.py function admin_user (line 25) | def admin_user(app): function authenticated_admin_client (line 36) | def authenticated_admin_client(client, admin_user): function sample_logo_image (line 66) | def sample_logo_image(): function uploads_dir (line 76) | def uploads_dir(app): function cleanup_test_files (line 83) | def cleanup_test_files(app): function test_uploads_directory_exists (line 103) | def test_uploads_directory_exists(app, uploads_dir): function test_logos_subdirectory_exists (line 113) | def test_logos_subdirectory_exists(app, uploads_dir): function test_avatars_subdirectory_exists (line 123) | def test_avatars_subdirectory_exists(app, uploads_dir): function test_uploads_directory_is_writable (line 133) | def test_uploads_directory_is_writable(app, uploads_dir): function test_logo_file_persists_after_upload (line 159) | def test_logo_file_persists_after_upload(authenticated_admin_client, sam... function test_logo_accessible_after_simulated_restart (line 194) | def test_logo_accessible_after_simulated_restart( function test_multiple_logos_in_directory (line 238) | def test_multiple_logos_in_directory(authenticated_admin_client, app, cl... function test_logo_path_is_in_uploads_directory (line 276) | def test_logo_path_is_in_uploads_directory( function test_settings_logo_path_resolution (line 310) | def test_settings_logo_path_resolution(app): function test_settings_logo_url_format (line 325) | def test_settings_logo_url_format(app): function test_settings_logo_path_none_when_no_filename (line 338) | def test_settings_logo_path_none_when_no_filename(app): function test_logo_file_has_correct_extension (line 356) | def test_logo_file_has_correct_extension(authenticated_admin_client, sam... function test_old_logo_removed_when_new_uploaded (line 378) | def test_old_logo_removed_when_new_uploaded(authenticated_admin_client, ... function test_logo_removed_when_deleted (line 432) | def test_logo_removed_when_deleted(authenticated_admin_client, sample_lo... function test_uploads_directory_accessible (line 467) | def test_uploads_directory_accessible(app, uploads_dir): function test_logo_upload_and_retrieve_workflow (line 483) | def test_logo_upload_and_retrieve_workflow(authenticated_admin_client, s... function test_settings_has_logo_with_existing_file (line 521) | def test_settings_has_logo_with_existing_file(authenticated_admin_client... function test_settings_has_logo_without_file (line 538) | def test_settings_has_logo_without_file(app): function test_settings_to_dict_includes_logo_info (line 550) | def test_settings_to_dict_includes_logo_info(authenticated_admin_client,... FILE: tests/test_user_report_entries_export_excel.py function _non_empty_rows (line 5) | def _non_empty_rows(ws): function test_export_user_entries_excel_returns_one_row_per_entry (line 13) | def test_export_user_entries_excel_returns_one_row_per_entry(client, app... function test_export_user_entries_excel_non_admin_cannot_export_other_users (line 91) | def test_export_user_entries_excel_non_admin_cannot_export_other_users(a... FILE: tests/test_user_settings.py class TestUserSettingsPage (line 13) | class TestUserSettingsPage: method test_settings_page_requires_login (line 16) | def test_settings_page_requires_login(self, client): method test_settings_page_loads_for_authenticated_user (line 22) | def test_settings_page_loads_for_authenticated_user(self, client, user): method test_settings_page_displays_current_values (line 35) | def test_settings_page_displays_current_values(self, client, user): method test_settings_page_includes_all_sections (line 56) | def test_settings_page_includes_all_sections(self, client, user): class TestUserSettingsUpdate (line 74) | class TestUserSettingsUpdate: method test_update_profile_information (line 77) | def test_update_profile_information(self, client, user): method test_update_notification_preferences (line 94) | def test_update_notification_preferences(self, client, user): method test_update_notification_preferences_all_disabled (line 121) | def test_update_notification_preferences_all_disabled(self, client, us... method test_update_theme_preference (line 144) | def test_update_theme_preference(self, client, user): method test_update_timezone (line 170) | def test_update_timezone(self, client, user): method test_update_timezone_with_invalid_value (line 181) | def test_update_timezone_with_invalid_value(self, client, user): method test_update_calendar_default_view_via_settings_form (line 191) | def test_update_calendar_default_view_via_settings_form(self, client, ... method test_update_date_format (line 216) | def test_update_date_format(self, client, user): method test_update_time_format (line 228) | def test_update_time_format(self, client, user): method test_update_week_start_day (line 247) | def test_update_week_start_day(self, client, user): method test_update_time_rounding_preferences (line 266) | def test_update_time_rounding_preferences(self, client, user): method test_update_time_rounding_intervals (line 283) | def test_update_time_rounding_intervals(self, client, user): method test_update_time_rounding_methods (line 301) | def test_update_time_rounding_methods(self, client, user): method test_update_standard_hours_per_day (line 317) | def test_update_standard_hours_per_day(self, client, user): method test_update_standard_hours_validation (line 328) | def test_update_standard_hours_validation(self, client, user): method test_update_overtime_calculation_mode_and_weekly_hours (line 345) | def test_update_overtime_calculation_mode_and_weekly_hours(self, clien... method test_update_standard_hours_per_week_validation (line 363) | def test_update_standard_hours_per_week_validation(self, client, user): method test_update_language_preference (line 384) | def test_update_language_preference(self, client, user): method test_update_multiple_settings_at_once (line 395) | def test_update_multiple_settings_at_once(self, client, user): class TestUserSettingsAPIEndpoints (line 434) | class TestUserSettingsAPIEndpoints: method test_update_preferences_api_requires_login (line 437) | def test_update_preferences_api_requires_login(self, client): method test_update_theme_via_api (line 442) | def test_update_theme_via_api(self, client, user): method test_update_email_notifications_via_api (line 456) | def test_update_email_notifications_via_api(self, client, user): method test_update_timezone_via_api (line 470) | def test_update_timezone_via_api(self, client, user): method test_update_invalid_timezone_via_api (line 484) | def test_update_invalid_timezone_via_api(self, client, user): method test_update_calendar_default_view_via_api (line 495) | def test_update_calendar_default_view_via_api(self, client, user): method test_update_calendar_default_view_invalid_via_api (line 513) | def test_update_calendar_default_view_invalid_via_api(self, client, us... method test_update_ui_feature_flags (line 523) | def test_update_ui_feature_flags(self, client, user): method test_ui_feature_flags_default_to_true (line 548) | def test_ui_feature_flags_default_to_true(self, client, user): method test_settings_page_includes_ui_customization_section (line 562) | def test_settings_page_includes_ui_customization_section(self, client,... method test_update_ui_feature_flags (line 582) | def test_update_ui_feature_flags(self, client, user): method test_ui_feature_flags_default_to_true (line 612) | def test_ui_feature_flags_default_to_true(self, client, user): method test_settings_page_includes_ui_customization_section (line 634) | def test_settings_page_includes_ui_customization_section(self, client,... method test_set_theme_api_endpoint (line 654) | def test_set_theme_api_endpoint(self, client, user): method test_set_invalid_theme_via_api (line 681) | def test_set_invalid_theme_via_api(self, client, user): class TestUserSettingsIntegration (line 693) | class TestUserSettingsIntegration: method test_settings_persist_across_sessions (line 696) | def test_settings_persist_across_sessions(self, client, user): method test_default_settings_for_new_user (line 726) | def test_default_settings_for_new_user(self, app): method test_settings_form_csrf_protection (line 747) | def test_settings_form_csrf_protection(self, app): FILE: tests/test_utils.py function test_local_datetime_filter (line 28) | def test_local_datetime_filter(app): function test_local_datetime_filter_none (line 41) | def test_local_datetime_filter_none(app): function test_local_date_filter (line 52) | def test_local_date_filter(app): function test_local_date_filter_none (line 65) | def test_local_date_filter_none(app): function test_local_time_filter (line 76) | def test_local_time_filter(app): function test_local_time_filter_none (line 89) | def test_local_time_filter_none(app): function test_local_datetime_short_filter (line 100) | def test_local_datetime_short_filter(app): function test_local_datetime_short_filter_none (line 113) | def test_local_datetime_short_filter_none(app): function test_nl2br_filter (line 124) | def test_nl2br_filter(app): function test_nl2br_filter_none (line 137) | def test_nl2br_filter_none(app): function test_markdown_filter_empty (line 148) | def test_markdown_filter_empty(app): function test_markdown_filter_with_text (line 161) | def test_markdown_filter_with_text(app): function test_format_date_filter_with_datetime (line 174) | def test_format_date_filter_with_datetime(app): function test_format_date_filter_with_date (line 187) | def test_format_date_filter_with_date(app): function test_format_date_filter_formats (line 200) | def test_format_date_filter_formats(app): function test_format_date_filter_none (line 218) | def test_format_date_filter_none(app): function test_format_date_filter_non_date (line 229) | def test_format_date_filter_non_date(app): function test_format_money_filter (line 240) | def test_format_money_filter(app): function test_format_money_filter_invalid (line 261) | def test_format_money_filter_invalid(app): function test_timeago_filter_none (line 272) | def test_timeago_filter_none(app): function test_timeago_filter_just_now (line 283) | def test_timeago_filter_just_now(app): function test_timeago_filter_minutes (line 297) | def test_timeago_filter_minutes(app): function test_timeago_filter_hours (line 312) | def test_timeago_filter_hours(app): function test_timeago_filter_days (line 327) | def test_timeago_filter_days(app): function test_timeago_filter_weeks (line 342) | def test_timeago_filter_weeks(app): function test_timeago_filter_months (line 357) | def test_timeago_filter_months(app): function test_timeago_filter_years (line 372) | def test_timeago_filter_years(app): function test_timeago_filter_future (line 387) | def test_timeago_filter_future(app): function test_timeago_filter_naive_datetime (line 401) | def test_timeago_filter_naive_datetime(app): function test_timeago_filter_singular_plural (line 415) | def test_timeago_filter_singular_plural(app): function test_inject_settings (line 440) | def test_inject_settings(app, client): function test_inject_globals (line 451) | def test_inject_globals(app, client): function test_before_request (line 461) | def test_before_request(app, client): function test_404_error_html (line 478) | def test_404_error_html(app, client): function test_404_error_api (line 487) | def test_404_error_api(app, client): function test_500_error_html (line 500) | def test_500_error_html(app, client): function test_500_error_api (line 514) | def test_500_error_api(app, client): function test_403_error_html (line 531) | def test_403_error_html(app, client): function test_403_error_api (line 545) | def test_403_error_api(app, client): function test_400_error_html (line 562) | def test_400_error_html(app, client): function test_400_error_api (line 576) | def test_400_error_api(app, client): function test_http_exception_handler (line 593) | def test_http_exception_handler(app, client): function test_needs_compile_mo_missing (line 612) | def test_needs_compile_mo_missing(): function test_needs_compile_po_newer (line 628) | def test_needs_compile_po_newer(): function test_needs_compile_mo_current (line 649) | def test_needs_compile_mo_current(): function test_compile_po_to_mo_success (line 670) | def test_compile_po_to_mo_success(): function test_compile_po_to_mo_invalid_file (line 695) | def test_compile_po_to_mo_invalid_file(): function test_ensure_translations_compiled_empty_dir (line 708) | def test_ensure_translations_compiled_empty_dir(): function test_ensure_translations_compiled_valid_structure (line 717) | def test_ensure_translations_compiled_valid_structure(): function test_ensure_translations_compiled_none (line 745) | def test_ensure_translations_compiled_none(): function test_ensure_translations_compiled_relative_path (line 753) | def test_ensure_translations_compiled_relative_path(): function test_ensure_translations_compiled_nonexistent_dir (line 771) | def test_ensure_translations_compiled_nonexistent_dir(): function test_safe_commit_success (line 784) | def test_safe_commit_success(app): function test_safe_commit_with_context (line 795) | def test_safe_commit_with_context(app): function test_safe_commit_sqlalchemy_error (line 806) | def test_safe_commit_sqlalchemy_error(app): function test_safe_commit_sqlalchemy_error_with_context (line 817) | def test_safe_commit_sqlalchemy_error_with_context(app): function test_safe_commit_sqlalchemy_error_no_action (line 827) | def test_safe_commit_sqlalchemy_error_no_action(app): function test_safe_commit_generic_exception (line 837) | def test_safe_commit_generic_exception(app): function test_safe_commit_rollback_error (line 848) | def test_safe_commit_rollback_error(app): function test_safe_commit_logging_error (line 866) | def test_safe_commit_logging_error(app): FILE: tests/test_utils/test_api_auth_enhanced.py class TestExtractToken (line 17) | class TestExtractToken: method test_extract_from_bearer_header (line 20) | def test_extract_from_bearer_header(self): method test_extract_from_token_header (line 30) | def test_extract_from_token_header(self): method test_extract_from_api_key_header (line 40) | def test_extract_from_api_key_header(self): method test_extract_none_when_missing (line 50) | def test_extract_none_when_missing(self): class TestAuthenticateToken (line 61) | class TestAuthenticateToken: method sample_user (line 65) | def sample_user(self, app): method sample_token (line 73) | def sample_token(self, app, sample_user): method test_authenticate_valid_token (line 82) | def test_authenticate_valid_token(self, app, sample_user, sample_token): method test_authenticate_expired_token (line 95) | def test_authenticate_expired_token(self, app, sample_user): method test_authenticate_revoked_token (line 111) | def test_authenticate_revoked_token(self, app, sample_user, sample_tok... method test_authenticate_with_ip_whitelist_allowed (line 124) | def test_authenticate_with_ip_whitelist_allowed(self, app, sample_user): method test_authenticate_with_ip_whitelist_denied (line 140) | def test_authenticate_with_ip_whitelist_denied(self, app, sample_user): method test_authenticate_with_cidr_block (line 156) | def test_authenticate_with_cidr_block(self, app, sample_user): method test_authenticate_invalid_token_format (line 170) | def test_authenticate_invalid_token_format(self, app): method test_authenticate_nonexistent_token (line 179) | def test_authenticate_nonexistent_token(self, app): method test_authenticate_inactive_user (line 190) | def test_authenticate_inactive_user(self, app, sample_token): class TestRequireApiToken (line 204) | class TestRequireApiToken: method app_with_routes (line 208) | def app_with_routes(self, app): method test_protected_route_with_valid_token (line 223) | def test_protected_route_with_valid_token(self, app_with_routes, sampl... method test_protected_route_without_token (line 235) | def test_protected_route_without_token(self, app_with_routes): method test_protected_route_with_insufficient_scope (line 245) | def test_protected_route_with_insufficient_scope(self, app_with_routes... method test_protected_route_with_wildcard_scope (line 261) | def test_protected_route_with_wildcard_scope(self, app_with_routes, sa... FILE: tests/test_utils/test_cache.py class TestInMemoryCache (line 13) | class TestInMemoryCache: method test_get_set_delete (line 16) | def test_get_set_delete(self): method test_expiration (line 28) | def test_expiration(self): method test_exists (line 40) | def test_exists(self): method test_clear (line 48) | def test_clear(self): class TestRedisCache (line 60) | class TestRedisCache: method test_redis_connection_success (line 64) | def test_redis_connection_success(self, mock_redis): method test_redis_connection_failure (line 76) | def test_redis_connection_failure(self, mock_redis): method test_redis_get_set (line 86) | def test_redis_get_set(self, mock_redis): method test_redis_fallback_on_error (line 111) | def test_redis_fallback_on_error(self, mock_redis): class TestCacheIntegration (line 125) | class TestCacheIntegration: method test_get_cache_with_redis_enabled (line 129) | def test_get_cache_with_redis_enabled(self, mock_app): method test_get_cache_fallback_to_memory (line 143) | def test_get_cache_fallback_to_memory(self, mock_app): method test_cache_decorator (line 156) | def test_cache_decorator(self): FILE: tests/test_utils/test_integration_sync_context.py function test_sync_result_item_count_prefers_synced_count (line 10) | def test_sync_result_item_count_prefers_synced_count(): function test_sync_result_item_count_falls_back_to_synced_items (line 16) | def test_sync_result_item_count_falls_back_to_synced_items(): function test_sync_result_item_count_empty (line 22) | def test_sync_result_item_count_empty(): function test_find_task_by_integration_ref_filters_by_source (line 30) | def test_find_task_by_integration_ref_filters_by_source(MockTask): function test_find_task_by_integration_ref_without_source_matches_any (line 44) | def test_find_task_by_integration_ref_without_source_matches_any(MockTask): FILE: tests/test_utils/test_scope_filter.py function test_get_accessible_project_and_client_ids_for_user_empty (line 32) | def test_get_accessible_project_and_client_ids_for_user_empty(db_session): function test_get_accessible_project_and_client_ids_for_user_via_time_entries (line 44) | def test_get_accessible_project_and_client_ids_for_user_via_time_entries... function test_get_allowed_client_ids_unrestricted_user (line 74) | def test_get_allowed_client_ids_unrestricted_user(app, user): function test_get_allowed_project_ids_unrestricted_user (line 82) | def test_get_allowed_project_ids_unrestricted_user(app, user): function client_portal_scoped_user (line 90) | def client_portal_scoped_user(app, test_client, project): function test_get_allowed_client_ids_client_portal_user (line 130) | def test_get_allowed_client_ids_client_portal_user(app, client_portal_sc... function test_get_allowed_project_ids_client_portal_user (line 137) | def test_get_allowed_project_ids_client_portal_user(app, client_portal_s... function test_get_allowed_client_ids_scope_restricted (line 145) | def test_get_allowed_client_ids_scope_restricted(app, scope_restricted_u... function test_get_allowed_project_ids_scope_restricted (line 153) | def test_get_allowed_project_ids_scope_restricted(app, scope_restricted_... function test_user_can_access_client_admin (line 166) | def test_user_can_access_client_admin(admin_user, test_client): function test_user_can_access_client_unrestricted (line 171) | def test_user_can_access_client_unrestricted(user, test_client): function test_user_can_access_client_scope_restricted_allowed (line 176) | def test_user_can_access_client_scope_restricted_allowed(scope_restricte... function test_user_can_access_client_scope_restricted_denied (line 181) | def test_user_can_access_client_scope_restricted_denied(app, scope_restr... function test_user_can_access_project_scope_restricted_allowed (line 190) | def test_user_can_access_project_scope_restricted_allowed(scope_restrict... function test_user_can_access_project_scope_restricted_denied (line 195) | def test_user_can_access_project_scope_restricted_denied(app, scope_rest... function test_user_can_access_client_client_portal_allowed (line 207) | def test_user_can_access_client_client_portal_allowed(client_portal_scop... function test_user_can_access_client_client_portal_denied (line 212) | def test_user_can_access_client_client_portal_denied(app, client_portal_... function test_user_can_access_project_client_portal_allowed (line 221) | def test_user_can_access_project_client_portal_allowed(client_portal_sco... function test_user_can_access_project_client_portal_denied (line 226) | def test_user_can_access_project_client_portal_denied(app, client_portal... function test_apply_client_scope_to_model_unrestricted (line 243) | def test_apply_client_scope_to_model_unrestricted(app, user): function test_apply_client_scope_to_model_scope_restricted (line 252) | def test_apply_client_scope_to_model_scope_restricted(app, scope_restric... function test_apply_project_scope_to_model_unrestricted (line 265) | def test_apply_project_scope_to_model_unrestricted(app, user): function test_apply_project_scope_to_model_scope_restricted (line 274) | def test_apply_project_scope_to_model_scope_restricted(app, scope_restri... function test_apply_project_scope_query_unrestricted (line 287) | def test_apply_project_scope_query_unrestricted(app, user): function test_apply_project_scope_query_restricted (line 297) | def test_apply_project_scope_query_restricted(app, scope_restricted_user... function test_apply_project_scope_to_model_client_portal (line 308) | def test_apply_project_scope_to_model_client_portal(app, client_portal_s... function test_apply_project_scope_query_client_portal (line 320) | def test_apply_project_scope_query_client_portal(app, client_portal_scop... function test_api_projects_list_filtered_by_scope (line 338) | def test_api_projects_list_filtered_by_scope(app, scope_restricted_user,... function test_api_projects_list_filtered_by_client_portal (line 374) | def test_api_projects_list_filtered_by_client_portal(app, client_portal_... FILE: tests/test_utils/test_version_compare.py function test_normalize_version_tag (line 21) | def test_normalize_version_tag(raw, expected): function test_normalize_version_tag_strips_v_only (line 29) | def test_normalize_version_tag_strips_v_only(): function test_is_upgrade (line 44) | def test_is_upgrade(current, latest, expect): FILE: tests/test_utils/test_webhook_service.py function test_user (line 14) | def test_user(db_session): function test_webhook (line 23) | def test_webhook(db_session, test_user): class TestWebhookService (line 38) | class TestWebhookService: method test_deliver_webhook_success (line 42) | def test_deliver_webhook_success(self, mock_post, db_session, test_web... method test_deliver_webhook_http_error (line 59) | def test_deliver_webhook_http_error(self, mock_post, db_session, test_... method test_deliver_webhook_timeout (line 76) | def test_deliver_webhook_timeout(self, mock_post, db_session, test_web... method test_deliver_webhook_inactive (line 90) | def test_deliver_webhook_inactive(self, db_session, test_webhook): method test_deliver_webhook_not_subscribed (line 100) | def test_deliver_webhook_not_subscribed(self, db_session, test_webhook): method test_get_available_events (line 107) | def test_get_available_events(self): method test_retry_failed_deliveries (line 117) | def test_retry_failed_deliveries(self, mock_post, db_session, test_web... FILE: tests/test_version_reading.py class TestVersionReading (line 10) | class TestVersionReading: method test_get_version_from_setup (line 13) | def test_get_version_from_setup(self): method test_version_in_analytics_config (line 27) | def test_version_in_analytics_config(self): method test_version_fallback (line 36) | def test_version_fallback(self, monkeypatch): FILE: tests/test_weekly_goals.py function test_weekly_goal_creation (line 21) | def test_weekly_goal_creation(app, user): function test_weekly_goal_default_week (line 40) | def test_weekly_goal_default_week(app, user): function test_weekly_goal_with_notes (line 57) | def test_weekly_goal_with_notes(app, user): function test_weekly_goal_actual_hours_calculation (line 69) | def test_weekly_goal_actual_hours_calculation(app, user, project): function test_weekly_goal_progress_percentage (line 101) | def test_weekly_goal_progress_percentage(app, user, project): function test_weekly_goal_remaining_hours (line 126) | def test_weekly_goal_remaining_hours(app, user, project): function test_weekly_goal_is_completed (line 150) | def test_weekly_goal_is_completed(app, user, project): function test_weekly_goal_average_hours_per_day (line 176) | def test_weekly_goal_average_hours_per_day(app, user, project): function test_weekly_goal_week_label (line 203) | def test_weekly_goal_week_label(app, user): function test_weekly_goal_status_update_completed (line 217) | def test_weekly_goal_status_update_completed(app, user, project): function test_weekly_goal_status_update_failed (line 243) | def test_weekly_goal_status_update_failed(app, user, project): function test_weekly_goal_get_current_week (line 269) | def test_weekly_goal_get_current_week(app, user): function test_weekly_goal_to_dict (line 289) | def test_weekly_goal_to_dict(app, user): function test_weekly_goals_index_page (line 320) | def test_weekly_goals_index_page(authenticated_client): function test_weekly_goals_create_page (line 327) | def test_weekly_goals_create_page(authenticated_client): function test_create_weekly_goal_via_form (line 334) | def test_create_weekly_goal_via_form(authenticated_client, app, user): function test_edit_weekly_goal (line 348) | def test_edit_weekly_goal(authenticated_client, app, user): function test_delete_weekly_goal (line 370) | def test_delete_weekly_goal(authenticated_client, app, user): function test_view_weekly_goal (line 389) | def test_view_weekly_goal(authenticated_client, app, user): function test_api_get_current_goal (line 408) | def test_api_get_current_goal(authenticated_client, app, user): function test_api_list_goals (line 425) | def test_api_list_goals(authenticated_client, app, user): function test_api_get_goal_stats (line 451) | def test_api_get_goal_stats(authenticated_client, app, user, project): function test_weekly_goal_user_relationship (line 485) | def test_weekly_goal_user_relationship(app, user): function test_user_has_weekly_goals_relationship (line 498) | def test_user_has_weekly_goals_relationship(app, user): function test_weekly_goal_exclude_weekends_creation (line 526) | def test_weekly_goal_exclude_weekends_creation(app, user): function test_weekly_goal_days_remaining_exclude_weekends_monday (line 544) | def test_weekly_goal_days_remaining_exclude_weekends_monday(app, user): function test_weekly_goal_average_hours_per_day_exclude_weekends (line 574) | def test_weekly_goal_average_hours_per_day_exclude_weekends(app, user): function test_weekly_goal_days_remaining_excludes_weekends (line 600) | def test_weekly_goal_days_remaining_excludes_weekends(app, user): function test_weekly_goal_actual_hours_excludes_weekends (line 637) | def test_weekly_goal_actual_hours_excludes_weekends(app, user, project): FILE: tests/test_zugferd.py function test_embed_facturx_xml_in_pdf_adds_cii_attachment (line 14) | def test_embed_facturx_xml_in_pdf_adds_cii_attachment(app): function test_embed_facturx_xml_has_correct_xmp_metadata (line 123) | def test_embed_facturx_xml_has_correct_xmp_metadata(app): function test_embed_returns_original_pdf_on_failure (line 180) | def test_embed_returns_original_pdf_on_failure(app):