gateway/modules/workflows/methods/methodJira/actions/mergeTicketData.py
2026-01-22 21:11:25 +01:00

138 lines
5.9 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
import logging
import json
from typing import Dict, Any, List
from modules.aichat.datamodelFeatureAiChat import ActionResult, ActionDocument
logger = logging.getLogger(__name__)
async def mergeTicketData(self, parameters: Dict[str, Any]) -> ActionResult:
try:
jiraDataParam = parameters.get("jiraData")
if not jiraDataParam:
return ActionResult.isFailure(error="jiraData parameter is required")
existingDataParam = parameters.get("existingData")
if not existingDataParam:
return ActionResult.isFailure(error="existingData parameter is required")
taskSyncDefinitionParam = parameters.get("taskSyncDefinition")
if not taskSyncDefinitionParam:
return ActionResult.isFailure(error="taskSyncDefinition parameter is required")
idField = parameters.get("idField", "ID")
# Parse taskSyncDefinition
if isinstance(taskSyncDefinitionParam, str):
try:
taskSyncDefinition = json.loads(taskSyncDefinitionParam)
except json.JSONDecodeError as e:
return ActionResult.isFailure(error=f"taskSyncDefinition is not valid JSON: {str(e)}")
elif isinstance(taskSyncDefinitionParam, dict):
taskSyncDefinition = taskSyncDefinitionParam
else:
return ActionResult.isFailure(error=f"taskSyncDefinition must be a dict or JSON string, got {type(taskSyncDefinitionParam)}")
# Get data from documents
jiraDataJson = self.documentParsing.parseJsonFromDocument(jiraDataParam)
if jiraDataJson is None or not isinstance(jiraDataJson, list):
return ActionResult.isFailure(error="Could not parse jiraData as JSON array")
existingDataJson = self.documentParsing.parseJsonFromDocument(existingDataParam)
if existingDataJson is None or not isinstance(existingDataJson, list):
# Empty existing data is OK
existingDataJson = []
# Perform merge
existingLookup = {row.get(idField): row for row in existingDataJson if row.get(idField)}
mergedData: List[dict] = []
changes: List[str] = []
updatedCount = addedCount = unchangedCount = 0
for jiraRow in jiraDataJson:
jiraId = jiraRow.get(idField)
if jiraId and jiraId in existingLookup:
existingRow = existingLookup[jiraId].copy()
rowChanges: List[str] = []
for fieldName, fieldConfig in taskSyncDefinition.items():
if fieldConfig[0] == 'get':
oldValue = "" if existingRow.get(fieldName) is None else str(existingRow.get(fieldName))
newValue = "" if jiraRow.get(fieldName) is None else str(jiraRow.get(fieldName))
# Convert ADF data to readable text for logging
if isinstance(newValue, dict) and newValue.get("type") == "doc":
newValueReadable = self.adfConverter.convertAdfToText(newValue)
if oldValue != newValueReadable:
rowChanges.append(f"{fieldName}: '{oldValue[:100]}...' -> '{newValueReadable[:100]}...'")
elif oldValue != newValue:
# Truncate long values for logging
oldTruncated = oldValue[:100] + "..." if len(oldValue) > 100 else oldValue
newTruncated = newValue[:100] + "..." if len(newValue) > 100 else newValue
rowChanges.append(f"{fieldName}: '{oldTruncated}' -> '{newTruncated}'")
existingRow[fieldName] = jiraRow.get(fieldName)
mergedData.append(existingRow)
if rowChanges:
updatedCount += 1
changes.append(f"Row ID {jiraId} updated: {', '.join(rowChanges)}")
else:
unchangedCount += 1
del existingLookup[jiraId]
else:
mergedData.append(jiraRow)
addedCount += 1
changes.append(f"Row ID {jiraId} added as new record")
# Add remaining existing rows
for remaining in existingLookup.values():
mergedData.append(remaining)
unchangedCount += 1
mergeDetails = {
"updated": updatedCount,
"added": addedCount,
"unchanged": unchangedCount,
"changes": changes
}
logger.info(f"Merged ticket data: {updatedCount} updated, {addedCount} added, {unchangedCount} unchanged")
# Generate filename
workflowContext = self.services.chat.getWorkflowContext() if hasattr(self.services, 'chat') else None
filename = self._generateMeaningfulFileName(
"merged_ticket_data",
"json",
workflowContext,
"mergeTicketData"
)
result = {
"data": mergedData,
"mergeDetails": mergeDetails
}
validationMetadata = self._createValidationMetadata(
"mergeTicketData",
updated=updatedCount,
added=addedCount,
unchanged=unchangedCount
)
document = ActionDocument(
documentName=filename,
documentData=json.dumps(result, indent=2, ensure_ascii=False),
mimeType="application/json",
validationMetadata=validationMetadata
)
return ActionResult.isSuccess(documents=[document])
except Exception as e:
errorMsg = f"Error merging ticket data: {str(e)}"
logger.error(errorMsg)
return ActionResult.isFailure(error=errorMsg)