116 lines
4.0 KiB
Python
116 lines
4.0 KiB
Python
"""Ticket mutation service — wraps PSA provider, resolves is_rf_user flag."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.psa_connection import PsaConnection
|
|
from app.models.psa_member_mapping import PsaMemberMapping
|
|
from app.schemas.psa_tickets import (
|
|
PSAResourceSchema,
|
|
PSATicketCreatedSchema,
|
|
PSATicketStatusUpdateSchema,
|
|
)
|
|
from app.services.psa.registry import get_provider_for_account
|
|
from app.services.psa.types import TicketCreatePayload
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def _get_mapped_member_ids(account_id: UUID, db: AsyncSession) -> set[int]:
|
|
"""Return set of external_member_id ints that are mapped to RF users."""
|
|
conn_result = await db.execute(
|
|
select(PsaConnection).where(PsaConnection.account_id == account_id)
|
|
)
|
|
conn = conn_result.scalar_one_or_none()
|
|
if not conn:
|
|
return set()
|
|
mappings = await db.execute(
|
|
select(PsaMemberMapping).where(PsaMemberMapping.psa_connection_id == conn.id)
|
|
)
|
|
return {int(m.external_member_id) for m in mappings.scalars().all() if m.external_member_id}
|
|
|
|
|
|
async def list_resources(
|
|
account_id: UUID, ticket_id: int, db: AsyncSession
|
|
) -> list[PSAResourceSchema]:
|
|
provider = await get_provider_for_account(account_id, db)
|
|
mapped_ids = await _get_mapped_member_ids(account_id, db)
|
|
resources = await provider.list_resources(ticket_id)
|
|
return [
|
|
PSAResourceSchema(
|
|
member_id=r.member_id,
|
|
member_name=r.member_name,
|
|
member_identifier=r.member_identifier,
|
|
is_rf_user=r.member_id in mapped_ids,
|
|
)
|
|
for r in resources
|
|
]
|
|
|
|
|
|
async def add_resource(
|
|
account_id: UUID, ticket_id: int, member_id: int, db: AsyncSession
|
|
) -> PSAResourceSchema:
|
|
provider = await get_provider_for_account(account_id, db)
|
|
mapped_ids = await _get_mapped_member_ids(account_id, db)
|
|
resource = await provider.add_resource(ticket_id, member_id)
|
|
return PSAResourceSchema(
|
|
member_id=resource.member_id,
|
|
member_name=resource.member_name,
|
|
member_identifier=resource.member_identifier,
|
|
is_rf_user=resource.member_id in mapped_ids,
|
|
)
|
|
|
|
|
|
async def remove_resource(
|
|
account_id: UUID, ticket_id: int, member_id: int, db: AsyncSession
|
|
) -> None:
|
|
provider = await get_provider_for_account(account_id, db)
|
|
await provider.remove_resource(ticket_id, member_id)
|
|
|
|
|
|
async def update_status(
|
|
account_id: UUID, ticket_id: int, status_id: int, db: AsyncSession
|
|
) -> PSATicketStatusUpdateSchema:
|
|
provider = await get_provider_for_account(account_id, db)
|
|
# get current status before updating
|
|
ticket = await provider.get_ticket(str(ticket_id))
|
|
previous_status = ticket.status_name or ""
|
|
await provider.update_ticket_status(str(ticket_id), status_id)
|
|
# get new status name from statuses list
|
|
statuses = await provider.get_ticket_statuses(ticket.board_id or 0)
|
|
new_status = next((s.name for s in statuses if s.id == status_id), str(status_id))
|
|
return PSATicketStatusUpdateSchema(
|
|
ticket_id=ticket_id,
|
|
previous_status=previous_status,
|
|
new_status=new_status,
|
|
)
|
|
|
|
|
|
async def create_ticket(
|
|
account_id: UUID, payload: TicketCreatePayload, db: AsyncSession
|
|
) -> PSATicketCreatedSchema:
|
|
provider = await get_provider_for_account(account_id, db)
|
|
mapped_ids = await _get_mapped_member_ids(account_id, db)
|
|
result = await provider.create_ticket(payload)
|
|
return PSATicketCreatedSchema(
|
|
id=result.id,
|
|
summary=result.summary,
|
|
board_name=result.board_name,
|
|
status_name=result.status_name,
|
|
priority_name=result.priority_name,
|
|
company_name=result.company_name,
|
|
resources=[
|
|
PSAResourceSchema(
|
|
member_id=r.member_id,
|
|
member_name=r.member_name,
|
|
member_identifier=r.member_identifier,
|
|
is_rf_user=r.member_id in mapped_ids,
|
|
)
|
|
for r in result.resources
|
|
],
|
|
)
|