diff --git a/web/paperclip_client.py b/web/paperclip_client.py index ddec65e..1fded6a 100644 --- a/web/paperclip_client.py +++ b/web/paperclip_client.py @@ -1,7 +1,12 @@ -"""Paperclip project creation via direct DB access (embedded PostgreSQL).""" +"""Paperclip integration via direct DB access (embedded PostgreSQL). + +Creates projects, issues, and plugin state entries to fully link +a legal-ai case into Paperclip's workflow. +""" from __future__ import annotations +import json import logging import os import uuid @@ -14,6 +19,8 @@ PAPERCLIP_DB_URL = os.environ.get( "PAPERCLIP_DB_URL", "postgresql://paperclip:paperclip@127.0.0.1:54329/paperclip" ) +PLUGIN_ID = "53461b5a-7f58-411a-9952-72f9c8d4a328" # marcusgroup.legal-ai + # Company IDs from Paperclip DB COMPANIES = { "licensing": "42a7acd0-30c5-4cbd-ac97-7424f65df294", # CMP — רישוי ובניה @@ -69,10 +76,20 @@ async def create_project( VALUES ($1, $2::uuid, $3, $4, 'backlog', $5)""", project_id, company_id, project_name, description[:500] if description else "", color, ) + # Create initial issue linked to the project + issue_id, identifier = await _create_issue( + conn, company_id, project_id, case_number, title, prefix, + ) + + # Link issue to legal-ai case via plugin state + await _link_case_to_issue(conn, issue_id, case_number) + return { "id": project_id, "company_id": company_id, "name": project_name, + "issue_id": issue_id, + "issue_identifier": identifier, "url": f"https://pc.nautilus.marcusgroup.org/{prefix}/projects/{project_id}/issues", "existing": False, } @@ -80,6 +97,49 @@ async def create_project( await conn.close() +async def _create_issue( + conn: asyncpg.Connection, + company_id: str, + project_id: str, + case_number: str, + title: str, + prefix: str, +) -> tuple[str, str]: + """Create an issue in the project and return (issue_id, identifier).""" + issue_id = str(uuid.uuid4()) + + # Get next issue number for this company + row = await conn.fetchrow( + "UPDATE companies SET issue_counter = issue_counter + 1 WHERE id = $1::uuid RETURNING issue_counter", + company_id, + ) + issue_number = row["issue_counter"] + identifier = f"{prefix}-{issue_number}" + + await conn.execute( + """INSERT INTO issues (id, company_id, project_id, title, description, status, priority, issue_number, identifier) + VALUES ($1, $2::uuid, $3::uuid, $4, $5, 'todo', 'medium', $6, $7)""", + issue_id, company_id, project_id, + f"[ערר {case_number}] {title}"[:200], + f"תיק ערר {case_number}\nנוצר אוטומטית מממשק העלאת מסמכים", + issue_number, identifier, + ) + + logger.info("Created Paperclip issue %s: [ערר %s] %s", identifier, case_number, title) + return issue_id, identifier + + +async def _link_case_to_issue(conn: asyncpg.Connection, issue_id: str, case_number: str) -> None: + """Store the legal-ai case number in plugin state, linked to the issue.""" + await conn.execute( + """INSERT INTO plugin_state (plugin_id, scope_kind, scope_id, namespace, state_key, value_json) + VALUES ($1::uuid, 'issue', $2, 'default', 'legal-case-number', $3::jsonb) + ON CONFLICT (plugin_id, scope_kind, scope_id, namespace, state_key) DO UPDATE SET value_json = $3::jsonb""", + PLUGIN_ID, issue_id, json.dumps(case_number), + ) + logger.info("Linked issue %s to case %s via plugin state", issue_id, case_number) + + async def get_project_url(case_number: str) -> str | None: """Find existing Paperclip project for a case number.""" conn = await asyncpg.connect(PAPERCLIP_DB_URL)