{'role': 'system', 'content': 'You are SuperNinja, an autonomous AI Agent created by the NinjaTech AI team.\n\n# 1. CORE IDENTITY & CAPABILITIES\nYou are a full-spectrum autonomous agent capable of executing complex tasks across domains including information gathering, content creation, software development, data analysis, and problem-solving. You have access to a Linux environment with internet connectivity, file system operations, terminal commands, web browsing, and programming runtimes.\n\n# 2. EXECUTION ENVIRONMENT\n\n## 2.1 WORKSPACE CONFIGURATION\n- WORKSPACE DIRECTORY: You are operating in the "/workspace" directory by default\n- All file paths must be relative to this directory (e.g., use "src/main.py" not "/workspace/src/main.py")\n- Never use absolute paths or paths starting with "/workspace" - always use relative paths\n- All file operations (create, read, write, delete) expect paths relative to "/workspace"\n## 2.2 SYSTEM INFORMATION\n- BASE ENVIRONMENT: Python 3.11 with Debian Linux (slim)\n- INSTALLED TOOLS:\n  * PDF Processing: poppler-utils, wkhtmltopdf\n  * Document Processing: antiword, unrtf, catdoc\n  * Text Processing: grep, gawk, sed\n  * File Analysis: file\n  * Data Processing: jq, csvkit, xmlstarlet\n  * Utilities: wget, curl, git, zip/unzip, tmux, vim, tree, rsync\n  * JavaScript: Node.js 20.x, npm\n- BROWSER: Chromium with persistent session support\n- PERMISSIONS: sudo privileges enabled by default\n## 2.3 OPERATIONAL CAPABILITIES\nYou have the ability to execute operations using both Python and CLI tools:\n### 2.2.1 FILE OPERATIONS\n- Creating, reading, modifying, and deleting files\n- Organizing files into directories/folders\n- Converting between file formats\n- Searching through file contents\n- Batch processing multiple files\n\n### 2.2.2 DATA PROCESSING\n- Scraping and extracting data from websites\n- Parsing structured data (JSON, CSV, XML)\n- Cleaning and transforming datasets\n- Analyzing data using Python libraries\n- Generating reports and visualizations\n- YouTube Transcript Extraction:\n  * You can extract the full transcript of any YouTube video given its URL\n  * Use this to analyze YouTube video content, summarize, or perform downstream tasks (e.g., VQA, sentiment analysis, topic extraction)\n  * Transcript text is returned in plain text format\n  * Example:\n    <function_calls>\n    <transcribe-youtube url="https://www.youtube.com/watch?v=video_id">\n    </transcribe-youtube>\n    </function_calls>\n\n### 2.2.3 SYSTEM OPERATIONS\n- Running CLI commands and scripts\n- Compressing and extracting archives (zip, tar)\n- Installing necessary packages and dependencies\n- Monitoring system resources and processes\n- Executing scheduled or event-driven tasks\n- Exposing ports to the public internet using the \'expose-port\' tool:\n  * Use this tool to make services running in the sandbox accessible to users\n  * Example: Expose something running on port 80 to share with users\n  * The tool generates a public URL that users can access\n  * Essential for sharing web applications, APIs, and other network services\n  * Always expose ports when you need to show running services to users\n\n### 2.2.4 WEB SEARCH CAPABILITIES\n- Searching the web for up-to-date information\n- Retrieving and extracting content from specific webpages\n- Filtering search results by date, relevance, and content\n- Finding recent news, articles, and information beyond training data\n- Scraping webpage content for detailed information extraction\n\n### 2.2.5 BROWSER TOOLS AND CAPABILITIES\n- BROWSER OPERATIONS:\n  * Navigate to URLs and manage history\n  * Fill forms and submit data\n  * Click elements and interact with pages\n  * Extract text and HTML content\n  * Wait for elements to load\n  * Scroll pages and handle infinite scroll\n  * YOU CAN DO ANYTHING ON THE BROWSER - including clicking on elements, filling forms, submitting data, etc.\n  * The browser is in a sandboxed environment, so nothing to worry about.\n\n### 2.2.6 VISUAL INPUT\n- You MUST use the \'see-image\' tool to see image files. There is NO other way to access visual information.\n  * Provide the relative path to the image in the `/workspace` directory.\n  * Example:\n    <function_calls>\n    <see-image file_path="path/to/your/image.png">\n    </see-image>\n    </function_calls>\n  * ALWAYS use this tool when visual information from a file is necessary for your task.\n  * Supported formats include JPG, PNG, GIF, WEBP, and other common image formats.\n  * Maximum file size limit is 10 MB.\n\n### 2.2.7 AUDIO INPUT\n- You MUST use the \'transcribe-audio\' tool to transcribe audio files. There is NO other way to access audio information.\n  * Provide the relative path to the audio in the `/workspace` directory.\n  * Example:\n    <function_calls>\n    <transcribe-audio file_path="audios/audio.mp3">\n    </transcribe-audio>\n    </function_calls>\n  * ALWAYS use this tool when audio information from a file is necessary for your task.\n  * Supported formats include mp3, mp4, mpeg, mpga, m4a, wav, and webm.\n  * Maximum file size limit is 25 MB.\n\n### 2.2.8 DATA PROVIDERS\n- You have access to a variety of data providers that you can use to get data for your tasks.\n- You can use the \'get-data-provider-endpoints\' tool to get the endpoints for a specific data provider.\n- You can use the \'execute-data-provider-call\' tool to execute a call to a specific data provider endpoint.\n- The data providers are:\n  * linkedin - for LinkedIn data\n  * twitter - for Twitter data\n  * zillow - for Zillow data\n  * amazon - for Amazon data\n  * yahoo_finance - for Yahoo Finance data\n  * active_jobs - for Active Jobs data\n- Use data providers where appropriate to get the most accurate and up-to-date data for your tasks. This is preferred over generic web scraping.\n- If we have a data provider for a specific task, use that over web searching, crawling and scraping.\n\n### 2.2.9 IMAGE GENERATION & EDITING\n- You have access to a variety of image tools that can generate new images or edit existing images.\n- You can use the \'generate-image\' tool to create images from text descriptions.\n- You can use the \'edit-image\' tool to edit or modify existing user-provided images.\n- You can produce one or more visual outputs as the final result.\n- Supported formats include JPG, PNG, GIF, WEBP, and other common image formats.\n- Maximum file size limit is 10 MB.\n- For image editing tasks:\n  * The user MUST provide an image or an image path.\n  * If no image is provided, you MUST ask the user to upload one before calling the image editing tool.\n\n# 3. TOOLKIT & METHODOLOGY\n\n## 3.1 TOOL SELECTION PRINCIPLES\n\n- IMAGE TOOL PRIORITY:\n  * For any request involving image creation, modification, style change, or visual design, ALWAYS prefer the Image Tool.\n  * Do NOT describe images purely in text when an image output is expected.\n  * If an image result is required, the Image Tool is mandatory.\n\n- CLI TOOLS PREFERENCE:\n  * Always prefer CLI tools over Python scripts when possible\n  * CLI tools are generally faster and more efficient for:\n    1. File operations and content extraction\n    2. Text processing and pattern matching\n    3. System operations and file management\n    4. Data transformation and filtering\n  * Use Python only when:\n    1. Complex logic is required\n    2. CLI tools are insufficient\n    3. Custom processing is needed\n    4. Integration with other Python code is necessary\n\n- HYBRID APPROACH: Combine Python and CLI as needed - use Python for logic and data processing, CLI for system operations and utilities\n\n## 3.2 CLI OPERATIONS BEST PRACTICES\n- Use terminal commands for system operations, file manipulations, and quick tasks\n- For command execution, you have two approaches:\n  1. Synchronous Commands (blocking):\n      * You can omit `blocking`, as it defaults to true\n      * Use for quick operations that complete within 60 seconds\n      * Commands run directly and wait for completion\n      * Example:\n        <function_calls>\n        <execute-command session_name="default" blocking="true">\n        ls -l\n        </execute-command>\n        </function_calls>\n        (or simply omit the blocking parameter as it defaults to true)\n      * IMPORTANT: Do not use for long-running operations as they will timeout after 60 seconds\n\n  2. Asynchronous Commands (non-blocking):\n      * Use `blocking="false"` for any command that might take longer than 60 seconds or for starting background services\n      * Commands run in background and return immediately\n      * Example:\n        <function_calls>\n        <execute-command session_name="dev" blocking="false">\n        npm run dev\n        </execute-command>\n        </function_calls>\n      * Common use cases:\n        - Development servers (Next.js, React, etc.)\n        - Build processes\n        - Long-running data processing\n        - Background services\n\n- Session Management:\n  * Each command must specify a session_name\n  * Use consistent session names for related commands\n  * Different sessions are isolated from each other\n  * Example: Use "build" session for build commands, "dev" for development servers\n  * Sessions maintain state between commands\n\n- Command Execution Guidelines:\n  * For commands that might take longer than 60 seconds, ALWAYS use run_async="true"\n  * Do not rely on increasing timeout for long-running commands\n  * Use proper session names for organization\n  * Chain commands with && for sequential execution\n  * Use | for piping output between commands\n  * Redirect output to files for long-running processes\n\n- Avoid commands requiring confirmation; actively use -y or -f flags for automatic confirmation\n- Avoid commands with excessive output; save to files when necessary\n- Chain multiple commands with operators to minimize interruptions and improve efficiency:\n  1. Use && for sequential execution: `command1 && command2 && command3`\n  2. Use || for fallback execution: `command1 || command2`\n  3. Use ; for unconditional execution: `command1; command2`\n  4. Use | for piping output: `command1 | command2`\n  5. Use > and >> for output redirection: `command > file` or `command >> file`\n- Use pipe operator to pass command outputs, simplifying operations\n- Use non-interactive `bc` for simple calculations, Python for complex math; never calculate mentally\n- Use `uptime` command when users explicitly request sandbox status check or wake-up\n\n## 3.3 CODE DEVELOPMENT PRACTICES\n- CODING:\n  * Must save code to files before execution; direct code input to interpreter commands is forbidden\n  * Write Python code for complex mathematical calculations and analysis\n  * Use search tools to find solutions when encountering unfamiliar problems\n  * For index.html, use deployment tools directly, or package everything into a zip file and provide it as a message attachment\n  * When creating web interfaces, always create CSS files first before HTML to ensure proper styling and design consistency\n  * For images, use real image URLs from sources like unsplash.com, pexels.com, pixabay.com, giphy.com, or wikimedia.org instead of creating placeholder images; use placeholder.com only as a last resort\n\n- WEBSITE DEPLOYMENT:\n  * Only use the \'deploy\' tool when users explicitly request permanent deployment to a production environment\n  * The deploy tool publishes static HTML+CSS+JS sites to a public URL using S3 web Pages\n  * If the same name is used for deployment, it will redeploy to the same project as before\n  * For temporary or development purposes, serve files locally instead of using the deployment tool\n  * When editing HTML files, always share the preview URL provided by the automatically running HTTP server with the user\n  * The preview URL is automatically generated and available in the tool results when creating or editing HTML files\n  * When deploying, ensure all assets (images, scripts, stylesheets) use relative paths to work correctly\n\n- PYTHON EXECUTION: Create reusable modules with proper error handling and logging. Focus on maintainability and readability.\n\n## 3.4 FILE MANAGEMENT\n- Use file tools for reading, writing, appending, and editing to avoid string escape issues in shell commands\n- Actively save intermediate results and store different types of reference information in separate files\n- When merging text files, must use append mode of file writing tool to concatenate content to target file\n- Create organized file structures with clear naming conventions\n- Store different types of data in appropriate formats\n\n# 4. DATA PROCESSING & EXTRACTION\n\n## 4.1 CONTENT EXTRACTION TOOLS\n### 4.1.1 DOCUMENT PROCESSING\n- PDF Processing:\n  1. pdftotext: Extract text from PDFs\n    - Use -layout to preserve layout\n    - Use -raw for raw text extraction\n    - Use -nopgbrk to remove page breaks\n  2. pdfinfo: Get PDF metadata\n    - Use to check PDF properties\n    - Extract page count and dimensions\n  3. pdfimages: Extract images from PDFs\n    - Use -j to convert to JPEG\n    - Use -png for PNG format\n- Document Processing:\n  1. antiword: Extract text from Word docs\n  2. unrtf: Convert RTF to text\n  3. catdoc: Extract text from Word docs\n\n### 4.1.2 TEXT & DATA PROCESSING\n- Text Processing:\n  1. grep: Pattern matching\n    - Use -i for case-insensitive\n    - Use -r for recursive search\n    - Use -A, -B, -C for context\n  2. awk: Column processing\n    - Use for structured data\n    - Use for data transformation\n  3. sed: Stream editing\n    - Use for text replacement\n    - Use for pattern matching\n- File Analysis:\n  1. file: Determine file type\n  2. wc: Count words/lines\n  3. head/tail: View file parts\n  4. less: View large files\n- Data Processing:\n  1. jq: JSON processing\n    - Use for JSON extraction\n    - Use for JSON transformation\n  2. csvkit: CSV processing\n    - csvcut: Extract columns\n    - csvgrep: Filter rows\n    - csvstat: Get statistics\n  3. xmlstarlet: XML processing\n    - Use for XML extraction\n    - Use for XML transformation\n\n## 4.2 REGEX & CLI DATA PROCESSING\n- CLI Tools Usage:\n  1. grep: Search files using regex patterns\n    - Use -i for case-insensitive search\n    - Use -r for recursive directory search\n    - Use -l to list matching files\n    - Use -n to show line numbers\n    - Use -A, -B, -C for context lines\n  2. head/tail: View file beginnings/endings\n    - Use -n to specify number of lines\n    - Use -f to follow file changes\n  3. awk: Pattern scanning and processing\n    - Use for column-based data processing\n    - Use for complex text transformations\n  4. find: Locate files and directories\n    - Use -name for filename patterns\n    - Use -type for file types\n  5. wc: Word count and line counting\n    - Use -l for line count\n    - Use -w for word count\n    - Use -c for character count\n- Regex Patterns:\n  1. Use for precise text matching\n  2. Combine with CLI tools for powerful searches\n  3. Save complex patterns to files for reuse\n  4. Test patterns with small samples first\n  5. Use extended regex (-E) for complex patterns\n- Data Processing Workflow:\n  1. Use grep to locate relevant files\n  2. Use head/tail to preview content\n  3. Use awk for data extraction\n  4. Use wc to verify results\n  5. Chain commands with pipes for efficiency\n\n## 4.3 DATA VERIFICATION & INTEGRITY\n- STRICT REQUIREMENTS:\n  * Only use data that has been explicitly verified through actual extraction or processing\n  * NEVER use assumed, hallucinated, or inferred data\n  * NEVER assume or hallucinate contents from PDFs, documents, or script outputs\n  * ALWAYS verify data by running scripts and tools to extract information\n\n- DATA PROCESSING WORKFLOW:\n  1. First extract the data using appropriate tools\n  2. Save the extracted data to a file\n  3. Verify the extracted data matches the source\n  4. Only use the verified extracted data for further processing\n  5. If verification fails, debug and re-extract\n\n- VERIFICATION PROCESS:\n  1. Extract data using CLI tools or scripts\n  2. Save raw extracted data to files\n  3. Compare extracted data with source\n  4. Only proceed with verified data\n  5. Document verification steps\n\n- ERROR HANDLING:\n  1. If data cannot be verified, stop processing\n  2. Report verification failures\n  3. **Use \'ask\' tool to request clarification if needed.**\n  4. Never proceed with unverified data\n  5. Always maintain data integrity\n\n- TOOL RESULTS ANALYSIS:\n  1. Carefully examine all tool execution results\n  2. Verify script outputs match expected results\n  3. Check for errors or unexpected behavior\n  4. Use actual output data, never assume or hallucinate\n  5. If results are unclear, create additional verification steps\n\n## 4.4 WEB SEARCH & CONTENT EXTRACTION\n- Research Best Practices:\n  1. ALWAYS use a multi-source approach for thorough research:\n    * Start with web-search to find direct answers, images, and relevant URLs\n    * Only use scrape-webpage when you need detailed content not available in the search results\n    * Utilize data providers for real-time, accurate data when available\n    * Only use browser tools when scrape-webpage fails or interaction is needed\n  2. Data Provider Priority:\n    * ALWAYS check if a data provider exists for your research topic\n    * Use data providers as the primary source when available\n    * Data providers offer real-time, accurate data for:\n      - LinkedIn data\n      - Twitter data\n      - Zillow data\n      - Amazon data\n      - Yahoo Finance data\n      - Active Jobs data\n    * Only fall back to web search when no data provider is available\n  3. Research Workflow:\n    a. First check for relevant data providers\n    b. If no data provider exists:\n      - Use web-search to to get direct answers, images, and relevant URLs\n      - Only if you need specific details not found in search results:\n          * Use scrape-webpage on specific URLs from web-search results\n      - Only if scrape-webpage fails or if the page requires interaction:\n      * Use browser tools via `browser-tool <action> [args...]` in execute-command\n      * This is needed for:\n        - Dynamic content loading\n        - JavaScript-heavy sites\n        - Pages requiring login\n        - Interactive elements\n        - Infinite scroll pages\n    c. Cross-reference information from multiple sources\n    d. Verify data accuracy and freshness\n    e. Document sources and timestamps\n\n- Web Search Best Practices:\n  1. Use specific, targeted questions to get direct answers from web-search\n  2. Include key terms and contextual information in search queries\n  3. Filter search results by date when freshness is important\n  4. Review the direct answer, images, and search results\n  5. Analyze multiple search results to cross-validate information\n\n- Web Content Extraction Workflow:\n  1. ALWAYS start with web-search to get direct answers, images, and search results\n  2. Only use scrape-webpage when you need:\n      - Complete article text beyond search snippets\n      - Structured data from specific pages\n      - Lengthy documentation or guides\n      - Detailed content across multiple sources\n  3. Never use scrape-webpage when:\n      - You can get the same information from a data provider\n      - You can download the file and directly use it like a csv, json, txt or pdf\n      - Web-search already answers the query\n      - Only basic facts or information are needed\n      - Only a high-level overview is needed\n  4. Only use browser tools if scrape-webpage fails or interaction is required\n      - Use browser tools via ` browser-tool <action> [args...]` in execute-command\n      - This is needed for:\n        * Dynamic content loading\n        * JavaScript-heavy sites\n        * Pages requiring login\n        * Interactive elements\n        * Infinite scroll pages\n      - DO NOT use browser tools directly unless scrape-webpage fails or interaction is required\n  5. Maintain this strict workflow order: web-search → scrape-webpage → direct browser tools (if needed)\n  6. If browser tools fail or encounter CAPTCHA/verification:\n      - Use web-browser-takeover to request user assistance\n      - Clearly explain what needs to be done (e.g., solve CAPTCHA)\n      - Wait for user confirmation before continuing\n      - Resume automated process after user completes the task\n\n- Web Content Extraction:\n  1. Verify URL validity before scraping\n  2. Extract and save content to files for further processing\n  3. Parse content using appropriate tools based on content type\n  4. Respect web content limitations - not all content may be accessible\n  5. Extract only the relevant portions of web content\n\n- Data Freshness:\n  1. Always check publication dates of search results\n  2. Prioritize recent sources for time-sensitive information\n  3. Use date filters to ensure information relevance\n  4. Provide timestamp context when sharing web search information\n  5. Specify date ranges when searching for time-sensitive topics\n\n- Results Limitations:\n  1. Acknowledge when content is not accessible or behind paywalls\n  2. Be transparent about scraping limitations when relevant\n  3. Use multiple search strategies when initial results are insufficient\n  4. Consider search result score when evaluating relevance\n  5. Try alternative queries if initial search results are inadequate\n\n- TIME CONTEXT FOR RESEARCH:\n  * CURRENT YEAR, DATE AND TIME: - Use terminal commands to get current year, date and time.\n  * CRITICAL: When searching for latest news or time-sensitive information, ALWAYS use these current date/time values as reference points. Never use outdated information or assume different dates.\n\n# 5. WORKFLOW MANAGEMENT\n\n## 5.1 AUTONOMOUS WORKFLOW SYSTEM\nYou operate through a self-maintained todo.md file that serves as your central source of truth and execution roadmap:\n\n1. Upon receiving a task, immediately create a lean, focused todo.md with essential sections covering the task lifecycle\n2. Each section contains specific, actionable subtasks based on complexity - use only as many as needed, no more\n3. Each task should be specific, actionable, and have clear completion criteria\n4. MUST actively work through these tasks one by one, checking them off as completed\n5. Adapt the plan as needed while maintaining its integrity as your execution compass\n\n## 5.2 TODO.MD FILE STRUCTURE AND USAGE\nThe todo.md file is your primary working document and action plan:\n\n1. Contains the complete list of tasks you MUST complete to fulfill the user\'s request\n2. Format with clear sections, each containing specific tasks marked with [ ] (incomplete) or [x] (complete)\n3. Each task should be specific, actionable, and have clear completion criteria\n4. MUST actively work through these tasks one by one, checking them off as completed\n5. Before every action, consult your todo.md to determine which task to tackle next\n6. The todo.md serves as your instruction set - if a task is in todo.md, you are responsible for completing it\n7. Update the todo.md as you make progress, adding new tasks as needed and marking completed ones\n8. Never delete tasks from todo.md - instead mark them complete with [x] to maintain a record of your work\n9. Once ALL tasks in todo.md are marked complete [x], you MUST call either the \'complete\' state or \'ask\' tool to signal task completion\n10. SCOPE CONSTRAINT: Focus on completing existing tasks before adding new ones; avoid continuously expanding scope\n11. CAPABILITY AWARENESS: Only add tasks that are achievable with your available tools and capabilities\n12. FINALITY: After marking a section complete, do not reopen it or add new tasks unless explicitly directed by the user\n13. STOPPING CONDITION: If you\'ve made 3 consecutive updates to todo.md without completing any tasks, reassess your approach and either simplify your plan or **use the \'ask\' tool to seek user guidance.**\n14. COMPLETION VERIFICATION: Only mark a task as [x] complete when you have concrete evidence of completion\n15. SIMPLICITY: Keep your todo.md lean and direct with clear actions, avoiding unnecessary verbosity or granularity\n\n## 5.3 EXECUTION PHILOSOPHY\nYour approach is deliberately methodical and persistent:\n\n1. Operate in a continuous loop until explicitly stopped\n2. Execute one step at a time, following a consistent loop: evaluate state → select tool → execute → provide narrative update → track progress\n3. Every action is guided by your todo.md, consulting it before selecting any tool\n4. Thoroughly verify each completed step before moving forward\n5. **Provide Markdown-formatted narrative updates directly in your responses** to keep the user informed of your progress, explain your thinking, and clarify the next steps. Use headers, brief descriptions, and context to make your process transparent.\n6. CRITICALLY IMPORTANT: Continue running in a loop until either:\n  - Using the **\'ask\' tool (THE ONLY TOOL THE USER CAN RESPOND TO)** to wait for essential user input (this pauses the loop)\n  - Using the \'complete\' tool when ALL tasks are finished\n7. For casual conversation:\n  - Use **\'ask\'** to properly end the conversation and wait for user input (**USER CAN RESPOND**)\n8. For tasks:\n  - Use **\'ask\'** when you need essential user input to proceed (**USER CAN RESPOND**)\n  - Provide **narrative updates** frequently in your responses to keep the user informed without requiring their input\n  - Use \'complete\' only when ALL tasks are finished\n9. MANDATORY COMPLETION:\n  - IMMEDIATELY use \'complete\' or \'ask\' after ALL tasks in todo.md are marked [x]\n  - NO additional commands or verifications after all tasks are complete\n  - NO further exploration or information gathering after completion\n  - NO redundant checks or validations after completion\n  - FAILURE to use \'complete\' or \'ask\' after task completion is a critical error\n\n## 5.4 TASK MANAGEMENT CYCLE\n1. STATE EVALUATION: Examine Todo.md for priorities, analyze recent Tool Results for environment understanding, and review past actions for context\n2. TOOL SELECTION: Choose exactly one tool that advances the current todo item\n3. EXECUTION: Wait for tool execution and observe results\n4. **NARRATIVE UPDATE:** Provide a **Markdown-formatted** narrative update directly in your response before the next tool call. Include explanations of what you\'ve done, what you\'re about to do, and why. Use headers, brief paragraphs, and formatting to enhance readability.\n5. PROGRESS TRACKING: Update todo.md with completed items and new tasks\n6. METHODICAL ITERATION: Repeat until section completion\n7. SECTION TRANSITION: Document completion and move to next section\n8. COMPLETION: IMMEDIATELY use \'complete\' or \'ask\' when ALL tasks are finished\n\n# 6. CONTENT CREATION\n\n## 6.1 WRITING GUIDELINES\n- Write content in continuous paragraphs using varied sentence lengths for engaging prose; avoid list formatting\n- Use prose and paragraphs by default; only employ lists when explicitly requested by users\n- All writing must be highly detailed with a minimum length of several thousand words, unless user explicitly specifies length or format requirements\n- When writing based on references, actively cite original text with sources and provide a reference list with URLs at the end\n- Focus on creating high-quality, cohesive documents directly rather than producing multiple intermediate files\n- Prioritize efficiency and document quality over quantity of files created\n- Use flowing paragraphs rather than lists; provide detailed content with proper citations\n- Strictly follow requirements in writing rules, and avoid using list formats in any files except todo.md\n\n## 6.2 DESIGN GUIDELINES\n- For any design-related task, first create the design in HTML+CSS to ensure maximum flexibility\n- Designs should be created with print-friendliness in mind - use appropriate margins, page breaks, and printable color schemes\n- After creating designs in HTML+CSS, convert directly to PDF as the final output format\n- When designing multi-page documents, ensure consistent styling and proper page numbering\n- Test print-readiness by confirming designs display correctly in print preview mode\n- For complex designs, test different media queries including print media type\n- Package all design assets (HTML, CSS, images, and PDF output) together when delivering final results\n- Ensure all fonts are properly embedded or use web-safe fonts to maintain design integrity in the PDF output\n- Set appropriate page sizes (A4, Letter, etc.) in the CSS using @page rules for consistent PDF rendering\n\n## Image Guidelines\n- ALWAYS use the Image Tool for image generation or image editing tasks\n- Write a single self-contained image prompt before calling the Image Tool\n- Clearly describe the main subject and overall composition\n- Explicitly specify the intended visual style and aesthetic\n- Provide exact text content if text is required; otherwise state “no text”\n- For image editing, clearly state what changes and what must remain unchanged\n- Request the image first if an edit is requested without a provided image\n- Ask clarification questions only when essential information is missing\n\n# 7. COMMUNICATION & USER INTERACTION\n\n## 7.1 CONVERSATIONAL INTERACTIONS\nFor casual conversation and social interactions:\n  - ALWAYS use **\'ask\'** tool to end the conversation and wait for user input (**USER CAN RESPOND**)\n  - NEVER use \'complete\' for casual conversation\n  - Keep responses friendly and natural\n  - Adapt to user\'s communication style\n  - Ask follow-up questions when appropriate (**using \'ask\'**)\n  - Show interest in user\'s responses\n\n## 7.2 COMMUNICATION PROTOCOLS\n- **Core Principle: Communicate proactively, directly, and descriptively throughout your responses.**\n\n- **Narrative-Style Communication:**\n  * Integrate descriptive Markdown-formatted text directly in your responses before, between, and after tool calls\n  * Use a conversational yet efficient tone that conveys what you\'re doing and why\n  * Structure your communication with Markdown headers, brief paragraphs, and formatting for enhanced readability\n  * Balance detail with conciseness - be informative without being verbose\n\n- **Communication Structure:**\n  * Begin tasks with a brief overview of your plan\n  * Provide context headers like `## Planning`, `### Researching`, `## Creating File`, etc.\n  * Before each tool call, explain what you\'re about to do and why\n  * After significant results, summarize what you learned or accomplished\n  * Use transitions between major steps or sections\n  * Maintain a clear narrative flow that makes your process transparent to the user\n\n- **Message Types & Usage:**\n  * **Direct Narrative:** Embed clear, descriptive text directly in your responses explaining your actions, reasoning, and observations\n  * **\'ask\' (USER CAN RESPOND):** Use ONLY for essential needs requiring user input (clarification, confirmation, options, missing info, validation). This blocks execution until user responds.\n  * Minimize blocking operations (\'ask\'); maximize narrative descriptions in your regular responses.\n- **Deliverables:**\n  * Attach all relevant files with the **\'ask\'** tool when asking a question related to them, or when delivering final results before completion.\n  * Always include representable files as attachments when using \'ask\' - this includes HTML files, presentations, writeups, visualizations, reports, and any other viewable content.\n  * For any created files that can be viewed or presented (such as index.html, slides, documents, charts, etc.), always attach them to the \'ask\' tool to ensure the user can immediately see the results.\n  * Share results and deliverables before entering complete state (use \'ask\' with attachments as appropriate).\n  * Ensure users have access to all necessary resources.\n\n- Communication Tools Summary:\n  * **\'ask\':** Essential questions/clarifications. BLOCKS execution. **USER CAN RESPOND.**\n  * **text via markdown format:** Frequent UI/progress updates. NON-BLOCKING. **USER CANNOT RESPOND.**\n  * Include the \'attachments\' parameter with file paths or URLs when sharing resources (works with both \'ask\').\n  * **\'complete\':** Only when ALL tasks are finished and verified. Terminates execution.\n\n- Tool Results: Carefully analyze all tool execution results to inform your next actions. **Use regular text in markdown format to communicate significant results or progress.**\n\n## 7.3 ATTACHMENT PROTOCOL\n- **CRITICAL: ALL VISUALIZATIONS MUST BE ATTACHED:**\n  * When using the \'ask\' or \'complete\' tool, ALWAYS attach ALL visualizations, markdown files, charts, graphs, reports, and any viewable content created.\n  * This includes but is not limited to: HTML files, PDF documents, markdown files, images, data visualizations, presentations, reports, dashboards, UI mockups and externally accessible results.\n  * NEVER mention a visualization or viewable content without attaching it\n  * If you\'ve created multiple visualizations, attach ALL of them\n  * Always make visualizations available to the user BEFORE marking tasks as complete\n  * For web applications or interactive content, always attach the main HTML file\n  * When creating data analysis results, charts must be attached, not just described\n  * Remember: If the user should SEE it, you must ATTACH it with the \'ask\' or \'complete\' tool\n  * Verify that ALL visual outputs have been attached before proceeding\n\n- **Attachment Checklist:**\n  * Data visualizations (charts, graphs, plots)\n  * Web interfaces (HTML/CSS/JS files)\n  * Reports and documents (PDF, HTML)\n  * Presentation materials\n  * Images and diagrams\n  * Interactive dashboards\n  * Analysis results with visual components\n  * UI designs and mockups\n  * Any file intended for user viewing or interaction\n\n\n# 8. COMPLETION PROTOCOLS\n\nCRITICAL: Every final response MUST use the \'ask\' or \'complete\' tool call, regardless of whether todo.md is used, plain text responses are NOT valid. All generated files and URLs MUST be included in the \'attachments\' and \'urls\' attributes respectively.\n\n## 8.1 TERMINATION RULES\n- IMMEDIATE COMPLETION:\n  * As soon as ALL tasks in todo.md are marked [x], you MUST use \'complete\' or \'ask\'\n  * No additional commands or verifications are allowed after completion\n  * No further exploration or information gathering is permitted\n  * No redundant checks or validations are needed\n\n- COMPLETION VERIFICATION:\n  * Verify task completion only once\n  * If all tasks are complete, immediately use \'complete\' or \'ask\'\n  * Do not perform additional checks after verification\n  * Do not gather more information after completion\n\n- COMPLETION TIMING:\n  * Use \'complete\' or \'ask\' immediately after the last task is marked [x]\n  * No delay between task completion and tool call\n  * No intermediate steps between completion and tool call\n  * No additional verifications between completion and tool call\n\n- COMPLETION CONSEQUENCES:\n  * Failure to use \'complete\' or \'ask\' after task completion is a critical error\n  * The system will continue running in a loop if completion is not signaled\n  * Additional commands after completion are considered errors\n  * Redundant verifications after completion are prohibited\n\n# 9. PRODUCT QUESTIONS (AUTHORITATIVE SOURCES)\n\nFor questions about SuperNinja or NinjaTech products that require accurate, official, or policy-level information and are likely covered in the official FAQ,\ntreat the request as an authoritative lookup task.\n\nUse https://www.ninjatech.ai/faq as the primary source (prefer using `scrape-webpage`).\nFor pricing or plans, https://www.ninjatech.ai/pricing may be used as a secondary reference.\nDo not guess or fabricate answers. If the information is not found, state that clearly.\n\n# 10. EXTERNAL SERVICE TOOLS (e.g. **Slack**, **Jira**, **Salesforce**, **Google Calendar**, **Gmail**, **Figma**, **Notion**)\n\nIf the user wants to interact with external services like **Slack**, **Jira**, **Salesforce**, **Google Calendar**, **Gmail**, **Figma**, or **Notion**, use the `mcp-tools` command:\n1. First, list available services: `mcp-tools services`\n   - This only shows services that are currently connected and running\n   - If the desired service is not listed, inform the user it\'s not available\n2. Then list tools for the relevant service: `mcp-tools list <service_name>`\n3. Finally, call the appropriate tool: `mcp-tools call <tool_name> \'<json_args>\'`\n\nIMPORTANT: ALWAYS follow this sequence - services → list tools → call tool. Never assume a service is available without checking first.\n\n\n# 11. BROWSER AUTOMATION TOOLS\n\n- BROWSER CONTROL: All browser interaction goes through `browser-tool <action> [args...]` via `execute-command`.\n  * The browser (Chromium) is already running. Each command connects, acts, observes, and disconnects.\n\n- WORKFLOW (observe-act loop):\n  1. Run an action (e.g. navigate, click, fill). The tool automatically observes the page after every action.\n  2. Read the output: URL, title, interactive elements list, accessibility tree, and screenshot path.\n  3. Reference elements by their `[index]` number from the elements list (e.g. `click "[3]"`).\n  4. Use `see-image` on the screenshot path when you need to verify visual layout or images.\n\n- AVAILABLE COMMANDS:\n  * `observe` - View current page state without acting\n  * `navigate <url>` - Go to a URL\n  * `click <selector>` - Click an element (use `[N]` for element index, or CSS selector)\n  * `fill <selector> <text>` - Clear a field and fill it with text\n  * `type <selector> <text>` - Type text character by character\n  * `press <key>` - Press a key (Enter, Tab, Escape, etc.)\n  * `select <selector> <value>` - Select a dropdown option\n  * `scroll_down [px]` / `scroll_up [px]` - Scroll (default 500px)\n  * `scroll_to_text <text>` - Scroll until text is visible\n  * `go_back` - Navigate back\n  * `wait [seconds]` - Wait (default 2s)\n  * `extract_text [selector]` - Extract text content from page or element\n  * `extract_links [selector]` - Extract all links\n  * `screenshot [filename]` - Take a manual screenshot\n  * `dismiss_overlay` - Dismiss cookie banners or modals\n  * `js <script>` - Execute JavaScript on the page\n\n- CAPTCHA / HUMAN ASSISTANCE: If you encounter a CAPTCHA, verification, or any situation where automated interaction is stuck, MUST use `web-browser-takeover` to hand control to the user.\n\n# 12. CHAT MODE\n\nYou should check the **latest** user message to check if chat mode is enabled. If the user is using "/chat" tag in the latest message, that means the chat mode is activated and the user wants you to use **ONLY** <ask> tool in your **IMMEDIATE** response to that specific query. No other tools are allowed in the response right after the query with "/chat". If the latest user\'s input doesn\'t contain "/chat" - you are in **agentic** mode, you can use all other tools as well.\n\nIMPORTANT:\n- if the user is asking to use other tools while in chat mode - ask the user to disable chat mode first. Do not use any other tools.\n- if the task user sends requires using other than <ask> tools - tell the user to disable chat mode first. Do not tell the user about the <ask> tool, but you can mention to the user what kind of tools you can use in agentic mode to solve the user\'s task (after the user disables the chat mode).\n- to disable the chat mode the user should switch the toggle in the bottom left of the text input area in the UI. "/chat" tag is being added automatically when the toggle is in chat mode position.\n- pay attention only to the latest user\'s input. If there is no "/chat" tag in the latest input - you are allowed to use all the tools.\n\n--- XML TOOL CALLING ---\n\nIn this environment you have access to a set of tools you can use to answer the user\'s question. The tools are specified in XML format.\nFormat your tool calls using the specified XML tags. Place parameters marked as \'attribute\' within the opening tag (e.g., `<tag attribute=\'value\'>`). Place parameters marked as \'content\' between the opening and closing tags. Place parameters marked as \'element\' within their own child tags (e.g., `<tag><element>value</element></tag>`). Refer to the examples provided below for the exact structure of each tool.\nString and scalar parameters should be specified as attributes, while content goes between tags.\nNote that spaces for string values are not stripped. The output is parsed with regular expressions.\nIMPORTANT: All tool calls MUST be wrapped in <function_calls> and </function_calls> tags.\n\nHere are the XML tools available with examples:\n<slides-generation-mode>\nExample: \n        <!-- Activate slides generation mode in case the user is asking to create slides -->\n        <function_calls>\n        <slides-generation-mode>\n        </slides-generation-mode>\n        </function_calls>\n        \n<transcribe-audio>\nExample: \n        <function_calls>\n        <!-- Example: Request to transcribe an audio file named \'audio.mp3\' inside the \'audios\' folder -->\n        <transcribe-audio file_path="audios/audio.mp3"></transcribe-audio>\n        </function_calls>\n        \n<edit-image>\nExample: \n        <!-- Edit an existing image -->\n        <function_calls>\n        <edit-image\n            file_path="docs/diagram.png"\n            size="1024x1024"\n            n="1">\n        Edit instructions:\n        - Remove the background and replace it with a pure white background.\n        - Keep the main subject unchanged.\n        - Improve sharpness slightly, avoid over-smoothing.\n        - Do not add any text or watermark.\n        </edit-image>\n        </function_calls>\n\n        <!-- Edit can be also helpful in creating images similar to the reference image (image to edit), for example when creating slides and set of icons, infographics to maintain same objects or styles on different images. -->\n        <function_calls>\n        <edit-image\n            file_path="docs/diagram.png"\n            size="1536x1024"\n            n="2">\n        Create similar to the reference image following the instructions:\n        - Similar colours, layout, style, but about different object\n        - The same object as on the provided image, but in different color, style.\n        </edit-image>\n        </function_calls>\n        \n<generate-image>\nExample: \n        <!--\n        Generate a new image from a text prompt.\n        When generating images pay attention to allowed sizes (especially when doing slides, presentations). Possible sizes are: "1024x1024", "1536x1024", "1024x1536"\n        -->\n        <function_calls>\n        <generate-image\n            size="1024x1024"\n            n="1">\n        A clean, modern product hero image of a sleek smart speaker on a wooden desk, minimal composition, soft natural lighting, no watermark, no text.\n        </generate-image>\n        </function_calls>\n\n        <!-- Generate multiple variants -->\n        <function_calls>\n        <generate-image\n            size="1536x1024"\n            n="3">\n        A simple flat-style illustration of a kangaroo holding a laptop, friendly corporate tone, minimal shapes, high contrast, no text.\n        </generate-image>\n        </function_calls>\n        \n<see-image>\nExample: \n        <!-- Example: Request to see an image named \'diagram.png\' inside the \'docs\' folder -->\n        <function_calls>\n        <see-image file_path="docs/diagram.png">\n        </see-image>\n        </function_calls>\n        \n<transcribe-youtube>\nExample: \n        <function_calls>\n        <transcribe-youtube url="https://www.youtube.com/watch?v=video_id">\n        </transcribe-youtube>\n        </function_calls>\n        \n<execute-command>\nExample: \n        <!-- BLOCKING COMMANDS (Direct Execution) -->\n        <!-- Example 1: Basic Command Execution -->\n        <function_calls>\n        <execute-command>\n        ls -la\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 2: Running in Specific Directory -->\n        <function_calls>\n        <execute-command folder="src">\n        npm install\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 3: Long-running Process with Extended Timeout -->\n        <function_calls>\n        <execute-command timeout="300">\n        npm run build\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 4: Complex Command with Environment Variables -->\n        <function_calls>\n        <execute-command>\n        export NODE_ENV=production && npm run preview\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 5: Command with Output Redirection -->\n        <function_calls>\n        <execute-command>\n        npm run build > build.log 2>&1\n        </execute-command>\n        </function_calls>\n\n        <!-- NON-BLOCKING COMMANDS (Background Execution) -->\n        <!-- Example 1: Run a HTTP server -->\n        <function_calls>\n        <execute-command blocking="false">\n        python -m http.server 8050\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 2: Run a long-running java program -->\n        <function_calls>\n        <execute-command blocking="false">\n        java -jar target/app.jar\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 3: Start a Vite Development Server -->\n        <function_calls>\n        <execute-command blocking="false">\n        cd /workspace && npm run dev\n        </execute-command>\n        </function_calls>\n\n        <!-- Example 4: Start a Vite Build Process -->\n        <function_calls>\n        <execute-command blocking="false">\n        tmux new-session -d -s vite_build "cd /workspace && npm run build"\n        </execute-command>\n        </function_calls>\n        \n<create-file>\nExample: \n        <function_calls>\n        <create-file file_path="src/main.py">\n        # This is the file content\n        def main():\n            print("Hello, World!")\n        if __name__ == "__main__":\n            main()\n        </create-file>\n        </function_calls>\n        \n<delete-file>\nExample: \n        <function_calls>\n        <delete-file file_path="src/main.py">\n        </delete-file>\n        </function_calls>\n        \n<full-file-rewrite>\nExample: \n        <function_calls>\n        <full-file-rewrite file_path="src/main.py">\n        This completely replaces the entire file content.\n        Use when making major changes to a file or when the changes are too extensive for str-replace.\n        All previous content will be lost and replaced with this text.\n        </full-file-rewrite>\n        </function_calls>\n        \n<str-replace>\nExample: \n        <function_calls>\n        <str-replace file_path="src/main.py">\n            <old_str>text to replace (must appear exactly once in the file)</old_str>\n            <new_str>replacement text that will be inserted instead</new_str>\n        </str-replace>\n        </function_calls>\n        \n<ask>\nExample: \n        Ask user a question and wait for response. Use this tool when user input is required to proceed, including: 1) Clarifying ambiguous requirements, 2) Confirming high-impact changes, 3) Gathering missing or critical information, 4) Offering options and requesting user preference, 5) Validating assumptions that affect task success.\n\n        IMPORTANT:\n        - Use this tool only when user input, review, or confirmation is required.\n        - Provide clear context and concrete options whenever applicable.\n        - When this tool is used at the end of a task, it represents the final delivery point for all user-facing results produced so far.\n        - All generated files MUST be in the \'attachments\' attribute and all generated URLs MUST be in the \'urls\' attribute. The first element in the attachment list should be the most important artifact.\n\n        <function_calls>\n        <ask attachments="recipes/chocolate_cake.txt,photos/cake_examples.jpg" urls="https://example-link">\n            I\'m planning to bake the chocolate cake for your birthday party. The recipe mentions "rich frosting" but doesn\'t specify what type. Could you clarify your preferences? For example:\n            1. Would you prefer buttercream or cream cheese frosting?\n            2. Do you want any specific flavor added to the frosting (vanilla, coffee, etc.)?\n            3. Should I add any decorative toppings like sprinkles or fruit?\n            4. Do you have any dietary restrictions I should be aware of?\n\n            This information will help ensure the final result meets your expectations.\n        </ask>\n        </function_calls>\n        \n<complete>\nExample: \n        Use this tool only when all tasks are fully finished and no user input is required, including: 1) the user\'s original request has been fully addressed, 2) All required tasks and validations are completed, 3) All outputs and results are ready for delivery, 4) There are no pending actions or follow-ups.\n\n        IMPORTANT:\n        - This tool represents the authoritative final output of the session.\n        - All final user-facing results must be delivered when this tool is used. All generated files MUST be in the \'attachments\' attribute and all generated URLs MUST be in the \'urls\' attribute.\n\n        <function_calls>\n        <complete attachments="output.txt" urls="https://example-link">\n            The task has been completed successfully.\n            All final results are included above.\n        </complete>\n        </function_calls>\n        \n<web-browser-takeover>\nExample: \n        <function_calls>\n        <web-browser-takeover>\n            I\'ve encountered a CAPTCHA verification on the page. Please solve it and let me know when you\'re done.\n        </web-browser-takeover>\n        </function_calls>\n        \n<scrape-webpage>\nExample: \n        <!--\n        The scrape-webpage tool extracts the complete text content from web pages using Firecrawl.\n        IMPORTANT WORKFLOW RULES:\n        1. ALWAYS use web-search first to find relevant URLs\n        2. Then use scrape-webpage on URLs from web-search results\n        3. Only if scrape-webpage fails or if the page requires interaction:\n           - Use `browser-tool <action> [args...]` via execute-command\n           - This is needed for dynamic content, JavaScript-heavy sites, or pages requiring interaction\n\n        Firecrawl Features:\n        - Converts web pages into clean markdown\n        - Handles dynamic content and JavaScript-rendered sites\n        - Manages proxies, caching, and rate limits\n        - Supports PDFs and images\n        - Outputs clean markdown\n        -->\n\n        <!-- Example workflow: -->\n        <!-- 1. First search for relevant content -->\n        <function_calls>\n        <web-search query="latest AI research papers" num_results="5">\n        </web-search>\n        </function_calls>\n\n        <!-- 2. Then scrape specific URLs from search results -->\n        <function_calls>\n        <scrape-webpage url="https://example.com/research/ai-paper-2024">\n        </scrape-webpage>\n        </function_calls>\n        \n<web-search>\nExample: \n        <!--\n        The web-search tool allows you to search the internet for real-time information.\n        Use this tool when you need to find current information, research topics, or verify facts.\n\n        The tool returns information including:\n        - Titles of relevant web pages\n        - URLs for accessing the pages\n        - Published dates (when available)\n        -->\n\n        <!-- Simple search example -->\n        <function_calls>\n        <web-search query="current weather in New York City" num_results="20">\n        </web-search>\n        </function_calls>\n\n        <!-- Another search example -->\n        <function_calls>\n        <web-search query="current weather in New York City" num_results="20">\n        </web-search>\n        </function_calls>\n        \n<expose-port>\nExample: \n        <!-- Example 1: Expose a web server running on port 80 -->\n        <!-- This will generate a public URL that users can access to view the web application -->\n        <function_calls>\n        <expose-port>\n        80\n        </expose-port>\n        </function_calls>\n\n        <!-- Example 2: Expose an API service running on port 3000 -->\n        <!-- This allows users to interact with the API endpoints from their browser -->\n        <function_calls>\n        <expose-port>\n        3000\n        </expose-port>\n        </function_calls>\n\n        <!-- Example 3: Expose a development server running on port 5173 -->\n        <!-- This is useful for sharing a development environment with users -->\n        <function_calls>\n        <expose-port>\n        5173\n        </expose-port>\n        </function_calls>\n        \n<deploy>\nExample: \n        <!--\n        IMPORTANT: Only use this tool when:\n        1. The user explicitly requests permanent deployment to production\n        2. You have a complete, ready-to-deploy directory\n\n        NOTE: If the same name is used, it will redeploy to the same project as before\n        -->\n\n        <function_calls>\n        <deploy name="my-site" directory_path="website">\n        </deploy>\n        </function_calls>\n\n        <!-- Example: Deploy a website with a custom homepage file -->\n        <function_calls>\n        <deploy name="customer-portal" directory_path="customer-dashboard" homepage_filename="dashboard.html">\n        </deploy>\n        </function_calls>\n        \n'}
{'role': 'user', 'content': 'Do tool calling warmup'}
{'role': 'assistant', 'content': 'Let me create an empty todo file to use further as a warmup.\n<function_calls>\n<create-file file_path="todo.md">\n\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': 'This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.\n\nAnalysis:\nLet me analyze the conversation chronologically to capture all important details:\n\n1. Initial Context:\n- The conversation started with a context continuation from a previous session that ran out of context\n- The summary indicated building "SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)"\n- This is a comprehensive enterprise software system with 27+ core modules\n\n2. Technical Stack Established:\n- Backend: FastAPI (Python)\n- Frontend: Next.js (React)\n- Database: PostgreSQL\n- Cache/Event Bus: Redis\n- APIs: REST + GraphQL\n- Infrastructure: Docker + Kubernetes\n- Architecture: DDD, Modular monolith, Event-driven, CQRS-compatible\n\n3. Files Already Created (from previous session):\n- Backend core: config.py, database.py, redis_client.py, security.py, events.py, exceptions.py\n- Models: base.py, company.py, user.py, accounting.py, treasury.py, invoice.py, hr.py, tax.py, workflow.py, legal.py, reports.py, consolidation.py, asset.py, ai.py\n- Schemas: base.py (and several others)\n\n4. My Actions in This Session:\n- Checked todo.md and verified existing schema files\n- Updated todo.md to reflect actual progress\n- Created backend/app/schemas/reports.py - Reports and dashboard schemas\n- Created backend/app/schemas/consolidation.py - Consolidation engine schemas\n- Created backend/app/schemas/asset.py - Fixed asset registry schemas\n- Created backend/app/schemas/ai.py - AI and analytics schemas\n- Created backend/app/schemas/__init__.py - Export all schemas\n- Updated todo.md to mark Phase 1.5 complete and add Phase 1.6 for repositories\n- Created backend/app/repositories/base.py - Base repository with CRUD operations\n- Created backend/app/repositories/company.py - Company repositories\n- Created backend/app/repositories/user.py - User repositories\n\n5. User Messages:\n- "Do tool calling warmup" (initial)\n- Context continuation message with detailed requirements\n- "Please continue where you left off."\n\n6. Current Work:\n- Just finished creating user repository with comprehensive user management and authentication functions\n- Was in the middle of creating repository layer for data access\n\n7. No errors encountered - all files created successfully\n\n8. Pending Work from todo.md:\n- Still need to create more repositories: Account, Journal entry, Treasury, Invoice, HR, Tax, Workflow, Legal, Reports, Consolidation, Asset, AI\n- Then services layer, API endpoints, frontend, tests, infrastructure configs\n\n\n\n\nSummary:\n1. Primary Request and Intent:\n   The user requested building a complete enterprise-grade software system called "SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)" with:\n   - 27 core modules including Company Management, Accounting (double-entry), Treasury, HR/Payroll, Tax Engine, Legal/Contracts, Workflow Engine, Consolidation, AI/Analytics, etc.\n   - Full ERP functionality with CRUD operations on all pages\n   - Multi-company hierarchy with holding/subsidiary support\n   - AI-driven features: anomaly detection, cash flow forecasting, contract analysis, recommendations\n   - Visual workflow builder with triggers like "invoice overdue → send email"\n   - Fixed Asset Registry with depreciation and automated journal entries\n   - Tax nexus engine with cross-jurisdictional calculations\n   - Intercompany reconciliation with automatic matching entries\n   - PDF report generation for financial statements\n   - World-class UI/UX with Command Center, Dashboard Builder, AI Copilot\n   - Full security: JWT, RBAC+ABAC, field-level permissions, audit logs\n   - Event-driven architecture with versioning/time machine\n   - Zero stats throughout the app initially\n   \n   User explicitly stated: "Generate EVERY file sequentially... Each file MUST include: full imports, full implementation, no placeholders"\n\n2. Key Technical Concepts:\n   - FastAPI (Python) backend\n   - Next.js (React) frontend\n   - PostgreSQL database with SQLAlchemy async\n   - Redis for caching and event bus\n   - REST + GraphQL APIs\n   - Domain-Driven Design (DDD)\n   - Event-driven architecture with event sourcing\n   - CQRS-compatible design\n   - JWT authentication with RBAC/ABAC\n   - Double-entry bookkeeping\n   - Multi-tenancy with company scoping\n   - Soft delete and versioning patterns\n   - AI/ML integration for anomaly detection and forecasting\n   - Pydantic v2 for schema validation\n   - Generic repository pattern with type hints\n\n3. Files and Code Sections:\n\n   - **todo.md** - Task tracking file updated multiple times\n     - Tracks all phases of development\n     - Phase 1.5 (Schemas) marked complete\n     - Phase 1.6 (Repositories) added\n\n   - **backend/app/schemas/reports.py** - Reports & Dashboard schemas (created)\n     - Report templates, parameters, schedules\n     - Dashboard widgets, KPIs\n     - Export formats, chart configurations\n     - ~1000+ lines of comprehensive schemas\n\n   - **backend/app/schemas/consolidation.py** - Consolidation Engine schemas (created)\n     - Intercompany transactions and matching\n     - Elimination entries and adjustments\n     - Consolidation worksheets and runs\n     - Minority interest, currency translation\n     - ~1100+ lines\n\n   - **backend/app/schemas/asset.py** - Fixed Asset Registry schemas (created)\n     - Asset classes and locations\n     - Fixed assets with depreciation schedules\n     - Asset transfers, disposals, revaluations, impairments\n     - Maintenance records and insurance\n     - ~1200+ lines\n\n   - **backend/app/schemas/ai.py** - AI & Analytics schemas (created)\n     - AI model configurations and metrics\n     - Anomaly detection configs and detected anomalies\n     - Forecasting configurations and runs\n     - AI insights, recommendations, alerts\n     - Document analysis, NL commands, explainability\n     - ~1300+ lines\n\n   - **backend/app/schemas/__init__.py** - Schema exports (created)\n     - Exports all schemas from all modules\n     - Comprehensive __all__ list\n\n   - **backend/app/repositories/base.py** - Base repository (created)\n     - Generic BaseRepository with CRUD operations\n     - Methods: create, get_by_id, update, delete (soft/hard), restore\n     - list_all, count, exists, search, bulk operations\n     - get_or_create, update_or_create, paginate\n     - CompanyScopedRepository for company-filtered queries\n     ```python\n     class BaseRepository(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):\n         def __init__(self, model: Type[ModelType], session: AsyncSession):\n             self.model = model\n             self.session = session\n         \n         async def create(self, data: CreateSchemaType, created_by_id: Optional[int] = None) -> ModelType:\n         async def get_by_id(self, id: int, load_relationships: Optional[List[str]] = None) -> Optional[ModelType]:\n         async def update(self, id: int, data: UpdateSchemaType, updated_by_id: Optional[int] = None) -> Optional[ModelType]:\n         async def delete(self, id: int, deleted_by_id: Optional[int] = None) -> bool:\n         # ... many more methods\n     ```\n\n   - **backend/app/repositories/company.py** - Company repositories (created)\n     - CompanyGroupRepository, CompanyRepository\n     - CompanySettingRepository, CompanyDocumentRepository\n     - Hierarchy management, consolidation tree\n     - Statistics and search functionality\n\n   - **backend/app/repositories/user.py** - User repositories (created)\n     - PermissionRepository, RoleRepository, UserRepository\n     - UserSessionRepository, UserActivityLogRepository\n     - Authentication, password management\n     - Role and permission assignment\n     - Session management and activity logging\n     ```python\n     async def authenticate(self, username: str, password: str) -> Optional[User]:\n         """Authenticate a user by username/email and password"""\n         query = select(User).where(\n             or_(User.username == username, User.email == username),\n             User.is_deleted == False\n         )\n         # ... verification logic\n     ```\n\n4. Errors and fixes:\n   - No errors were encountered during this session. All files were created successfully.\n\n5. Problem Solving:\n   - Successfully designed comprehensive Pydantic schemas covering multiple business domains\n   - Implemented proper validation patterns using Pydantic v2 validators\n   - Created consistent schema patterns (Base, Create, Update, Response, ListResponse)\n   - Designed generic repository pattern with company scoping support\n   - Implemented soft delete, eager loading, and pagination patterns\n\n6. All user messages:\n   - "Do tool calling warmup"\n   - [Context continuation message with detailed system requirements from previous session]\n   - "Please continue where you left off."\n\n7. Pending Tasks:\n   From todo.md Phase 1.6 - Backend Repositories:\n   - [ ] Account repository\n   - [ ] Journal entry repository\n   - [ ] Treasury repository\n   - [ ] Invoice repository\n   - [ ] HR repository\n   - [ ] Tax repository\n   - [ ] Workflow repository\n   - [ ] Legal repository\n   - [ ] Reports repository\n   - [ ] Consolidation repository\n   - [ ] Asset repository\n   - [ ] AI repository\n   - [ ] Repositories __init__.py\n   \n   Remaining phases still to complete:\n   - Phase 2: Core Backend Modules (services layer)\n   - Phase 3: Frontend UI/UX System\n   - Phase 4: AI System\n   - Phase 5: Testing & DevOps\n   - Phase 6: Final Verification\n\n8. Current Work:\n   Just completed creating `backend/app/repositories/user.py` with comprehensive user management and authentication functionality. Was working on Phase 1.6 (Backend Repositories) after completing Phase 1.5 (Backend Schemas).\n   \n   The most recent work created:\n   - Base repository with generic CRUD operations\n   - Company repositories (CompanyGroupRepository, CompanyRepository, CompanySettingRepository, CompanyDocumentRepository)\n   - User repositories (PermissionRepository, RoleRepository, UserRepository, UserSessionRepository, UserActivityLogRepository)\n\n9. Optional Next Step:\n   Continue creating the remaining repository files for Phase 1.6. The next repository to create would be the Account repository for the accounting module, following the pattern established in base.py.\n   \n   From the todo.md update:\n   ```\n   ## Phase 1.6: Backend Repositories (Data Access Layer)\n   - [x] Base repository\n   - [x] Company repository\n   - [x] User repository\n   - [ ] Account repository\n   - [ ] Journal entry repository\n   ...\n   ```\n\n\nIf you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: /workspace/summarized_conversations/original_conversation_1775260827_9232.txt'}
{'role': 'assistant', 'content': 'Let me check the current state of the project and continue from where I left off.\n\n<function_calls>\n<execute-command>\nls -la backend/app/repositories/\n</execute-command>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <execute-command> ToolResult(success=True, output=\'{\\n  "output": "total 76\\\\ndrwxr-xr-x  2 root root  4096 Apr  3 23:59 .\\\\ndrwxr-xr-x 13 root root  4096 Apr  1 20:24 ..\\\\n-rw-r--r--  1 root root 22634 Apr  3 23:54 base.py\\\\n-rw-r--r--  1 root root 17761 Apr  3 23:56 company.py\\\\n-rw-r--r--  1 root root 24403 Apr  3 23:59 user.py\\\\n",\\n  "exit_code": 0,\\n  "cwd": "/workspace"\\n}\') </execute-command> </tool_result>'}
{'role': 'assistant', 'content': 'Let me check the todo.md and continue creating the remaining repositories.\n\n\n<function_calls>\n<execute-command>\ncat todo.md\n</execute-command>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <execute-command> ToolResult(success=True, output=\'{\\n  "output": "# SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM - BUILD TRACKER\\\\n\\\\n## Phase 1: Project Setup & Infrastructure\\\\n- [x] Create folder structure\\\\n- [x] Backend core setup (FastAPI)\\\\n- [ ] Frontend core setup (Next.js)\\\\n- [x] Database configuration\\\\n- [ ] Docker & Kubernetes configs\\\\n\\\\n## Phase 1.5: Backend Schemas (Pydantic)\\\\n- [x] Base schemas\\\\n- [x] Company schemas\\\\n- [x] User schemas\\\\n- [x] Accounting schemas\\\\n- [x] Treasury schemas\\\\n- [x] Invoice schemas\\\\n- [x] HR schemas\\\\n- [x] Tax schemas\\\\n- [x] Workflow schemas\\\\n- [x] Legal schemas\\\\n- [x] Reports schemas\\\\n- [x] Consolidation schemas\\\\n- [x] Asset schemas\\\\n- [x] AI schemas\\\\n- [x] Schemas __init__.py\\\\n\\\\n## Phase 1.6: Backend Repositories (Data Access Layer)\\\\n- [ ] Base repository\\\\n- [ ] Company repository\\\\n- [ ] User repository\\\\n- [ ] Account repository\\\\n- [ ] Journal entry repository\\\\n- [ ] Treasury repository\\\\n- [ ] Invoice repository\\\\n- [ ] HR repository\\\\n- [ ] Tax repository\\\\n- [ ] Workflow repository\\\\n- [ ] Legal repository\\\\n- [ ] Reports repository\\\\n- [ ] Consolidation repository\\\\n- [ ] Asset repository\\\\n- [ ] AI repository\\\\n- [ ] Repositories __init__.py\\\\n\\\\n## Phase 2: Core Backend Modules\\\\n- [ ] Company Management\\\\n- [ ] Dynamic Schema Builder\\\\n- [ ] Organizational Structure Engine\\\\n- [ ] Accounting System (double-entry)\\\\n- [ ] Treasury + Banking\\\\n- [ ] Revenue + Billing\\\\n- [ ] HR + Payroll\\\\n- [ ] Tax Engine\\\\n- [ ] Legal + Contract Lifecycle Management\\\\n- [ ] Governance + Policy Engine\\\\n- [ ] Workflow + Automation Engine\\\\n- [ ] Consolidation Engine\\\\n- [ ] Integration Hub\\\\n- [ ] Document + Data Room System\\\\n- [ ] Analytics + AI Engine\\\\n- [ ] Permissions + Security\\\\n- [ ] Event System\\\\n- [ ] Versioning + Time Machine\\\\n- [ ] Plugin System\\\\n- [ ] Simulation Engine\\\\n- [ ] Internal Marketplace\\\\n- [ ] Dashboard System\\\\n- [ ] Audit System\\\\n- [ ] Feature Flag System\\\\n- [ ] Localization\\\\n- [ ] SDK Generator\\\\n- [ ] CLI / Admin Terminal\\\\n- [ ] Reports Module\\\\n- [ ] Fixed Asset Registry\\\\n- [ ] Cash Flow Forecasting\\\\n- [ ] Tax Nexus Engine\\\\n- [ ] Intercompany Reconciliation\\\\n\\\\n## Phase 3: Frontend UI/UX System\\\\n- [ ] Command Center Dashboard\\\\n- [ ] Global Search + Command Palette\\\\n- [ ] Company Switcher\\\\n- [ ] Action-based UI\\\\n- [ ] Embedded AI Copilot\\\\n- [ ] Drag-and-drop Dashboard Builder\\\\n- [ ] Workflow Builder (visual)\\\\n- [ ] Smart Forms System\\\\n- [ ] Decision Engine UI\\\\n- [ ] Company Graph Visualization\\\\n- [ ] Notification System\\\\n- [ ] Time Machine UI\\\\n- [ ] Permission Visualizer\\\\n- [ ] Sandbox / Simulation Mode\\\\n- [ ] Internal App Builder\\\\n\\\\n## Phase 4: AI System\\\\n- [ ] Natural language commands\\\\n- [ ] Anomaly detection\\\\n- [ ] Forecasting\\\\n- [ ] Decision recommendations\\\\n- [ ] Explainability layer\\\\n- [ ] Contract analysis tool\\\\n\\\\n## Phase 5: Testing & DevOps\\\\n- [ ] Unit tests\\\\n- [ ] Integration tests\\\\n- [ ] Frontend tests\\\\n- [ ] CI/CD pipelines\\\\n\\\\n## Phase 6: Final Verification\\\\n- [ ] Verify all modules complete\\\\n- [ ] Verify all CRUD operations\\\\n- [ ] Verify all integrations\\\\n- [ ] Final system test",\\n  "exit_code": 0,\\n  "cwd": "/workspace"\\n}\') </execute-command> </tool_result>'}
{'role': 'assistant', 'content': 'I see the repositories are created but not marked complete in todo.md. Let me update the todo.md to reflect actual progress and continue creating the remaining repositories.\n\n<function_calls>\n<str-replace file_path="todo.md">\n<old_str>## Phase 1.6: Backend Repositories (Data Access Layer)\n- [ ] Base repository\n- [ ] Company repository\n- [ ] User repository\n- [ ] Account repository</old_str>\n<new_str>## Phase 1.6: Backend Repositories (Data Access Layer)\n- [x] Base repository\n- [x] Company repository\n- [x] User repository\n- [ ] Account repository</new_str>\n</str-replace>\n</function_calls>'}
{'role': 'user', 'content': "<tool_result> <str-replace> ToolResult(success=True, output='Replacement successful.') </str-replace> </tool_result>"}
{'role': 'assistant', 'content': 'Now let me continue creating the Account repository for the accounting module. This is a critical component for the double-entry accounting system.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/account.py">\n"""\nAccount Repository - Data Access Layer for Chart of Accounts and Accounting Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple, TypeVar, Generic\nfrom datetime import date, datetime\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal, \n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager, \n    aliased, with_loader_criteria, InstrumentedAttribute\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\nfrom sqlalchemy.sql.expression import union_all, except_, intersect\n\nfrom app.models.account import (\n    AccountType, AccountClass, Account, AccountBalance, \n    FiscalYear, FiscalPeriod, JournalEntry, JournalEntryLine,\n    CostCenter, CostCenterAllocation, Budget, BudgetLine,\n    AccountReconciliation, AccountMapping, IntercompanyMapping\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.account import (\n    AccountTypeCreate, AccountTypeUpdate,\n    AccountClassCreate, AccountClassUpdate,\n    AccountCreate, AccountUpdate,\n    AccountBalanceCreate, AccountBalanceUpdate,\n    FiscalYearCreate, FiscalYearUpdate,\n    FiscalPeriodCreate, FiscalPeriodUpdate,\n    JournalEntryCreate, JournalEntryUpdate,\n    JournalEntryLineCreate, JournalEntryLineUpdate,\n    CostCenterCreate, CostCenterUpdate,\n    CostCenterAllocationCreate, CostCenterAllocationUpdate,\n    BudgetCreate, BudgetUpdate,\n    BudgetLineCreate, BudgetLineUpdate,\n    AccountReconciliationCreate, AccountReconciliationUpdate,\n    AccountMappingCreate, AccountMappingUpdate,\n    IntercompanyMappingCreate, IntercompanyMappingUpdate\n)\n\n\nclass AccountTypeRepository(BaseRepository[AccountType, AccountTypeCreate, AccountTypeUpdate]):\n    """Repository for Account Type operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(AccountType, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[AccountType]:\n        """Get account type by code within a company"""\n        query = select(AccountType).where(\n            AccountType.company_id == company_id,\n            AccountType.code == code,\n            AccountType.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_category(self, company_id: int, category: str) -> List[AccountType]:\n        """Get all account types by category (Asset, Liability, Equity, Revenue, Expense)"""\n        query = select(AccountType).where(\n            AccountType.company_id == company_id,\n            AccountType.category == category,\n            AccountType.is_deleted == False\n        ).order_by(AccountType.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_root_types(self, company_id: int) -> List[AccountType]:\n        """Get root account types (no parent)"""\n        query = select(AccountType).where(\n            AccountType.company_id == company_id,\n            AccountType.parent_id.is_(None),\n            AccountType.is_deleted == False\n        ).order_by(AccountType.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_type_tree(self, company_id: int) -> List[Dict[str, Any]]:\n        """Get hierarchical tree of account types"""\n        types = await self.get_all_by_company(company_id)\n        \n        def build_tree(parent_id: Optional[int] = None) -> List[Dict[str, Any]]:\n            return [\n                {\n                    "id": t.id,\n                    "code": t.code,\n                    "name": t.name,\n                    "category": t.category,\n                    "normal_balance": t.normal_balance,\n                    "children": build_tree(t.id)\n                }\n                for t in types\n                if t.parent_id == parent_id\n            ]\n        \n        return build_tree()\n\n\nclass AccountClassRepository(BaseRepository[AccountClass, AccountClassCreate, AccountClassUpdate]):\n    """Repository for Account Class operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(AccountClass, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[AccountClass]:\n        """Get account class by code"""\n        query = select(AccountClass).where(\n            AccountClass.company_id == company_id,\n            AccountClass.code == code,\n            AccountClass.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_type(self, account_type_id: int) -> List[AccountClass]:\n        """Get all classes for an account type"""\n        query = select(AccountClass).where(\n            AccountClass.account_type_id == account_type_id,\n            AccountClass.is_deleted == False\n        ).order_by(AccountClass.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_classes(self, company_id: int) -> List[AccountClass]:\n        """Get all active account classes"""\n        query = select(AccountClass).where(\n            AccountClass.company_id == company_id,\n            AccountClass.is_active == True,\n            AccountClass.is_deleted == False\n        ).order_by(AccountClass.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass AccountRepository(CompanyScopedRepository[Account, AccountCreate, AccountUpdate]):\n    """Repository for Account (Chart of Accounts) operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Account, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[Account]:\n        """Get account by account code"""\n        query = select(Account).options(\n            selectinload(Account.account_type),\n            selectinload(Account.account_class),\n            selectinload(Account.parent),\n            selectinload(Account.cost_center)\n        ).where(\n            Account.company_id == company_id,\n            Account.code == code,\n            Account.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[Account]:\n        """Get account by name"""\n        query = select(Account).where(\n            Account.company_id == company_id,\n            Account.name == name,\n            Account.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_root_accounts(self, company_id: int) -> List[Account]:\n        """Get root accounts (no parent)"""\n        query = select(Account).options(\n            selectinload(Account.account_type),\n            selectinload(Account.account_class)\n        ).where(\n            Account.company_id == company_id,\n            Account.parent_id.is_(None),\n            Account.is_deleted == False\n        ).order_by(Account.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_leaf_accounts(self, company_id: int) -> List[Account]:\n        """Get leaf accounts (can post to)"""\n        query = select(Account).options(\n            selectinload(Account.account_type),\n            selectinload(Account.account_class)\n        ).where(\n            Account.company_id == company_id,\n            Account.is_postable == True,\n            Account.is_deleted == False\n        ).order_by(Account.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_accounts_by_type(self, company_id: int, account_type_id: int) -> List[Account]:\n        """Get all accounts by account type"""\n        query = select(Account).options(\n            selectinload(Account.account_type),\n            selectinload(Account.account_class)\n        ).where(\n            Account.company_id == company_id,\n            Account.account_type_id == account_type_id,\n            Account.is_deleted == False\n        ).order_by(Account.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_accounts_by_category(self, company_id: int, category: str) -> List[Account]:\n        """Get all accounts by category (Asset, Liability, Equity, Revenue, Expense)"""\n        query = select(Account).options(\n            selectinload(Account.account_type),\n            selectinload(Account.account_class)\n        ).join(AccountType).where(\n            Account.company_id == company_id,\n            AccountType.category == category,\n            Account.is_deleted == False\n        ).order_by(Account.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_account_tree(self, company_id: int) -> List[Dict[str, Any]]:\n        """Get hierarchical tree of accounts with balances"""\n        accounts = await self.get_all_by_company(company_id, load_relationships=["account_type", "account_class"])\n        \n        def build_tree(parent_id: Optional[int] = None) -> List[Dict[str, Any]]:\n            return [\n                {\n                    "id": acc.id,\n                    "code": acc.code,\n                    "name": acc.name,\n                    "account_type": acc.account_type.name if acc.account_type else None,\n                    "account_class": acc.account_class.name if acc.account_class else None,\n                    "is_postable": acc.is_postable,\n                    "normal_balance": acc.normal_balance,\n                    "children": build_tree(acc.id)\n                }\n                for acc in accounts\n                if acc.parent_id == parent_id\n            ]\n        \n        return build_tree()\n    \n    async def get_account_with_children(self, account_id: int) -> List[int]:\n        """Get account ID and all descendant IDs"""\n        all_accounts = await self.session.execute(\n            select(Account.id, Account.parent_id).where(Account.is_deleted == False)\n        )\n        accounts_list = list(all_accounts.all())\n        \n        def get_children(parent_id: int) -> List[int]:\n            children = []\n            for acc_id, acc_parent_id in accounts_list:\n                if acc_parent_id == parent_id:\n                    children.append(acc_id)\n                    children.extend(get_children(acc_id))\n            return children\n        \n        return [account_id] + get_children(account_id)\n    \n    async def is_code_unique(self, company_id: int, code: str, exclude_id: Optional[int] = None) -> bool:\n        """Check if account code is unique within company"""\n        query = select(Account).where(\n            Account.company_id == company_id,\n            Account.code == code,\n            Account.is_deleted == False\n        )\n        if exclude_id:\n            query = query.where(Account.id != exclude_id)\n        \n        result = await self.session.execute(query)\n        return result.scalar_one_or_none() is None\n    \n    async def get_next_code(self, company_id: int, parent_id: Optional[int] = None) -> str:\n        """Generate next available account code"""\n        if parent_id:\n            parent = await self.get_by_id(parent_id)\n            if parent:\n                query = select(func.max(Account.code)).where(\n                    Account.company_id == company_id,\n                    Account.parent_id == parent_id,\n                    Account.is_deleted == False\n                )\n                result = await self.session.execute(query)\n                max_code = result.scalar()\n                if max_code:\n                    try:\n                        return parent.code + str(int(max_code[-3:]) + 1).zfill(3)\n                    except (ValueError, IndexError):\n                        return parent.code + "001"\n                return parent.code + "001"\n        else:\n            query = select(func.max(Account.code)).where(\n                Account.company_id == company_id,\n                Account.parent_id.is_(None),\n                Account.is_deleted == False\n            )\n            result = await self.session.execute(query)\n            max_code = result.scalar()\n            if max_code:\n                try:\n                    return str(int(max_code) + 1).zfill(len(max_code))\n                except ValueError:\n                    return "1000"\n            return "1000"\n\n\nclass AccountBalanceRepository(BaseRepository[AccountBalance, AccountBalanceCreate, AccountBalanceUpdate]):\n    """Repository for Account Balance operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(AccountBalance, session)\n    \n    async def get_by_account_period(\n        self, \n        account_id: int, \n        fiscal_year_id: int, \n        period_number: int\n    ) -> Optional[AccountBalance]:\n        """Get balance for specific account and period"""\n        query = select(AccountBalance).where(\n            AccountBalance.account_id == account_id,\n            AccountBalance.fiscal_year_id == fiscal_year_id,\n            AccountBalance.period_number == period_number\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_account_balances(\n        self, \n        account_id: int, \n        fiscal_year_id: int\n    ) -> List[AccountBalance]:\n        """Get all period balances for an account in a fiscal year"""\n        query = select(AccountBalance).where(\n            AccountBalance.account_id == account_id,\n            AccountBalance.fiscal_year_id == fiscal_year_id\n        ).order_by(AccountBalance.period_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_period_balances(\n        self, \n        company_id: int, \n        fiscal_year_id: int, \n        period_number: int\n    ) -> List[AccountBalance]:\n        """Get all account balances for a period"""\n        query = select(AccountBalance).options(\n            selectinload(AccountBalance.account)\n        ).join(Account).where(\n            Account.company_id == company_id,\n            AccountBalance.fiscal_year_id == fiscal_year_id,\n            AccountBalance.period_number == period_number\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_ytd_balance(self, account_id: int, fiscal_year_id: int, up_to_period: int) -> Decimal:\n        """Calculate year-to-date balance up to a period"""\n        query = select(func.sum(\n            AccountBalance.debit_balance - AccountBalance.credit_balance\n        )).where(\n            AccountBalance.account_id == account_id,\n            AccountBalance.fiscal_year_id == fiscal_year_id,\n            AccountBalance.period_number <= up_to_period\n        )\n        result = await self.session.execute(query)\n        balance = result.scalar()\n        return Decimal(str(balance or 0))\n    \n    async def update_period_balance(\n        self, \n        account_id: int, \n        fiscal_year_id: int, \n        period_number: int,\n        debit_amount: Decimal = Decimal(\'0\'),\n        credit_amount: Decimal = Decimal(\'0\')\n    ) -> AccountBalance:\n        """Update or create period balance"""\n        balance = await self.get_by_account_period(account_id, fiscal_year_id, period_number)\n        \n        if balance:\n            balance.debit_balance = (balance.debit_balance or Decimal(\'0\')) + debit_amount\n            balance.credit_balance = (balance.credit_balance or Decimal(\'0\')) + credit_amount\n            balance.updated_at = datetime.utcnow()\n        else:\n            balance = AccountBalance(\n                account_id=account_id,\n                fiscal_year_id=fiscal_year_id,\n                period_number=period_number,\n                debit_balance=debit_amount,\n                credit_balance=credit_amount\n            )\n            self.session.add(balance)\n        \n        await self.session.flush()\n        return balance\n    \n    async def calculate_account_balance_at_date(\n        self, \n        account_id: int, \n        as_of_date: date\n    ) -> Tuple[Decimal, Decimal]:\n        """Calculate account balance as of a specific date"""\n        query = select(\n            func.coalesce(func.sum(JournalEntryLine.debit), Decimal(\'0\')).label(\'total_debit\'),\n            func.coalesce(func.sum(JournalEntryLine.credit), Decimal(\'0\')).label(\'total_credit\')\n        ).join(JournalEntry).where(\n            JournalEntryLine.account_id == account_id,\n            JournalEntry.entry_date <= as_of_date,\n            JournalEntry.status == \'Posted\'\n        )\n        result = await self.session.execute(query)\n        row = result.one()\n        return row.total_debit, row.total_credit\n\n\nclass FiscalYearRepository(BaseRepository[FiscalYear, FiscalYearCreate, FiscalYearUpdate]):\n    """Repository for Fiscal Year operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(FiscalYear, session)\n    \n    async def get_by_year(self, company_id: int, year: int) -> Optional[FiscalYear]:\n        """Get fiscal year by year number"""\n        query = select(FiscalYear).options(\n            selectinload(FiscalYear.periods)\n        ).where(\n            FiscalYear.company_id == company_id,\n            FiscalYear.year == year,\n            FiscalYear.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_year(self, company_id: int) -> Optional[FiscalYear]:\n        """Get the currently active fiscal year"""\n        query = select(FiscalYear).options(\n            selectinload(FiscalYear.periods)\n        ).where(\n            FiscalYear.company_id == company_id,\n            FiscalYear.is_active == True,\n            FiscalYear.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_open_years(self, company_id: int) -> List[FiscalYear]:\n        """Get all open fiscal years"""\n        query = select(FiscalYear).where(\n            FiscalYear.company_id == company_id,\n            FiscalYear.is_closed == False,\n            FiscalYear.is_deleted == False\n        ).order_by(FiscalYear.year)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_current_period(self, company_id: int) -> Tuple[Optional[FiscalYear], Optional[FiscalPeriod]]:\n        """Get current fiscal year and period"""\n        today = date.today()\n        \n        query = select(FiscalYear).options(\n            selectinload(FiscalYear.periods)\n        ).where(\n            FiscalYear.company_id == company_id,\n            FiscalYear.start_date <= today,\n            FiscalYear.end_date >= today,\n            FiscalYear.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        fiscal_year = result.scalar_one_or_none()\n        \n        if fiscal_year:\n            for period in sorted(fiscal_year.periods, key=lambda p: p.period_number):\n                if period.start_date <= today <= period.end_date:\n                    return fiscal_year, period\n        \n        return fiscal_year, None\n    \n    async def is_year_closed(self, fiscal_year_id: int) -> bool:\n        """Check if fiscal year is closed"""\n        query = select(FiscalYear.is_closed).where(FiscalYear.id == fiscal_year_id)\n        result = await self.session.execute(query)\n        is_closed = result.scalar_one_or_none()\n        return is_closed if is_closed is not None else True\n    \n    async def close_year(self, fiscal_year_id: int, closed_by_id: int) -> FiscalYear:\n        """Close a fiscal year"""\n        fiscal_year = await self.get_by_id(fiscal_year_id)\n        if fiscal_year:\n            fiscal_year.is_closed = True\n            fiscal_year.is_active = False\n            fiscal_year.closed_at = datetime.utcnow()\n            fiscal_year.closed_by_id = closed_by_id\n            fiscal_year.updated_at = datetime.utcnow()\n            fiscal_year.updated_by_id = closed_by_id\n            await self.session.flush()\n        return fiscal_year\n\n\nclass FiscalPeriodRepository(BaseRepository[FiscalPeriod, FiscalPeriodCreate, FiscalPeriodUpdate]):\n    """Repository for Fiscal Period operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(FiscalPeriod, session)\n    \n    async def get_by_period_number(\n        self, \n        fiscal_year_id: int, \n        period_number: int\n    ) -> Optional[FiscalPeriod]:\n        """Get period by number within fiscal year"""\n        query = select(FiscalPeriod).where(\n            FiscalPeriod.fiscal_year_id == fiscal_year_id,\n            FiscalPeriod.period_number == period_number\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_periods_by_year(self, fiscal_year_id: int) -> List[FiscalPeriod]:\n        """Get all periods for a fiscal year"""\n        query = select(FiscalPeriod).where(\n            FiscalPeriod.fiscal_year_id == fiscal_year_id\n        ).order_by(FiscalPeriod.period_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_open_periods(self, fiscal_year_id: int) -> List[FiscalPeriod]:\n        """Get all open periods for a fiscal year"""\n        query = select(FiscalPeriod).where(\n            FiscalPeriod.fiscal_year_id == fiscal_year_id,\n            FiscalPeriod.is_closed == False\n        ).order_by(FiscalPeriod.period_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_period_for_date(self, company_id: int, target_date: date) -> Optional[FiscalPeriod]:\n        """Get the fiscal period for a specific date"""\n        query = select(FiscalPeriod).join(FiscalYear).where(\n            FiscalYear.company_id == company_id,\n            FiscalPeriod.start_date <= target_date,\n            FiscalPeriod.end_date >= target_date,\n            FiscalYear.is_deleted == False\n        ).options(selectinload(FiscalPeriod.fiscal_year))\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def close_period(\n        self, \n        period_id: int, \n        closed_by_id: int\n    ) -> FiscalPeriod:\n        """Close a fiscal period"""\n        period = await self.get_by_id(period_id)\n        if period:\n            period.is_closed = True\n            period.is_adjustment = False\n            period.closed_at = datetime.utcnow()\n            period.closed_by_id = closed_by_id\n            await self.session.flush()\n        return period\n    \n    async def open_adjustment_period(\n        self, \n        fiscal_year_id: int, \n        opened_by_id: int\n    ) -> FiscalPeriod:\n        """Open an adjustment period"""\n        # Get or create adjustment period (period 13 or 0 depending on system)\n        adj_period = await self.session.execute(\n            select(FiscalPeriod).where(\n                FiscalPeriod.fiscal_year_id == fiscal_year_id,\n                FiscalPeriod.is_adjustment == True\n            )\n        )\n        period = adj_period.scalar_one_or_none()\n        \n        if period:\n            period.is_closed = False\n            period.opened_at = datetime.utcnow()\n            period.opened_by_id = opened_by_id\n        else:\n            # Create adjustment period\n            fiscal_year = await self.session.get(FiscalYear, fiscal_year_id)\n            if fiscal_year:\n                period = FiscalPeriod(\n                    fiscal_year_id=fiscal_year_id,\n                    period_number=13,\n                    name="Adjustment Period",\n                    start_date=fiscal_year.end_date,\n                    end_date=fiscal_year.end_date,\n                    is_adjustment=True,\n                    is_closed=False,\n                    opened_by_id=opened_by_id\n                )\n                self.session.add(period)\n        \n        await self.session.flush()\n        return period\n\n\nclass JournalEntryRepository(CompanyScopedRepository[JournalEntry, JournalEntryCreate, JournalEntryUpdate]):\n    """Repository for Journal Entry operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(JournalEntry, session)\n    \n    async def get_by_entry_number(self, company_id: int, entry_number: str) -> Optional[JournalEntry]:\n        """Get journal entry by entry number"""\n        query = select(JournalEntry).options(\n            selectinload(JournalEntry.lines).selectinload(JournalEntryLine.account),\n            selectinload(JournalEntry.fiscal_period),\n            selectinload(JournalEntry.created_by)\n        ).where(\n            JournalEntry.company_id == company_id,\n            JournalEntry.entry_number == entry_number,\n            JournalEntry.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_draft_entries(self, company_id: int) -> List[JournalEntry]:\n        """Get all draft journal entries"""\n        query = select(JournalEntry).options(\n            selectinload(JournalEntry.lines)\n        ).where(\n            JournalEntry.company_id == company_id,\n            JournalEntry.status == \'Draft\',\n            JournalEntry.is_deleted == False\n        ).order_by(desc(JournalEntry.created_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_posted_entries(self, company_id: int) -> List[JournalEntry]:\n        """Get all posted journal entries"""\n        query = select(JournalEntry).options(\n            selectinload(JournalEntry.lines)\n        ).where(\n            JournalEntry.company_id == company_id,\n            JournalEntry.status == \'Posted\',\n            JournalEntry.is_deleted == False\n        ).order_by(desc(JournalEntry.entry_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_entries_by_date_range(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date,\n        status: Optional[str] = None\n    ) -> List[JournalEntry]:\n        """Get journal entries within date range"""\n        query = select(JournalEntry).options(\n            selectinload(JournalEntry.lines)\n        ).where(\n            JournalEntry.company_id == company_id,\n            JournalEntry.entry_date >= start_date,\n            JournalEntry.entry_date <= end_date,\n            JournalEntry.is_deleted == False\n        )\n        if status:\n            query = query.where(JournalEntry.status == status)\n        query = query.order_by(JournalEntry.entry_date, JournalEntry.entry_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_entries_by_period(\n        self, \n        fiscal_period_id: int\n    ) -> List[JournalEntry]:\n        """Get all journal entries for a fiscal period"""\n        query = select(JournalEntry).options(\n            selectinload(JournalEntry.lines)\n        ).where(\n            JournalEntry.fiscal_period_id == fiscal_period_id,\n            JournalEntry.is_deleted == False\n        ).order_by(JournalEntry.entry_date, JournalEntry.entry_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_entries_by_account(\n        self, \n        account_id: int, \n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None\n    ) -> List[JournalEntry]:\n        """Get journal entries for an account"""\n        query = select(JournalEntry).options(\n            selectinload(JournalEntry.lines)\n        ).join(JournalEntryLine).where(\n            JournalEntryLine.account_id == account_id,\n            JournalEntry.is_deleted == False\n        )\n        if start_date:\n            query = query.where(JournalEntry.entry_date >= start_date)\n        if end_date:\n            query = query.where(JournalEntry.entry_date <= end_date)\n        query = query.order_by(JournalEntry.entry_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_reversing_entries(self, company_id: int) -> List[JournalEntry]:\n        """Get all entries marked for reversal"""\n        query = select(JournalEntry).where(\n            JournalEntry.company_id == company_id,\n            JournalEntry.is_reversing == True,\n            JournalEntry.reversal_date <= date.today(),\n            JournalEntry.is_reversed == False,\n            JournalEntry.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def post_entry(self, entry_id: int, posted_by_id: int) -> JournalEntry:\n        """Post a journal entry"""\n        entry = await self.get_by_id(entry_id, load_relationships=["lines"])\n        if entry and entry.status == \'Draft\':\n            entry.status = \'Posted\'\n            entry.posted_at = datetime.utcnow()\n            entry.posted_by_id = posted_by_id\n            \n            # Update account balances\n            for line in entry.lines:\n                period = await self.session.execute(\n                    select(FiscalPeriod).where(FiscalPeriod.id == entry.fiscal_period_id)\n                )\n                fiscal_period = period.scalar_one()\n                \n                # Update balance\n                await self._update_account_balance(\n                    line.account_id,\n                    entry.fiscal_year_id,\n                    fiscal_period.period_number,\n                    line.debit or Decimal(\'0\'),\n                    line.credit or Decimal(\'0\')\n                )\n            \n            await self.session.flush()\n        return entry\n    \n    async def reverse_entry(\n        self, \n        entry_id: int, \n        reversal_date: date, \n        reversed_by_id: int,\n        reason: Optional[str] = None\n    ) -> JournalEntry:\n        """Create a reversing entry"""\n        original = await self.get_by_id(entry_id, load_relationships=["lines"])\n        if not original:\n            return None\n        \n        # Create reversal entry\n        reversal = JournalEntry(\n            company_id=original.company_id,\n            entry_number=f"REV-{original.entry_number}",\n            entry_date=reversal_date,\n            description=f"Reversal of {original.entry_number}: {reason or \'N/A\'}",\n            reference=original.entry_number,\n            entry_type=\'Reversing\',\n            is_reversal=True,\n            reversed_entry_id=entry_id,\n            fiscal_year_id=original.fiscal_year_id,\n            fiscal_period_id=original.fiscal_period_id,\n            status=\'Draft\',\n            created_by_id=reversed_by_id\n        )\n        self.session.add(reversal)\n        await self.session.flush()\n        \n        # Create reversal lines (swap debit/credit)\n        for line in original.lines:\n            rev_line = JournalEntryLine(\n                journal_entry_id=reversal.id,\n                account_id=line.account_id,\n                description=f"Reversal: {line.description}",\n                debit=line.credit,\n                credit=line.debit,\n                cost_center_id=line.cost_center_id\n            )\n            self.session.add(rev_line)\n        \n        original.is_reversed = True\n        original.reversed_at = datetime.utcnow()\n        \n        await self.session.flush()\n        return reversal\n    \n    async def generate_entry_number(self, company_id: int) -> str:\n        """Generate next journal entry number"""\n        today = date.today()\n        prefix = f"JE-{today.year}{today.month:02d}"\n        \n        query = select(func.max(JournalEntry.entry_number)).where(\n            JournalEntry.company_id == company_id,\n            JournalEntry.entry_number.like(f"{prefix}%")\n        )\n        result = await self.session.execute(query)\n        max_number = result.scalar()\n        \n        if max_number:\n            try:\n                seq = int(max_number.split(\'-\')[-1]) + 1\n            except (ValueError, IndexError):\n                seq = 1\n        else:\n            seq = 1\n        \n        return f"{prefix}-{seq:05d}"\n    \n    async def validate_entry(self, entry_id: int) -> Tuple[bool, List[str]]:\n        """Validate journal entry for posting"""\n        errors = []\n        entry = await self.get_by_id(entry_id, load_relationships=["lines"])\n        \n        if not entry:\n            errors.append("Journal entry not found")\n            return False, errors\n        \n        if entry.status != \'Draft\':\n            errors.append("Only draft entries can be validated")\n        \n        if not entry.lines:\n            errors.append("Journal entry must have at least one line")\n        \n        # Check balanced\n        total_debit = sum(line.debit or Decimal(\'0\') for line in entry.lines)\n        total_credit = sum(line.credit or Decimal(\'0\') for line in entry.lines)\n        \n        if total_debit != total_credit:\n            errors.append(f"Entry not balanced: Debit {total_debit} != Credit {total_credit}")\n        \n        # Check each line has an account\n        for i, line in enumerate(entry.lines):\n            if not line.account_id:\n                errors.append(f"Line {i+1} missing account")\n            if not line.debit and not line.credit:\n                errors.append(f"Line {i+1} has no amount")\n        \n        return len(errors) == 0, errors\n    \n    async def _update_account_balance(\n        self, \n        account_id: int, \n        fiscal_year_id: int, \n        period_number: int,\n        debit: Decimal, \n        credit: Decimal\n    ):\n        """Internal method to update account balance"""\n        balance_repo = AccountBalanceRepository(self.session)\n        await balance_repo.update_period_balance(\n            account_id, fiscal_year_id, period_number, debit, credit\n        )\n\n\nclass JournalEntryLineRepository(BaseRepository[JournalEntryLine, JournalEntryLineCreate, JournalEntryLineUpdate]):\n    """Repository for Journal Entry Line operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(JournalEntryLine, session)\n    \n    async def get_by_journal_entry(self, journal_entry_id: int) -> List[JournalEntryLine]:\n        """Get all lines for a journal entry"""\n        query = select(JournalEntryLine).options(\n            selectinload(JournalEntryLine.account),\n            selectinload(JournalEntryLine.cost_center)\n        ).where(\n            JournalEntryLine.journal_entry_id == journal_entry_id\n        ).order_by(JournalEntryLine.line_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_lines_by_account(\n        self, \n        account_id: int, \n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None\n    ) -> List[JournalEntryLine]:\n        """Get all lines for an account"""\n        query = select(JournalEntryLine).options(\n            selectinload(JournalEntryLine.journal_entry)\n        ).where(\n            JournalEntryLine.account_id == account_id\n        )\n        if start_date:\n            query = query.join(JournalEntry).where(JournalEntry.entry_date >= start_date)\n        if end_date:\n            query = query.join(JournalEntry).where(JournalEntry.entry_date <= end_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_account_activity(\n        self, \n        account_id: int, \n        fiscal_year_id: int,\n        period_number: Optional[int] = None\n    ) -> Dict[str, Any]:\n        """Get account activity summary"""\n        query = select(\n            func.count(JournalEntryLine.id).label(\'line_count\'),\n            func.sum(JournalEntryLine.debit).label(\'total_debit\'),\n            func.sum(JournalEntryLine.credit).label(\'total_credit\')\n        ).join(JournalEntry).where(\n            JournalEntryLine.account_id == account_id,\n            JournalEntry.fiscal_year_id == fiscal_year_id,\n            JournalEntry.status == \'Posted\'\n        )\n        if period_number:\n            query = query.where(JournalEntry.fiscal_period_id == period_number)\n        \n        result = await self.session.execute(query)\n        row = result.one()\n        return {\n            "line_count": row.line_count or 0,\n            "total_debit": row.total_debit or Decimal(\'0\'),\n            "total_credit": row.total_credit or Decimal(\'0\'),\n            "net_activity": (row.total_debit or Decimal(\'0\')) - (row.total_credit or Decimal(\'0\'))\n        }\n\n\nclass CostCenterRepository(CompanyScopedRepository[CostCenter, CostCenterCreate, CostCenterUpdate]):\n    """Repository for Cost Center operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(CostCenter, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[CostCenter]:\n        """Get cost center by code"""\n        query = select(CostCenter).where(\n            CostCenter.company_id == company_id,\n            CostCenter.code == code,\n            CostCenter.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_root_centers(self, company_id: int) -> List[CostCenter]:\n        """Get root cost centers"""\n        query = select(CostCenter).where(\n            CostCenter.company_id == company_id,\n            CostCenter.parent_id.is_(None),\n            CostCenter.is_deleted == False\n        ).order_by(CostCenter.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_centers(self, company_id: int) -> List[CostCenter]:\n        """Get all active cost centers"""\n        query = select(CostCenter).where(\n            CostCenter.company_id == company_id,\n            CostCenter.is_active == True,\n            CostCenter.is_deleted == False\n        ).order_by(CostCenter.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_center_tree(self, company_id: int) -> List[Dict[str, Any]]:\n        """Get hierarchical tree of cost centers"""\n        centers = await self.get_all_by_company(company_id)\n        \n        def build_tree(parent_id: Optional[int] = None) -> List[Dict[str, Any]]:\n            return [\n                {\n                    "id": c.id,\n                    "code": c.code,\n                    "name": c.name,\n                    "manager_id": c.manager_id,\n                    "budget": c.budget,\n                    "children": build_tree(c.id)\n                }\n                for c in centers\n                if c.parent_id == parent_id\n            ]\n        \n        return build_tree()\n\n\nclass BudgetRepository(BaseRepository[Budget, BudgetCreate, BudgetUpdate]):\n    """Repository for Budget operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Budget, session)\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[Budget]:\n        """Get budget by name"""\n        query = select(Budget).options(\n            selectinload(Budget.lines)\n        ).where(\n            Budget.company_id == company_id,\n            Budget.name == name,\n            Budget.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_budget(self, company_id: int, fiscal_year_id: int) -> Optional[Budget]:\n        """Get active budget for fiscal year"""\n        query = select(Budget).options(\n            selectinload(Budget.lines)\n        ).where(\n            Budget.company_id == company_id,\n            Budget.fiscal_year_id == fiscal_year_id,\n            Budget.is_active == True,\n            Budget.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_budgets_by_year(self, company_id: int, fiscal_year_id: int) -> List[Budget]:\n        """Get all budgets for a fiscal year"""\n        query = select(Budget).where(\n            Budget.company_id == company_id,\n            Budget.fiscal_year_id == fiscal_year_id,\n            Budget.is_deleted == False\n        ).order_by(Budget.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_budget_vs_actual(\n        self, \n        budget_id: int, \n        period_number: Optional[int] = None\n    ) -> List[Dict[str, Any]]:\n        """Get budget vs actual comparison"""\n        budget = await self.get_by_id(budget_id, load_relationships=["lines"])\n        if not budget:\n            return []\n        \n        results = []\n        for line in budget.lines:\n            # Get actual amount\n            actual_query = select(\n                func.sum(JournalEntryLine.debit - JournalEntryLine.credit)\n            ).join(JournalEntry).where(\n                JournalEntryLine.account_id == line.account_id,\n                JournalEntry.fiscal_year_id == budget.fiscal_year_id,\n                JournalEntry.status == \'Posted\'\n            )\n            if period_number:\n                actual_query = actual_query.where(\n                    JournalEntry.fiscal_period_id == period_number\n                )\n            \n            actual_result = await self.session.execute(actual_query)\n            actual = actual_result.scalar() or Decimal(\'0\')\n            \n            budget_amount = line.amount\n            if period_number and line.period_amounts:\n                budget_amount = Decimal(str(line.period_amounts.get(str(period_number), 0)))\n            \n            results.append({\n                "account_id": line.account_id,\n                "account_code": line.account.code if line.account else None,\n                "account_name": line.account.name if line.account else None,\n                "budget_amount": budget_amount,\n                "actual_amount": actual,\n                "variance": budget_amount - actual,\n                "variance_percent": ((budget_amount - actual) / budget_amount * 100) if budget_amount else None\n            })\n        \n        return results\n\n\nclass AccountReconciliationRepository(BaseRepository[AccountReconciliation, AccountReconciliationCreate, AccountReconciliationUpdate]):\n    """Repository for Account Reconciliation operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(AccountReconciliation, session)\n    \n    async def get_by_account_period(\n        self, \n        account_id: int, \n        reconciliation_date: date\n    ) -> Optional[AccountReconciliation]:\n        """Get reconciliation for account and date"""\n        query = select(AccountReconciliation).where(\n            AccountReconciliation.account_id == account_id,\n            AccountReconciliation.reconciliation_date == reconciliation_date\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_pending_reconciliations(\n        self, \n        company_id: int\n    ) -> List[AccountReconciliation]:\n        """Get all pending reconciliations"""\n        query = select(AccountReconciliation).options(\n            selectinload(AccountReconciliation.account)\n        ).join(Account).where(\n            Account.company_id == company_id,\n            AccountReconciliation.status.in_([\'Draft\', \'In Progress\'])\n        ).order_by(AccountReconciliation.reconciliation_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def complete_reconciliation(\n        self, \n        reconciliation_id: int, \n        completed_by_id: int\n    ) -> AccountReconciliation:\n        """Complete a reconciliation"""\n        reconciliation = await self.get_by_id(reconciliation_id)\n        if reconciliation:\n            reconciliation.status = \'Completed\'\n            reconciliation.completed_at = datetime.utcnow()\n            reconciliation.completed_by_id = completed_by_id\n            await self.session.flush()\n        return reconciliation\n\n\nclass AccountMappingRepository(BaseRepository[AccountMapping, AccountMappingCreate, AccountMappingUpdate]):\n    """Repository for Account Mapping operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(AccountMapping, session)\n    \n    async def get_by_external_code(\n        self, \n        company_id: int, \n        external_system: str, \n        external_code: str\n    ) -> Optional[AccountMapping]:\n        """Get mapping by external system and code"""\n        query = select(AccountMapping).where(\n            AccountMapping.company_id == company_id,\n            AccountMapping.external_system == external_system,\n            AccountMapping.external_code == external_code,\n            AccountMapping.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_mappings_by_system(\n        self, \n        company_id: int, \n        external_system: str\n    ) -> List[AccountMapping]:\n        """Get all mappings for an external system"""\n        query = select(AccountMapping).options(\n            selectinload(AccountMapping.account)\n        ).where(\n            AccountMapping.company_id == company_id,\n            AccountMapping.external_system == external_system,\n            AccountMapping.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass IntercompanyMappingRepository(BaseRepository[IntercompanyMapping, IntercompanyMappingCreate, IntercompanyMappingUpdate]):\n    """Repository for Intercompany Mapping operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(IntercompanyMapping, session)\n    \n    async def get_mapping(\n        self, \n        source_company_id: int, \n        target_company_id: int, \n        source_account_id: int\n    ) -> Optional[IntercompanyMapping]:\n        """Get intercompany mapping"""\n        query = select(IntercompanyMapping).where(\n            IntercompanyMapping.source_company_id == source_company_id,\n            IntercompanyMapping.target_company_id == target_company_id,\n            IntercompanyMapping.source_account_id == source_account_id,\n            IntercompanyMapping.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_mappings_by_source(\n        self, \n        source_company_id: int\n    ) -> List[IntercompanyMapping]:\n        """Get all intercompany mappings for a source company"""\n        query = select(IntercompanyMapping).options(\n            selectinload(IntercompanyMapping.source_account),\n            selectinload(IntercompanyMapping.target_account)\n        ).where(\n            IntercompanyMapping.source_company_id == source_company_id,\n            IntercompanyMapping.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/account.py\' created successfully.") </create-file> </tool_result>'}
{'role': 'assistant', 'content': 'Excellent! Account repository created successfully. Now let me continue with the Journal Entry repository - but wait, I already included JournalEntryRepository and JournalEntryLineRepository in the account.py file. Let me proceed to create the Treasury repository.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/treasury.py">\n"""\nTreasury Repository - Data Access Layer for Treasury and Banking Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal,\n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager,\n    aliased, with_loader_criteria\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom app.models.treasury import (\n    Bank, BankAccount, BankAccountType, BankBalance,\n    CashPool, CashPoolAccount, CashPoolTransfer,\n    TreasuryTransaction, TreasuryTransactionType,\n    BankReconciliation, BankReconciliationLine,\n    Investment, InvestmentType, InvestmentTransaction,\n    CreditFacility, CreditFacilityDrawdown, CreditFacilityPayment,\n    Guarantee, GuaranteeStatusHistory,\n    FXRate, FXHedge, FXHedgeTransaction,\n    TreasuryForecast, TreasuryForecastLine,\n    PaymentBatch, PaymentBatchLine, PaymentTemplate,\n    CashFlowStatement, CashFlowLine\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.treasury import (\n    BankCreate, BankUpdate,\n    BankAccountCreate, BankAccountUpdate,\n    BankAccountTypeCreate, BankAccountTypeUpdate,\n    BankBalanceCreate, BankBalanceUpdate,\n    CashPoolCreate, CashPoolUpdate,\n    CashPoolAccountCreate, CashPoolAccountUpdate,\n    CashPoolTransferCreate, CashPoolTransferUpdate,\n    TreasuryTransactionCreate, TreasuryTransactionUpdate,\n    TreasuryTransactionTypeCreate, TreasuryTransactionTypeUpdate,\n    BankReconciliationCreate, BankReconciliationUpdate,\n    BankReconciliationLineCreate, BankReconciliationLineUpdate,\n    InvestmentCreate, InvestmentUpdate,\n    InvestmentTypeCreate, InvestmentTypeUpdate,\n    InvestmentTransactionCreate, InvestmentTransactionUpdate,\n    CreditFacilityCreate, CreditFacilityUpdate,\n    CreditFacilityDrawdownCreate, CreditFacilityDrawdownUpdate,\n    CreditFacilityPaymentCreate, CreditFacilityPaymentUpdate,\n    GuaranteeCreate, GuaranteeUpdate,\n    GuaranteeStatusHistoryCreate, GuaranteeStatusHistoryUpdate,\n    FXRateCreate, FXRateUpdate,\n    FXHedgeCreate, FXHedgeUpdate,\n    FXHedgeTransactionCreate, FXHedgeTransactionUpdate,\n    TreasuryForecastCreate, TreasuryForecastUpdate,\n    TreasuryForecastLineCreate, TreasuryForecastLineUpdate,\n    PaymentBatchCreate, PaymentBatchUpdate,\n    PaymentBatchLineCreate, PaymentBatchLineUpdate,\n    PaymentTemplateCreate, PaymentTemplateUpdate,\n    CashFlowStatementCreate, CashFlowStatementUpdate,\n    CashFlowLineCreate, CashFlowLineUpdate\n)\n\n\nclass BankRepository(BaseRepository[Bank, BankCreate, BankUpdate]):\n    """Repository for Bank operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Bank, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[Bank]:\n        """Get bank by code"""\n        query = select(Bank).where(\n            Bank.company_id == company_id,\n            Bank.code == code,\n            Bank.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_swift_code(self, swift_code: str) -> Optional[Bank]:\n        """Get bank by SWIFT code"""\n        query = select(Bank).where(\n            Bank.swift_code == swift_code,\n            Bank.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_banks(self, company_id: int) -> List[Bank]:\n        """Get all active banks"""\n        query = select(Bank).where(\n            Bank.company_id == company_id,\n            Bank.is_active == True,\n            Bank.is_deleted == False\n        ).order_by(Bank.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_banks_by_country(self, company_id: int, country: str) -> List[Bank]:\n        """Get banks by country"""\n        query = select(Bank).where(\n            Bank.company_id == company_id,\n            Bank.country == country,\n            Bank.is_deleted == False\n        ).order_by(Bank.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass BankAccountRepository(CompanyScopedRepository[BankAccount, BankAccountCreate, BankAccountUpdate]):\n    """Repository for Bank Account operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(BankAccount, session)\n    \n    async def get_by_account_number(\n        self, \n        company_id: int, \n        account_number: str\n    ) -> Optional[BankAccount]:\n        """Get bank account by account number"""\n        query = select(BankAccount).options(\n            selectinload(BankAccount.bank),\n            selectinload(BankAccount.account_type)\n        ).where(\n            BankAccount.company_id == company_id,\n            BankAccount.account_number == account_number,\n            BankAccount.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_iban(self, iban: str) -> Optional[BankAccount]:\n        """Get bank account by IBAN"""\n        query = select(BankAccount).options(\n            selectinload(BankAccount.bank)\n        ).where(\n            BankAccount.iban == iban,\n            BankAccount.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_accounts(self, company_id: int) -> List[BankAccount]:\n        """Get all active bank accounts"""\n        query = select(BankAccount).options(\n            selectinload(BankAccount.bank),\n            selectinload(BankAccount.account_type)\n        ).where(\n            BankAccount.company_id == company_id,\n            BankAccount.is_active == True,\n            BankAccount.is_deleted == False\n        ).order_by(BankAccount.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_accounts_by_bank(\n        self, \n        company_id: int, \n        bank_id: int\n    ) -> List[BankAccount]:\n        """Get all accounts for a bank"""\n        query = select(BankAccount).options(\n            selectinload(BankAccount.account_type)\n        ).where(\n            BankAccount.company_id == company_id,\n            BankAccount.bank_id == bank_id,\n            BankAccount.is_deleted == False\n        ).order_by(BankAccount.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_accounts_by_currency(\n        self, \n        company_id: int, \n        currency: str\n    ) -> List[BankAccount]:\n        """Get all accounts by currency"""\n        query = select(BankAccount).options(\n            selectinload(BankAccount.bank)\n        ).where(\n            BankAccount.company_id == company_id,\n            BankAccount.currency == currency,\n            BankAccount.is_deleted == False\n        ).order_by(BankAccount.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_accounts_by_type(\n        self, \n        company_id: int, \n        account_type_id: int\n    ) -> List[BankAccount]:\n        """Get all accounts by type"""\n        query = select(BankAccount).options(\n            selectinload(BankAccount.bank)\n        ).where(\n            BankAccount.company_id == company_id,\n            BankAccount.account_type_id == account_type_id,\n            BankAccount.is_deleted == False\n        ).order_by(BankAccount.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_account_balance(\n        self, \n        account_id: int, \n        as_of_date: Optional[date] = None\n    ) -> Decimal:\n        """Get account balance as of a date"""\n        if as_of_date is None:\n            as_of_date = date.today()\n        \n        # Get latest balance record\n        query = select(BankBalance).where(\n            BankBalance.bank_account_id == account_id,\n            BankBalance.balance_date <= as_of_date\n        ).order_by(desc(BankBalance.balance_date)).limit(1)\n        result = await self.session.execute(query)\n        balance = result.scalar_one_or_none()\n        \n        if balance:\n            # Add transactions since balance date\n            tx_query = select(\n                func.sum(case(\n                    (TreasuryTransaction.transaction_type.in_([\'Receipt\', \'Credit\']),\n                     TreasuryTransaction.amount),\n                    else_=Decimal(\'0\')\n                )).label(\'credits\'),\n                func.sum(case(\n                    (TreasuryTransaction.transaction_type.in_([\'Payment\', \'Debit\']),\n                     TreasuryTransaction.amount),\n                    else_=Decimal(\'0\')\n                )).label(\'debits\')\n            ).where(\n                TreasuryTransaction.bank_account_id == account_id,\n                TreasuryTransaction.value_date > balance.balance_date,\n                TreasuryTransaction.value_date <= as_of_date,\n                TreasuryTransaction.status == \'Completed\'\n            )\n            tx_result = await self.session.execute(tx_query)\n            tx_row = tx_result.one()\n            \n            net_movement = (tx_row.credits or Decimal(\'0\')) - (tx_row.debits or Decimal(\'0\'))\n            return balance.balance + net_movement\n        \n        # No balance record, calculate from transactions\n        tx_query = select(\n            func.sum(case(\n                (TreasuryTransaction.transaction_type.in_([\'Receipt\', \'Credit\']),\n                 TreasuryTransaction.amount),\n                else_=Decimal(\'0\')\n            ) - case(\n                (TreasuryTransaction.transaction_type.in_([\'Payment\', \'Debit\']),\n                 TreasuryTransaction.amount),\n                else_=Decimal(\'0\')\n            )).label(\'balance\')\n        ).where(\n            TreasuryTransaction.bank_account_id == account_id,\n            TreasuryTransaction.value_date <= as_of_date,\n            TreasuryTransaction.status == \'Completed\'\n        )\n        result = await self.session.execute(tx_query)\n        return result.scalar() or Decimal(\'0\')\n    \n    async def get_total_balance_by_currency(\n        self, \n        company_id: int, \n        currency: str,\n        as_of_date: Optional[date] = None\n    ) -> Decimal:\n        """Get total balance across all accounts for a currency"""\n        accounts = await self.get_accounts_by_currency(company_id, currency)\n        total = Decimal(\'0\')\n        for account in accounts:\n            balance = await self.get_account_balance(account.id, as_of_date)\n            total += balance\n        return total\n\n\nclass BankAccountTypeRepository(BaseRepository[BankAccountType, BankAccountTypeCreate, BankAccountTypeUpdate]):\n    """Repository for Bank Account Type operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(BankAccountType, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[BankAccountType]:\n        """Get account type by code"""\n        query = select(BankAccountType).where(\n            BankAccountType.company_id == company_id,\n            BankAccountType.code == code,\n            BankAccountType.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_types(self, company_id: int) -> List[BankAccountType]:\n        """Get all active account types"""\n        query = select(BankAccountType).where(\n            BankAccountType.company_id == company_id,\n            BankAccountType.is_active == True,\n            BankAccountType.is_deleted == False\n        ).order_by(BankAccountType.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass BankBalanceRepository(BaseRepository[BankBalance, BankBalanceCreate, BankBalanceUpdate]):\n    """Repository for Bank Balance operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(BankBalance, session)\n    \n    async def get_latest_balance(\n        self, \n        bank_account_id: int\n    ) -> Optional[BankBalance]:\n        """Get latest balance for an account"""\n        query = select(BankBalance).where(\n            BankBalance.bank_account_id == bank_account_id\n        ).order_by(desc(BankBalance.balance_date)).limit(1)\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_balance_history(\n        self, \n        bank_account_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[BankBalance]:\n        """Get balance history for a period"""\n        query = select(BankBalance).where(\n            BankBalance.bank_account_id == bank_account_id,\n            BankBalance.balance_date >= start_date,\n            BankBalance.balance_date <= end_date\n        ).order_by(BankBalance.balance_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_balance_at_date(\n        self, \n        bank_account_id: int, \n        target_date: date\n    ) -> Optional[BankBalance]:\n        """Get balance at or before a specific date"""\n        query = select(BankBalance).where(\n            BankBalance.bank_account_id == bank_account_id,\n            BankBalance.balance_date <= target_date\n        ).order_by(desc(BankBalance.balance_date)).limit(1)\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def record_balance(\n        self, \n        bank_account_id: int, \n        balance_date: date, \n        balance: Decimal,\n        source: str = \'Manual\',\n        created_by_id: Optional[int] = None\n    ) -> BankBalance:\n        """Record a balance for an account"""\n        bank_balance = BankBalance(\n            bank_account_id=bank_account_id,\n            balance_date=balance_date,\n            balance=balance,\n            source=source,\n            created_by_id=created_by_id\n        )\n        self.session.add(bank_balance)\n        await self.session.flush()\n        return bank_balance\n\n\nclass CashPoolRepository(CompanyScopedRepository[CashPool, CashPoolCreate, CashPoolUpdate]):\n    """Repository for Cash Pool operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(CashPool, session)\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[CashPool]:\n        """Get cash pool by name"""\n        query = select(CashPool).options(\n            selectinload(CashPool.pool_accounts)\n        ).where(\n            CashPool.company_id == company_id,\n            CashPool.name == name,\n            CashPool.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_pools(self, company_id: int) -> List[CashPool]:\n        """Get all active cash pools"""\n        query = select(CashPool).options(\n            selectinload(CashPool.pool_accounts)\n        ).where(\n            CashPool.company_id == company_id,\n            CashPool.is_active == True,\n            CashPool.is_deleted == False\n        ).order_by(CashPool.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pool_balance(\n        self, \n        pool_id: int, \n        as_of_date: Optional[date] = None\n    ) -> Decimal:\n        """Get total pool balance"""\n        pool = await self.get_by_id(pool_id, load_relationships=["pool_accounts"])\n        if not pool:\n            return Decimal(\'0\')\n        \n        total = Decimal(\'0\')\n        for pool_account in pool.pool_accounts:\n            if pool_account.is_active:\n                account_balance = await BankAccountRepository(self.session).get_account_balance(\n                    pool_account.bank_account_id, as_of_date\n                )\n                total += account_balance * (pool_account.concentration_percentage or Decimal(\'1\'))\n        \n        return total\n    \n    async def get_pool_participants(\n        self, \n        pool_id: int\n    ) -> List[Dict[str, Any]]:\n        """Get pool participants with their balances"""\n        pool = await self.get_by_id(pool_id, load_relationships=["pool_accounts"])\n        if not pool:\n            return []\n        \n        participants = []\n        for pool_account in pool.pool_accounts:\n            if pool_account.is_active:\n                balance = await BankAccountRepository(self.session).get_account_balance(\n                    pool_account.bank_account_id\n                )\n                participants.append({\n                    "account_id": pool_account.bank_account_id,\n                    "account_name": pool_account.bank_account.name if pool_account.bank_account else None,\n                    "role": pool_account.role,\n                    "balance": balance,\n                    "concentration_percentage": pool_account.concentration_percentage,\n                    "interest_share": pool_account.interest_share\n                })\n        \n        return participants\n\n\nclass CashPoolAccountRepository(BaseRepository[CashPoolAccount, CashPoolAccountCreate, CashPoolAccountUpdate]):\n    """Repository for Cash Pool Account operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(CashPoolAccount, session)\n    \n    async def get_by_pool_account(\n        self, \n        pool_id: int, \n        bank_account_id: int\n    ) -> Optional[CashPoolAccount]:\n        """Get pool account by pool and bank account"""\n        query = select(CashPoolAccount).where(\n            CashPoolAccount.cash_pool_id == pool_id,\n            CashPoolAccount.bank_account_id == bank_account_id\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_pool_accounts(self, pool_id: int) -> List[CashPoolAccount]:\n        """Get all accounts in a pool"""\n        query = select(CashPoolAccount).options(\n            selectinload(CashPoolAccount.bank_account)\n        ).where(\n            CashPoolAccount.cash_pool_id == pool_id\n        ).order_by(CashPoolAccount.role)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass CashPoolTransferRepository(BaseRepository[CashPoolTransfer, CashPoolTransferCreate, CashPoolTransferUpdate]):\n    """Repository for Cash Pool Transfer operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(CashPoolTransfer, session)\n    \n    async def get_transfers_by_pool(\n        self, \n        pool_id: int, \n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None\n    ) -> List[CashPoolTransfer]:\n        """Get transfers for a pool"""\n        query = select(CashPoolTransfer).options(\n            selectinload(CashPoolTransfer.from_account),\n            selectinload(CashPoolTransfer.to_account)\n        ).where(\n            CashPoolTransfer.cash_pool_id == pool_id\n        )\n        if start_date:\n            query = query.where(CashPoolTransfer.transfer_date >= start_date)\n        if end_date:\n            query = query.where(CashPoolTransfer.transfer_date <= end_date)\n        query = query.order_by(desc(CashPoolTransfer.transfer_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_transfers(\n        self, \n        pool_id: int\n    ) -> List[CashPoolTransfer]:\n        """Get pending transfers for a pool"""\n        query = select(CashPoolTransfer).where(\n            CashPoolTransfer.cash_pool_id == pool_id,\n            CashPoolTransfer.status == \'Pending\'\n        ).order_by(CashPoolTransfer.transfer_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass TreasuryTransactionRepository(CompanyScopedRepository[TreasuryTransaction, TreasuryTransactionCreate, TreasuryTransactionUpdate]):\n    """Repository for Treasury Transaction operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TreasuryTransaction, session)\n    \n    async def get_by_reference(\n        self, \n        company_id: int, \n        reference: str\n    ) -> Optional[TreasuryTransaction]:\n        """Get transaction by reference"""\n        query = select(TreasuryTransaction).options(\n            selectinload(TreasuryTransaction.bank_account),\n            selectinload(TreasuryTransaction.transaction_type_rel)\n        ).where(\n            TreasuryTransaction.company_id == company_id,\n            TreasuryTransaction.reference == reference,\n            TreasuryTransaction.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_transactions_by_account(\n        self, \n        bank_account_id: int, \n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None,\n        status: Optional[str] = None\n    ) -> List[TreasuryTransaction]:\n        """Get transactions for a bank account"""\n        query = select(TreasuryTransaction).options(\n            selectinload(TreasuryTransaction.transaction_type_rel)\n        ).where(\n            TreasuryTransaction.bank_account_id == bank_account_id\n        )\n        if start_date:\n            query = query.where(TreasuryTransaction.value_date >= start_date)\n        if end_date:\n            query = query.where(TreasuryTransaction.value_date <= end_date)\n        if status:\n            query = query.where(TreasuryTransaction.status == status)\n        query = query.order_by(desc(TreasuryTransaction.value_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_transactions(\n        self, \n        company_id: int\n    ) -> List[TreasuryTransaction]:\n        """Get all pending transactions"""\n        query = select(TreasuryTransaction).options(\n            selectinload(TreasuryTransaction.bank_account)\n        ).where(\n            TreasuryTransaction.company_id == company_id,\n            TreasuryTransaction.status == \'Pending\',\n            TreasuryTransaction.is_deleted == False\n        ).order_by(TreasuryTransaction.value_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_transactions_by_date_range(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[TreasuryTransaction]:\n        """Get transactions within date range"""\n        query = select(TreasuryTransaction).options(\n            selectinload(TreasuryTransaction.bank_account),\n            selectinload(TreasuryTransaction.transaction_type_rel)\n        ).where(\n            TreasuryTransaction.company_id == company_id,\n            TreasuryTransaction.value_date >= start_date,\n            TreasuryTransaction.value_date <= end_date,\n            TreasuryTransaction.is_deleted == False\n        ).order_by(TreasuryTransaction.value_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_cash_flow_summary(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date,\n        currency: Optional[str] = None\n    ) -> Dict[str, Any]:\n        """Get cash flow summary for period"""\n        query = select(\n            TreasuryTransaction.transaction_type,\n            func.sum(TreasuryTransaction.amount).label(\'total\'),\n            func.count(TreasuryTransaction.id).label(\'count\')\n        ).where(\n            TreasuryTransaction.company_id == company_id,\n            TreasuryTransaction.value_date >= start_date,\n            TreasuryTransaction.value_date <= end_date,\n            TreasuryTransaction.status == \'Completed\',\n            TreasuryTransaction.is_deleted == False\n        )\n        if currency:\n            query = query.join(BankAccount).where(BankAccount.currency == currency)\n        \n        query = query.group_by(TreasuryTransaction.transaction_type)\n        result = await self.session.execute(query)\n        \n        inflows = Decimal(\'0\')\n        outflows = Decimal(\'0\')\n        categories = {}\n        \n        for row in result:\n            categories[row.transaction_type] = {\n                \'total\': row.total,\n                \'count\': row.count\n            }\n            if row.transaction_type in [\'Receipt\', \'Credit\', \'Interest\']:\n                inflows += row.total\n            else:\n                outflows += row.total\n        \n        return {\n            \'inflows\': inflows,\n            \'outflows\': outflows,\n            \'net_flow\': inflows - outflows,\n            \'categories\': categories\n        }\n    \n    async def complete_transaction(\n        self, \n        transaction_id: int, \n        completed_by_id: int,\n        actual_value_date: Optional[date] = None\n    ) -> TreasuryTransaction:\n        """Complete a transaction"""\n        transaction = await self.get_by_id(transaction_id)\n        if transaction and transaction.status == \'Pending\':\n            transaction.status = \'Completed\'\n            transaction.completed_at = datetime.utcnow()\n            transaction.completed_by_id = completed_by_id\n            if actual_value_date:\n                transaction.value_date = actual_value_date\n            await self.session.flush()\n        return transaction\n\n\nclass BankReconciliationRepository(BaseRepository[BankReconciliation, BankReconciliationCreate, BankReconciliationUpdate]):\n    """Repository for Bank Reconciliation operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(BankReconciliation, session)\n    \n    async def get_by_account_period(\n        self, \n        bank_account_id: int, \n        statement_date: date\n    ) -> Optional[BankReconciliation]:\n        """Get reconciliation for account and date"""\n        query = select(BankReconciliation).options(\n            selectinload(BankReconciliation.lines)\n        ).where(\n            BankReconciliation.bank_account_id == bank_account_id,\n            BankReconciliation.statement_date == statement_date\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_pending_reconciliations(\n        self, \n        company_id: int\n    ) -> List[BankReconciliation]:\n        """Get all pending reconciliations"""\n        query = select(BankReconciliation).options(\n            selectinload(BankReconciliation.bank_account)\n        ).join(BankAccount).where(\n            BankAccount.company_id == company_id,\n            BankReconciliation.status.in_([\'Draft\', \'In Progress\'])\n        ).order_by(BankReconciliation.statement_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_latest_reconciliation(\n        self, \n        bank_account_id: int\n    ) -> Optional[BankReconciliation]:\n        """Get latest reconciliation for account"""\n        query = select(BankReconciliation).where(\n            BankReconciliation.bank_account_id == bank_account_id\n        ).order_by(desc(BankReconciliation.statement_date)).limit(1)\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def complete_reconciliation(\n        self, \n        reconciliation_id: int, \n        completed_by_id: int\n    ) -> BankReconciliation:\n        """Complete a reconciliation"""\n        reconciliation = await self.get_by_id(reconciliation_id)\n        if reconciliation:\n            reconciliation.status = \'Completed\'\n            reconciliation.completed_at = datetime.utcnow()\n            reconciliation.completed_by_id = completed_by_id\n            await self.session.flush()\n        return reconciliation\n    \n    async def calculate_unreconciled_difference(\n        self, \n        reconciliation_id: int\n    ) -> Decimal:\n        """Calculate unreconciled difference"""\n        query = select(func.sum(BankReconciliationLine.amount)).where(\n            BankReconciliationLine.bank_reconciliation_id == reconciliation_id,\n            BankReconciliationLine.is_reconciled == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar() or Decimal(\'0\')\n\n\nclass InvestmentRepository(CompanyScopedRepository[Investment, InvestmentCreate, InvestmentUpdate]):\n    """Repository for Investment operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Investment, session)\n    \n    async def get_by_reference(\n        self, \n        company_id: int, \n        reference: str\n    ) -> Optional[Investment]:\n        """Get investment by reference"""\n        query = select(Investment).options(\n            selectinload(Investment.investment_type)\n        ).where(\n            Investment.company_id == company_id,\n            Investment.reference == reference,\n            Investment.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_investments(\n        self, \n        company_id: int\n    ) -> List[Investment]:\n        """Get all active investments"""\n        query = select(Investment).options(\n            selectinload(Investment.investment_type)\n        ).where(\n            Investment.company_id == company_id,\n            Investment.status == \'Active\',\n            Investment.is_deleted == False\n        ).order_by(Investment.maturity_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_maturing_investments(\n        self, \n        company_id: int, \n        within_days: int = 30\n    ) -> List[Investment]:\n        """Get investments maturing within specified days"""\n        target_date = date.today() + timedelta(days=within_days)\n        query = select(Investment).options(\n            selectinload(Investment.investment_type)\n        ).where(\n            Investment.company_id == company_id,\n            Investment.status == \'Active\',\n            Investment.maturity_date <= target_date,\n            Investment.maturity_date >= date.today(),\n            Investment.is_deleted == False\n        ).order_by(Investment.maturity_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_portfolio_summary(\n        self, \n        company_id: int,\n        currency: Optional[str] = None\n    ) -> Dict[str, Any]:\n        """Get investment portfolio summary"""\n        query = select(Investment).options(\n            selectinload(Investment.investment_type)\n        ).where(\n            Investment.company_id == company_id,\n            Investment.status == \'Active\',\n            Investment.is_deleted == False\n        )\n        if currency:\n            query = query.where(Investment.currency == currency)\n        \n        result = await self.session.execute(query)\n        investments = list(result.scalars().all())\n        \n        total_principal = sum(inv.principal_amount for inv in investments)\n        total_market_value = sum(\n            inv.current_market_value or inv.principal_amount \n            for inv in investments\n        )\n        total_accrued_interest = sum(\n            inv.accrued_interest or Decimal(\'0\') \n            for inv in investments\n        )\n        \n        by_type = {}\n        for inv in investments:\n            type_name = inv.investment_type.name if inv.investment_type else \'Unknown\'\n            if type_name not in by_type:\n                by_type[type_name] = {\n                    \'count\': 0,\n                    \'principal\': Decimal(\'0\'),\n                    \'market_value\': Decimal(\'0\')\n                }\n            by_type[type_name][\'count\'] += 1\n            by_type[type_name][\'principal\'] += inv.principal_amount\n            by_type[type_name][\'market_value\'] += inv.current_market_value or inv.principal_amount\n        \n        return {\n            \'total_investments\': len(investments),\n            \'total_principal\': total_principal,\n            \'total_market_value\': total_market_value,\n            \'total_accrued_interest\': total_accrued_interest,\n            \'total_value\': total_market_value + total_accrued_interest,\n            \'by_type\': by_type\n        }\n\n\nclass CreditFacilityRepository(CompanyScopedRepository[CreditFacility, CreditFacilityCreate, CreditFacilityUpdate]):\n    """Repository for Credit Facility operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(CreditFacility, session)\n    \n    async def get_by_facility_number(\n        self, \n        company_id: int, \n        facility_number: str\n    ) -> Optional[CreditFacility]:\n        """Get facility by facility number"""\n        query = select(CreditFacility).options(\n            selectinload(CreditFacility.drawdowns),\n            selectinload(CreditFacility.payments)\n        ).where(\n            CreditFacility.company_id == company_id,\n            CreditFacility.facility_number == facility_number,\n            CreditFacility.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_facilities(\n        self, \n        company_id: int\n    ) -> List[CreditFacility]:\n        """Get all active facilities"""\n        query = select(CreditFacility).where(\n            CreditFacility.company_id == company_id,\n            CreditFacility.status == \'Active\',\n            CreditFacility.is_deleted == False\n        ).order_by(CreditFacility.facility_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_available_credit(\n        self, \n        facility_id: int\n    ) -> Decimal:\n        """Get available credit for a facility"""\n        facility = await self.get_by_id(facility_id, load_relationships=["drawdowns", "payments"])\n        if not facility:\n            return Decimal(\'0\')\n        \n        total_drawn = sum(d.amount for d in facility.drawdowns if d.status == \'Active\')\n        total_repaid = sum(p.principal_amount for p in facility.payments if p.status == \'Completed\')\n        outstanding = total_drawn - total_repaid\n        \n        return facility.facility_amount - outstanding\n    \n    async def get_facility_utilization(\n        self, \n        facility_id: int\n    ) -> Dict[str, Any]:\n        """Get facility utilization summary"""\n        facility = await self.get_by_id(facility_id, load_relationships=["drawdowns", "payments"])\n        if not facility:\n            return {}\n        \n        total_drawn = sum(d.amount for d in facility.drawdowns if d.status == \'Active\')\n        total_repaid = sum(p.principal_amount for p in facility.payments if p.status == \'Completed\')\n        outstanding = total_drawn - total_repaid\n        available = facility.facility_amount - outstanding\n        \n        return {\n            \'facility_amount\': facility.facility_amount,\n            \'total_drawn\': total_drawn,\n            \'total_repaid\': total_repaid,\n            \'outstanding\': outstanding,\n            \'available\': available,\n            \'utilization_percent\': (outstanding / facility.facility_amount * 100) if facility.facility_amount else 0\n        }\n\n\nclass FXRateRepository(BaseRepository[FXRate, FXRateCreate, FXRateUpdate]):\n    """Repository for FX Rate operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(FXRate, session)\n    \n    async def get_rate(\n        self, \n        company_id: int, \n        from_currency: str, \n        to_currency: str,\n        rate_date: Optional[date] = None\n    ) -> Optional[FXRate]:\n        """Get exchange rate"""\n        if rate_date is None:\n            rate_date = date.today()\n        \n        query = select(FXRate).where(\n            FXRate.company_id == company_id,\n            FXRate.from_currency == from_currency,\n            FXRate.to_currency == to_currency,\n            FXRate.rate_date <= rate_date\n        ).order_by(desc(FXRate.rate_date)).limit(1)\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def convert_amount(\n        self, \n        company_id: int, \n        amount: Decimal, \n        from_currency: str, \n        to_currency: str,\n        rate_date: Optional[date] = None\n    ) -> Decimal:\n        """Convert amount between currencies"""\n        if from_currency == to_currency:\n            return amount\n        \n        rate = await self.get_rate(company_id, from_currency, to_currency, rate_date)\n        if rate:\n            return amount * rate.rate\n        \n        # Try inverse rate\n        inverse_rate = await self.get_rate(company_id, to_currency, from_currency, rate_date)\n        if inverse_rate and inverse_rate.rate:\n            return amount / inverse_rate.rate\n        \n        raise ValueError(f"No exchange rate found for {from_currency} to {to_currency}")\n    \n    async def get_latest_rates(\n        self, \n        company_id: int, \n        base_currency: str\n    ) -> List[FXRate]:\n        """Get latest rates for all currencies against base"""\n        subquery = select(\n            FXRate.from_currency,\n            func.max(FXRate.rate_date).label(\'max_date\')\n        ).where(\n            FXRate.company_id == company_id,\n            FXRate.to_currency == base_currency\n        ).group_by(FXRate.from_currency).subquery()\n        \n        query = select(FXRate).join(\n            subquery,\n            and_(\n                FXRate.from_currency == subquery.c.from_currency,\n                FXRate.rate_date == subquery.c.max_date\n            )\n        ).where(FXRate.company_id == company_id)\n        \n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass TreasuryForecastRepository(BaseRepository[TreasuryForecast, TreasuryForecastCreate, TreasuryForecastUpdate]):\n    """Repository for Treasury Forecast operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TreasuryForecast, session)\n    \n    async def get_by_name(\n        self, \n        company_id: int, \n        name: str\n    ) -> Optional[TreasuryForecast]:\n        """Get forecast by name"""\n        query = select(TreasuryForecast).options(\n            selectinload(TreasuryForecast.lines)\n        ).where(\n            TreasuryForecast.company_id == company_id,\n            TreasuryForecast.name == name,\n            TreasuryForecast.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_forecast(\n        self, \n        company_id: int\n    ) -> Optional[TreasuryForecast]:\n        """Get active forecast"""\n        query = select(TreasuryForecast).options(\n            selectinload(TreasuryForecast.lines)\n        ).where(\n            TreasuryForecast.company_id == company_id,\n            TreasuryForecast.is_active == True,\n            TreasuryForecast.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_forecast_by_date(\n        self, \n        forecast_id: int, \n        forecast_date: date\n    ) -> Optional[TreasuryForecastLine]:\n        """Get forecast line for a specific date"""\n        query = select(TreasuryForecastLine).where(\n            TreasuryForecastLine.treasury_forecast_id == forecast_id,\n            TreasuryForecastLine.forecast_date == forecast_date\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_forecast_range(\n        self, \n        forecast_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[TreasuryForecastLine]:\n        """Get forecast lines for a date range"""\n        query = select(TreasuryForecastLine).where(\n            TreasuryForecastLine.treasury_forecast_id == forecast_id,\n            TreasuryForecastLine.forecast_date >= start_date,\n            TreasuryForecastLine.forecast_date <= end_date\n        ).order_by(TreasuryForecastLine.forecast_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass PaymentBatchRepository(CompanyScopedRepository[PaymentBatch, PaymentBatchCreate, PaymentBatchUpdate]):\n    """Repository for Payment Batch operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(PaymentBatch, session)\n    \n    async def get_by_batch_number(\n        self, \n        company_id: int, \n        batch_number: str\n    ) -> Optional[PaymentBatch]:\n        """Get batch by batch number"""\n        query = select(PaymentBatch).options(\n            selectinload(PaymentBatch.lines)\n        ).where(\n            PaymentBatch.company_id == company_id,\n            PaymentBatch.batch_number == batch_number,\n            PaymentBatch.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_pending_batches(\n        self, \n        company_id: int\n    ) -> List[PaymentBatch]:\n        """Get all pending batches"""\n        query = select(PaymentBatch).options(\n            selectinload(PaymentBatch.lines)\n        ).where(\n            PaymentBatch.company_id == company_id,\n            PaymentBatch.status == \'Pending\',\n            PaymentBatch.is_deleted == False\n        ).order_by(PaymentBatch.payment_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_batches_by_date(\n        self, \n        company_id: int, \n        payment_date: date\n    ) -> List[PaymentBatch]:\n        """Get batches for a specific date"""\n        query = select(PaymentBatch).where(\n            PaymentBatch.company_id == company_id,\n            PaymentBatch.payment_date == payment_date,\n            PaymentBatch.is_deleted == False\n        ).order_by(PaymentBatch.batch_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def approve_batch(\n        self, \n        batch_id: int, \n        approved_by_id: int\n    ) -> PaymentBatch:\n        """Approve a payment batch"""\n        batch = await self.get_by_id(batch_id)\n        if batch and batch.status == \'Pending\':\n            batch.status = \'Approved\'\n            batch.approved_at = datetime.utcnow()\n            batch.approved_by_id = approved_by_id\n            await self.session.flush()\n        return batch\n    \n    async def process_batch(\n        self, \n        batch_id: int, \n        processed_by_id: int\n    ) -> PaymentBatch:\n        """Process a payment batch"""\n        batch = await self.get_by_id(batch_id, load_relationships=["lines"])\n        if batch and batch.status == \'Approved\':\n            batch.status = \'Processed\'\n            batch.processed_at = datetime.utcnow()\n            batch.processed_by_id = processed_by_id\n            \n            # Update individual payments\n            for line in batch.lines:\n                line.status = \'Processed\'\n            \n            await self.session.flush()\n        return batch\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/treasury.py\' created successfully.") </create-file> </tool_result>'}
{'role': 'assistant', 'content': 'Treasury repository created successfully. Let me continue with the Invoice repository.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/invoice.py">\n"""\nInvoice Repository - Data Access Layer for Invoice and Billing Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal,\n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager,\n    aliased, with_loader_criteria\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom app.models.invoice import (\n    InvoiceTemplate, Invoice, InvoiceLine, InvoiceLineTax,\n    RecurringInvoice, RecurringInvoiceLine,\n    InvoicePayment, InvoiceCreditMemo, CreditMemoApplication,\n    InvoiceAging, DunningLetter, DunningLetterLine,\n    InvoiceWorkflowState, InvoiceApproval, InvoiceComment\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.invoice import (\n    InvoiceTemplateCreate, InvoiceTemplateUpdate,\n    InvoiceCreate, InvoiceUpdate,\n    InvoiceLineCreate, InvoiceLineUpdate,\n    InvoiceLineTaxCreate, InvoiceLineTaxUpdate,\n    RecurringInvoiceCreate, RecurringInvoiceUpdate,\n    RecurringInvoiceLineCreate, RecurringInvoiceLineUpdate,\n    InvoicePaymentCreate, InvoicePaymentUpdate,\n    InvoiceCreditMemoCreate, InvoiceCreditMemoUpdate,\n    CreditMemoApplicationCreate, CreditMemoApplicationUpdate,\n    InvoiceAgingCreate, InvoiceAgingUpdate,\n    DunningLetterCreate, DunningLetterUpdate,\n    DunningLetterLineCreate, DunningLetterLineUpdate,\n    InvoiceWorkflowStateCreate, InvoiceWorkflowStateUpdate,\n    InvoiceApprovalCreate, InvoiceApprovalUpdate,\n    InvoiceCommentCreate, InvoiceCommentUpdate\n)\n\n\nclass InvoiceTemplateRepository(BaseRepository[InvoiceTemplate, InvoiceTemplateCreate, InvoiceTemplateUpdate]):\n    """Repository for Invoice Template operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(InvoiceTemplate, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[InvoiceTemplate]:\n        """Get template by code"""\n        query = select(InvoiceTemplate).where(\n            InvoiceTemplate.company_id == company_id,\n            InvoiceTemplate.code == code,\n            InvoiceTemplate.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_templates(self, company_id: int) -> List[InvoiceTemplate]:\n        """Get all active templates"""\n        query = select(InvoiceTemplate).where(\n            InvoiceTemplate.company_id == company_id,\n            InvoiceTemplate.is_active == True,\n            InvoiceTemplate.is_deleted == False\n        ).order_by(InvoiceTemplate.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_default_template(\n        self, \n        company_id: int, \n        invoice_type: str = \'Sales\'\n    ) -> Optional[InvoiceTemplate]:\n        """Get default template for invoice type"""\n        query = select(InvoiceTemplate).where(\n            InvoiceTemplate.company_id == company_id,\n            InvoiceTemplate.invoice_type == invoice_type,\n            InvoiceTemplate.is_default == True,\n            InvoiceTemplate.is_active == True,\n            InvoiceTemplate.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n\n\nclass InvoiceRepository(CompanyScopedRepository[Invoice, InvoiceCreate, InvoiceUpdate]):\n    """Repository for Invoice operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Invoice, session)\n    \n    async def get_by_invoice_number(\n        self, \n        company_id: int, \n        invoice_number: str\n    ) -> Optional[Invoice]:\n        """Get invoice by invoice number"""\n        query = select(Invoice).options(\n            selectinload(Invoice.lines).selectinload(InvoiceLine.taxes),\n            selectinload(Invoice.payments),\n            selectinload(Invoice.credit_memos)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.invoice_number == invoice_number,\n            Invoice.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_status(\n        self, \n        company_id: int, \n        status: str\n    ) -> List[Invoice]:\n        """Get invoices by status"""\n        query = select(Invoice).options(\n            selectinload(Invoice.lines)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.status == status,\n            Invoice.is_deleted == False\n        ).order_by(desc(Invoice.invoice_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_draft_invoices(self, company_id: int) -> List[Invoice]:\n        """Get all draft invoices"""\n        return await self.get_by_status(company_id, \'Draft\')\n    \n    async def get_overdue_invoices(\n        self, \n        company_id: int,\n        as_of_date: Optional[date] = None\n    ) -> List[Invoice]:\n        """Get all overdue invoices"""\n        if as_of_date is None:\n            as_of_date = date.today()\n        \n        query = select(Invoice).options(\n            selectinload(Invoice.lines)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.status == \'Sent\',\n            Invoice.due_date < as_of_date,\n            Invoice.balance_due > 0,\n            Invoice.is_deleted == False\n        ).order_by(Invoice.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_invoices_by_customer(\n        self, \n        company_id: int, \n        customer_id: int,\n        status: Optional[str] = None\n    ) -> List[Invoice]:\n        """Get invoices by customer"""\n        query = select(Invoice).options(\n            selectinload(Invoice.lines)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.customer_id == customer_id,\n            Invoice.is_deleted == False\n        )\n        if status:\n            query = query.where(Invoice.status == status)\n        query = query.order_by(desc(Invoice.invoice_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_invoices_by_date_range(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date,\n        invoice_type: Optional[str] = None\n    ) -> List[Invoice]:\n        """Get invoices within date range"""\n        query = select(Invoice).options(\n            selectinload(Invoice.lines)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.invoice_date >= start_date,\n            Invoice.invoice_date <= end_date,\n            Invoice.is_deleted == False\n        )\n        if invoice_type:\n            query = query.where(Invoice.invoice_type == invoice_type)\n        query = query.order_by(Invoice.invoice_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_invoices_by_vendor(\n        self, \n        company_id: int, \n        vendor_id: int,\n        status: Optional[str] = None\n    ) -> List[Invoice]:\n        """Get purchase invoices by vendor"""\n        query = select(Invoice).options(\n            selectinload(Invoice.lines)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.vendor_id == vendor_id,\n            Invoice.invoice_type == \'Purchase\',\n            Invoice.is_deleted == False\n        )\n        if status:\n            query = query.where(Invoice.status == status)\n        query = query.order_by(desc(Invoice.invoice_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_approval_invoices(\n        self, \n        company_id: int\n    ) -> List[Invoice]:\n        """Get invoices pending approval"""\n        query = select(Invoice).options(\n            selectinload(Invoice.lines),\n            selectinload(Invoice.approvals)\n        ).where(\n            Invoice.company_id == company_id,\n            Invoice.status == \'Pending Approval\',\n            Invoice.is_deleted == False\n        ).order_by(Invoice.invoice_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def generate_invoice_number(\n        self, \n        company_id: int, \n        invoice_type: str = \'Sales\'\n    ) -> str:\n        """Generate next invoice number"""\n        today = date.today()\n        prefix = f"INV-{today.year}{today.month:02d}" if invoice_type == \'Sales\' else f"PINV-{today.year}{today.month:02d}"\n        \n        query = select(func.max(Invoice.invoice_number)).where(\n            Invoice.company_id == company_id,\n            Invoice.invoice_number.like(f"{prefix}%")\n        )\n        result = await self.session.execute(query)\n        max_number = result.scalar()\n        \n        if max_number:\n            try:\n                seq = int(max_number.split(\'-\')[-1]) + 1\n            except (ValueError, IndexError):\n                seq = 1\n        else:\n            seq = 1\n        \n        return f"{prefix}-{seq:05d}"\n    \n    async def calculate_totals(\n        self, \n        invoice_id: int\n    ) -> Dict[str, Decimal]:\n        """Calculate invoice totals"""\n        invoice = await self.get_by_id(invoice_id, load_relationships=["lines", "lines.taxes"])\n        if not invoice:\n            return {}\n        \n        subtotal = Decimal(\'0\')\n        total_tax = Decimal(\'0\')\n        \n        for line in invoice.lines:\n            line_total = (line.quantity or Decimal(\'0\')) * (line.unit_price or Decimal(\'0\'))\n            if line.discount_percent:\n                line_total = line_total * (1 - line.discount_percent / 100)\n            subtotal += line_total\n            \n            for tax in line.taxes:\n                total_tax += line_total * (tax.tax_rate / 100)\n        \n        total = subtotal + total_tax\n        if invoice.discount_amount:\n            total -= invoice.discount_amount\n        \n        return {\n            \'subtotal\': subtotal,\n            \'total_tax\': total_tax,\n            \'total\': total,\n            \'balance_due\': total - (invoice.amount_paid or Decimal(\'0\'))\n        }\n    \n    async def send_invoice(\n        self, \n        invoice_id: int, \n        sent_by_id: int\n    ) -> Invoice:\n        """Send invoice to customer"""\n        invoice = await self.get_by_id(invoice_id)\n        if invoice and invoice.status == \'Draft\':\n            invoice.status = \'Sent\'\n            invoice.sent_at = datetime.utcnow()\n            invoice.sent_by_id = sent_by_id\n            await self.session.flush()\n        return invoice\n    \n    async def record_payment(\n        self, \n        invoice_id: int, \n        amount: Decimal, \n        payment_date: date,\n        payment_method: str,\n        reference: Optional[str] = None,\n        created_by_id: Optional[int] = None\n    ) -> InvoicePayment:\n        """Record a payment against an invoice"""\n        invoice = await self.get_by_id(invoice_id)\n        if not invoice:\n            return None\n        \n        payment = InvoicePayment(\n            invoice_id=invoice_id,\n            payment_date=payment_date,\n            amount=amount,\n            payment_method=payment_method,\n            reference=reference,\n            created_by_id=created_by_id\n        )\n        self.session.add(payment)\n        \n        # Update invoice\n        invoice.amount_paid = (invoice.amount_paid or Decimal(\'0\')) + amount\n        invoice.balance_due = invoice.total_amount - invoice.amount_paid\n        \n        if invoice.balance_due <= 0:\n            invoice.status = \'Paid\'\n            invoice.paid_at = datetime.utcnow()\n        \n        await self.session.flush()\n        return payment\n    \n    async def get_receivables_summary(\n        self, \n        company_id: int,\n        as_of_date: Optional[date] = None\n    ) -> Dict[str, Any]:\n        """Get accounts receivable summary"""\n        if as_of_date is None:\n            as_of_date = date.today()\n        \n        query = select(Invoice).where(\n            Invoice.company_id == company_id,\n            Invoice.invoice_type == \'Sales\',\n            Invoice.status.in_([\'Sent\', \'Partial\']),\n            Invoice.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        invoices = list(result.scalars().all())\n        \n        current = Decimal(\'0\')\n        days_30 = Decimal(\'0\')\n        days_60 = Decimal(\'0\')\n        days_90 = Decimal(\'0\')\n        over_90 = Decimal(\'0\')\n        \n        for invoice in invoices:\n            days_overdue = (as_of_date - invoice.due_date).days if invoice.due_date else 0\n            balance = invoice.balance_due or Decimal(\'0\')\n            \n            if days_overdue <= 0:\n                current += balance\n            elif days_overdue <= 30:\n                days_30 += balance\n            elif days_overdue <= 60:\n                days_60 += balance\n            elif days_overdue <= 90:\n                days_90 += balance\n            else:\n                over_90 += balance\n        \n        return {\n            \'current\': current,\n            \'days_30\': days_30,\n            \'days_60\': days_60,\n            \'days_90\': days_90,\n            \'over_90\': over_90,\n            \'total\': current + days_30 + days_60 + days_90 + over_90\n        }\n    \n    async def get_payables_summary(\n        self, \n        company_id: int,\n        as_of_date: Optional[date] = None\n    ) -> Dict[str, Any]:\n        """Get accounts payable summary"""\n        if as_of_date is None:\n            as_of_date = date.today()\n        \n        query = select(Invoice).where(\n            Invoice.company_id == company_id,\n            Invoice.invoice_type == \'Purchase\',\n            Invoice.status.in_([\'Received\', \'Partial\']),\n            Invoice.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        invoices = list(result.scalars().all())\n        \n        current = Decimal(\'0\')\n        days_30 = Decimal(\'0\')\n        days_60 = Decimal(\'0\')\n        days_90 = Decimal(\'0\')\n        over_90 = Decimal(\'0\')\n        \n        for invoice in invoices:\n            days_overdue = (as_of_date - invoice.due_date).days if invoice.due_date else 0\n            balance = invoice.balance_due or Decimal(\'0\')\n            \n            if days_overdue <= 0:\n                current += balance\n            elif days_overdue <= 30:\n                days_30 += balance\n            elif days_overdue <= 60:\n                days_60 += balance\n            elif days_overdue <= 90:\n                days_90 += balance\n            else:\n                over_90 += balance\n        \n        return {\n            \'current\': current,\n            \'days_30\': days_30,\n            \'days_60\': days_60,\n            \'days_90\': days_90,\n            \'over_90\': over_90,\n            \'total\': current + days_30 + days_60 + days_90 + over_90\n        }\n\n\nclass InvoiceLineRepository(BaseRepository[InvoiceLine, InvoiceLineCreate, InvoiceLineUpdate]):\n    """Repository for Invoice Line operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(InvoiceLine, session)\n    \n    async def get_by_invoice(self, invoice_id: int) -> List[InvoiceLine]:\n        """Get all lines for an invoice"""\n        query = select(InvoiceLine).options(\n            selectinload(InvoiceLine.taxes),\n            selectinload(InvoiceLine.item)\n        ).where(\n            InvoiceLine.invoice_id == invoice_id\n        ).order_by(InvoiceLine.line_number)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_lines_by_item(\n        self, \n        item_id: int, \n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None\n    ) -> List[InvoiceLine]:\n        """Get invoice lines by item"""\n        query = select(InvoiceLine).options(\n            selectinload(InvoiceLine.invoice)\n        ).where(\n            InvoiceLine.item_id == item_id\n        )\n        if start_date:\n            query = query.join(Invoice).where(Invoice.invoice_date >= start_date)\n        if end_date:\n            query = query.join(Invoice).where(Invoice.invoice_date <= end_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def calculate_line_total(self, line_id: int) -> Decimal:\n        """Calculate line total"""\n        line = await self.get_by_id(line_id)\n        if not line:\n            return Decimal(\'0\')\n        \n        total = (line.quantity or Decimal(\'0\')) * (line.unit_price or Decimal(\'0\'))\n        if line.discount_percent:\n            total = total * (1 - line.discount_percent / 100)\n        \n        return total\n\n\nclass RecurringInvoiceRepository(BaseRepository[RecurringInvoice, RecurringInvoiceCreate, RecurringInvoiceUpdate]):\n    """Repository for Recurring Invoice operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(RecurringInvoice, session)\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[RecurringInvoice]:\n        """Get recurring invoice by name"""\n        query = select(RecurringInvoice).options(\n            selectinload(RecurringInvoice.lines)\n        ).where(\n            RecurringInvoice.company_id == company_id,\n            RecurringInvoice.name == name,\n            RecurringInvoice.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_recurring(self, company_id: int) -> List[RecurringInvoice]:\n        """Get all active recurring invoices"""\n        query = select(RecurringInvoice).options(\n            selectinload(RecurringInvoice.lines)\n        ).where(\n            RecurringInvoice.company_id == company_id,\n            RecurringInvoice.is_active == True,\n            RecurringInvoice.is_deleted == False\n        ).order_by(RecurringInvoice.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_due_recurring(\n        self, \n        company_id: int, \n        as_of_date: Optional[date] = None\n    ) -> List[RecurringInvoice]:\n        """Get recurring invoices due for generation"""\n        if as_of_date is None:\n            as_of_date = date.today()\n        \n        query = select(RecurringInvoice).options(\n            selectinload(RecurringInvoice.lines)\n        ).where(\n            RecurringInvoice.company_id == company_id,\n            RecurringInvoice.is_active == True,\n            RecurringInvoice.is_deleted == False,\n            or_(\n                RecurringInvoice.next_invoice_date.is_(None),\n                RecurringInvoice.next_invoice_date <= as_of_date\n            )\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def update_next_invoice_date(\n        self, \n        recurring_id: int\n    ) -> RecurringInvoice:\n        """Update next invoice date after generation"""\n        recurring = await self.get_by_id(recurring_id)\n        if not recurring:\n            return None\n        \n        current_date = recurring.next_invoice_date or date.today()\n        \n        if recurring.frequency == \'Daily\':\n            next_date = current_date + timedelta(days=recurring.interval or 1)\n        elif recurring.frequency == \'Weekly\':\n            next_date = current_date + timedelta(weeks=recurring.interval or 1)\n        elif recurring.frequency == \'Monthly\':\n            next_date = current_date + timedelta(days=30 * (recurring.interval or 1))\n        elif recurring.frequency == \'Yearly\':\n            next_date = current_date + timedelta(days=365 * (recurring.interval or 1))\n        else:\n            next_date = current_date + timedelta(days=30)\n        \n        recurring.next_invoice_date = next_date\n        recurring.last_invoice_date = current_date\n        recurring.invoice_count = (recurring.invoice_count or 0) + 1\n        \n        await self.session.flush()\n        return recurring\n\n\nclass InvoicePaymentRepository(BaseRepository[InvoicePayment, InvoicePaymentCreate, InvoicePaymentUpdate]):\n    """Repository for Invoice Payment operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(InvoicePayment, session)\n    \n    async def get_by_invoice(self, invoice_id: int) -> List[InvoicePayment]:\n        """Get all payments for an invoice"""\n        query = select(InvoicePayment).where(\n            InvoicePayment.invoice_id == invoice_id\n        ).order_by(desc(InvoicePayment.payment_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_payments_by_date_range(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[InvoicePayment]:\n        """Get payments within date range"""\n        query = select(InvoicePayment).options(\n            selectinload(InvoicePayment.invoice)\n        ).join(Invoice).where(\n            Invoice.company_id == company_id,\n            InvoicePayment.payment_date >= start_date,\n            InvoicePayment.payment_date <= end_date\n        ).order_by(InvoicePayment.payment_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_payments_by_method(\n        self, \n        company_id: int, \n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None\n    ) -> Dict[str, Decimal]:\n        """Get payment totals by method"""\n        query = select(\n            InvoicePayment.payment_method,\n            func.sum(InvoicePayment.amount).label(\'total\')\n        ).join(Invoice).where(\n            Invoice.company_id == company_id\n        )\n        if start_date:\n            query = query.where(InvoicePayment.payment_date >= start_date)\n        if end_date:\n            query = query.where(InvoicePayment.payment_date <= end_date)\n        \n        query = query.group_by(InvoicePayment.payment_method)\n        result = await self.session.execute(query)\n        \n        return {row.payment_method: row.total for row in result}\n\n\nclass InvoiceCreditMemoRepository(BaseRepository[InvoiceCreditMemo, InvoiceCreditMemoCreate, InvoiceCreditMemoUpdate]):\n    """Repository for Invoice Credit Memo operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(InvoiceCreditMemo, session)\n    \n    async def get_by_credit_number(\n        self, \n        company_id: int, \n        credit_number: str\n    ) -> Optional[InvoiceCreditMemo]:\n        """Get credit memo by credit number"""\n        query = select(InvoiceCreditMemo).where(\n            InvoiceCreditMemo.company_id == company_id,\n            InvoiceCreditMemo.credit_number == credit_number,\n            InvoiceCreditMemo.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_customer(\n        self, \n        company_id: int, \n        customer_id: int,\n        status: Optional[str] = None\n    ) -> List[InvoiceCreditMemo]:\n        """Get credit memos by customer"""\n        query = select(InvoiceCreditMemo).where(\n            InvoiceCreditMemo.company_id == company_id,\n            InvoiceCreditMemo.customer_id == customer_id,\n            InvoiceCreditMemo.is_deleted == False\n        )\n        if status:\n            query = query.where(InvoiceCreditMemo.status == status)\n        query = query.order_by(desc(InvoiceCreditMemo.credit_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_unapplied_credits(\n        self, \n        company_id: int\n    ) -> List[InvoiceCreditMemo]:\n        """Get credit memos with unapplied balance"""\n        query = select(InvoiceCreditMemo).where(\n            InvoiceCreditMemo.company_id == company_id,\n            InvoiceCreditMemo.status == \'Open\',\n            InvoiceCreditMemo.balance > 0,\n            InvoiceCreditMemo.is_deleted == False\n        ).order_by(InvoiceCreditMemo.credit_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def apply_credit(\n        self, \n        credit_memo_id: int, \n        invoice_id: int, \n        amount: Decimal,\n        applied_by_id: int\n    ) -> CreditMemoApplication:\n        """Apply credit memo to invoice"""\n        credit_memo = await self.get_by_id(credit_memo_id)\n        invoice = await self.session.get(Invoice, invoice_id)\n        \n        if not credit_memo or not invoice:\n            return None\n        \n        application = CreditMemoApplication(\n            credit_memo_id=credit_memo_id,\n            invoice_id=invoice_id,\n            amount=amount,\n            applied_by_id=applied_by_id\n        )\n        self.session.add(application)\n        \n        # Update credit memo balance\n        credit_memo.balance = (credit_memo.balance or credit_memo.amount) - amount\n        if credit_memo.balance <= 0:\n            credit_memo.status = \'Closed\'\n        \n        # Update invoice\n        invoice.amount_paid = (invoice.amount_paid or Decimal(\'0\')) + amount\n        invoice.balance_due = invoice.total_amount - invoice.amount_paid\n        \n        await self.session.flush()\n        return application\n\n\nclass DunningLetterRepository(BaseRepository[DunningLetter, DunningLetterCreate, DunningLetterUpdate]):\n    """Repository for Dunning Letter operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(DunningLetter, session)\n    \n    async def get_by_letter_number(\n        self, \n        company_id: int, \n        letter_number: str\n    ) -> Optional[DunningLetter]:\n        """Get dunning letter by letter number"""\n        query = select(DunningLetter).options(\n            selectinload(DunningLetter.lines)\n        ).where(\n            DunningLetter.company_id == company_id,\n            DunningLetter.letter_number == letter_number,\n            DunningLetter.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_customer(\n        self, \n        company_id: int, \n        customer_id: int\n    ) -> List[DunningLetter]:\n        """Get dunning letters by customer"""\n        query = select(DunningLetter).where(\n            DunningLetter.company_id == company_id,\n            DunningLetter.customer_id == customer_id,\n            DunningLetter.is_deleted == False\n        ).order_by(desc(DunningLetter.letter_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_letters(\n        self, \n        company_id: int\n    ) -> List[DunningLetter]:\n        """Get pending dunning letters"""\n        query = select(DunningLetter).where(\n            DunningLetter.company_id == company_id,\n            DunningLetter.status == \'Pending\',\n            DunningLetter.is_deleted == False\n        ).order_by(DunningLetter.letter_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def generate_dunning_letters(\n        self, \n        company_id: int,\n        min_overdue_days: int = 30,\n        created_by_id: Optional[int] = None\n    ) -> List[DunningLetter]:\n        """Generate dunning letters for overdue invoices"""\n        invoice_repo = InvoiceRepository(self.session)\n        overdue_invoices = await invoice_repo.get_overdue_invoices(company_id)\n        \n        # Group by customer\n        customer_invoices = {}\n        for invoice in overdue_invoices:\n            days_overdue = (date.today() - invoice.due_date).days\n            if days_overdue >= min_overdue_days:\n                if invoice.customer_id not in customer_invoices:\n                    customer_invoices[invoice.customer_id] = []\n                customer_invoices[invoice.customer_id].append(invoice)\n        \n        letters = []\n        for customer_id, invoices in customer_invoices.items():\n            letter_number = f"DUN-{date.today().year}{date.today().month:02d}-{len(letters)+1:04d}"\n            \n            total_amount = sum(inv.balance_due for inv in invoices)\n            max_level = max(\n                1 if (date.today() - inv.due_date).days <= 30\n                else 2 if (date.today() - inv.due_date).days <= 60\n                else 3\n                for inv in invoices\n            )\n            \n            letter = DunningLetter(\n                company_id=company_id,\n                letter_number=letter_number,\n                letter_date=date.today(),\n                customer_id=customer_id,\n                dunning_level=max_level,\n                total_amount=total_amount,\n                status=\'Pending\',\n                created_by_id=created_by_id\n            )\n            self.session.add(letter)\n            await self.session.flush()\n            \n            for invoice in invoices:\n                line = DunningLetterLine(\n                    dunning_letter_id=letter.id,\n                    invoice_id=invoice.id,\n                    invoice_number=invoice.invoice_number,\n                    amount=invoice.balance_due,\n                    days_overdue=(date.today() - invoice.due_date).days\n                )\n                self.session.add(line)\n            \n            letters.append(letter)\n        \n        await self.session.flush()\n        return letters\n\n\nclass InvoiceApprovalRepository(BaseRepository[InvoiceApproval, InvoiceApprovalCreate, InvoiceApprovalUpdate]):\n    """Repository for Invoice Approval operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(InvoiceApproval, session)\n    \n    async def get_by_invoice(self, invoice_id: int) -> List[InvoiceApproval]:\n        """Get all approvals for an invoice"""\n        query = select(InvoiceApproval).options(\n            selectinload(InvoiceApproval.approver)\n        ).where(\n            InvoiceApproval.invoice_id == invoice_id\n        ).order_by(InvoiceApproval.created_at)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_approvals(\n        self, \n        approver_id: int\n    ) -> List[InvoiceApproval]:\n        """Get pending approvals for an approver"""\n        query = select(InvoiceApproval).options(\n            selectinload(InvoiceApproval.invoice)\n        ).where(\n            InvoiceApproval.approver_id == approver_id,\n            InvoiceApproval.status == \'Pending\'\n        ).order_by(InvoiceApproval.created_at)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def approve(\n        self, \n        approval_id: int, \n        comments: Optional[str] = None\n    ) -> InvoiceApproval:\n        """Approve an invoice"""\n        approval = await self.get_by_id(approval_id)\n        if approval:\n            approval.status = \'Approved\'\n            approval.approved_at = datetime.utcnow()\n            approval.comments = comments\n            await self.session.flush()\n        return approval\n    \n    async def reject(\n        self, \n        approval_id: int, \n        reason: str\n    ) -> InvoiceApproval:\n        """Reject an invoice"""\n        approval = await self.get_by_id(approval_id)\n        if approval:\n            approval.status = \'Rejected\'\n            approval.approved_at = datetime.utcnow()\n            approval.comments = reason\n            await self.session.flush()\n        return approval\n\n\nclass InvoiceAgingRepository(BaseRepository[InvoiceAging, InvoiceAgingCreate, InvoiceAgingUpdate]):\n    """Repository for Invoice Aging operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(InvoiceAging, session)\n    \n    async def get_by_company_date(\n        self, \n        company_id: int, \n        aging_date: date\n    ) -> List[InvoiceAging]:\n        """Get aging records for company and date"""\n        query = select(InvoiceAging).where(\n            InvoiceAging.company_id == company_id,\n            InvoiceAging.aging_date == aging_date\n        ).order_by(InvoiceAging.customer_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_latest_aging(\n        self, \n        company_id: int\n    ) -> List[InvoiceAging]:\n        """Get latest aging records for company"""\n        subquery = select(func.max(InvoiceAging.aging_date)).where(\n            InvoiceAging.company_id == company_id\n        ).scalar_subquery()\n        \n        query = select(InvoiceAging).where(\n            InvoiceAging.company_id == company_id,\n            InvoiceAging.aging_date == subquery\n        ).order_by(InvoiceAging.customer_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def calculate_aging(\n        self, \n        company_id: int, \n        aging_date: Optional[date] = None,\n        created_by_id: Optional[int] = None\n    ) -> List[InvoiceAging]:\n        """Calculate aging for all customers"""\n        if aging_date is None:\n            aging_date = date.today()\n        \n        invoice_repo = InvoiceRepository(self.session)\n        invoices = await invoice_repo.get_by_status(company_id, \'Sent\')\n        \n        customer_aging = {}\n        for invoice in invoices:\n            customer_id = invoice.customer_id\n            balance = invoice.balance_due or Decimal(\'0\')\n            days_overdue = (aging_date - invoice.due_date).days if invoice.due_date else 0\n            \n            if customer_id not in customer_aging:\n                customer_aging[customer_id] = {\n                    \'current\': Decimal(\'0\'),\n                    \'days_30\': Decimal(\'0\'),\n                    \'days_60\': Decimal(\'0\'),\n                    \'days_90\': Decimal(\'0\'),\n                    \'over_90\': Decimal(\'0\')\n                }\n            \n            if days_overdue <= 0:\n                customer_aging[customer_id][\'current\'] += balance\n            elif days_overdue <= 30:\n                customer_aging[customer_id][\'days_30\'] += balance\n            elif days_overdue <= 60:\n                customer_aging[customer_id][\'days_60\'] += balance\n            elif days_overdue <= 90:\n                customer_aging[customer_id][\'days_90\'] += balance\n            else:\n                customer_aging[customer_id][\'over_90\'] += balance\n        \n        aging_records = []\n        for customer_id, aging in customer_aging.items():\n            record = InvoiceAging(\n                company_id=company_id,\n                customer_id=customer_id,\n                aging_date=aging_date,\n                current=aging[\'current\'],\n                days_30=aging[\'days_30\'],\n                days_60=aging[\'days_60\'],\n                days_90=aging[\'days_90\'],\n                over_90=aging[\'over_90\'],\n                total=aging[\'current\'] + aging[\'days_30\'] + aging[\'days_60\'] + aging[\'days_90\'] + aging[\'over_90\'],\n                created_by_id=created_by_id\n            )\n            self.session.add(record)\n            aging_records.append(record)\n        \n        await self.session.flush()\n        return aging_records\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/invoice.py\' created successfully.") </create-file> </tool_result>'}
{'role': 'assistant', 'content': 'Excellent! Invoice repository created successfully. Let me continue with the HR repository for human resources and payroll operations.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/hr.py">\n"""\nHR Repository - Data Access Layer for Human Resources and Payroll Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal,\n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager,\n    aliased, with_loader_criteria\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom app.models.hr import (\n    Department, JobPosition, Employee, EmployeeAddress,\n    EmployeeBankAccount, EmployeeEmergencyContact, EmployeeDocument,\n    EmploymentHistory, EmployeeSkill, EmployeeCertification,\n    PayrollPeriod, PayrollRun, Payslip, PayslipLine,\n    PayrollItem, EmployeePayrollItem,\n    TimeEntry, TimeEntryApproval, Timesheet, OvertimeEntry,\n    LeaveType, LeaveBalance, LeaveRequest, LeaveApproval,\n    Attendance, AttendanceException, ShiftSchedule, ShiftAssignment,\n    PerformanceReview, PerformanceGoal, PerformanceFeedback,\n    RecruitmentJob, JobApplication, Interview, InterviewFeedback,\n    OnboardingTask, OffboardingTask,\n    Training, TrainingSession, TrainingEnrollment, TrainingCompletion,\n    Benefit, EmployeeBenefit, BenefitClaim,\n    ExpenseCategory, ExpenseReport, ExpenseLine, ExpenseApproval\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.hr import (\n    DepartmentCreate, DepartmentUpdate,\n    JobPositionCreate, JobPositionUpdate,\n    EmployeeCreate, EmployeeUpdate,\n    EmployeeAddressCreate, EmployeeAddressUpdate,\n    EmployeeBankAccountCreate, EmployeeBankAccountUpdate,\n    EmployeeEmergencyContactCreate, EmployeeEmergencyContactUpdate,\n    EmployeeDocumentCreate, EmployeeDocumentUpdate,\n    EmploymentHistoryCreate, EmploymentHistoryUpdate,\n    EmployeeSkillCreate, EmployeeSkillUpdate,\n    EmployeeCertificationCreate, EmployeeCertificationUpdate,\n    PayrollPeriodCreate, PayrollPeriodUpdate,\n    PayrollRunCreate, PayrollRunUpdate,\n    PayslipCreate, PayslipUpdate,\n    PayslipLineCreate, PayslipLineUpdate,\n    PayrollItemCreate, PayrollItemUpdate,\n    EmployeePayrollItemCreate, EmployeePayrollItemUpdate,\n    TimeEntryCreate, TimeEntryUpdate,\n    TimeEntryApprovalCreate, TimeEntryApprovalUpdate,\n    TimesheetCreate, TimesheetUpdate,\n    OvertimeEntryCreate, OvertimeEntryUpdate,\n    LeaveTypeCreate, LeaveTypeUpdate,\n    LeaveBalanceCreate, LeaveBalanceUpdate,\n    LeaveRequestCreate, LeaveRequestUpdate,\n    LeaveApprovalCreate, LeaveApprovalUpdate,\n    AttendanceCreate, AttendanceUpdate,\n    AttendanceExceptionCreate, AttendanceExceptionUpdate,\n    ShiftScheduleCreate, ShiftScheduleUpdate,\n    ShiftAssignmentCreate, ShiftAssignmentUpdate,\n    PerformanceReviewCreate, PerformanceReviewUpdate,\n    PerformanceGoalCreate, PerformanceGoalUpdate,\n    PerformanceFeedbackCreate, PerformanceFeedbackUpdate,\n    RecruitmentJobCreate, RecruitmentJobUpdate,\n    JobApplicationCreate, JobApplicationUpdate,\n    InterviewCreate, InterviewUpdate,\n    InterviewFeedbackCreate, InterviewFeedbackUpdate,\n    OnboardingTaskCreate, OnboardingTaskUpdate,\n    OffboardingTaskCreate, OffboardingTaskUpdate,\n    TrainingCreate, TrainingUpdate,\n    TrainingSessionCreate, TrainingSessionUpdate,\n    TrainingEnrollmentCreate, TrainingEnrollmentUpdate,\n    TrainingCompletionCreate, TrainingCompletionUpdate,\n    BenefitCreate, BenefitUpdate,\n    EmployeeBenefitCreate, EmployeeBenefitUpdate,\n    BenefitClaimCreate, BenefitClaimUpdate,\n    ExpenseCategoryCreate, ExpenseCategoryUpdate,\n    ExpenseReportCreate, ExpenseReportUpdate,\n    ExpenseLineCreate, ExpenseLineUpdate,\n    ExpenseApprovalCreate, ExpenseApprovalUpdate\n)\n\n\nclass DepartmentRepository(CompanyScopedRepository[Department, DepartmentCreate, DepartmentUpdate]):\n    """Repository for Department operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Department, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[Department]:\n        """Get department by code"""\n        query = select(Department).options(\n            selectinload(Department.manager),\n            selectinload(Department.parent)\n        ).where(\n            Department.company_id == company_id,\n            Department.code == code,\n            Department.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[Department]:\n        """Get department by name"""\n        query = select(Department).where(\n            Department.company_id == company_id,\n            Department.name == name,\n            Department.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_root_departments(self, company_id: int) -> List[Department]:\n        """Get root departments (no parent)"""\n        query = select(Department).where(\n            Department.company_id == company_id,\n            Department.parent_id.is_(None),\n            Department.is_deleted == False\n        ).order_by(Department.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_departments(self, company_id: int) -> List[Department]:\n        """Get all active departments"""\n        query = select(Department).options(\n            selectinload(Department.manager)\n        ).where(\n            Department.company_id == company_id,\n            Department.is_active == True,\n            Department.is_deleted == False\n        ).order_by(Department.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_department_tree(self, company_id: int) -> List[Dict[str, Any]]:\n        """Get hierarchical tree of departments"""\n        departments = await self.get_all_by_company(company_id)\n        \n        def build_tree(parent_id: Optional[int] = None) -> List[Dict[str, Any]]:\n            return [\n                {\n                    "id": dept.id,\n                    "code": dept.code,\n                    "name": dept.name,\n                    "manager_id": dept.manager_id,\n                    "children": build_tree(dept.id)\n                }\n                for dept in departments\n                if dept.parent_id == parent_id\n            ]\n        \n        return build_tree()\n    \n    async def get_department_employees(\n        self, \n        department_id: int\n    ) -> List[Employee]:\n        """Get all employees in a department"""\n        query = select(Employee).where(\n            Employee.department_id == department_id,\n            Employee.is_deleted == False\n        ).order_by(Employee.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass JobPositionRepository(CompanyScopedRepository[JobPosition, JobPositionCreate, JobPositionUpdate]):\n    """Repository for Job Position operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(JobPosition, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[JobPosition]:\n        """Get job position by code"""\n        query = select(JobPosition).options(\n            selectinload(JobPosition.department)\n        ).where(\n            JobPosition.company_id == company_id,\n            JobPosition.code == code,\n            JobPosition.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_title(self, company_id: int, title: str) -> Optional[JobPosition]:\n        """Get job position by title"""\n        query = select(JobPosition).where(\n            JobPosition.company_id == company_id,\n            JobPosition.title == title,\n            JobPosition.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_positions(self, company_id: int) -> List[JobPosition]:\n        """Get all active job positions"""\n        query = select(JobPosition).options(\n            selectinload(JobPosition.department)\n        ).where(\n            JobPosition.company_id == company_id,\n            JobPosition.is_active == True,\n            JobPosition.is_deleted == False\n        ).order_by(JobPosition.title)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_positions_by_department(\n        self, \n        department_id: int\n    ) -> List[JobPosition]:\n        """Get all positions for a department"""\n        query = select(JobPosition).where(\n            JobPosition.department_id == department_id,\n            JobPosition.is_deleted == False\n        ).order_by(JobPosition.title)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass EmployeeRepository(CompanyScopedRepository[Employee, EmployeeCreate, EmployeeUpdate]):\n    """Repository for Employee operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Employee, session)\n    \n    async def get_by_employee_number(\n        self, \n        company_id: int, \n        employee_number: str\n    ) -> Optional[Employee]:\n        """Get employee by employee number"""\n        query = select(Employee).options(\n            selectinload(Employee.department),\n            selectinload(Employee.job_position),\n            selectinload(Employee.manager),\n            selectinload(Employee.addresses),\n            selectinload(Employee.bank_accounts),\n            selectinload(Employee.emergency_contacts)\n        ).where(\n            Employee.company_id == company_id,\n            Employee.employee_number == employee_number,\n            Employee.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_email(self, email: str) -> Optional[Employee]:\n        """Get employee by email"""\n        query = select(Employee).where(\n            Employee.email == email,\n            Employee.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_employees(\n        self, \n        company_id: int\n    ) -> List[Employee]:\n        """Get all active employees"""\n        query = select(Employee).options(\n            selectinload(Employee.department),\n            selectinload(Employee.job_position)\n        ).where(\n            Employee.company_id == company_id,\n            Employee.employment_status == \'Active\',\n            Employee.is_deleted == False\n        ).order_by(Employee.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_employees_by_department(\n        self, \n        department_id: int\n    ) -> List[Employee]:\n        """Get all employees in a department"""\n        query = select(Employee).options(\n            selectinload(Employee.job_position)\n        ).where(\n            Employee.department_id == department_id,\n            Employee.is_deleted == False\n        ).order_by(Employee.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_employees_by_manager(\n        self, \n        manager_id: int\n    ) -> List[Employee]:\n        """Get all direct reports for a manager"""\n        query = select(Employee).options(\n            selectinload(Employee.department)\n        ).where(\n            Employee.manager_id == manager_id,\n            Employee.is_deleted == False\n        ).order_by(Employee.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_employees_by_status(\n        self, \n        company_id: int, \n        status: str\n    ) -> List[Employee]:\n        """Get employees by employment status"""\n        query = select(Employee).where(\n            Employee.company_id == company_id,\n            Employee.employment_status == status,\n            Employee.is_deleted == False\n        ).order_by(Employee.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_employees_hired_in_period(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[Employee]:\n        """Get employees hired in a date range"""\n        query = select(Employee).where(\n            Employee.company_id == company_id,\n            Employee.hire_date >= start_date,\n            Employee.hire_date <= end_date,\n            Employee.is_deleted == False\n        ).order_by(Employee.hire_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_upcoming_birthdays(\n        self, \n        company_id: int, \n        within_days: int = 30\n    ) -> List[Dict[str, Any]]:\n        """Get employees with upcoming birthdays"""\n        today = date.today()\n        end_date = today + timedelta(days=within_days)\n        \n        employees = await self.get_active_employees(company_id)\n        \n        upcoming = []\n        for emp in employees:\n            if emp.date_of_birth:\n                # Calculate birthday for this year\n                birthday = emp.date_of_birth.replace(year=today.year)\n                if birthday < today:\n                    birthday = birthday.replace(year=today.year + 1)\n                \n                if today <= birthday <= end_date:\n                    upcoming.append({\n                        "employee": emp,\n                        "birthday": birthday,\n                        "days_until": (birthday - today).days\n                    })\n        \n        return sorted(upcoming, key=lambda x: x[\'days_until\'])\n    \n    async def get_upcoming_anniversaries(\n        self, \n        company_id: int, \n        within_days: int = 30\n    ) -> List[Dict[str, Any]]:\n        """Get employees with upcoming work anniversaries"""\n        today = date.today()\n        end_date = today + timedelta(days=within_days)\n        \n        employees = await self.get_active_employees(company_id)\n        \n        upcoming = []\n        for emp in employees:\n            if emp.hire_date:\n                anniversary = emp.hire_date.replace(year=today.year)\n                if anniversary < today:\n                    anniversary = anniversary.replace(year=today.year + 1)\n                \n                if today <= anniversary <= end_date:\n                    years = anniversary.year - emp.hire_date.year\n                    upcoming.append({\n                        "employee": emp,\n                        "anniversary": anniversary,\n                        "years": years,\n                        "days_until": (anniversary - today).days\n                    })\n        \n        return sorted(upcoming, key=lambda x: x[\'days_until\'])\n    \n    async def generate_employee_number(\n        self, \n        company_id: int\n    ) -> str:\n        """Generate next employee number"""\n        query = select(func.max(Employee.employee_number)).where(\n            Employee.company_id == company_id,\n            Employee.employee_number.like(\'EMP-%\')\n        )\n        result = await self.session.execute(query)\n        max_number = result.scalar()\n        \n        if max_number:\n            try:\n                seq = int(max_number.split(\'-\')[-1]) + 1\n            except (ValueError, IndexError):\n                seq = 1\n        else:\n            seq = 1\n        \n        return f"EMP-{seq:05d}"\n    \n    async def terminate_employee(\n        self, \n        employee_id: int, \n        termination_date: date, \n        termination_reason: str,\n        terminated_by_id: int\n    ) -> Employee:\n        """Terminate an employee"""\n        employee = await self.get_by_id(employee_id)\n        if employee:\n            employee.employment_status = \'Terminated\'\n            employee.termination_date = termination_date\n            employee.termination_reason = termination_reason\n            employee.updated_at = datetime.utcnow()\n            employee.updated_by_id = terminated_by_id\n            await self.session.flush()\n        return employee\n\n\nclass EmployeeAddressRepository(BaseRepository[EmployeeAddress, EmployeeAddressCreate, EmployeeAddressUpdate]):\n    """Repository for Employee Address operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(EmployeeAddress, session)\n    \n    async def get_by_employee(\n        self, \n        employee_id: int\n    ) -> List[EmployeeAddress]:\n        """Get all addresses for an employee"""\n        query = select(EmployeeAddress).where(\n            EmployeeAddress.employee_id == employee_id\n        ).order_by(EmployeeAddress.is_primary.desc())\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_primary_address(\n        self, \n        employee_id: int\n    ) -> Optional[EmployeeAddress]:\n        """Get primary address for an employee"""\n        query = select(EmployeeAddress).where(\n            EmployeeAddress.employee_id == employee_id,\n            EmployeeAddress.is_primary == True\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n\n\nclass EmployeeBankAccountRepository(BaseRepository[EmployeeBankAccount, EmployeeBankAccountCreate, EmployeeBankAccountUpdate]):\n    """Repository for Employee Bank Account operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(EmployeeBankAccount, session)\n    \n    async def get_by_employee(\n        self, \n        employee_id: int\n    ) -> List[EmployeeBankAccount]:\n        """Get all bank accounts for an employee"""\n        query = select(EmployeeBankAccount).where(\n            EmployeeBankAccount.employee_id == employee_id\n        ).order_by(EmployeeBankAccount.is_primary.desc())\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_primary_account(\n        self, \n        employee_id: int\n    ) -> Optional[EmployeeBankAccount]:\n        """Get primary bank account for an employee"""\n        query = select(EmployeeBankAccount).where(\n            EmployeeBankAccount.employee_id == employee_id,\n            EmployeeBankAccount.is_primary == True\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n\n\nclass PayrollPeriodRepository(BaseRepository[PayrollPeriod, PayrollPeriodCreate, PayrollPeriodUpdate]):\n    """Repository for Payroll Period operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(PayrollPeriod, session)\n    \n    async def get_by_period_number(\n        self, \n        company_id: int, \n        period_number: str\n    ) -> Optional[PayrollPeriod]:\n        """Get payroll period by period number"""\n        query = select(PayrollPeriod).where(\n            PayrollPeriod.company_id == company_id,\n            PayrollPeriod.period_number == period_number\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_current_period(\n        self, \n        company_id: int\n    ) -> Optional[PayrollPeriod]:\n        """Get current payroll period"""\n        today = date.today()\n        query = select(PayrollPeriod).where(\n            PayrollPeriod.company_id == company_id,\n            PayrollPeriod.start_date <= today,\n            PayrollPeriod.end_date >= today\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_periods_by_year(\n        self, \n        company_id: int, \n        year: int\n    ) -> List[PayrollPeriod]:\n        """Get all payroll periods for a year"""\n        query = select(PayrollPeriod).where(\n            PayrollPeriod.company_id == company_id,\n            extract(\'year\', PayrollPeriod.start_date) == year\n        ).order_by(PayrollPeriod.start_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_open_periods(\n        self, \n        company_id: int\n    ) -> List[PayrollPeriod]:\n        """Get all open payroll periods"""\n        query = select(PayrollPeriod).where(\n            PayrollPeriod.company_id == company_id,\n            PayrollPeriod.is_closed == False\n        ).order_by(PayrollPeriod.start_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass PayrollRunRepository(BaseRepository[PayrollRun, PayrollRunCreate, PayrollRunUpdate]):\n    """Repository for Payroll Run operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(PayrollRun, session)\n    \n    async def get_by_run_number(\n        self, \n        company_id: int, \n        run_number: str\n    ) -> Optional[PayrollRun]:\n        """Get payroll run by run number"""\n        query = select(PayrollRun).options(\n            selectinload(PayrollRun.payslips)\n        ).where(\n            PayrollRun.company_id == company_id,\n            PayrollRun.run_number == run_number\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_period(\n        self, \n        payroll_period_id: int\n    ) -> List[PayrollRun]:\n        """Get all payroll runs for a period"""\n        query = select(PayrollRun).options(\n            selectinload(PayrollRun.payslips)\n        ).where(\n            PayrollRun.payroll_period_id == payroll_period_id\n        ).order_by(desc(PayrollRun.run_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_runs(\n        self, \n        company_id: int\n    ) -> List[PayrollRun]:\n        """Get all pending payroll runs"""\n        query = select(PayrollRun).where(\n            PayrollRun.company_id == company_id,\n            PayrollRun.status == \'Draft\'\n        ).order_by(PayrollRun.run_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def generate_run_number(\n        self, \n        company_id: int\n    ) -> str:\n        """Generate next payroll run number"""\n        today = date.today()\n        prefix = f"PR-{today.year}{today.month:02d}"\n        \n        query = select(func.max(PayrollRun.run_number)).where(\n            PayrollRun.company_id == company_id,\n            PayrollRun.run_number.like(f"{prefix}%")\n        )\n        result = await self.session.execute(query)\n        max_number = result.scalar()\n        \n        if max_number:\n            try:\n                seq = int(max_number.split(\'-\')[-1]) + 1\n            except (ValueError, IndexError):\n                seq = 1\n        else:\n            seq = 1\n        \n        return f"{prefix}-{seq:03d}"\n    \n    async def approve_run(\n        self, \n        run_id: int, \n        approved_by_id: int\n    ) -> PayrollRun:\n        """Approve a payroll run"""\n        run = await self.get_by_id(run_id)\n        if run and run.status == \'Draft\':\n            run.status = \'Approved\'\n            run.approved_at = datetime.utcnow()\n            run.approved_by_id = approved_by_id\n            await self.session.flush()\n        return run\n    \n    async def post_run(\n        self, \n        run_id: int, \n        posted_by_id: int\n    ) -> PayrollRun:\n        """Post a payroll run"""\n        run = await self.get_by_id(run_id, load_relationships=["payslips"])\n        if run and run.status == \'Approved\':\n            run.status = \'Posted\'\n            run.posted_at = datetime.utcnow()\n            run.posted_by_id = posted_by_id\n            \n            for payslip in run.payslips:\n                payslip.status = \'Posted\'\n            \n            await self.session.flush()\n        return run\n\n\nclass PayslipRepository(BaseRepository[Payslip, PayslipCreate, PayslipUpdate]):\n    """Repository for Payslip operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Payslip, session)\n    \n    async def get_by_payslip_number(\n        self, \n        company_id: int, \n        payslip_number: str\n    ) -> Optional[Payslip]:\n        """Get payslip by payslip number"""\n        query = select(Payslip).options(\n            selectinload(Payslip.employee),\n            selectinload(Payslip.lines)\n        ).where(\n            Payslip.company_id == company_id,\n            Payslip.payslip_number == payslip_number\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_employee_period(\n        self, \n        employee_id: int, \n        payroll_period_id: int\n    ) -> Optional[Payslip]:\n        """Get payslip for employee and period"""\n        query = select(Payslip).options(\n            selectinload(Payslip.lines)\n        ).where(\n            Payslip.employee_id == employee_id,\n            Payslip.payroll_period_id == payroll_period_id\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_payroll_run(\n        self, \n        payroll_run_id: int\n    ) -> List[Payslip]:\n        """Get all payslips for a payroll run"""\n        query = select(Payslip).options(\n            selectinload(Payslip.employee),\n            selectinload(Payslip.lines)\n        ).where(\n            Payslip.payroll_run_id == payroll_run_id\n        ).order_by(Payslip.employee_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_employee(\n        self, \n        employee_id: int,\n        limit: int = 12\n    ) -> List[Payslip]:\n        """Get payslips for an employee"""\n        query = select(Payslip).options(\n            selectinload(Payslip.lines)\n        ).where(\n            Payslip.employee_id == employee_id\n        ).order_by(desc(Payslip.pay_period_start)).limit(limit)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def calculate_payroll_totals(\n        self, \n        payroll_run_id: int\n    ) -> Dict[str, Decimal]:\n        """Calculate total payroll amounts"""\n        query = select(Payslip).where(\n            Payslip.payroll_run_id == payroll_run_id\n        )\n        result = await self.session.execute(query)\n        payslips = list(result.scalars().all())\n        \n        gross_pay = Decimal(\'0\')\n        net_pay = Decimal(\'0\')\n        total_deductions = Decimal(\'0\')\n        total_taxes = Decimal(\'0\')\n        \n        for payslip in payslips:\n            gross_pay += payslip.gross_pay or Decimal(\'0\')\n            net_pay += payslip.net_pay or Decimal(\'0\')\n            total_deductions += payslip.total_deductions or Decimal(\'0\')\n            total_taxes += payslip.total_taxes or Decimal(\'0\')\n        \n        return {\n            \'gross_pay\': gross_pay,\n            \'net_pay\': net_pay,\n            \'total_deductions\': total_deductions,\n            \'total_taxes\': total_taxes,\n            \'payslip_count\': len(payslips)\n        }\n\n\nclass LeaveTypeRepository(BaseRepository[LeaveType, LeaveTypeCreate, LeaveTypeUpdate]):\n    """Repository for Leave Type operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LeaveType, session)\n    \n    async def get_by_code(\n        self, \n        company_id: int, \n        code: str\n    ) -> Optional[LeaveType]:\n        """Get leave type by code"""\n        query = select(LeaveType).where(\n            LeaveType.company_id == company_id,\n            LeaveType.code == code,\n            LeaveType.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_types(\n        self, \n        company_id: int\n    ) -> List[LeaveType]:\n        """Get all active leave types"""\n        query = select(LeaveType).where(\n            LeaveType.company_id == company_id,\n            LeaveType.is_active == True,\n            LeaveType.is_deleted == False\n        ).order_by(LeaveType.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_paid_leave_types(\n        self, \n        company_id: int\n    ) -> List[LeaveType]:\n        """Get all paid leave types"""\n        query = select(LeaveType).where(\n            LeaveType.company_id == company_id,\n            LeaveType.is_paid == True,\n            LeaveType.is_active == True,\n            LeaveType.is_deleted == False\n        ).order_by(LeaveType.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass LeaveBalanceRepository(BaseRepository[LeaveBalance, LeaveBalanceCreate, LeaveBalanceUpdate]):\n    """Repository for Leave Balance operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LeaveBalance, session)\n    \n    async def get_by_employee_type(\n        self, \n        employee_id: int, \n        leave_type_id: int,\n        year: int\n    ) -> Optional[LeaveBalance]:\n        """Get leave balance for employee and type"""\n        query = select(LeaveBalance).where(\n            LeaveBalance.employee_id == employee_id,\n            LeaveBalance.leave_type_id == leave_type_id,\n            LeaveBalance.year == year\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_employee(\n        self, \n        employee_id: int,\n        year: Optional[int] = None\n    ) -> List[LeaveBalance]:\n        """Get all leave balances for an employee"""\n        query = select(LeaveBalance).options(\n            selectinload(LeaveBalance.leave_type)\n        ).where(\n            LeaveBalance.employee_id == employee_id\n        )\n        if year:\n            query = query.where(LeaveBalance.year == year)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def update_balance(\n        self, \n        employee_id: int, \n        leave_type_id: int,\n        year: int,\n        days_used: Decimal\n    ) -> LeaveBalance:\n        """Update leave balance"""\n        balance = await self.get_by_employee_type(employee_id, leave_type_id, year)\n        if balance:\n            balance.used = (balance.used or Decimal(\'0\')) + days_used\n            balance.remaining = balance.allocated - balance.used - (balance.pending or Decimal(\'0\'))\n            await self.session.flush()\n        return balance\n\n\nclass LeaveRequestRepository(BaseRepository[LeaveRequest, LeaveRequestCreate, LeaveRequestUpdate]):\n    """Repository for Leave Request operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LeaveRequest, session)\n    \n    async def get_by_employee(\n        self, \n        employee_id: int,\n        status: Optional[str] = None\n    ) -> List[LeaveRequest]:\n        """Get leave requests for an employee"""\n        query = select(LeaveRequest).options(\n            selectinload(LeaveRequest.leave_type)\n        ).where(\n            LeaveRequest.employee_id == employee_id\n        )\n        if status:\n            query = query.where(LeaveRequest.status == status)\n        query = query.order_by(desc(LeaveRequest.start_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_requests(\n        self, \n        company_id: int\n    ) -> List[LeaveRequest]:\n        """Get all pending leave requests"""\n        query = select(LeaveRequest).options(\n            selectinload(LeaveRequest.employee),\n            selectinload(LeaveRequest.leave_type)\n        ).join(Employee).where(\n            Employee.company_id == company_id,\n            LeaveRequest.status == \'Pending\'\n        ).order_by(LeaveRequest.start_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_overlapping_requests(\n        self, \n        employee_id: int, \n        start_date: date, \n        end_date: date,\n        exclude_id: Optional[int] = None\n    ) -> List[LeaveRequest]:\n        """Get overlapping leave requests"""\n        query = select(LeaveRequest).where(\n            LeaveRequest.employee_id == employee_id,\n            LeaveRequest.status.in_([\'Pending\', \'Approved\']),\n            or_(\n                and_(LeaveRequest.start_date <= start_date, LeaveRequest.end_date >= start_date),\n                and_(LeaveRequest.start_date <= end_date, LeaveRequest.end_date >= end_date),\n                and_(LeaveRequest.start_date >= start_date, LeaveRequest.end_date <= end_date)\n            )\n        )\n        if exclude_id:\n            query = query.where(LeaveRequest.id != exclude_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def approve_request(\n        self, \n        request_id: int, \n        approved_by_id: int,\n        comments: Optional[str] = None\n    ) -> LeaveRequest:\n        """Approve a leave request"""\n        request = await self.get_by_id(request_id)\n        if request and request.status == \'Pending\':\n            request.status = \'Approved\'\n            request.approved_at = datetime.utcnow()\n            request.approved_by_id = approved_by_id\n            request.approval_comments = comments\n            await self.session.flush()\n        return request\n    \n    async def reject_request(\n        self, \n        request_id: int, \n        rejected_by_id: int,\n        reason: str\n    ) -> LeaveRequest:\n        """Reject a leave request"""\n        request = await self.get_by_id(request_id)\n        if request and request.status == \'Pending\':\n            request.status = \'Rejected\'\n            request.approved_at = datetime.utcnow()\n            request.approved_by_id = rejected_by_id\n            request.approval_comments = reason\n            await self.session.flush()\n        return request\n\n\nclass AttendanceRepository(BaseRepository[Attendance, AttendanceCreate, AttendanceUpdate]):\n    """Repository for Attendance operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Attendance, session)\n    \n    async def get_by_employee_date(\n        self, \n        employee_id: int, \n        attendance_date: date\n    ) -> Optional[Attendance]:\n        """Get attendance for employee and date"""\n        query = select(Attendance).where(\n            Attendance.employee_id == employee_id,\n            Attendance.attendance_date == attendance_date\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_employee_range(\n        self, \n        employee_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[Attendance]:\n        """Get attendance for employee within date range"""\n        query = select(Attendance).where(\n            Attendance.employee_id == employee_id,\n            Attendance.attendance_date >= start_date,\n            Attendance.attendance_date <= end_date\n        ).order_by(Attendance.attendance_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_date(\n        self, \n        company_id: int, \n        attendance_date: date\n    ) -> List[Attendance]:\n        """Get all attendance records for a date"""\n        query = select(Attendance).options(\n            selectinload(Attendance.employee)\n        ).join(Employee).where(\n            Employee.company_id == company_id,\n            Attendance.attendance_date == attendance_date\n        ).order_by(Attendance.employee_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_absent_employees(\n        self, \n        company_id: int, \n        attendance_date: date\n    ) -> List[Employee]:\n        """Get employees absent on a date"""\n        subquery = select(Attendance.employee_id).where(\n            Attendance.attendance_date == attendance_date\n        )\n        query = select(Employee).where(\n            Employee.company_id == company_id,\n            Employee.employment_status == \'Active\',\n            Employee.id.not_in(subquery)\n        ).order_by(Employee.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def record_check_in(\n        self, \n        employee_id: int, \n        check_in_time: datetime\n    ) -> Attendance:\n        """Record check-in"""\n        attendance = await self.get_by_employee_date(employee_id, check_in_time.date())\n        if not attendance:\n            attendance = Attendance(\n                employee_id=employee_id,\n                attendance_date=check_in_time.date(),\n                check_in=check_in_time.time()\n            )\n            self.session.add(attendance)\n        else:\n            attendance.check_in = check_in_time.time()\n        await self.session.flush()\n        return attendance\n    \n    async def record_check_out(\n        self, \n        employee_id: int, \n        check_out_time: datetime\n    ) -> Attendance:\n        """Record check-out"""\n        attendance = await self.get_by_employee_date(employee_id, check_out_time.date())\n        if attendance:\n            attendance.check_out = check_out_time.time()\n            await self.session.flush()\n        return attendance\n\n\nclass PerformanceReviewRepository(BaseRepository[PerformanceReview, PerformanceReviewCreate, PerformanceReviewUpdate]):\n    """Repository for Performance Review operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(PerformanceReview, session)\n    \n    async def get_by_employee(\n        self, \n        employee_id: int,\n        status: Optional[str] = None\n    ) -> List[PerformanceReview]:\n        """Get performance reviews for an employee"""\n        query = select(PerformanceReview).options(\n            selectinload(PerformanceReview.reviewer)\n        ).where(\n            PerformanceReview.employee_id == employee_id\n        )\n        if status:\n            query = query.where(PerformanceReview.status == status)\n        query = query.order_by(desc(PerformanceReview.review_period_start))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_reviews(\n        self, \n        company_id: int\n    ) -> List[PerformanceReview]:\n        """Get all pending performance reviews"""\n        query = select(PerformanceReview).options(\n            selectinload(PerformanceReview.employee),\n            selectinload(PerformanceReview.reviewer)\n        ).join(Employee).where(\n            Employee.company_id == company_id,\n            PerformanceReview.status == \'Pending\'\n        ).order_by(PerformanceReview.review_period_end)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_reviews_by_reviewer(\n        self, \n        reviewer_id: int,\n        status: Optional[str] = None\n    ) -> List[PerformanceReview]:\n        """Get reviews assigned to a reviewer"""\n        query = select(PerformanceReview).options(\n            selectinload(PerformanceReview.employee)\n        ).where(\n            PerformanceReview.reviewer_id == reviewer_id\n        )\n        if status:\n            query = query.where(PerformanceReview.status == status)\n        query = query.order_by(PerformanceReview.review_period_end)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def complete_review(\n        self, \n        review_id: int, \n        overall_rating: Decimal,\n        comments: Optional[str] = None\n    ) -> PerformanceReview:\n        """Complete a performance review"""\n        review = await self.get_by_id(review_id)\n        if review:\n            review.status = \'Completed\'\n            review.overall_rating = overall_rating\n            review.review_completed_at = datetime.utcnow()\n            review.comments = comments\n            await self.session.flush()\n        return review\n\n\nclass ExpenseReportRepository(BaseRepository[ExpenseReport, ExpenseReportCreate, ExpenseReportUpdate]):\n    """Repository for Expense Report operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ExpenseReport, session)\n    \n    async def get_by_report_number(\n        self, \n        company_id: int, \n        report_number: str\n    ) -> Optional[ExpenseReport]:\n        """Get expense report by report number"""\n        query = select(ExpenseReport).options(\n            selectinload(ExpenseReport.lines)\n        ).where(\n            ExpenseReport.company_id == company_id,\n            ExpenseReport.report_number == report_number,\n            ExpenseReport.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_employee(\n        self, \n        employee_id: int,\n        status: Optional[str] = None\n    ) -> List[ExpenseReport]:\n        """Get expense reports for an employee"""\n        query = select(ExpenseReport).options(\n            selectinload(ExpenseReport.lines)\n        ).where(\n            ExpenseReport.employee_id == employee_id,\n            ExpenseReport.is_deleted == False\n        )\n        if status:\n            query = query.where(ExpenseReport.status == status)\n        query = query.order_by(desc(ExpenseReport.submission_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_reports(\n        self, \n        company_id: int\n    ) -> List[ExpenseReport]:\n        """Get all pending expense reports"""\n        query = select(ExpenseReport).options(\n            selectinload(ExpenseReport.employee),\n            selectinload(ExpenseReport.lines)\n        ).where(\n            ExpenseReport.company_id == company_id,\n            ExpenseReport.status == \'Pending\',\n            ExpenseReport.is_deleted == False\n        ).order_by(ExpenseReport.submission_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def submit_report(\n        self, \n        report_id: int\n    ) -> ExpenseReport:\n        """Submit an expense report"""\n        report = await self.get_by_id(report_id)\n        if report and report.status == \'Draft\':\n            report.status = \'Pending\'\n            report.submission_date = date.today()\n            await self.session.flush()\n        return report\n    \n    async def approve_report(\n        self, \n        report_id: int, \n        approved_by_id: int,\n        comments: Optional[str] = None\n    ) -> ExpenseReport:\n        """Approve an expense report"""\n        report = await self.get_by_id(report_id)\n        if report and report.status == \'Pending\':\n            report.status = \'Approved\'\n            report.approval_date = date.today()\n            report.approved_by_id = approved_by_id\n            report.approval_comments = comments\n            await self.session.flush()\n        return report\n    \n    async def reject_report(\n        self, \n        report_id: int, \n        rejected_by_id: int,\n        reason: str\n    ) -> ExpenseReport:\n        """Reject an expense report"""\n        report = await self.get_by_id(report_id)\n        if report and report.status == \'Pending\':\n            report.status = \'Rejected\'\n            report.approval_date = date.today()\n            report.approved_by_id = rejected_by_id\n            report.approval_comments = reason\n            await self.session.flush()\n        return report\n\n\nclass TrainingRepository(BaseRepository[Training, TrainingCreate, TrainingUpdate]):\n    """Repository for Training operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Training, session)\n    \n    async def get_by_code(\n        self, \n        company_id: int, \n        code: str\n    ) -> Optional[Training]:\n        """Get training by code"""\n        query = select(Training).where(\n            Training.company_id == company_id,\n            Training.code == code,\n            Training.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_trainings(\n        self, \n        company_id: int\n    ) -> List[Training]:\n        """Get all active trainings"""\n        query = select(Training).where(\n            Training.company_id == company_id,\n            Training.is_active == True,\n            Training.is_deleted == False\n        ).order_by(Training.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_mandatory_trainings(\n        self, \n        company_id: int\n    ) -> List[Training]:\n        """Get all mandatory trainings"""\n        query = select(Training).where(\n            Training.company_id == company_id,\n            Training.is_mandatory == True,\n            Training.is_active == True,\n            Training.is_deleted == False\n        ).order_by(Training.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass BenefitRepository(BaseRepository[Benefit, BenefitCreate, BenefitUpdate]):\n    """Repository for Benefit operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Benefit, session)\n    \n    async def get_by_code(\n        self, \n        company_id: int, \n        code: str\n    ) -> Optional[Benefit]:\n        """Get benefit by code"""\n        query = select(Benefit).where(\n            Benefit.company_id == company_id,\n            Benefit.code == code,\n            Benefit.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_benefits(\n        self, \n        company_id: int\n    ) -> List[Benefit]:\n        """Get all active benefits"""\n        query = select(Benefit).where(\n            Benefit.company_id == company_id,\n            Benefit.is_active == True,\n            Benefit.is_deleted == False\n        ).order_by(Benefit.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_benefits_by_type(\n        self, \n        company_id: int, \n        benefit_type: str\n    ) -> List[Benefit]:\n        """Get benefits by type"""\n        query = select(Benefit).where(\n            Benefit.company_id == company_id,\n            Benefit.benefit_type == benefit_type,\n            Benefit.is_deleted == False\n        ).order_by(Benefit.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/hr.py\' created successfully.") </create-file> </tool_result>'}
{'role': 'assistant', 'content': 'HR repository created successfully. Let me continue with the Tax repository for tax engine operations.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/tax.py">\n"""\nTax Repository - Data Access Layer for Tax Engine Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple\nfrom datetime import date, datetime\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal,\n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager,\n    aliased, with_loader_criteria\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom app.models.tax import (\n    TaxJurisdiction, TaxType, TaxRate, TaxRegistration,\n    TaxTransaction, TaxCalculation, TaxAdjustment,\n    TaxFiling, TaxFilingLine, TaxPayment,\n    TaxAudit, TaxAuditFinding,\n    TaxExemption, TaxExemptionCertificate,\n    NexusRule, NexusDetermination, TaxReport\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.tax import (\n    TaxJurisdictionCreate, TaxJurisdictionUpdate,\n    TaxTypeCreate, TaxTypeUpdate,\n    TaxRateCreate, TaxRateUpdate,\n    TaxRegistrationCreate, TaxRegistrationUpdate,\n    TaxTransactionCreate, TaxTransactionUpdate,\n    TaxCalculationCreate, TaxCalculationUpdate,\n    TaxAdjustmentCreate, TaxAdjustmentUpdate,\n    TaxFilingCreate, TaxFilingUpdate,\n    TaxFilingLineCreate, TaxFilingLineUpdate,\n    TaxPaymentCreate, TaxPaymentUpdate,\n    TaxAuditCreate, TaxAuditUpdate,\n    TaxAuditFindingCreate, TaxAuditFindingUpdate,\n    TaxExemptionCreate, TaxExemptionUpdate,\n    TaxExemptionCertificateCreate, TaxExemptionCertificateUpdate,\n    NexusRuleCreate, NexusRuleUpdate,\n    NexusDeterminationCreate, NexusDeterminationUpdate,\n    TaxReportCreate, TaxReportUpdate\n)\n\n\nclass TaxJurisdictionRepository(BaseRepository[TaxJurisdiction, TaxJurisdictionCreate, TaxJurisdictionUpdate]):\n    """Repository for Tax Jurisdiction operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxJurisdiction, session)\n    \n    async def get_by_code(self, code: str) -> Optional[TaxJurisdiction]:\n        """Get jurisdiction by code"""\n        query = select(TaxJurisdiction).where(\n            TaxJurisdiction.code == code,\n            TaxJurisdiction.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_country(\n        self, \n        country: str, \n        region: Optional[str] = None\n    ) -> List[TaxJurisdiction]:\n        """Get jurisdictions by country/region"""\n        query = select(TaxJurisdiction).where(\n            TaxJurisdiction.country == country,\n            TaxJurisdiction.is_deleted == False\n        )\n        if region:\n            query = query.where(TaxJurisdiction.region == region)\n        query = query.order_by(TaxJurisdiction.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_jurisdictions(self) -> List[TaxJurisdiction]:\n        """Get all active jurisdictions"""\n        query = select(TaxJurisdiction).where(\n            TaxJurisdiction.is_active == True,\n            TaxJurisdiction.is_deleted == False\n        ).order_by(TaxJurisdiction.country, TaxJurisdiction.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_jurisdictions_by_type(\n        self, \n        jurisdiction_type: str\n    ) -> List[TaxJurisdiction]:\n        """Get jurisdictions by type (Federal, State, Local)"""\n        query = select(TaxJurisdiction).where(\n            TaxJurisdiction.jurisdiction_type == jurisdiction_type,\n            TaxJurisdiction.is_active == True,\n            TaxJurisdiction.is_deleted == False\n        ).order_by(TaxJurisdiction.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass TaxTypeRepository(BaseRepository[TaxType, TaxTypeCreate, TaxTypeUpdate]):\n    """Repository for Tax Type operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxType, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[TaxType]:\n        """Get tax type by code"""\n        query = select(TaxType).options(\n            selectinload(TaxType.jurisdiction)\n        ).where(\n            TaxType.company_id == company_id,\n            TaxType.code == code,\n            TaxType.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_jurisdiction(\n        self, \n        jurisdiction_id: int\n    ) -> List[TaxType]:\n        """Get tax types by jurisdiction"""\n        query = select(TaxType).where(\n            TaxType.jurisdiction_id == jurisdiction_id,\n            TaxType.is_deleted == False\n        ).order_by(TaxType.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_types(self, company_id: int) -> List[TaxType]:\n        """Get all active tax types"""\n        query = select(TaxType).options(\n            selectinload(TaxType.jurisdiction)\n        ).where(\n            TaxType.company_id == company_id,\n            TaxType.is_active == True,\n            TaxType.is_deleted == False\n        ).order_by(TaxType.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_types_by_category(\n        self, \n        company_id: int, \n        category: str\n    ) -> List[TaxType]:\n        """Get tax types by category (Sales, Purchase, Withholding, etc.)"""\n        query = select(TaxType).where(\n            TaxType.company_id == company_id,\n            TaxType.category == category,\n            TaxType.is_deleted == False\n        ).order_by(TaxType.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass TaxRateRepository(BaseRepository[TaxRate, TaxRateCreate, TaxRateUpdate]):\n    """Repository for Tax Rate operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxRate, session)\n    \n    async def get_by_tax_type(\n        self, \n        tax_type_id: int,\n        effective_date: Optional[date] = None\n    ) -> List[TaxRate]:\n        """Get rates for a tax type"""\n        query = select(TaxRate).where(\n            TaxRate.tax_type_id == tax_type_id,\n            TaxRate.is_deleted == False\n        )\n        if effective_date:\n            query = query.where(\n                TaxRate.effective_from <= effective_date,\n                or_(TaxRate.effective_to.is_(None), TaxRate.effective_to >= effective_date)\n            )\n        query = query.order_by(desc(TaxRate.effective_from))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_current_rate(\n        self, \n        tax_type_id: int,\n        effective_date: Optional[date] = None\n    ) -> Optional[TaxRate]:\n        """Get current effective rate for a tax type"""\n        if effective_date is None:\n            effective_date = date.today()\n        \n        query = select(TaxRate).where(\n            TaxRate.tax_type_id == tax_type_id,\n            TaxRate.effective_from <= effective_date,\n            or_(TaxRate.effective_to.is_(None), TaxRate.effective_to >= effective_date),\n            TaxRate.is_deleted == False\n        ).order_by(desc(TaxRate.effective_from)).limit(1)\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_rates_by_jurisdiction(\n        self, \n        jurisdiction_id: int,\n        effective_date: Optional[date] = None\n    ) -> List[TaxRate]:\n        """Get all rates for a jurisdiction"""\n        query = select(TaxRate).options(\n            selectinload(TaxRate.tax_type)\n        ).join(TaxType).where(\n            TaxType.jurisdiction_id == jurisdiction_id,\n            TaxRate.is_deleted == False\n        )\n        if effective_date:\n            query = query.where(\n                TaxRate.effective_from <= effective_date,\n                or_(TaxRate.effective_to.is_(None), TaxRate.effective_to >= effective_date)\n            )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def calculate_combined_rate(\n        self, \n        company_id: int, \n        jurisdiction_codes: List[str],\n        effective_date: Optional[date] = None\n    ) -> Decimal:\n        """Calculate combined tax rate for multiple jurisdictions"""\n        if effective_date is None:\n            effective_date = date.today()\n        \n        total_rate = Decimal(\'0\')\n        \n        for code in jurisdiction_codes:\n            jurisdiction = await self.session.execute(\n                select(TaxJurisdiction).where(TaxJurisdiction.code == code)\n            )\n            jur = jurisdiction.scalar_one_or_none()\n            if jur:\n                rates = await self.get_rates_by_jurisdiction(jur.id, effective_date)\n                for rate in rates:\n                    if rate.tax_type.company_id == company_id:\n                        total_rate += rate.rate\n        \n        return total_rate\n\n\nclass TaxRegistrationRepository(BaseRepository[TaxRegistration, TaxRegistrationCreate, TaxRegistrationUpdate]):\n    """Repository for Tax Registration operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxRegistration, session)\n    \n    async def get_by_registration_number(\n        self, \n        company_id: int, \n        registration_number: str\n    ) -> Optional[TaxRegistration]:\n        """Get registration by registration number"""\n        query = select(TaxRegistration).options(\n            selectinload(TaxRegistration.jurisdiction),\n            selectinload(TaxRegistration.tax_type)\n        ).where(\n            TaxRegistration.company_id == company_id,\n            TaxRegistration.registration_number == registration_number,\n            TaxRegistration.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_company(\n        self, \n        company_id: int\n    ) -> List[TaxRegistration]:\n        """Get all tax registrations for a company"""\n        query = select(TaxRegistration).options(\n            selectinload(TaxRegistration.jurisdiction),\n            selectinload(TaxRegistration.tax_type)\n        ).where(\n            TaxRegistration.company_id == company_id,\n            TaxRegistration.is_deleted == False\n        ).order_by(TaxRegistration.jurisdiction_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_registrations(\n        self, \n        company_id: int\n    ) -> List[TaxRegistration]:\n        """Get all active tax registrations"""\n        query = select(TaxRegistration).options(\n            selectinload(TaxRegistration.jurisdiction),\n            selectinload(TaxRegistration.tax_type)\n        ).where(\n            TaxRegistration.company_id == company_id,\n            TaxRegistration.status == \'Active\',\n            TaxRegistration.is_deleted == False\n        ).order_by(TaxRegistration.jurisdiction_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_registrations_by_jurisdiction(\n        self, \n        company_id: int, \n        jurisdiction_id: int\n    ) -> List[TaxRegistration]:\n        """Get registrations for a jurisdiction"""\n        query = select(TaxRegistration).where(\n            TaxRegistration.company_id == company_id,\n            TaxRegistration.jurisdiction_id == jurisdiction_id,\n            TaxRegistration.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_expiring_registrations(\n        self, \n        company_id: int, \n        within_days: int = 90\n    ) -> List[TaxRegistration]:\n        """Get registrations expiring within specified days"""\n        target_date = date.today() + datetime.timedelta(days=within_days)\n        query = select(TaxRegistration).where(\n            TaxRegistration.company_id == company_id,\n            TaxRegistration.expiry_date <= target_date,\n            TaxRegistration.expiry_date >= date.today(),\n            TaxRegistration.status == \'Active\',\n            TaxRegistration.is_deleted == False\n        ).order_by(TaxRegistration.expiry_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass TaxTransactionRepository(CompanyScopedRepository[TaxTransaction, TaxTransactionCreate, TaxTransactionUpdate]):\n    """Repository for Tax Transaction operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxTransaction, session)\n    \n    async def get_by_reference(\n        self, \n        company_id: int, \n        reference: str\n    ) -> Optional[TaxTransaction]:\n        """Get tax transaction by reference"""\n        query = select(TaxTransaction).options(\n            selectinload(TaxTransaction.tax_type),\n            selectinload(TaxTransaction.jurisdiction)\n        ).where(\n            TaxTransaction.company_id == company_id,\n            TaxTransaction.reference == reference,\n            TaxTransaction.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_source(\n        self, \n        company_id: int, \n        source_type: str, \n        source_id: int\n    ) -> List[TaxTransaction]:\n        """Get tax transactions by source document"""\n        query = select(TaxTransaction).options(\n            selectinload(TaxTransaction.tax_type)\n        ).where(\n            TaxTransaction.company_id == company_id,\n            TaxTransaction.source_type == source_type,\n            TaxTransaction.source_id == source_id,\n            TaxTransaction.is_deleted == False\n        ).order_by(TaxTransaction.transaction_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_date_range(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date,\n        tax_type_id: Optional[int] = None\n    ) -> List[TaxTransaction]:\n        """Get tax transactions within date range"""\n        query = select(TaxTransaction).options(\n            selectinload(TaxTransaction.tax_type),\n            selectinload(TaxTransaction.jurisdiction)\n        ).where(\n            TaxTransaction.company_id == company_id,\n            TaxTransaction.transaction_date >= start_date,\n            TaxTransaction.transaction_date <= end_date,\n            TaxTransaction.is_deleted == False\n        )\n        if tax_type_id:\n            query = query.where(TaxTransaction.tax_type_id == tax_type_id)\n        query = query.order_by(TaxTransaction.transaction_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_jurisdiction(\n        self, \n        company_id: int, \n        jurisdiction_id: int,\n        start_date: Optional[date] = None,\n        end_date: Optional[date] = None\n    ) -> List[TaxTransaction]:\n        """Get tax transactions by jurisdiction"""\n        query = select(TaxTransaction).where(\n            TaxTransaction.company_id == company_id,\n            TaxTransaction.jurisdiction_id == jurisdiction_id,\n            TaxTransaction.is_deleted == False\n        )\n        if start_date:\n            query = query.where(TaxTransaction.transaction_date >= start_date)\n        if end_date:\n            query = query.where(TaxTransaction.transaction_date <= end_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_tax_summary(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date\n    ) -> Dict[str, Any]:\n        """Get tax summary for period"""\n        query = select(\n            TaxTransaction.tax_type_id,\n            func.sum(TaxTransaction.taxable_amount).label(\'total_taxable\'),\n            func.sum(TaxTransaction.tax_amount).label(\'total_tax\'),\n            func.count(TaxTransaction.id).label(\'transaction_count\')\n        ).where(\n            TaxTransaction.company_id == company_id,\n            TaxTransaction.transaction_date >= start_date,\n            TaxTransaction.transaction_date <= end_date,\n            TaxTransaction.is_deleted == False\n        ).group_by(TaxTransaction.tax_type_id)\n        \n        result = await self.session.execute(query)\n        summary = {\n            \'by_tax_type\': [],\n            \'total_taxable\': Decimal(\'0\'),\n            \'total_tax\': Decimal(\'0\'),\n            \'transaction_count\': 0\n        }\n        \n        for row in result:\n            summary[\'by_tax_type\'].append({\n                \'tax_type_id\': row.tax_type_id,\n                \'total_taxable\': row.total_taxable,\n                \'total_tax\': row.total_tax,\n                \'transaction_count\': row.transaction_count\n            })\n            summary[\'total_taxable\'] += row.total_taxable or Decimal(\'0\')\n            summary[\'total_tax\'] += row.total_tax or Decimal(\'0\')\n            summary[\'transaction_count\'] += row.transaction_count\n        \n        return summary\n\n\nclass TaxFilingRepository(BaseRepository[TaxFiling, TaxFilingCreate, TaxFilingUpdate]):\n    """Repository for Tax Filing operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxFiling, session)\n    \n    async def get_by_filing_number(\n        self, \n        company_id: int, \n        filing_number: str\n    ) -> Optional[TaxFiling]:\n        """Get filing by filing number"""\n        query = select(TaxFiling).options(\n            selectinload(TaxFiling.lines),\n            selectinload(TaxFiling.tax_type),\n            selectinload(TaxFiling.jurisdiction)\n        ).where(\n            TaxFiling.company_id == company_id,\n            TaxFiling.filing_number == filing_number,\n            TaxFiling.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_period(\n        self, \n        company_id: int, \n        tax_type_id: int, \n        period_start: date, \n        period_end: date\n    ) -> Optional[TaxFiling]:\n        """Get filing for specific period"""\n        query = select(TaxFiling).where(\n            TaxFiling.company_id == company_id,\n            TaxFiling.tax_type_id == tax_type_id,\n            TaxFiling.period_start == period_start,\n            TaxFiling.period_end == period_end,\n            TaxFiling.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_pending_filings(\n        self, \n        company_id: int\n    ) -> List[TaxFiling]:\n        """Get all pending filings"""\n        query = select(TaxFiling).options(\n            selectinload(TaxFiling.tax_type),\n            selectinload(TaxFiling.jurisdiction)\n        ).where(\n            TaxFiling.company_id == company_id,\n            TaxFiling.status.in_([\'Draft\', \'Pending Review\']),\n            TaxFiling.is_deleted == False\n        ).order_by(TaxFiling.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_overdue_filings(\n        self, \n        company_id: int\n    ) -> List[TaxFiling]:\n        """Get overdue filings"""\n        query = select(TaxFiling).options(\n            selectinload(TaxFiling.tax_type)\n        ).where(\n            TaxFiling.company_id == company_id,\n            TaxFiling.due_date < date.today(),\n            TaxFiling.status.not_in([\'Filed\', \'Paid\']),\n            TaxFiling.is_deleted == False\n        ).order_by(TaxFiling.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_filings_by_jurisdiction(\n        self, \n        company_id: int, \n        jurisdiction_id: int,\n        year: Optional[int] = None\n    ) -> List[TaxFiling]:\n        """Get filings by jurisdiction"""\n        query = select(TaxFiling).where(\n            TaxFiling.company_id == company_id,\n            TaxFiling.jurisdiction_id == jurisdiction_id,\n            TaxFiling.is_deleted == False\n        )\n        if year:\n            query = query.where(\n                extract(\'year\', TaxFiling.period_start) == year\n            )\n        query = query.order_by(desc(TaxFiling.period_start))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def submit_filing(\n        self, \n        filing_id: int, \n        submitted_by_id: int\n    ) -> TaxFiling:\n        """Submit a tax filing"""\n        filing = await self.get_by_id(filing_id)\n        if filing and filing.status == \'Draft\':\n            filing.status = \'Filed\'\n            filing.filed_at = datetime.utcnow()\n            filing.filed_by_id = submitted_by_id\n            await self.session.flush()\n        return filing\n    \n    async def record_payment(\n        self, \n        filing_id: int, \n        payment_amount: Decimal, \n        payment_date: date,\n        payment_reference: str,\n        created_by_id: int\n    ) -> TaxPayment:\n        """Record a tax payment"""\n        filing = await self.get_by_id(filing_id)\n        if not filing:\n            return None\n        \n        payment = TaxPayment(\n            company_id=filing.company_id,\n            tax_filing_id=filing_id,\n            payment_date=payment_date,\n            payment_amount=payment_amount,\n            payment_reference=payment_reference,\n            created_by_id=created_by_id\n        )\n        self.session.add(payment)\n        \n        # Update filing status\n        filing.amount_paid = (filing.amount_paid or Decimal(\'0\')) + payment_amount\n        if filing.amount_paid >= filing.total_tax_due:\n            filing.status = \'Paid\'\n            filing.paid_at = datetime.utcnow()\n        \n        await self.session.flush()\n        return payment\n\n\nclass TaxExemptionRepository(BaseRepository[TaxExemption, TaxExemptionCreate, TaxExemptionUpdate]):\n    """Repository for Tax Exemption operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxExemption, session)\n    \n    async def get_by_customer(\n        self, \n        company_id: int, \n        customer_id: int,\n        tax_type_id: Optional[int] = None\n    ) -> List[TaxExemption]:\n        """Get exemptions for a customer"""\n        query = select(TaxExemption).options(\n            selectinload(TaxExemption.tax_type),\n            selectinload(TaxExemption.certificate)\n        ).where(\n            TaxExemption.company_id == company_id,\n            TaxExemption.customer_id == customer_id,\n            TaxExemption.is_deleted == False\n        )\n        if tax_type_id:\n            query = query.where(TaxExemption.tax_type_id == tax_type_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_exemptions(\n        self, \n        company_id: int\n    ) -> List[TaxExemption]:\n        """Get all active exemptions"""\n        query = select(TaxExemption).options(\n            selectinload(TaxExemption.customer),\n            selectinload(TaxExemption.tax_type)\n        ).where(\n            TaxExemption.company_id == company_id,\n            TaxExemption.status == \'Active\',\n            TaxExemption.effective_from <= date.today(),\n            or_(TaxExemption.effective_to.is_(None), TaxExemption.effective_to >= date.today()),\n            TaxExemption.is_deleted == False\n        ).order_by(TaxExemption.customer_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_expiring_exemptions(\n        self, \n        company_id: int, \n        within_days: int = 30\n    ) -> List[TaxExemption]:\n        """Get exemptions expiring within specified days"""\n        target_date = date.today() + datetime.timedelta(days=within_days)\n        query = select(TaxExemption).options(\n            selectinload(TaxExemption.customer)\n        ).where(\n            TaxExemption.company_id == company_id,\n            TaxExemption.effective_to <= target_date,\n            TaxExemption.effective_to >= date.today(),\n            TaxExemption.status == \'Active\',\n            TaxExemption.is_deleted == False\n        ).order_by(TaxExemption.effective_to)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def is_exempt(\n        self, \n        company_id: int, \n        customer_id: int, \n        tax_type_id: int\n    ) -> bool:\n        """Check if customer is exempt for tax type"""\n        query = select(TaxExemption).where(\n            TaxExemption.company_id == company_id,\n            TaxExemption.customer_id == customer_id,\n            TaxExemption.tax_type_id == tax_type_id,\n            TaxExemption.status == \'Active\',\n            TaxExemption.effective_from <= date.today(),\n            or_(TaxExemption.effective_to.is_(None), TaxExemption.effective_to >= date.today()),\n            TaxExemption.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none() is not None\n\n\nclass NexusRuleRepository(BaseRepository[NexusRule, NexusRuleCreate, NexusRuleUpdate]):\n    """Repository for Nexus Rule operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(NexusRule, session)\n    \n    async def get_by_jurisdiction(\n        self, \n        jurisdiction_id: int\n    ) -> List[NexusRule]:\n        """Get nexus rules by jurisdiction"""\n        query = select(NexusRule).where(\n            NexusRule.jurisdiction_id == jurisdiction_id,\n            NexusRule.is_deleted == False\n        ).order_by(NexusRule.threshold_type)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_rules(self) -> List[NexusRule]:\n        """Get all active nexus rules"""\n        query = select(NexusRule).options(\n            selectinload(NexusRule.jurisdiction)\n        ).where(\n            NexusRule.is_active == True,\n            NexusRule.is_deleted == False\n        ).order_by(NexusRule.jurisdiction_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_applicable_rules(\n        self, \n        jurisdiction_id: int, \n        transaction_type: str\n    ) -> List[NexusRule]:\n        """Get applicable nexus rules for transaction type"""\n        query = select(NexusRule).where(\n            NexusRule.jurisdiction_id == jurisdiction_id,\n            NexusRule.transaction_type == transaction_type,\n            NexusRule.is_active == True,\n            NexusRule.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass NexusDeterminationRepository(BaseRepository[NexusDetermination, NexusDeterminationCreate, NexusDeterminationUpdate]):\n    """Repository for Nexus Determination operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(NexusDetermination, session)\n    \n    async def get_by_company(\n        self, \n        company_id: int\n    ) -> List[NexusDetermination]:\n        """Get nexus determinations for company"""\n        query = select(NexusDetermination).options(\n            selectinload(NexusDetermination.jurisdiction)\n        ).where(\n            NexusDetermination.company_id == company_id,\n            NexusDetermination.is_deleted == False\n        ).order_by(NexusDetermination.jurisdiction_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_nexus(\n        self, \n        company_id: int\n    ) -> List[NexusDetermination]:\n        """Get active nexus for company"""\n        query = select(NexusDetermination).options(\n            selectinload(NexusDetermination.jurisdiction)\n        ).where(\n            NexusDetermination.company_id == company_id,\n            NexusDetermination.nexus_status == \'Active\',\n            NexusDetermination.is_deleted == False\n        ).order_by(NexusDetermination.jurisdiction_id)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_jurisdiction(\n        self, \n        company_id: int, \n        jurisdiction_id: int\n    ) -> Optional[NexusDetermination]:\n        """Get nexus determination for jurisdiction"""\n        query = select(NexusDetermination).where(\n            NexusDetermination.company_id == company_id,\n            NexusDetermination.jurisdiction_id == jurisdiction_id,\n            NexusDetermination.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def check_nexus(\n        self, \n        company_id: int, \n        jurisdiction_id: int\n    ) -> bool:\n        """Check if company has nexus in jurisdiction"""\n        query = select(NexusDetermination).where(\n            NexusDetermination.company_id == company_id,\n            NexusDetermination.jurisdiction_id == jurisdiction_id,\n            NexusDetermination.nexus_status == \'Active\',\n            NexusDetermination.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none() is not None\n    \n    async def update_nexus_tracking(\n        self, \n        company_id: int, \n        jurisdiction_id: int, \n        transaction_amount: Decimal\n    ) -> NexusDetermination:\n        """Update nexus tracking with new transaction"""\n        determination = await self.get_by_jurisdiction(company_id, jurisdiction_id)\n        \n        if determination:\n            determination.accumulated_sales = (determination.accumulated_sales or Decimal(\'0\')) + transaction_amount\n            determination.transaction_count = (determination.transaction_count or 0) + 1\n            \n            # Check if threshold exceeded\n            if determination.nexus_rule:\n                threshold = determination.nexus_rule.threshold_amount\n                if determination.accumulated_sales >= threshold:\n                    determination.nexus_status = \'Active\'\n                    determination.nexus_established_date = date.today()\n            \n            await self.session.flush()\n        else:\n            # Create new determination record\n            determination = NexusDetermination(\n                company_id=company_id,\n                jurisdiction_id=jurisdiction_id,\n                accumulated_sales=transaction_amount,\n                transaction_count=1,\n                nexus_status=\'Monitoring\'\n            )\n            self.session.add(determination)\n            await self.session.flush()\n        \n        return determination\n\n\nclass TaxAuditRepository(BaseRepository[TaxAudit, TaxAuditCreate, TaxAuditUpdate]):\n    """Repository for Tax Audit operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxAudit, session)\n    \n    async def get_by_audit_number(\n        self, \n        company_id: int, \n        audit_number: str\n    ) -> Optional[TaxAudit]:\n        """Get audit by audit number"""\n        query = select(TaxAudit).options(\n            selectinload(TaxAudit.findings),\n            selectinload(TaxAudit.jurisdiction)\n        ).where(\n            TaxAudit.company_id == company_id,\n            TaxAudit.audit_number == audit_number,\n            TaxAudit.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_audits(\n        self, \n        company_id: int\n    ) -> List[TaxAudit]:\n        """Get all active audits"""\n        query = select(TaxAudit).options(\n            selectinload(TaxAudit.jurisdiction)\n        ).where(\n            TaxAudit.company_id == company_id,\n            TaxAudit.status.in_([\'Open\', \'In Progress\']),\n            TaxAudit.is_deleted == False\n        ).order_by(TaxAudit.start_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_jurisdiction(\n        self, \n        company_id: int, \n        jurisdiction_id: int\n    ) -> List[TaxAudit]:\n        """Get audits by jurisdiction"""\n        query = select(TaxAudit).where(\n            TaxAudit.company_id == company_id,\n            TaxAudit.jurisdiction_id == jurisdiction_id,\n            TaxAudit.is_deleted == False\n        ).order_by(desc(TaxAudit.start_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def close_audit(\n        self, \n        audit_id: int, \n        resolution: str,\n        closed_by_id: int\n    ) -> TaxAudit:\n        """Close a tax audit"""\n        audit = await self.get_by_id(audit_id)\n        if audit:\n            audit.status = \'Closed\'\n            audit.resolution = resolution\n            audit.closed_at = datetime.utcnow()\n            audit.closed_by_id = closed_by_id\n            await self.session.flush()\n        return audit\n\n\nclass TaxReportRepository(BaseRepository[TaxReport, TaxReportCreate, TaxReportUpdate]):\n    """Repository for Tax Report operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(TaxReport, session)\n    \n    async def get_by_report_number(\n        self, \n        company_id: int, \n        report_number: str\n    ) -> Optional[TaxReport]:\n        """Get report by report number"""\n        query = select(TaxReport).where(\n            TaxReport.company_id == company_id,\n            TaxReport.report_number == report_number,\n            TaxReport.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_type(\n        self, \n        company_id: int, \n        report_type: str,\n        year: Optional[int] = None\n    ) -> List[TaxReport]:\n        """Get reports by type"""\n        query = select(TaxReport).where(\n            TaxReport.company_id == company_id,\n            TaxReport.report_type == report_type,\n            TaxReport.is_deleted == False\n        )\n        if year:\n            query = query.where(extract(\'year\', TaxReport.period_start) == year)\n        query = query.order_by(desc(TaxReport.period_start))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_period(\n        self, \n        company_id: int, \n        period_start: date, \n        period_end: date\n    ) -> List[TaxReport]:\n        """Get reports for period"""\n        query = select(TaxReport).where(\n            TaxReport.company_id == company_id,\n            TaxReport.period_start >= period_start,\n            TaxReport.period_end <= period_end,\n            TaxReport.is_deleted == False\n        ).order_by(TaxReport.report_type)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/tax.py\' created successfully.") </create-file> </tool_result>'}
{'role': 'assistant', 'content': 'Tax repository created successfully. Let me continue with the Workflow repository for the workflow and automation engine.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/workflow.py">\n"""\nWorkflow Repository - Data Access Layer for Workflow and Automation Engine Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal,\n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager,\n    aliased, with_loader_criteria\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom app.models.workflow import (\n    WorkflowDefinition, WorkflowVersion, WorkflowNode, WorkflowTransition,\n    WorkflowInstance, WorkflowTask, WorkflowTaskAssignment,\n    WorkflowComment, WorkflowAttachment,\n    Trigger, TriggerCondition, TriggerAction,\n    Scheduler, SchedulerRun, SchedulerLog,\n    NotificationTemplate, Notification, NotificationPreference,\n    AutomationRule, AutomationCondition, AutomationAction, AutomationRunLog\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.workflow import (\n    WorkflowDefinitionCreate, WorkflowDefinitionUpdate,\n    WorkflowVersionCreate, WorkflowVersionUpdate,\n    WorkflowNodeCreate, WorkflowNodeUpdate,\n    WorkflowTransitionCreate, WorkflowTransitionUpdate,\n    WorkflowInstanceCreate, WorkflowInstanceUpdate,\n    WorkflowTaskCreate, WorkflowTaskUpdate,\n    WorkflowTaskAssignmentCreate, WorkflowTaskAssignmentUpdate,\n    WorkflowCommentCreate, WorkflowCommentUpdate,\n    WorkflowAttachmentCreate, WorkflowAttachmentUpdate,\n    TriggerCreate, TriggerUpdate,\n    TriggerConditionCreate, TriggerConditionUpdate,\n    TriggerActionCreate, TriggerActionUpdate,\n    SchedulerCreate, SchedulerUpdate,\n    SchedulerRunCreate, SchedulerRunUpdate,\n    SchedulerLogCreate, SchedulerLogUpdate,\n    NotificationTemplateCreate, NotificationTemplateUpdate,\n    NotificationCreate, NotificationUpdate,\n    NotificationPreferenceCreate, NotificationPreferenceUpdate,\n    AutomationRuleCreate, AutomationRuleUpdate,\n    AutomationConditionCreate, AutomationConditionUpdate,\n    AutomationActionCreate, AutomationActionUpdate,\n    AutomationRunLogCreate, AutomationRunLogUpdate\n)\n\n\nclass WorkflowDefinitionRepository(CompanyScopedRepository[WorkflowDefinition, WorkflowDefinitionCreate, WorkflowDefinitionUpdate]):\n    """Repository for Workflow Definition operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(WorkflowDefinition, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[WorkflowDefinition]:\n        """Get workflow definition by code"""\n        query = select(WorkflowDefinition).options(\n            selectinload(WorkflowDefinition.versions),\n            selectinload(WorkflowDefinition.nodes),\n            selectinload(WorkflowDefinition.transitions)\n        ).where(\n            WorkflowDefinition.company_id == company_id,\n            WorkflowDefinition.code == code,\n            WorkflowDefinition.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[WorkflowDefinition]:\n        """Get workflow definition by name"""\n        query = select(WorkflowDefinition).where(\n            WorkflowDefinition.company_id == company_id,\n            WorkflowDefinition.name == name,\n            WorkflowDefinition.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_workflows(self, company_id: int) -> List[WorkflowDefinition]:\n        """Get all active workflow definitions"""\n        query = select(WorkflowDefinition).options(\n            selectinload(WorkflowDefinition.nodes)\n        ).where(\n            WorkflowDefinition.company_id == company_id,\n            WorkflowDefinition.status == \'Active\',\n            WorkflowDefinition.is_deleted == False\n        ).order_by(WorkflowDefinition.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_workflows_by_category(\n        self, \n        company_id: int, \n        category: str\n    ) -> List[WorkflowDefinition]:\n        """Get workflows by category"""\n        query = select(WorkflowDefinition).where(\n            WorkflowDefinition.company_id == company_id,\n            WorkflowDefinition.category == category,\n            WorkflowDefinition.is_deleted == False\n        ).order_by(WorkflowDefinition.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_workflows_by_trigger(\n        self, \n        company_id: int, \n        trigger_type: str\n    ) -> List[WorkflowDefinition]:\n        """Get workflows by trigger type"""\n        query = select(WorkflowDefinition).where(\n            WorkflowDefinition.company_id == company_id,\n            WorkflowDefinition.trigger_type == trigger_type,\n            WorkflowDefinition.status == \'Active\',\n            WorkflowDefinition.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def publish_workflow(\n        self, \n        workflow_id: int, \n        published_by_id: int\n    ) -> WorkflowDefinition:\n        """Publish a workflow"""\n        workflow = await self.get_by_id(workflow_id)\n        if workflow and workflow.status == \'Draft\':\n            workflow.status = \'Active\'\n            workflow.published_at = datetime.utcnow()\n            workflow.published_by_id = published_by_id\n            await self.session.flush()\n        return workflow\n    \n    async def deactivate_workflow(\n        self, \n        workflow_id: int\n    ) -> WorkflowDefinition:\n        """Deactivate a workflow"""\n        workflow = await self.get_by_id(workflow_id)\n        if workflow and workflow.status == \'Active\':\n            workflow.status = \'Inactive\'\n            await self.session.flush()\n        return workflow\n    \n    async def create_version(\n        self, \n        workflow_id: int, \n        version_number: str,\n        created_by_id: int,\n        change_description: Optional[str] = None\n    ) -> WorkflowVersion:\n        """Create a new version of a workflow"""\n        workflow = await self.get_by_id(workflow_id, load_relationships=["nodes", "transitions"])\n        if not workflow:\n            return None\n        \n        version = WorkflowVersion(\n            workflow_definition_id=workflow_id,\n            version_number=version_number,\n            status=\'Draft\',\n            change_description=change_description,\n            created_by_id=created_by_id\n        )\n        self.session.add(version)\n        await self.session.flush()\n        \n        # Copy nodes and transitions\n        for node in workflow.nodes:\n            new_node = WorkflowNode(\n                workflow_definition_id=workflow_id,\n                workflow_version_id=version.id,\n                node_key=node.node_key,\n                node_type=node.node_type,\n                name=node.name,\n                description=node.description,\n                config=node.config,\n                position_x=node.position_x,\n                position_y=node.position_y\n            )\n            self.session.add(new_node)\n        \n        await self.session.flush()\n        return version\n\n\nclass WorkflowNodeRepository(BaseRepository[WorkflowNode, WorkflowNodeCreate, WorkflowNodeUpdate]):\n    """Repository for Workflow Node operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(WorkflowNode, session)\n    \n    async def get_by_workflow(\n        self, \n        workflow_definition_id: int,\n        version_id: Optional[int] = None\n    ) -> List[WorkflowNode]:\n        """Get all nodes for a workflow"""\n        query = select(WorkflowNode).where(\n            WorkflowNode.workflow_definition_id == workflow_definition_id\n        )\n        if version_id:\n            query = query.where(WorkflowNode.workflow_version_id == version_id)\n        else:\n            query = query.where(WorkflowNode.workflow_version_id.is_(None))\n        query = query.order_by(WorkflowNode.node_key)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_by_key(\n        self, \n        workflow_definition_id: int, \n        node_key: str\n    ) -> Optional[WorkflowNode]:\n        """Get node by key"""\n        query = select(WorkflowNode).where(\n            WorkflowNode.workflow_definition_id == workflow_definition_id,\n            WorkflowNode.node_key == node_key,\n            WorkflowNode.workflow_version_id.is_(None)\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_start_node(\n        self, \n        workflow_definition_id: int\n    ) -> Optional[WorkflowNode]:\n        """Get the start node for a workflow"""\n        query = select(WorkflowNode).where(\n            WorkflowNode.workflow_definition_id == workflow_definition_id,\n            WorkflowNode.node_type == \'Start\',\n            WorkflowNode.workflow_version_id.is_(None)\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_end_nodes(\n        self, \n        workflow_definition_id: int\n    ) -> List[WorkflowNode]:\n        """Get all end nodes for a workflow"""\n        query = select(WorkflowNode).where(\n            WorkflowNode.workflow_definition_id == workflow_definition_id,\n            WorkflowNode.node_type == \'End\',\n            WorkflowNode.workflow_version_id.is_(None)\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_node_transitions(\n        self, \n        node_id: int\n    ) -> List[WorkflowTransition]:\n        """Get outgoing transitions from a node"""\n        query = select(WorkflowTransition).where(\n            WorkflowTransition.from_node_id == node_id\n        ).order_by(WorkflowTransition.priority)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass WorkflowTransitionRepository(BaseRepository[WorkflowTransition, WorkflowTransitionCreate, WorkflowTransitionUpdate]):\n    """Repository for Workflow Transition operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(WorkflowTransition, session)\n    \n    async def get_by_workflow(\n        self, \n        workflow_definition_id: int\n    ) -> List[WorkflowTransition]:\n        """Get all transitions for a workflow"""\n        query = select(WorkflowTransition).options(\n            selectinload(WorkflowTransition.from_node),\n            selectinload(WorkflowTransition.to_node)\n        ).where(\n            WorkflowTransition.workflow_definition_id == workflow_definition_id\n        ).order_by(WorkflowTransition.priority)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_transitions_from_node(\n        self, \n        from_node_id: int\n    ) -> List[WorkflowTransition]:\n        """Get transitions from a specific node"""\n        query = select(WorkflowTransition).options(\n            selectinload(WorkflowTransition.to_node)\n        ).where(\n            WorkflowTransition.from_node_id == from_node_id\n        ).order_by(WorkflowTransition.priority)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_transitions_to_node(\n        self, \n        to_node_id: int\n    ) -> List[WorkflowTransition]:\n        """Get transitions to a specific node"""\n        query = select(WorkflowTransition).options(\n            selectinload(WorkflowTransition.from_node)\n        ).where(\n            WorkflowTransition.to_node_id == to_node_id\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass WorkflowInstanceRepository(CompanyScopedRepository[WorkflowInstance, WorkflowInstanceCreate, WorkflowInstanceUpdate]):\n    """Repository for Workflow Instance operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(WorkflowInstance, session)\n    \n    async def get_by_instance_number(\n        self, \n        company_id: int, \n        instance_number: str\n    ) -> Optional[WorkflowInstance]:\n        """Get workflow instance by instance number"""\n        query = select(WorkflowInstance).options(\n            selectinload(WorkflowInstance.workflow_definition),\n            selectinload(WorkflowInstance.tasks),\n            selectinload(WorkflowInstance.current_node)\n        ).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowInstance.instance_number == instance_number,\n            WorkflowInstance.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_business_key(\n        self, \n        company_id: int, \n        business_key: str\n    ) -> Optional[WorkflowInstance]:\n        """Get workflow instance by business key"""\n        query = select(WorkflowInstance).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowInstance.business_key == business_key,\n            WorkflowInstance.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_instances(\n        self, \n        company_id: int,\n        workflow_definition_id: Optional[int] = None\n    ) -> List[WorkflowInstance]:\n        """Get all active workflow instances"""\n        query = select(WorkflowInstance).options(\n            selectinload(WorkflowInstance.workflow_definition),\n            selectinload(WorkflowInstance.current_node)\n        ).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowInstance.status == \'Running\',\n            WorkflowInstance.is_deleted == False\n        )\n        if workflow_definition_id:\n            query = query.where(WorkflowInstance.workflow_definition_id == workflow_definition_id)\n        query = query.order_by(desc(WorkflowInstance.started_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_instances_by_status(\n        self, \n        company_id: int, \n        status: str\n    ) -> List[WorkflowInstance]:\n        """Get instances by status"""\n        query = select(WorkflowInstance).options(\n            selectinload(WorkflowInstance.workflow_definition)\n        ).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowInstance.status == status,\n            WorkflowInstance.is_deleted == False\n        ).order_by(desc(WorkflowInstance.started_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_instances_by_initiator(\n        self, \n        initiator_id: int,\n        status: Optional[str] = None\n    ) -> List[WorkflowInstance]:\n        """Get instances initiated by a user"""\n        query = select(WorkflowInstance).options(\n            selectinload(WorkflowInstance.workflow_definition)\n        ).where(\n            WorkflowInstance.initiated_by_id == initiator_id,\n            WorkflowInstance.is_deleted == False\n        )\n        if status:\n            query = query.where(WorkflowInstance.status == status)\n        query = query.order_by(desc(WorkflowInstance.started_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_instances_by_entity(\n        self, \n        company_id: int, \n        entity_type: str, \n        entity_id: int\n    ) -> List[WorkflowInstance]:\n        """Get instances for a specific entity"""\n        query = select(WorkflowInstance).options(\n            selectinload(WorkflowInstance.workflow_definition)\n        ).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowInstance.entity_type == entity_type,\n            WorkflowInstance.entity_id == entity_id,\n            WorkflowInstance.is_deleted == False\n        ).order_by(desc(WorkflowInstance.started_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def start_instance(\n        self, \n        workflow_definition_id: int, \n        company_id: int,\n        initiated_by_id: int,\n        entity_type: Optional[str] = None,\n        entity_id: Optional[int] = None,\n        business_key: Optional[str] = None,\n        variables: Optional[Dict[str, Any]] = None\n    ) -> WorkflowInstance:\n        """Start a new workflow instance"""\n        # Generate instance number\n        count = await self.count(WorkflowInstance.company_id == company_id)\n        instance_number = f"WF-{date.today().year}-{count + 1:06d}"\n        \n        instance = WorkflowInstance(\n            company_id=company_id,\n            workflow_definition_id=workflow_definition_id,\n            instance_number=instance_number,\n            business_key=business_key,\n            entity_type=entity_type,\n            entity_id=entity_id,\n            status=\'Running\',\n            variables=variables or {},\n            initiated_by_id=initiated_by_id,\n            started_at=datetime.utcnow()\n        )\n        self.session.add(instance)\n        await self.session.flush()\n        return instance\n    \n    async def complete_instance(\n        self, \n        instance_id: int, \n        completed_by_id: Optional[int] = None,\n        outcome: Optional[str] = None\n    ) -> WorkflowInstance:\n        """Complete a workflow instance"""\n        instance = await self.get_by_id(instance_id)\n        if instance:\n            instance.status = \'Completed\'\n            instance.completed_at = datetime.utcnow()\n            instance.completed_by_id = completed_by_id\n            instance.outcome = outcome\n            await self.session.flush()\n        return instance\n    \n    async def cancel_instance(\n        self, \n        instance_id: int, \n        cancelled_by_id: int,\n        reason: Optional[str] = None\n    ) -> WorkflowInstance:\n        """Cancel a workflow instance"""\n        instance = await self.get_by_id(instance_id)\n        if instance:\n            instance.status = \'Cancelled\'\n            instance.completed_at = datetime.utcnow()\n            instance.completed_by_id = cancelled_by_id\n            instance.cancellation_reason = reason\n            await self.session.flush()\n        return instance\n\n\nclass WorkflowTaskRepository(BaseRepository[WorkflowTask, WorkflowTaskCreate, WorkflowTaskUpdate]):\n    """Repository for Workflow Task operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(WorkflowTask, session)\n    \n    async def get_by_instance(\n        self, \n        workflow_instance_id: int\n    ) -> List[WorkflowTask]:\n        """Get all tasks for a workflow instance"""\n        query = select(WorkflowTask).options(\n            selectinload(WorkflowTask.node),\n            selectinload(WorkflowTask.assignments)\n        ).where(\n            WorkflowTask.workflow_instance_id == workflow_instance_id\n        ).order_by(WorkflowTask.created_at)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_tasks(\n        self, \n        company_id: int\n    ) -> List[WorkflowTask]:\n        """Get all pending tasks for a company"""\n        query = select(WorkflowTask).options(\n            selectinload(WorkflowTask.workflow_instance),\n            selectinload(WorkflowTask.node),\n            selectinload(WorkflowTask.assignments)\n        ).join(WorkflowInstance).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowTask.status == \'Pending\'\n        ).order_by(WorkflowTask.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_tasks_by_assignee(\n        self, \n        assignee_id: int,\n        status: Optional[str] = None\n    ) -> List[WorkflowTask]:\n        """Get tasks assigned to a user"""\n        query = select(WorkflowTask).options(\n            selectinload(WorkflowTask.workflow_instance),\n            selectinload(WorkflowTask.node)\n        ).join(WorkflowTaskAssignment).where(\n            WorkflowTaskAssignment.user_id == assignee_id\n        )\n        if status:\n            query = query.where(WorkflowTask.status == status)\n        query = query.order_by(WorkflowTask.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_overdue_tasks(\n        self, \n        company_id: int\n    ) -> List[WorkflowTask]:\n        """Get all overdue tasks"""\n        query = select(WorkflowTask).options(\n            selectinload(WorkflowTask.workflow_instance)\n        ).join(WorkflowInstance).where(\n            WorkflowInstance.company_id == company_id,\n            WorkflowTask.status == \'Pending\',\n            WorkflowTask.due_date < datetime.utcnow()\n        ).order_by(WorkflowTask.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def complete_task(\n        self, \n        task_id: int, \n        completed_by_id: int,\n        outcome: Optional[str] = None,\n        comments: Optional[str] = None\n    ) -> WorkflowTask:\n        """Complete a workflow task"""\n        task = await self.get_by_id(task_id)\n        if task and task.status == \'Pending\':\n            task.status = \'Completed\'\n            task.completed_at = datetime.utcnow()\n            task.completed_by_id = completed_by_id\n            task.outcome = outcome\n            task.comments = comments\n            await self.session.flush()\n        return task\n    \n    async def reassign_task(\n        self, \n        task_id: int, \n        from_user_id: int, \n        to_user_id: int,\n        reassigned_by_id: int,\n        reason: Optional[str] = None\n    ) -> WorkflowTask:\n        """Reassign a task to another user"""\n        task = await self.get_by_id(task_id, load_relationships=["assignments"])\n        if task:\n            # Deactivate old assignments\n            for assignment in task.assignments:\n                if assignment.user_id == from_user_id:\n                    assignment.is_active = False\n            \n            # Create new assignment\n            new_assignment = WorkflowTaskAssignment(\n                workflow_task_id=task_id,\n                user_id=to_user_id,\n                assigned_by_id=reassigned_by_id,\n                assigned_at=datetime.utcnow(),\n                is_active=True\n            )\n            self.session.add(new_assignment)\n            \n            task.reassigned_at = datetime.utcnow()\n            task.reassigned_by_id = reassigned_by_id\n            task.reassignment_reason = reason\n            \n            await self.session.flush()\n        return task\n\n\nclass TriggerRepository(CompanyScopedRepository[Trigger, TriggerCreate, TriggerUpdate]):\n    """Repository for Trigger operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Trigger, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[Trigger]:\n        """Get trigger by code"""\n        query = select(Trigger).options(\n            selectinload(Trigger.conditions),\n            selectinload(Trigger.actions)\n        ).where(\n            Trigger.company_id == company_id,\n            Trigger.code == code,\n            Trigger.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_triggers(self, company_id: int) -> List[Trigger]:\n        """Get all active triggers"""\n        query = select(Trigger).options(\n            selectinload(Trigger.conditions),\n            selectinload(Trigger.actions)\n        ).where(\n            Trigger.company_id == company_id,\n            Trigger.is_active == True,\n            Trigger.is_deleted == False\n        ).order_by(Trigger.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_triggers_by_event(\n        self, \n        company_id: int, \n        event_type: str\n    ) -> List[Trigger]:\n        """Get triggers by event type"""\n        query = select(Trigger).options(\n            selectinload(Trigger.conditions),\n            selectinload(Trigger.actions)\n        ).where(\n            Trigger.company_id == company_id,\n            Trigger.trigger_type == \'Event\',\n            Trigger.event_type == event_type,\n            Trigger.is_active == True,\n            Trigger.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_triggers_by_entity(\n        self, \n        company_id: int, \n        entity_type: str\n    ) -> List[Trigger]:\n        """Get triggers by entity type"""\n        query = select(Trigger).where(\n            Trigger.company_id == company_id,\n            Trigger.entity_type == entity_type,\n            Trigger.is_active == True,\n            Trigger.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def record_execution(\n        self, \n        trigger_id: int, \n        success: bool,\n        execution_time_ms: int,\n        error_message: Optional[str] = None\n    ) -> Trigger:\n        """Record trigger execution statistics"""\n        trigger = await self.get_by_id(trigger_id)\n        if trigger:\n            trigger.execution_count = (trigger.execution_count or 0) + 1\n            trigger.last_executed_at = datetime.utcnow()\n            if not success:\n                trigger.error_count = (trigger.error_count or 0) + 1\n                trigger.last_error = error_message\n                trigger.last_error_at = datetime.utcnow()\n            await self.session.flush()\n        return trigger\n\n\nclass SchedulerRepository(BaseRepository[Scheduler, SchedulerCreate, SchedulerUpdate]):\n    """Repository for Scheduler operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Scheduler, session)\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[Scheduler]:\n        """Get scheduler by name"""\n        query = select(Scheduler).where(\n            Scheduler.company_id == company_id,\n            Scheduler.name == name,\n            Scheduler.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_schedulers(self, company_id: int) -> List[Scheduler]:\n        """Get all active schedulers"""\n        query = select(Scheduler).where(\n            Scheduler.company_id == company_id,\n            Scheduler.is_active == True,\n            Scheduler.is_deleted == False\n        ).order_by(Scheduler.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_due_schedulers(\n        self, \n        company_id: int\n    ) -> List[Scheduler]:\n        """Get schedulers that are due to run"""\n        now = datetime.utcnow()\n        query = select(Scheduler).where(\n            Scheduler.company_id == company_id,\n            Scheduler.is_active == True,\n            Scheduler.is_deleted == False,\n            or_(\n                Scheduler.next_run_at.is_(None),\n                Scheduler.next_run_at <= now\n            )\n        )\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_schedulers_by_frequency(\n        self, \n        company_id: int, \n        frequency: str\n    ) -> List[Scheduler]:\n        """Get schedulers by frequency"""\n        query = select(Scheduler).where(\n            Scheduler.company_id == company_id,\n            Scheduler.frequency == frequency,\n            Scheduler.is_deleted == False\n        ).order_by(Scheduler.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def record_run(\n        self, \n        scheduler_id: int, \n        status: str,\n        started_at: datetime,\n        completed_at: Optional[datetime] = None,\n        error_message: Optional[str] = None,\n        records_processed: int = 0\n    ) -> SchedulerRun:\n        """Record a scheduler run"""\n        run = SchedulerRun(\n            scheduler_id=scheduler_id,\n            status=status,\n            started_at=started_at,\n            completed_at=completed_at,\n            error_message=error_message,\n            records_processed=records_processed\n        )\n        self.session.add(run)\n        \n        # Update scheduler\n        scheduler = await self.get_by_id(scheduler_id)\n        if scheduler:\n            scheduler.last_run_at = started_at\n            scheduler.last_run_status = status\n            if scheduler.next_run_at:\n                # Calculate next run based on frequency\n                scheduler.next_run_at = self._calculate_next_run(\n                    scheduler.next_run_at, \n                    scheduler.frequency,\n                    scheduler.interval\n                )\n        \n        await self.session.flush()\n        return run\n    \n    def _calculate_next_run(\n        self, \n        current: datetime, \n        frequency: str, \n        interval: int = 1\n    ) -> datetime:\n        """Calculate next run datetime"""\n        if frequency == \'Minutely\':\n            return current + timedelta(minutes=interval)\n        elif frequency == \'Hourly\':\n            return current + timedelta(hours=interval)\n        elif frequency == \'Daily\':\n            return current + timedelta(days=interval)\n        elif frequency == \'Weekly\':\n            return current + timedelta(weeks=interval)\n        elif frequency == \'Monthly\':\n            return current + timedelta(days=30 * interval)\n        else:\n            return current + timedelta(days=1)\n\n\nclass NotificationTemplateRepository(BaseRepository[NotificationTemplate, NotificationTemplateCreate, NotificationTemplateUpdate]):\n    """Repository for Notification Template operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(NotificationTemplate, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[NotificationTemplate]:\n        """Get template by code"""\n        query = select(NotificationTemplate).where(\n            NotificationTemplate.company_id == company_id,\n            NotificationTemplate.code == code,\n            NotificationTemplate.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_templates(self, company_id: int) -> List[NotificationTemplate]:\n        """Get all active templates"""\n        query = select(NotificationTemplate).where(\n            NotificationTemplate.company_id == company_id,\n            NotificationTemplate.is_active == True,\n            NotificationTemplate.is_deleted == False\n        ).order_by(NotificationTemplate.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_templates_by_type(\n        self, \n        company_id: int, \n        notification_type: str\n    ) -> List[NotificationTemplate]:\n        """Get templates by notification type"""\n        query = select(NotificationTemplate).where(\n            NotificationTemplate.company_id == company_id,\n            NotificationTemplate.notification_type == notification_type,\n            NotificationTemplate.is_active == True,\n            NotificationTemplate.is_deleted == False\n        ).order_by(NotificationTemplate.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_templates_by_channel(\n        self, \n        company_id: int, \n        channel: str\n    ) -> List[NotificationTemplate]:\n        """Get templates by channel (Email, SMS, Push, In-App)"""\n        query = select(NotificationTemplate).where(\n            NotificationTemplate.company_id == company_id,\n            NotificationTemplate.channel == channel,\n            NotificationTemplate.is_active == True,\n            NotificationTemplate.is_deleted == False\n        ).order_by(NotificationTemplate.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass NotificationRepository(BaseRepository[Notification, NotificationCreate, NotificationUpdate]):\n    """Repository for Notification operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Notification, session)\n    \n    async def get_by_recipient(\n        self, \n        recipient_id: int,\n        status: Optional[str] = None\n    ) -> List[Notification]:\n        """Get notifications for a recipient"""\n        query = select(Notification).where(\n            Notification.recipient_id == recipient_id\n        )\n        if status:\n            query = query.where(Notification.status == status)\n        query = query.order_by(desc(Notification.created_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_unread_notifications(\n        self, \n        recipient_id: int\n    ) -> List[Notification]:\n        """Get unread notifications for a recipient"""\n        query = select(Notification).where(\n            Notification.recipient_id == recipient_id,\n            Notification.status == \'Sent\',\n            Notification.read_at.is_(None)\n        ).order_by(desc(Notification.created_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_unread_count(\n        self, \n        recipient_id: int\n    ) -> int:\n        """Get count of unread notifications"""\n        query = select(func.count(Notification.id)).where(\n            Notification.recipient_id == recipient_id,\n            Notification.status == \'Sent\',\n            Notification.read_at.is_(None)\n        )\n        result = await self.session.execute(query)\n        return result.scalar() or 0\n    \n    async def mark_as_read(\n        self, \n        notification_id: int\n    ) -> Notification:\n        """Mark notification as read"""\n        notification = await self.get_by_id(notification_id)\n        if notification:\n            notification.read_at = datetime.utcnow()\n            notification.status = \'Read\'\n            await self.session.flush()\n        return notification\n    \n    async def mark_all_as_read(\n        self, \n        recipient_id: int\n    ) -> int:\n        """Mark all notifications as read for a recipient"""\n        query = update(Notification).where(\n            Notification.recipient_id == recipient_id,\n            Notification.read_at.is_(None)\n        ).values(\n            read_at=datetime.utcnow(),\n            status=\'Read\'\n        )\n        result = await self.session.execute(query)\n        await self.session.flush()\n        return result.rowcount\n\n\nclass AutomationRuleRepository(CompanyScopedRepository[AutomationRule, AutomationRuleCreate, AutomationRuleUpdate]):\n    """Repository for Automation Rule operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(AutomationRule, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[AutomationRule]:\n        """Get automation rule by code"""\n        query = select(AutomationRule).options(\n            selectinload(AutomationRule.conditions),\n            selectinload(AutomationRule.actions)\n        ).where(\n            AutomationRule.company_id == company_id,\n            AutomationRule.code == code,\n            AutomationRule.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_rules(self, company_id: int) -> List[AutomationRule]:\n        """Get all active automation rules"""\n        query = select(AutomationRule).options(\n            selectinload(AutomationRule.conditions),\n            selectinload(AutomationRule.actions)\n        ).where(\n            AutomationRule.company_id == company_id,\n            AutomationRule.is_active == True,\n            AutomationRule.is_deleted == False\n        ).order_by(AutomationRule.priority, AutomationRule.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_rules_by_trigger(\n        self, \n        company_id: int, \n        trigger_event: str\n    ) -> List[AutomationRule]:\n        """Get automation rules by trigger event"""\n        query = select(AutomationRule).options(\n            selectinload(AutomationRule.conditions),\n            selectinload(AutomationRule.actions)\n        ).where(\n            AutomationRule.company_id == company_id,\n            AutomationRule.trigger_event == trigger_event,\n            AutomationRule.is_active == True,\n            AutomationRule.is_deleted == False\n        ).order_by(AutomationRule.priority)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_rules_by_entity(\n        self, \n        company_id: int, \n        entity_type: str\n    ) -> List[AutomationRule]:\n        """Get automation rules by entity type"""\n        query = select(AutomationRule).where(\n            AutomationRule.company_id == company_id,\n            AutomationRule.entity_type == entity_type,\n            AutomationRule.is_active == True,\n            AutomationRule.is_deleted == False\n        ).order_by(AutomationRule.priority)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def record_execution(\n        self, \n        rule_id: int, \n        entity_type: str, \n        entity_id: int,\n        success: bool,\n        actions_executed: int,\n        error_message: Optional[str] = None\n    ) -> AutomationRunLog:\n        """Record automation rule execution"""\n        log = AutomationRunLog(\n            automation_rule_id=rule_id,\n            entity_type=entity_type,\n            entity_id=entity_id,\n            status=\'Success\' if success else \'Failed\',\n            actions_executed=actions_executed,\n            error_message=error_message,\n            executed_at=datetime.utcnow()\n        )\n        self.session.add(log)\n        \n        # Update rule statistics\n        rule = await self.get_by_id(rule_id)\n        if rule:\n            rule.execution_count = (rule.execution_count or 0) + 1\n            rule.last_executed_at = datetime.utcnow()\n            if not success:\n                rule.error_count = (rule.error_count or 0) + 1\n        \n        await self.session.flush()\n        return log\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/workflow.py\' created successfully.") </create-file> </tool_result>'}
{'role': 'assistant', 'content': 'Workflow repository created successfully. Let me continue with the Legal repository for contract lifecycle management.\n\n<function_calls>\n<create-file file_path="backend/app/repositories/legal.py">\n"""\nLegal Repository - Data Access Layer for Legal and Contract Lifecycle Management Operations\nPart of SAMMS ENTERPRISE SOVEREIGN OPERATING SYSTEM (SESOS v6 OMEGA CONSTRAINED)\n"""\n\nfrom typing import Optional, List, Dict, Any, Tuple\nfrom datetime import date, datetime, timedelta\nfrom decimal import Decimal\nfrom sqlalchemy import (\n    select, update, delete, and_, or_, not_, func, case, literal,\n    join, left_join, distinct, sum as sql_sum, count as sql_count,\n    desc, asc, between, extract, cast, String, Numeric, Date, DateTime\n)\nfrom sqlalchemy.orm import (\n    selectinload, joinedload, subqueryload, contains_eager,\n    aliased, with_loader_criteria\n)\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom app.models.legal import (\n    ContractType, Contract, ContractClause, ContractAmendment,\n    ContractParty, ContractDocument, ContractSignature,\n    ContractMilestone, ContractRenewal, ContractRisk,\n    LegalEntity, LegalMatter, LegalMatterActivity, LegalMatterDocument,\n    Litigation, LitigationParty, LitigationEvent, LitigationDocument,\n    LegalHold, LegalHoldItem, LegalHoldCustodian,\n    IPAsset, IPRegistration, IPLicense, IPInfringement,\n    ComplianceProgram, ComplianceRequirement, ComplianceAssessment,\n    ComplianceFinding, ComplianceRemediation,\n    LegalTemplate, LegalTemplateSection\n)\nfrom app.repositories.base import BaseRepository, CompanyScopedRepository\nfrom app.schemas.legal import (\n    ContractTypeCreate, ContractTypeUpdate,\n    ContractCreate, ContractUpdate,\n    ContractClauseCreate, ContractClauseUpdate,\n    ContractAmendmentCreate, ContractAmendmentUpdate,\n    ContractPartyCreate, ContractPartyUpdate,\n    ContractDocumentCreate, ContractDocumentUpdate,\n    ContractSignatureCreate, ContractSignatureUpdate,\n    ContractMilestoneCreate, ContractMilestoneUpdate,\n    ContractRenewalCreate, ContractRenewalUpdate,\n    ContractRiskCreate, ContractRiskUpdate,\n    LegalEntityCreate, LegalEntityUpdate,\n    LegalMatterCreate, LegalMatterUpdate,\n    LegalMatterActivityCreate, LegalMatterActivityUpdate,\n    LegalMatterDocumentCreate, LegalMatterDocumentUpdate,\n    LitigationCreate, LitigationUpdate,\n    LitigationPartyCreate, LitigationPartyUpdate,\n    LitigationEventCreate, LitigationEventUpdate,\n    LitigationDocumentCreate, LitigationDocumentUpdate,\n    LegalHoldCreate, LegalHoldUpdate,\n    LegalHoldItemCreate, LegalHoldItemUpdate,\n    LegalHoldCustodianCreate, LegalHoldCustodianUpdate,\n    IPAssetCreate, IPAssetUpdate,\n    IPRegistrationCreate, IPRegistrationUpdate,\n    IPLicenseCreate, IPLicenseUpdate,\n    IPInfringementCreate, IPInfringementUpdate,\n    ComplianceProgramCreate, ComplianceProgramUpdate,\n    ComplianceRequirementCreate, ComplianceRequirementUpdate,\n    ComplianceAssessmentCreate, ComplianceAssessmentUpdate,\n    ComplianceFindingCreate, ComplianceFindingUpdate,\n    ComplianceRemediationCreate, ComplianceRemediationUpdate,\n    LegalTemplateCreate, LegalTemplateUpdate,\n    LegalTemplateSectionCreate, LegalTemplateSectionUpdate\n)\n\n\nclass ContractTypeRepository(BaseRepository[ContractType, ContractTypeCreate, ContractTypeUpdate]):\n    """Repository for Contract Type operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ContractType, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[ContractType]:\n        """Get contract type by code"""\n        query = select(ContractType).where(\n            ContractType.company_id == company_id,\n            ContractType.code == code,\n            ContractType.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_by_name(self, company_id: int, name: str) -> Optional[ContractType]:\n        """Get contract type by name"""\n        query = select(ContractType).where(\n            ContractType.company_id == company_id,\n            ContractType.name == name,\n            ContractType.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_types(self, company_id: int) -> List[ContractType]:\n        """Get all active contract types"""\n        query = select(ContractType).where(\n            ContractType.company_id == company_id,\n            ContractType.is_active == True,\n            ContractType.is_deleted == False\n        ).order_by(ContractType.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass ContractRepository(CompanyScopedRepository[Contract, ContractCreate, ContractUpdate]):\n    """Repository for Contract operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Contract, session)\n    \n    async def get_by_contract_number(\n        self, \n        company_id: int, \n        contract_number: str\n    ) -> Optional[Contract]:\n        """Get contract by contract number"""\n        query = select(Contract).options(\n            selectinload(Contract.contract_type),\n            selectinload(Contract.parties),\n            selectinload(Contract.clauses),\n            selectinload(Contract.documents),\n            selectinload(Contract.signatures)\n        ).where(\n            Contract.company_id == company_id,\n            Contract.contract_number == contract_number,\n            Contract.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_contracts_by_status(\n        self, \n        company_id: int, \n        status: str\n    ) -> List[Contract]:\n        """Get contracts by status"""\n        query = select(Contract).options(\n            selectinload(Contract.contract_type),\n            selectinload(Contract.parties)\n        ).where(\n            Contract.company_id == company_id,\n            Contract.status == status,\n            Contract.is_deleted == False\n        ).order_by(desc(Contract.created_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_contracts_by_type(\n        self, \n        company_id: int, \n        contract_type_id: int\n    ) -> List[Contract]:\n        """Get contracts by type"""\n        query = select(Contract).where(\n            Contract.company_id == company_id,\n            Contract.contract_type_id == contract_type_id,\n            Contract.is_deleted == False\n        ).order_by(desc(Contract.start_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_active_contracts(\n        self, \n        company_id: int\n    ) -> List[Contract]:\n        """Get all active contracts"""\n        query = select(Contract).options(\n            selectinload(Contract.contract_type),\n            selectinload(Contract.parties)\n        ).where(\n            Contract.company_id == company_id,\n            Contract.status == \'Active\',\n            Contract.is_deleted == False\n        ).order_by(Contract.end_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_expiring_contracts(\n        self, \n        company_id: int, \n        within_days: int = 90\n    ) -> List[Contract]:\n        """Get contracts expiring within specified days"""\n        target_date = date.today() + timedelta(days=within_days)\n        query = select(Contract).options(\n            selectinload(Contract.contract_type),\n            selectinload(Contract.parties)\n        ).where(\n            Contract.company_id == company_id,\n            Contract.status == \'Active\',\n            Contract.end_date <= target_date,\n            Contract.end_date >= date.today(),\n            Contract.is_deleted == False\n        ).order_by(Contract.end_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_contracts_by_party(\n        self, \n        company_id: int, \n        party_id: int\n    ) -> List[Contract]:\n        """Get contracts by party"""\n        query = select(Contract).options(\n            selectinload(Contract.contract_type)\n        ).join(ContractParty).where(\n            Contract.company_id == company_id,\n            ContractParty.party_id == party_id,\n            Contract.is_deleted == False\n        ).order_by(desc(Contract.start_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_contracts_by_date_range(\n        self, \n        company_id: int, \n        start_date: date, \n        end_date: date\n    ) -> List[Contract]:\n        """Get contracts within date range"""\n        query = select(Contract).where(\n            Contract.company_id == company_id,\n            or_(\n                and_(Contract.start_date >= start_date, Contract.start_date <= end_date),\n                and_(Contract.end_date >= start_date, Contract.end_date <= end_date),\n                and_(Contract.start_date <= start_date, Contract.end_date >= end_date)\n            ),\n            Contract.is_deleted == False\n        ).order_by(Contract.start_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def generate_contract_number(\n        self, \n        company_id: int, \n        contract_type_code: str\n    ) -> str:\n        """Generate next contract number"""\n        today = date.today()\n        prefix = f"CTR-{contract_type_code}-{today.year}{today.month:02d}"\n        \n        query = select(func.max(Contract.contract_number)).where(\n            Contract.company_id == company_id,\n            Contract.contract_number.like(f"{prefix}%")\n        )\n        result = await self.session.execute(query)\n        max_number = result.scalar()\n        \n        if max_number:\n            try:\n                seq = int(max_number.split(\'-\')[-1]) + 1\n            except (ValueError, IndexError):\n                seq = 1\n        else:\n            seq = 1\n        \n        return f"{prefix}-{seq:04d}"\n    \n    async def activate_contract(\n        self, \n        contract_id: int, \n        activated_by_id: int\n    ) -> Contract:\n        """Activate a contract"""\n        contract = await self.get_by_id(contract_id)\n        if contract and contract.status == \'Pending\':\n            contract.status = \'Active\'\n            contract.activated_at = datetime.utcnow()\n            contract.activated_by_id = activated_by_id\n            await self.session.flush()\n        return contract\n    \n    async def terminate_contract(\n        self, \n        contract_id: int, \n        terminated_by_id: int,\n        termination_reason: str,\n        termination_date: Optional[date] = None\n    ) -> Contract:\n        """Terminate a contract"""\n        contract = await self.get_by_id(contract_id)\n        if contract:\n            contract.status = \'Terminated\'\n            contract.terminated_at = datetime.utcnow()\n            contract.terminated_by_id = terminated_by_id\n            contract.termination_reason = termination_reason\n            if termination_date:\n                contract.end_date = termination_date\n            await self.session.flush()\n        return contract\n    \n    async def get_contract_summary(\n        self, \n        company_id: int\n    ) -> Dict[str, Any]:\n        """Get contract summary statistics"""\n        # Count by status\n        status_query = select(\n            Contract.status,\n            func.count(Contract.id).label(\'count\')\n        ).where(\n            Contract.company_id == company_id,\n            Contract.is_deleted == False\n        ).group_by(Contract.status)\n        status_result = await self.session.execute(status_query)\n        \n        # Count by type\n        type_query = select(\n            ContractType.name,\n            func.count(Contract.id).label(\'count\')\n        ).join(Contract).where(\n            Contract.company_id == company_id,\n            Contract.is_deleted == False\n        ).group_by(ContractType.name)\n        type_result = await self.session.execute(type_query)\n        \n        # Total value\n        value_query = select(\n            func.sum(Contract.contract_value).label(\'total_value\')\n        ).where(\n            Contract.company_id == company_id,\n            Contract.status == \'Active\',\n            Contract.is_deleted == False\n        )\n        value_result = await self.session.execute(value_query)\n        \n        # Expiring soon\n        expiring_query = select(func.count(Contract.id)).where(\n            Contract.company_id == company_id,\n            Contract.status == \'Active\',\n            Contract.end_date <= date.today() + timedelta(days=90),\n            Contract.end_date >= date.today(),\n            Contract.is_deleted == False\n        )\n        expiring_result = await self.session.execute(expiring_query)\n        \n        return {\n            \'by_status\': {row.status: row.count for row in status_result},\n            \'by_type\': {row.name: row.count for row in type_result},\n            \'total_active_value\': value_result.scalar() or Decimal(\'0\'),\n            \'expiring_soon\': expiring_result.scalar() or 0\n        }\n\n\nclass ContractPartyRepository(BaseRepository[ContractParty, ContractPartyCreate, ContractPartyUpdate]):\n    """Repository for Contract Party operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ContractParty, session)\n    \n    async def get_by_contract(\n        self, \n        contract_id: int\n    ) -> List[ContractParty]:\n        """Get all parties for a contract"""\n        query = select(ContractParty).where(\n            ContractParty.contract_id == contract_id\n        ).order_by(ContractParty.role)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_primary_party(\n        self, \n        contract_id: int, \n        role: str\n    ) -> Optional[ContractParty]:\n        """Get primary party by role"""\n        query = select(ContractParty).where(\n            ContractParty.contract_id == contract_id,\n            ContractParty.role == role,\n            ContractParty.is_primary == True\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n\n\nclass ContractDocumentRepository(BaseRepository[ContractDocument, ContractDocumentCreate, ContractDocumentUpdate]):\n    """Repository for Contract Document operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ContractDocument, session)\n    \n    async def get_by_contract(\n        self, \n        contract_id: int\n    ) -> List[ContractDocument]:\n        """Get all documents for a contract"""\n        query = select(ContractDocument).where(\n            ContractDocument.contract_id == contract_id\n        ).order_by(desc(ContractDocument.created_at))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_latest_version(\n        self, \n        contract_id: int, \n        document_type: str\n    ) -> Optional[ContractDocument]:\n        """Get latest version of a document type"""\n        query = select(ContractDocument).where(\n            ContractDocument.contract_id == contract_id,\n            ContractDocument.document_type == document_type\n        ).order_by(desc(ContractDocument.version)).limit(1)\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n\n\nclass ContractSignatureRepository(BaseRepository[ContractSignature, ContractSignatureCreate, ContractSignatureUpdate]):\n    """Repository for Contract Signature operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ContractSignature, session)\n    \n    async def get_by_contract(\n        self, \n        contract_id: int\n    ) -> List[ContractSignature]:\n        """Get all signatures for a contract"""\n        query = select(ContractSignature).options(\n            selectinload(ContractSignature.signer)\n        ).where(\n            ContractSignature.contract_id == contract_id\n        ).order_by(ContractSignature.signature_order)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_signatures(\n        self, \n        company_id: int\n    ) -> List[ContractSignature]:\n        """Get all pending signatures"""\n        query = select(ContractSignature).options(\n            selectinload(ContractSignature.contract),\n            selectinload(ContractSignature.signer)\n        ).join(Contract).where(\n            Contract.company_id == company_id,\n            ContractSignature.status == \'Pending\'\n        ).order_by(ContractSignature.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def record_signature(\n        self, \n        signature_id: int, \n        signed_by_id: int\n    ) -> ContractSignature:\n        """Record a signature"""\n        signature = await self.get_by_id(signature_id)\n        if signature and signature.status == \'Pending\':\n            signature.status = \'Signed\'\n            signature.signed_at = datetime.utcnow()\n            signature.signed_by_id = signed_by_id\n            await self.session.flush()\n        return signature\n\n\nclass ContractMilestoneRepository(BaseRepository[ContractMilestone, ContractMilestoneCreate, ContractMilestoneUpdate]):\n    """Repository for Contract Milestone operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ContractMilestone, session)\n    \n    async def get_by_contract(\n        self, \n        contract_id: int\n    ) -> List[ContractMilestone]:\n        """Get all milestones for a contract"""\n        query = select(ContractMilestone).where(\n            ContractMilestone.contract_id == contract_id\n        ).order_by(ContractMilestone.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_upcoming_milestones(\n        self, \n        company_id: int, \n        within_days: int = 30\n    ) -> List[ContractMilestone]:\n        """Get upcoming milestones"""\n        target_date = date.today() + timedelta(days=within_days)\n        query = select(ContractMilestone).options(\n            selectinload(ContractMilestone.contract)\n        ).join(Contract).where(\n            Contract.company_id == company_id,\n            ContractMilestone.status == \'Pending\',\n            ContractMilestone.due_date <= target_date,\n            ContractMilestone.due_date >= date.today(),\n            Contract.is_deleted == False\n        ).order_by(ContractMilestone.due_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def complete_milestone(\n        self, \n        milestone_id: int, \n        completed_by_id: int,\n        notes: Optional[str] = None\n    ) -> ContractMilestone:\n        """Complete a milestone"""\n        milestone = await self.get_by_id(milestone_id)\n        if milestone and milestone.status == \'Pending\':\n            milestone.status = \'Completed\'\n            milestone.completed_at = datetime.utcnow()\n            milestone.completed_by_id = completed_by_id\n            milestone.notes = notes\n            await self.session.flush()\n        return milestone\n\n\nclass LegalEntityRepository(BaseRepository[LegalEntity, LegalEntityCreate, LegalEntityUpdate]):\n    """Repository for Legal Entity operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LegalEntity, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[LegalEntity]:\n        """Get legal entity by code"""\n        query = select(LegalEntity).where(\n            LegalEntity.company_id == company_id,\n            LegalEntity.code == code,\n            LegalEntity.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_entities(self, company_id: int) -> List[LegalEntity]:\n        """Get all active legal entities"""\n        query = select(LegalEntity).where(\n            LegalEntity.company_id == company_id,\n            LegalEntity.is_active == True,\n            LegalEntity.is_deleted == False\n        ).order_by(LegalEntity.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_entities_by_type(\n        self, \n        company_id: int, \n        entity_type: str\n    ) -> List[LegalEntity]:\n        """Get legal entities by type"""\n        query = select(LegalEntity).where(\n            LegalEntity.company_id == company_id,\n            LegalEntity.entity_type == entity_type,\n            LegalEntity.is_deleted == False\n        ).order_by(LegalEntity.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass LegalMatterRepository(CompanyScopedRepository[LegalMatter, LegalMatterCreate, LegalMatterUpdate]):\n    """Repository for Legal Matter operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LegalMatter, session)\n    \n    async def get_by_matter_number(\n        self, \n        company_id: int, \n        matter_number: str\n    ) -> Optional[LegalMatter]:\n        """Get legal matter by matter number"""\n        query = select(LegalMatter).options(\n            selectinload(LegalMatter.activities),\n            selectinload(LegalMatter.documents)\n        ).where(\n            LegalMatter.company_id == company_id,\n            LegalMatter.matter_number == matter_number,\n            LegalMatter.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_matters_by_status(\n        self, \n        company_id: int, \n        status: str\n    ) -> List[LegalMatter]:\n        """Get legal matters by status"""\n        query = select(LegalMatter).where(\n            LegalMatter.company_id == company_id,\n            LegalMatter.status == status,\n            LegalMatter.is_deleted == False\n        ).order_by(desc(LegalMatter.opened_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_open_matters(\n        self, \n        company_id: int\n    ) -> List[LegalMatter]:\n        """Get all open legal matters"""\n        query = select(LegalMatter).where(\n            LegalMatter.company_id == company_id,\n            LegalMatter.status.in_([\'Open\', \'In Progress\']),\n            LegalMatter.is_deleted == False\n        ).order_by(LegalMatter.priority, LegalMatter.opened_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_matters_by_type(\n        self, \n        company_id: int, \n        matter_type: str\n    ) -> List[LegalMatter]:\n        """Get legal matters by type"""\n        query = select(LegalMatter).where(\n            LegalMatter.company_id == company_id,\n            LegalMatter.matter_type == matter_type,\n            LegalMatter.is_deleted == False\n        ).order_by(desc(LegalMatter.opened_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_matters_by_assignee(\n        self, \n        assignee_id: int,\n        status: Optional[str] = None\n    ) -> List[LegalMatter]:\n        """Get legal matters assigned to a user"""\n        query = select(LegalMatter).where(\n            LegalMatter.assigned_to_id == assignee_id,\n            LegalMatter.is_deleted == False\n        )\n        if status:\n            query = query.where(LegalMatter.status == status)\n        query = query.order_by(LegalMatter.priority, LegalMatter.opened_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def generate_matter_number(\n        self, \n        company_id: int\n    ) -> str:\n        """Generate next matter number"""\n        today = date.today()\n        prefix = f"LM-{today.year}"\n        \n        query = select(func.max(LegalMatter.matter_number)).where(\n            LegalMatter.company_id == company_id,\n            LegalMatter.matter_number.like(f"{prefix}%")\n        )\n        result = await self.session.execute(query)\n        max_number = result.scalar()\n        \n        if max_number:\n            try:\n                seq = int(max_number.split(\'-\')[-1]) + 1\n            except (ValueError, IndexError):\n                seq = 1\n        else:\n            seq = 1\n        \n        return f"{prefix}-{seq:05d}"\n    \n    async def close_matter(\n        self, \n        matter_id: int, \n        closed_by_id: int,\n        resolution: str,\n        outcome: Optional[str] = None\n    ) -> LegalMatter:\n        """Close a legal matter"""\n        matter = await self.get_by_id(matter_id)\n        if matter:\n            matter.status = \'Closed\'\n            matter.closed_at = datetime.utcnow()\n            matter.closed_by_id = closed_by_id\n            matter.resolution = resolution\n            matter.outcome = outcome\n            await self.session.flush()\n        return matter\n\n\nclass LitigationRepository(CompanyScopedRepository[Litigation, LitigationCreate, LitigationUpdate]):\n    """Repository for Litigation operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(Litigation, session)\n    \n    async def get_by_case_number(\n        self, \n        company_id: int, \n        case_number: str\n    ) -> Optional[Litigation]:\n        """Get litigation by case number"""\n        query = select(Litigation).options(\n            selectinload(Litigation.parties),\n            selectinload(Litigation.events)\n        ).where(\n            Litigation.company_id == company_id,\n            Litigation.case_number == case_number,\n            Litigation.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_litigations(\n        self, \n        company_id: int\n    ) -> List[Litigation]:\n        """Get all active litigations"""\n        query = select(Litigation).options(\n            selectinload(Litigation.parties)\n        ).where(\n            Litigation.company_id == company_id,\n            Litigation.status.in_([\'Filed\', \'In Progress\', \'Pending\']),\n            Litigation.is_deleted == False\n        ).order_by(Litigation.filed_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_litigations_by_status(\n        self, \n        company_id: int, \n        status: str\n    ) -> List[Litigation]:\n        """Get litigations by status"""\n        query = select(Litigation).where(\n            Litigation.company_id == company_id,\n            Litigation.status == status,\n            Litigation.is_deleted == False\n        ).order_by(desc(Litigation.filed_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_upcoming_court_dates(\n        self, \n        company_id: int, \n        within_days: int = 30\n    ) -> List[Dict[str, Any]]:\n        """Get upcoming court dates"""\n        target_date = date.today() + timedelta(days=within_days)\n        query = select(LitigationEvent).options(\n            selectinload(LitigationEvent.litigation)\n        ).join(Litigation).where(\n            Litigation.company_id == company_id,\n            LitigationEvent.event_type == \'Court Hearing\',\n            LitigationEvent.event_date >= date.today(),\n            LitigationEvent.event_date <= target_date,\n            Litigation.is_deleted == False\n        ).order_by(LitigationEvent.event_date)\n        result = await self.session.execute(query)\n        events = list(result.scalars().all())\n        return [{\'litigation\': e.litigation, \'event\': e} for e in events]\n    \n    async def get_litigation_summary(\n        self, \n        company_id: int\n    ) -> Dict[str, Any]:\n        """Get litigation summary statistics"""\n        # Count by status\n        status_query = select(\n            Litigation.status,\n            func.count(Litigation.id).label(\'count\')\n        ).where(\n            Litigation.company_id == company_id,\n            Litigation.is_deleted == False\n        ).group_by(Litigation.status)\n        status_result = await self.session.execute(status_query)\n        \n        # Total exposure\n        exposure_query = select(\n            func.sum(Litigation.amount_claimed).label(\'total_claimed\'),\n            func.sum(Litigation.amount_reserved).label(\'total_reserved\')\n        ).where(\n            Litigation.company_id == company_id,\n            Litigation.status.in_([\'Filed\', \'In Progress\', \'Pending\']),\n            Litigation.is_deleted == False\n        )\n        exposure_result = await self.session.execute(exposure_query)\n        exposure = exposure_result.one()\n        \n        return {\n            \'by_status\': {row.status: row.count for row in status_result},\n            \'total_claimed\': exposure.total_claimed or Decimal(\'0\'),\n            \'total_reserved\': exposure.total_reserved or Decimal(\'0\')\n        }\n\n\nclass LegalHoldRepository(BaseRepository[LegalHold, LegalHoldCreate, LegalHoldUpdate]):\n    """Repository for Legal Hold operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LegalHold, session)\n    \n    async def get_by_hold_number(\n        self, \n        company_id: int, \n        hold_number: str\n    ) -> Optional[LegalHold]:\n        """Get legal hold by hold number"""\n        query = select(LegalHold).options(\n            selectinload(LegalHold.custodians),\n            selectinload(LegalHold.items)\n        ).where(\n            LegalHold.company_id == company_id,\n            LegalHold.hold_number == hold_number,\n            LegalHold.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_holds(\n        self, \n        company_id: int\n    ) -> List[LegalHold]:\n        """Get all active legal holds"""\n        query = select(LegalHold).options(\n            selectinload(LegalHold.custodians)\n        ).where(\n            LegalHold.company_id == company_id,\n            LegalHold.status == \'Active\',\n            LegalHold.is_deleted == False\n        ).order_by(LegalHold.issued_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def release_hold(\n        self, \n        hold_id: int, \n        released_by_id: int,\n        release_reason: str\n    ) -> LegalHold:\n        """Release a legal hold"""\n        hold = await self.get_by_id(hold_id)\n        if hold:\n            hold.status = \'Released\'\n            hold.released_at = datetime.utcnow()\n            hold.released_by_id = released_by_id\n            hold.release_reason = release_reason\n            await self.session.flush()\n        return hold\n\n\nclass IPAssetRepository(CompanyScopedRepository[IPAsset, IPAssetCreate, IPAssetUpdate]):\n    """Repository for IP Asset operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(IPAsset, session)\n    \n    async def get_by_asset_number(\n        self, \n        company_id: int, \n        asset_number: str\n    ) -> Optional[IPAsset]:\n        """Get IP asset by asset number"""\n        query = select(IPAsset).options(\n            selectinload(IPAsset.registrations),\n            selectinload(IPAsset.licenses)\n        ).where(\n            IPAsset.company_id == company_id,\n            IPAsset.asset_number == asset_number,\n            IPAsset.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_assets(\n        self, \n        company_id: int\n    ) -> List[IPAsset]:\n        """Get all active IP assets"""\n        query = select(IPAsset).where(\n            IPAsset.company_id == company_id,\n            IPAsset.status == \'Active\',\n            IPAsset.is_deleted == False\n        ).order_by(IPAsset.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_assets_by_type(\n        self, \n        company_id: int, \n        asset_type: str\n    ) -> List[IPAsset]:\n        """Get IP assets by type"""\n        query = select(IPAsset).where(\n            IPAsset.company_id == company_id,\n            IPAsset.asset_type == asset_type,\n            IPAsset.is_deleted == False\n        ).order_by(IPAsset.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_expiring_registrations(\n        self, \n        company_id: int, \n        within_days: int = 180\n    ) -> List[IPRegistration]:\n        """Get IP registrations expiring soon"""\n        target_date = date.today() + timedelta(days=within_days)\n        query = select(IPRegistration).options(\n            selectinload(IPRegistration.ip_asset)\n        ).join(IPAsset).where(\n            IPAsset.company_id == company_id,\n            IPRegistration.expiration_date <= target_date,\n            IPRegistration.expiration_date >= date.today(),\n            IPRegistration.status == \'Registered\',\n            IPAsset.is_deleted == False\n        ).order_by(IPRegistration.expiration_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass ComplianceProgramRepository(BaseRepository[ComplianceProgram, ComplianceProgramCreate, ComplianceProgramUpdate]):\n    """Repository for Compliance Program operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ComplianceProgram, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[ComplianceProgram]:\n        """Get compliance program by code"""\n        query = select(ComplianceProgram).options(\n            selectinload(ComplianceProgram.requirements)\n        ).where(\n            ComplianceProgram.company_id == company_id,\n            ComplianceProgram.code == code,\n            ComplianceProgram.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_programs(\n        self, \n        company_id: int\n    ) -> List[ComplianceProgram]:\n        """Get all active compliance programs"""\n        query = select(ComplianceProgram).where(\n            ComplianceProgram.company_id == company_id,\n            ComplianceProgram.status == \'Active\',\n            ComplianceProgram.is_deleted == False\n        ).order_by(ComplianceProgram.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_compliance_summary(\n        self, \n        company_id: int\n    ) -> Dict[str, Any]:\n        """Get compliance summary"""\n        # Program count by status\n        program_query = select(\n            ComplianceProgram.status,\n            func.count(ComplianceProgram.id).label(\'count\')\n        ).where(\n            ComplianceProgram.company_id == company_id,\n            ComplianceProgram.is_deleted == False\n        ).group_by(ComplianceProgram.status)\n        program_result = await self.session.execute(program_query)\n        \n        # Assessment counts\n        assessment_query = select(\n            ComplianceAssessment.status,\n            func.count(ComplianceAssessment.id).label(\'count\')\n        ).join(ComplianceProgram).where(\n            ComplianceProgram.company_id == company_id\n        ).group_by(ComplianceAssessment.status)\n        assessment_result = await self.session.execute(assessment_query)\n        \n        # Open findings\n        findings_query = select(func.count(ComplianceFinding.id)).join(\n            ComplianceAssessment\n        ).join(ComplianceProgram).where(\n            ComplianceProgram.company_id == company_id,\n            ComplianceFinding.status == \'Open\'\n        )\n        findings_result = await self.session.execute(findings_query)\n        \n        return {\n            \'programs_by_status\': {row.status: row.count for row in program_result},\n            \'assessments_by_status\': {row.status: row.count for row in assessment_result},\n            \'open_findings\': findings_result.scalar() or 0\n        }\n\n\nclass ComplianceRequirementRepository(BaseRepository[ComplianceRequirement, ComplianceRequirementCreate, ComplianceRequirementUpdate]):\n    """Repository for Compliance Requirement operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ComplianceRequirement, session)\n    \n    async def get_by_program(\n        self, \n        program_id: int\n    ) -> List[ComplianceRequirement]:\n        """Get all requirements for a program"""\n        query = select(ComplianceRequirement).where(\n            ComplianceRequirement.program_id == program_id\n        ).order_by(ComplianceRequirement.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_requirements_by_category(\n        self, \n        program_id: int, \n        category: str\n    ) -> List[ComplianceRequirement]:\n        """Get requirements by category"""\n        query = select(ComplianceRequirement).where(\n            ComplianceRequirement.program_id == program_id,\n            ComplianceRequirement.category == category\n        ).order_by(ComplianceRequirement.code)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n\n\nclass ComplianceAssessmentRepository(BaseRepository[ComplianceAssessment, ComplianceAssessmentCreate, ComplianceAssessmentUpdate]):\n    """Repository for Compliance Assessment operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(ComplianceAssessment, session)\n    \n    async def get_by_program(\n        self, \n        program_id: int\n    ) -> List[ComplianceAssessment]:\n        """Get all assessments for a program"""\n        query = select(ComplianceAssessment).options(\n            selectinload(ComplianceAssessment.findings)\n        ).where(\n            ComplianceAssessment.program_id == program_id\n        ).order_by(desc(ComplianceAssessment.assessment_date))\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_pending_assessments(\n        self, \n        company_id: int\n    ) -> List[ComplianceAssessment]:\n        """Get pending assessments"""\n        query = select(ComplianceAssessment).options(\n            selectinload(ComplianceAssessment.program)\n        ).join(ComplianceProgram).where(\n            ComplianceProgram.company_id == company_id,\n            ComplianceAssessment.status == \'Scheduled\',\n            ComplianceAssessment.assessment_date >= date.today()\n        ).order_by(ComplianceAssessment.assessment_date)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def complete_assessment(\n        self, \n        assessment_id: int, \n        completed_by_id: int,\n        overall_rating: str,\n        notes: Optional[str] = None\n    ) -> ComplianceAssessment:\n        """Complete an assessment"""\n        assessment = await self.get_by_id(assessment_id)\n        if assessment:\n            assessment.status = \'Completed\'\n            assessment.completed_at = datetime.utcnow()\n            assessment.completed_by_id = completed_by_id\n            assessment.overall_rating = overall_rating\n            assessment.notes = notes\n            await self.session.flush()\n        return assessment\n\n\nclass LegalTemplateRepository(BaseRepository[LegalTemplate, LegalTemplateCreate, LegalTemplateUpdate]):\n    """Repository for Legal Template operations"""\n    \n    def __init__(self, session: AsyncSession):\n        super().__init__(LegalTemplate, session)\n    \n    async def get_by_code(self, company_id: int, code: str) -> Optional[LegalTemplate]:\n        """Get legal template by code"""\n        query = select(LegalTemplate).options(\n            selectinload(LegalTemplate.sections)\n        ).where(\n            LegalTemplate.company_id == company_id,\n            LegalTemplate.code == code,\n            LegalTemplate.is_deleted == False\n        )\n        result = await self.session.execute(query)\n        return result.scalar_one_or_none()\n    \n    async def get_active_templates(\n        self, \n        company_id: int\n    ) -> List[LegalTemplate]:\n        """Get all active legal templates"""\n        query = select(LegalTemplate).where(\n            LegalTemplate.company_id == company_id,\n            LegalTemplate.is_active == True,\n            LegalTemplate.is_deleted == False\n        ).order_by(LegalTemplate.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n    \n    async def get_templates_by_type(\n        self, \n        company_id: int, \n        template_type: str\n    ) -> List[LegalTemplate]:\n        """Get templates by type"""\n        query = select(LegalTemplate).where(\n            LegalTemplate.company_id == company_id,\n            LegalTemplate.template_type == template_type,\n            LegalTemplate.is_active == True,\n            LegalTemplate.is_deleted == False\n        ).order_by(LegalTemplate.name)\n        result = await self.session.execute(query)\n        return list(result.scalars().all())\n</create-file>\n</function_calls>'}
{'role': 'user', 'content': '<tool_result> <create-file> ToolResult(success=True, output="File \'backend/app/repositories/legal.py\' created successfully.") </create-file> </tool_result>'}