98 lines
4.3 KiB
Python
98 lines
4.3 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
"""
|
|
Sync trustee positions to accounting (Buha).
|
|
Input: featureInstanceId, documentList (reference to processDocuments result message).
|
|
Reads positionIds from the document and calls AccountingBridge.pushBatchToAccounting.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
from typing import Dict, Any, List
|
|
|
|
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
|
|
from modules.datamodels.datamodelDocref import DocumentReferenceList
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _resolveFirstDocument(documentListParam, services) -> Dict[str, Any] | None:
|
|
"""Resolve the first document from either Graph-Editor output (list of dicts) or Chat references.
|
|
|
|
Returns the parsed JSON dict or None.
|
|
"""
|
|
if isinstance(documentListParam, list) and documentListParam:
|
|
first = documentListParam[0]
|
|
if isinstance(first, dict) and ("documentData" in first or "documentName" in first):
|
|
rawData = first.get("documentData")
|
|
if rawData:
|
|
try:
|
|
return json.loads(rawData) if isinstance(rawData, str) else rawData
|
|
except (json.JSONDecodeError, TypeError):
|
|
pass
|
|
|
|
chatService = getattr(services, "chat", None)
|
|
if not chatService:
|
|
return None
|
|
|
|
try:
|
|
docList = DocumentReferenceList.from_string_list(
|
|
documentListParam if isinstance(documentListParam, list) else [documentListParam]
|
|
)
|
|
chatDocuments = chatService.getChatDocumentsFromDocumentList(docList)
|
|
if not chatDocuments:
|
|
return None
|
|
doc = chatDocuments[0]
|
|
rawBytes = chatService.getFileData(doc.fileId)
|
|
if not rawBytes:
|
|
return None
|
|
content = rawBytes.decode("utf-8") if isinstance(rawBytes, bytes) else rawBytes
|
|
return json.loads(content) if isinstance(content, str) else content
|
|
except Exception as e:
|
|
logger.debug("_resolveFirstDocument chat fallback failed: %s", e)
|
|
return None
|
|
|
|
|
|
async def syncToAccounting(self, parameters: Dict[str, Any]) -> ActionResult:
|
|
"""
|
|
Push trustee positions to the configured accounting system.
|
|
documentList must reference the message from processDocuments (one document with JSON { positionIds, documentIds }).
|
|
"""
|
|
featureInstanceId = parameters.get("featureInstanceId") or (self.services.featureInstanceId if hasattr(self.services, "featureInstanceId") else None)
|
|
documentListParam = parameters.get("documentList")
|
|
|
|
if not featureInstanceId:
|
|
return ActionResult.isFailure(error="featureInstanceId is required")
|
|
if not documentListParam:
|
|
return ActionResult.isFailure(error="documentList is required (reference to processDocuments result)")
|
|
|
|
try:
|
|
data = _resolveFirstDocument(documentListParam, self.services)
|
|
if data is None:
|
|
return ActionResult.isFailure(error="No document found for documentList; ensure processDocuments ran before this action")
|
|
|
|
positionIds = data.get("positionIds") or []
|
|
if not positionIds:
|
|
return ActionResult.isSuccess(documents=[
|
|
ActionDocument(documentName="sync_result", documentData=json.dumps({"pushed": 0, "message": "No positionIds in document"}), mimeType="application/json")
|
|
])
|
|
|
|
from modules.features.trustee.interfaceFeatureTrustee import getInterface as getTrusteeInterface
|
|
from modules.features.trustee.accounting.accountingBridge import AccountingBridge
|
|
|
|
trusteeInterface = getTrusteeInterface(
|
|
self.services.user,
|
|
mandateId=self.services.mandateId,
|
|
featureInstanceId=featureInstanceId
|
|
)
|
|
bridge = AccountingBridge(trusteeInterface)
|
|
results = await bridge.pushBatchToAccounting(featureInstanceId, positionIds)
|
|
successCount = sum(1 for r in results if r.success)
|
|
summary = {"pushed": successCount, "total": len(positionIds), "results": [{"positionId": pid, "success": r.success, "error": getattr(r, "errorMessage", None)} for pid, r in zip(positionIds, results)]}
|
|
|
|
return ActionResult.isSuccess(documents=[
|
|
ActionDocument(documentName="sync_result", documentData=json.dumps(summary), mimeType="application/json")
|
|
])
|
|
except Exception as e:
|
|
logger.exception("syncToAccounting failed")
|
|
return ActionResult.isFailure(error=str(e))
|