Feature: Opdater vTiger Timelog med Hub ordre ID efter eksport
- Tilføjet update_timelog_billed() metode til vtiger_sync.py - Opdaterer billed_via_thehub_id felt i vTiger Timelog records - Kaldes automatisk efter succesfuld e-conomic eksport - Respekterer READ_ONLY og DRY_RUN safety flags - Fejler ikke eksporten hvis vTiger update fejler (bare logger warning)
This commit is contained in:
parent
a2857f5e12
commit
807e7f6395
@ -24,6 +24,7 @@ from app.timetracking.backend.models import (
|
||||
TModuleEconomicExportResult
|
||||
)
|
||||
from app.timetracking.backend.audit import audit
|
||||
from app.timetracking.backend.vtiger_sync import vtiger_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -412,6 +413,32 @@ class EconomicExportService:
|
||||
(request.order_id,)
|
||||
)
|
||||
|
||||
# Hent vTiger IDs for tidsregistreringerne
|
||||
vtiger_ids_query = """
|
||||
SELECT t.vtiger_id
|
||||
FROM tmodule_times t
|
||||
WHERE t.id IN (
|
||||
SELECT UNNEST(time_entry_ids)
|
||||
FROM tmodule_order_lines
|
||||
WHERE order_id = %s
|
||||
)
|
||||
"""
|
||||
vtiger_time_records = execute_query(vtiger_ids_query, (request.order_id,))
|
||||
vtiger_ids = [r['vtiger_id'] for r in vtiger_time_records]
|
||||
|
||||
# Opdater Timelog records i vTiger med Hub ordre ID
|
||||
if vtiger_ids:
|
||||
logger.info(f"📝 Updating {len(vtiger_ids)} timelogs in vTiger with Hub order {request.order_id}...")
|
||||
try:
|
||||
vtiger_update_result = await vtiger_service.update_timelog_billed(
|
||||
vtiger_ids=vtiger_ids,
|
||||
hub_order_id=request.order_id
|
||||
)
|
||||
logger.info(f"✅ vTiger update: {vtiger_update_result}")
|
||||
except Exception as vtiger_error:
|
||||
# Don't fail export if vTiger update fails - just log it
|
||||
logger.error(f"⚠️ Could not update vTiger timelogs: {vtiger_error}")
|
||||
|
||||
# Log successful export
|
||||
audit.log_export_completed(
|
||||
order_id=request.order_id,
|
||||
|
||||
@ -210,6 +210,77 @@ class TimeTrackingVTigerService:
|
||||
logger.error(f"❌ vTiger connection error: {e}")
|
||||
return False
|
||||
|
||||
async def update_timelog_billed(self, vtiger_ids: List[str], hub_order_id: int) -> Dict[str, int]:
|
||||
"""
|
||||
Update Timelog records in vTiger with Hub ordre ID (markér som faktureret).
|
||||
|
||||
🚨 WRITE operation - respekterer safety flags
|
||||
|
||||
Args:
|
||||
vtiger_ids: Liste af vTiger Timelog IDs (format: "43x1234")
|
||||
hub_order_id: Hub ordre ID til at sætte i billed_via_thehub_id felt
|
||||
|
||||
Returns:
|
||||
Dict with success/error counts
|
||||
"""
|
||||
if self.read_only:
|
||||
logger.warning(f"🔒 READ-ONLY mode: Would update {len(vtiger_ids)} timelogs with Hub order {hub_order_id}")
|
||||
return {"updated": 0, "errors": 0, "message": "READ-ONLY mode"}
|
||||
|
||||
if self.dry_run:
|
||||
logger.warning(f"🏃 DRY-RUN mode: Would update {len(vtiger_ids)} timelogs with Hub order {hub_order_id}")
|
||||
return {"updated": 0, "errors": 0, "message": "DRY-RUN mode"}
|
||||
|
||||
stats = {"updated": 0, "errors": 0}
|
||||
|
||||
logger.info(f"📝 Updating {len(vtiger_ids)} timelogs in vTiger with Hub order {hub_order_id}...")
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
for vtiger_id in vtiger_ids:
|
||||
try:
|
||||
# Build update payload
|
||||
update_url = f"{self.rest_endpoint}/update"
|
||||
payload = {
|
||||
"elementType": "Timelog",
|
||||
"element": {
|
||||
"id": vtiger_id,
|
||||
"billed_via_thehub_id": str(hub_order_id)
|
||||
}
|
||||
}
|
||||
|
||||
async with session.post(
|
||||
update_url,
|
||||
json=payload,
|
||||
auth=self._get_auth(),
|
||||
timeout=aiohttp.ClientTimeout(total=30)
|
||||
) as response:
|
||||
text = await response.text()
|
||||
|
||||
if response.status == 200:
|
||||
data = json.loads(text)
|
||||
if data.get('success'):
|
||||
logger.debug(f"✅ Updated timelog {vtiger_id}")
|
||||
stats["updated"] += 1
|
||||
else:
|
||||
error_msg = data.get('error', {}).get('message', 'Unknown error')
|
||||
logger.error(f"❌ vTiger error for {vtiger_id}: {error_msg}")
|
||||
stats["errors"] += 1
|
||||
else:
|
||||
logger.error(f"❌ HTTP {response.status} for {vtiger_id}: {text[:200]}")
|
||||
stats["errors"] += 1
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error updating timelog {vtiger_id}: {e}")
|
||||
stats["errors"] += 1
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Batch update error: {e}")
|
||||
stats["errors"] += len(vtiger_ids)
|
||||
|
||||
logger.info(f"✅ vTiger update complete: {stats['updated']} updated, {stats['errors']} errors")
|
||||
return stats
|
||||
|
||||
async def _fetch_user_name(self, user_id: str) -> str:
|
||||
"""
|
||||
Fetch user name from vTiger using retrieve API.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user