diff --git a/lib/EventListener/StackiqEventListener.php b/lib/EventListener/StackiqEventListener.php index 9bdceaf3b..68c952662 100644 --- a/lib/EventListener/StackiqEventListener.php +++ b/lib/EventListener/StackiqEventListener.php @@ -54,6 +54,37 @@ * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class StackiqEventListener implements IEventListener { + /** + * The log lines for a contact person (or contactgegevens) update or deletion: + * matched, done and failed. + */ + private const CONTACT_MESSAGES = [ + 'update' => [ + 'contactPerson' => [ + 'Stackiq: Matched contactpersoon schema - processing update', + 'Stackiq: Successfully processed contactpersoon update', + 'Stackiq: Failed to process contactpersoon update', + ], + 'contactgegevens' => [ + 'Stackiq: Matched contactgegevens schema - processing update (backward compatibility)', + 'Stackiq: Successfully processed contactgegevens update (as contactpersoon)', + 'Stackiq: Failed to process contactgegevens update', + ], + ], + 'deletion' => [ + 'contactPerson' => [ + 'Stackiq: Matched contactpersoon schema - processing deletion', + 'Stackiq: Successfully processed contactpersoon deletion', + 'Stackiq: Failed to process contactpersoon deletion', + ], + 'contactgegevens' => [ + 'Stackiq: Matched contactgegevens schema - processing deletion (backward compatibility)', + 'Stackiq: Successfully processed contactgegevens deletion', + 'Stackiq: Failed to process contactgegevens deletion', + ], + ], + ]; + /** * Constructor for StackiqEventListener * @@ -92,9 +123,7 @@ public function handle(Event $event): void { $this->dispatchEvent( event: $event, - contactSvc: $contactSvc, - settingsService: $settingsService, - logger: $logger + services: ['contactSvc' => $contactSvc, 'settings' => $settingsService, 'logger' => $logger] ); } catch (\Exception $e) { try { @@ -118,51 +147,26 @@ public function handle(Event $event): void { /** * Dispatches the supplied event to the matching per-lifecycle handler. * - * Extracted from {@see handle()} as part of the task 6.1 decomposition so the - * outer method retains only the try/catch envelope and the logging shell. - * * @param Event $event The event to dispatch. - * @param ContactpersoonService $contactSvc Contact-person service handle. - * @param SettingsService $settingsService Settings service handle. - * @param LoggerInterface $logger Logger handle. + * @param array $services The contactSvc, settings and logger services. * * @return void * * @spec openspec/changes/method-decomposition/tasks.md#task-6 */ - private function dispatchEvent( - Event $event, - ContactpersoonService $contactSvc, - SettingsService $settingsService, - LoggerInterface $logger, - ): void { + private function dispatchEvent(Event $event, array $services): void { if ($event instanceof ObjectCreatedEvent) { - $this->handleObjectCreated( - event: $event, - contactSvc: $contactSvc, - settingsService: $settingsService, - logger: $logger - ); + $this->handleObjectCreated(event: $event, services: $services); return; } if ($event instanceof ObjectUpdatedEvent) { - $this->handleObjectUpdated( - event: $event, - contactSvc: $contactSvc, - settingsService: $settingsService, - logger: $logger - ); + $this->handleObjectUpdated(event: $event, services: $services); return; } if ($event instanceof ObjectDeletedEvent) { - $this->handleObjectDeleted( - event: $event, - contactSvc: $contactSvc, - settingsService: $settingsService, - logger: $logger - ); + $this->handleObjectDeleted(event: $event, services: $services); return; } @@ -170,7 +174,7 @@ private function dispatchEvent( || $event instanceof ObjectUnlockedEvent || $event instanceof ObjectRevertedEvent ) { - $logger->debug( + $services['logger']->debug( 'Stackiq: Ignoring object lifecycle event', [ 'eventType' => get_class($event), @@ -390,190 +394,246 @@ private function refetchOrganizationWithContactpersonen( }//end try }//end refetchOrganizationWithContactpersonen() + /** + * The facts every handler reads off an object, with the services. + * + * @param \OCA\OpenRegister\Db\ObjectEntity $object The event's object. + * @param array $services The contactSvc, settings and logger services. + * + * @return array The object, its id, schema (raw and as int) and register, and the services. + */ + private function objectContext(\OCA\OpenRegister\Db\ObjectEntity $object, array $services): array { + $schemaId = $object->getSchema(); + return $services + [ + 'object' => $object, + 'objectId' => $object->getUuid(), + 'schemaId' => $schemaId, + 'schemaIdInt' => (int)$schemaId, + 'registerId' => $object->getRegister(), + ]; + }//end objectContext() + + /** + * Look the catalog schemas up one by one, until one matches the object's schema. + * + * @param array $ctx The object context. + * @param array $kinds The catalog object types, in lookup order. + * + * @return array{kind: string|null, ids: array} The matching type and the ids looked up. + */ + private function firstMatchingSchema(array $ctx, array $kinds): array { + $ids = []; + foreach ($kinds as $kind) { + $ids[$kind] = $ctx['settings']->getSchemaIdForObjectType(objectType: $kind); + if ($this->matchesSchema(objectSchemaIdInt: $ctx['schemaIdInt'], configured: $ids[$kind]) === true) { + return ['kind' => $kind, 'ids' => $ids]; + } + } + + return ['kind' => null, 'ids' => $ids]; + }//end firstMatchingSchema() + /** * Handles object creation events * * @param ObjectCreatedEvent $event The creation event - * @param ContactpersoonService $contactSvc The contact person service - * @param SettingsService $settingsService The settings service - * @param LoggerInterface $logger The logger instance + * @param array $services The contactSvc, settings and logger services. * * @return void * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * * @spec openspec/specs/method-decomposition/spec.md */ - private function handleObjectCreated( - ObjectCreatedEvent $event, - ContactpersoonService $contactSvc, - SettingsService $settingsService, - LoggerInterface $logger, - ): void { + private function handleObjectCreated(ObjectCreatedEvent $event, array $services): void { $object = $event->getObject(); if ($object === null) { - $logger->warning('Stackiq: ObjectCreatedEvent received with null object'); + $services['logger']->warning('Stackiq: ObjectCreatedEvent received with null object'); return; } - $objectSchemaId = $object->getSchema(); - $objectId = $object->getUuid(); - $objectRegisterId = $object->getRegister(); - - // Convert schema ID to integer for consistent comparison. - $objectSchemaIdInt = (int)$objectSchemaId; - + $ctx = $this->objectContext(object: $object, services: $services); + $logger = $ctx['logger']; $logger->info( 'Stackiq: Processing object creation', [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'schemaIdInt' => $objectSchemaIdInt, - 'registerId' => $objectRegisterId, + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'schemaIdInt' => $ctx['schemaIdInt'], + 'registerId' => $ctx['registerId'], 'objectData' => json_encode($object->getObject()), ] ); - // Get configuration for different object types. - $catalogSchemaIds = $this->resolveCatalogSchemaIds(settingsService: $settingsService); - $organisationSchemaId = $catalogSchemaIds['organization']; - $contactSchemaId = $catalogSchemaIds['contactPerson']; - $contactInfoSchemaId = $catalogSchemaIds['contactgegevens']; - $gebruikSchemaId = $catalogSchemaIds['usage']; - + $ids = $this->resolveCatalogSchemaIds(settingsService: $ctx['settings']); $logger->debug( 'Stackiq: Configuration lookup results', [ - 'organisatieSchemaId' => $organisationSchemaId, - 'contactpersoonSchemaId' => $contactSchemaId, - 'contactgegevensSchemaId' => $contactInfoSchemaId, - 'gebruikSchemaId' => $gebruikSchemaId, - 'objectSchemaId' => $objectSchemaIdInt, + 'organisatieSchemaId' => $ids['organization'], + 'contactpersoonSchemaId' => $ids['contactPerson'], + 'contactgegevensSchemaId' => $ids['contactgegevens'], + 'gebruikSchemaId' => $ids['usage'], + 'objectSchemaId' => $ctx['schemaIdInt'], ] ); - // Check if this is an organization object. - if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $organisationSchemaId) === true) { - $objectData = $object->getObject(); - $status = strtolower($objectData['status'] ?? ''); - - // Only process active organizations. - if ($this->isActiveStatus(status: $status) === false) { - $logger->debug( - 'Stackiq: Skipping non-active organization creation', - [ - 'objectId' => $objectId, - 'status' => $status, - ] - ); - return; + $kind = null; + foreach ($ids as $type => $configured) { + if ($kind === null && $this->matchesSchema(objectSchemaIdInt: $ctx['schemaIdInt'], configured: $configured) === true) { + $kind = $type; } + } - $logger->info( - 'Stackiq: Processing active organization creation', + match ($kind) { + 'organization' => $this->onOrganisationCreated(ctx: $ctx), + 'contactPerson' => $this->onContactPersonCreated(ctx: $ctx), + 'contactgegevens' => $logger->info('Stackiq: Processing contactgegevens creation (deprecated)', ['objectId' => $ctx['objectId']]), + 'usage' => $this->onUsageCreated(ctx: $ctx), + default => $logger->debug( + 'Stackiq: Object creation not handled - not a supported object type', [ - 'objectId' => $objectId, + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaIdInt'], + 'registerId' => $ctx['registerId'], + 'supportedSchemas' => $ids, + ] + ), + }; + }//end handleObjectCreated() + + /** + * A created organisation is synced when it is active. + * + * @param array $ctx The object context. + * + * @return void + */ + private function onOrganisationCreated(array $ctx): void { + $status = strtolower($ctx['object']->getObject()['status'] ?? ''); + if ($this->isActiveStatus(status: $status) === false) { + $ctx['logger']->debug( + 'Stackiq: Skipping non-active organization creation', + [ + 'objectId' => $ctx['objectId'], 'status' => $status, ] ); - - $this->runOrganizationSync(object: $object, phase: 'creation', logger: $logger); - return; - }//end if - - // Check if this is a contactpersoon object. - if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $contactSchemaId) === true) { - $logger->info('Stackiq: Processing contactpersoon creation', ['objectId' => $objectId]); - $contactSvc->processContactpersoon($object); - return; - } - - // Check if this is a contactgegevens object (deprecated - use contactpersoon instead). - if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $contactInfoSchemaId) === true) { - $logger->info('Stackiq: Processing contactgegevens creation (deprecated)', ['objectId' => $objectId]); - // Contactgegevens is deprecated, use contactpersoon instead. return; } - // Check if this is a gebruik object. - if ($this->matchesSchema(objectSchemaIdInt: $objectSchemaIdInt, configured: $gebruikSchemaId) === true) { - $logger->info('Stackiq: Processing gebruik creation', ['objectId' => $objectId]); - $this->runGebruikSync(object: $object, phase: 'creation', logger: $logger); - return; - }//end if - - // Log unhandled object types. - $logger->debug( - 'Stackiq: Object creation not handled - not a supported object type', + $ctx['logger']->info( + 'Stackiq: Processing active organization creation', [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaIdInt, - 'registerId' => $objectRegisterId, - 'supportedSchemas' => [ - 'organization' => $organisationSchemaId, - 'contactPerson' => $contactSchemaId, - 'contactgegevens' => $contactInfoSchemaId, - 'usage' => $gebruikSchemaId, - ], + 'objectId' => $ctx['objectId'], + 'status' => $status, ] ); - }//end handleObjectCreated() + + $this->runOrganizationSync(object: $ctx['object'], phase: 'creation', logger: $ctx['logger']); + }//end onOrganisationCreated() + + /** + * A created contact person gets processed. + * + * @param array $ctx The object context. + * + * @return void + */ + private function onContactPersonCreated(array $ctx): void { + $ctx['logger']->info('Stackiq: Processing contactpersoon creation', ['objectId' => $ctx['objectId']]); + $ctx['contactSvc']->processContactpersoon($ctx['object']); + }//end onContactPersonCreated() + + /** + * A created usage gets synced. + * + * @param array $ctx The object context. + * + * @return void + */ + private function onUsageCreated(array $ctx): void { + $ctx['logger']->info('Stackiq: Processing gebruik creation', ['objectId' => $ctx['objectId']]); + $this->runGebruikSync(object: $ctx['object'], phase: 'creation', logger: $ctx['logger']); + }//end onUsageCreated() /** * Handles object update events * * @param ObjectUpdatedEvent $event The update event - * @param ContactpersoonService $contactSvc The contact person service - * @param SettingsService $settingsService The settings service - * @param LoggerInterface $logger The logger instance + * @param array $services The contactSvc, settings and logger services. * * @return void * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * * @spec openspec/specs/method-decomposition/spec.md */ - private function handleObjectUpdated( - ObjectUpdatedEvent $event, - ContactpersoonService $contactSvc, - SettingsService $settingsService, - LoggerInterface $logger, - ): void { + private function handleObjectUpdated(ObjectUpdatedEvent $event, array $services): void { $object = $event->getNewObject(); - $oldObject = $event->getOldObject(); - if ($object === null) { - $logger->warning('Stackiq: ObjectUpdatedEvent received with null object'); + $services['logger']->warning('Stackiq: ObjectUpdatedEvent received with null object'); return; } - $objectSchemaId = $object->getSchema(); - $objectId = $object->getUuid(); - $objectRegisterId = $object->getRegister(); + $ctx = $this->objectContext(object: $object, services: $services) + ['oldObject' => $event->getOldObject()]; + $ctx['logger']->info( + 'Stackiq: Processing object update', + [ + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'schemaIdInt' => $ctx['schemaIdInt'], + 'registerId' => $ctx['registerId'], + 'hasOldObject' => $ctx['oldObject'] !== null, + ] + ); - // Convert schema ID to integer for consistent comparison. - $objectSchemaIdInt = (int)$objectSchemaId; + if ($this->isOrganisationUpdate(ctx: $ctx) === true) { + $this->onOrganisationUpdated(ctx: $ctx); + return; + } - $logger->info( - 'Stackiq: Processing object update', + $match = $this->firstMatchingSchema(ctx: $ctx, kinds: ['contactPerson', 'contactgegevens', 'usage']); + if ($match['kind'] === 'contactPerson' || $match['kind'] === 'contactgegevens') { + $this->runContactAction(ctx: $ctx, action: ['phase' => 'update', 'kind' => $match['kind'], 'configured' => $match['ids'][$match['kind']]]); + return; + } + + if ($match['kind'] === 'usage') { + $ctx['logger']->info( + 'Stackiq: Matched gebruik schema - processing update', + [ + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'configuredSchemaId' => $match['ids']['usage'], + ] + ); + + $this->runGebruikSync(object: $object, phase: 'update', logger: $ctx['logger']); + return; + } + + $ctx['logger']->debug( + 'Stackiq: Object update not handled - focusing only on organisatie, contactpersonen, and gebruik', [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'schemaIdInt' => $objectSchemaIdInt, - 'registerId' => $objectRegisterId, - 'hasOldObject' => $oldObject !== null, + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'schemaIdInt' => $ctx['schemaIdInt'], + 'schemaIdType' => gettype($ctx['schemaId']), + 'registerId' => $ctx['registerId'], + 'handledSchemas' => ['organization' => $ctx['organisationSchemaId']] + $match['ids'], ] ); + }//end handleObjectUpdated() - // Check if this is an organization update. - $organisationSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'organization'); + /** + * Whether an updated object is an organisation; logs the schema check. + * + * @param array $ctx The object context; gets the organisation schema id. + * + * @return bool True when the object's schema is the organisation schema. + */ + private function isOrganisationUpdate(array &$ctx): bool { + $organisationSchemaId = $ctx['settings']->getSchemaIdForObjectType(objectType: 'organization'); + $ctx['organisationSchemaId'] = $organisationSchemaId; $orgSchemaIdInt = (int)$organisationSchemaId; - $logger->debug( + $ctx['logger']->debug( 'Got organisation schema ID', [ 'app' => 'stackiq', @@ -582,378 +642,208 @@ private function handleObjectUpdated( ] ); - $logger->debug( + $ctx['logger']->debug( 'Organization schema check', [ 'app' => 'stackiq', - 'objectSchemaId' => $objectSchemaId, - 'objectSchemaIdInt' => $objectSchemaIdInt, + 'objectSchemaId' => $ctx['schemaId'], + 'objectSchemaIdInt' => $ctx['schemaIdInt'], 'organisatieSchemaId' => $organisationSchemaId, 'organisatieSchemaIdInt' => $orgSchemaIdInt, - 'matches' => ($objectSchemaIdInt === $orgSchemaIdInt), + 'matches' => ($ctx['schemaIdInt'] === $orgSchemaIdInt), ] ); - if ($organisationSchemaId !== null && $objectSchemaIdInt === $orgSchemaIdInt) { - $objectData = $object->getObject(); - $status = strtolower($objectData['status'] ?? ''); - - $oldStatus = ''; - if ($oldObject !== null) { - $oldData = $oldObject->getObject(); - $oldStatus = strtolower($oldData['status'] ?? ''); - } - - $logger->debug( - 'Organization status check', - [ - 'app' => 'stackiq', - 'objectId' => $objectId, - 'status' => $status, - 'oldStatus' => $oldStatus, - 'statusChanged' => ($status !== $oldStatus), - 'isActief' => $this->isActiveStatus(status: $status), - 'willProcess' => ($this->isActiveStatus(status: $status) === true - && $status !== $oldStatus), - ] - ); + return $this->matchesSchema(objectSchemaIdInt: $ctx['schemaIdInt'], configured: $organisationSchemaId); + }//end isOrganisationUpdate() - // Only process active organizations. - if ($this->isActiveStatus(status: $status) === true && $status !== $oldStatus) { - $logger->info( - 'Stackiq: Processing active organization update', - [ - 'objectId' => $objectId, - 'status' => $status, - 'schemaId' => $objectSchemaId, - ] - ); + /** + * An updated organisation that just became active is refetched with its contact persons and synced. + * + * @param array $ctx The object context, with the old object. + * + * @return void + */ + private function onOrganisationUpdated(array $ctx): void { + $status = strtolower($ctx['object']->getObject()['status'] ?? ''); + $oldStatus = ''; + if ($ctx['oldObject'] !== null) { + $oldStatus = strtolower($ctx['oldObject']->getObject()['status'] ?? ''); + } - $orgWithContacts = $this->refetchOrganizationWithContactpersonen( - objectId: $objectId, - settingsService: $settingsService, - logger: $logger - ); - if ($orgWithContacts !== null) { - $this->runOrganizationSync(object: $orgWithContacts, phase: 'update', logger: $logger); - } - }//end if - - if ($this->isActiveStatus(status: $status) === false || $status === $oldStatus) { - $logger->debug( - 'Stackiq: Skipping non-active organization update', - [ - 'objectId' => $objectId, - 'status' => $status, - 'schemaId' => $objectSchemaId, - ] - ); - } + $becameActive = $this->isActiveStatus(status: $status) === true && $status !== $oldStatus; + $ctx['logger']->debug( + 'Organization status check', + [ + 'app' => 'stackiq', + 'objectId' => $ctx['objectId'], + 'status' => $status, + 'oldStatus' => $oldStatus, + 'statusChanged' => ($status !== $oldStatus), + 'isActief' => $this->isActiveStatus(status: $status), + 'willProcess' => $becameActive, + ] + ); + $facts = [ + 'objectId' => $ctx['objectId'], + 'status' => $status, + 'schemaId' => $ctx['schemaId'], + ]; + if ($becameActive === false) { + $ctx['logger']->debug('Stackiq: Skipping non-active organization update', $facts); return; - }//end if - - // Handle contactpersoon updates. - $contactSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'contactPerson'); - $cntSchemaIdInt = (int)$contactSchemaId; - - if ($contactSchemaId !== null && $objectSchemaIdInt === $cntSchemaIdInt) { - $logger->info( - 'Stackiq: Matched contactpersoon schema - processing update', - [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'configuredSchemaId' => $contactSchemaId, - ] - ); + } - try { - $contactSvc->handleContactpersoonUpdate( - contactPersonObject: $object, - oldContactPersonObject: $oldObject - ); + $ctx['logger']->info('Stackiq: Processing active organization update', $facts); + $orgWithContacts = $this->refetchOrganizationWithContactpersonen( + objectId: $ctx['objectId'], + settingsService: $ctx['settings'], + logger: $ctx['logger'] + ); + if ($orgWithContacts !== null) { + $this->runOrganizationSync(object: $orgWithContacts, phase: 'update', logger: $ctx['logger']); + } + }//end onOrganisationUpdated() - $logger->info( - 'Stackiq: Successfully processed contactpersoon update', - [ - 'objectId' => $objectId, - 'timestamp' => date('Y-m-d H:i:s'), - ] - ); - } catch (\Exception $e) { - $logger->error( - 'Stackiq: Failed to process contactpersoon update', - [ - 'objectId' => $objectId, - 'exception' => $e->getMessage(), - 'file' => $e->getFile(), - 'line' => $e->getLine(), - 'trace' => $e->getTraceAsString(), - ] - ); - }//end try + /** + * Hand an updated or deleted contact person (or contactgegevens) to the contact person service. + * + * @param array $ctx The object context. + * @param array{phase: string, kind: string, configured: int|null} $action The phase, the matched type and its configured schema id. + * + * @return void + */ + private function runContactAction(array $ctx, array $action): void { + [$matched, $done, $failed] = self::CONTACT_MESSAGES[$action['phase']][$action['kind']]; + $ctx['logger']->info( + $matched, + [ + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'configuredSchemaId' => $action['configured'], + ] + ); - return; - }//end if + $call = fn () => $ctx['contactSvc']->handleContactDeletion($ctx['object']); + if ($action['phase'] === 'update') { + $call = fn () => $ctx['contactSvc']->handleContactpersoonUpdate( + contactPersonObject: $ctx['object'], + oldContactPersonObject: $ctx['oldObject'] + ); + } - // Handle contactgegevens updates (backward compatibility). - $contactInfoSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'contactgegevens'); - $infoSchemaIdInt = (int)$contactInfoSchemaId; + try { + $call(); - if ($contactInfoSchemaId !== null && $objectSchemaIdInt === $infoSchemaIdInt) { - $logger->info( - 'Stackiq: Matched contactgegevens schema - processing update (backward compatibility)', + $ctx['logger']->info( + $done, [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'configuredSchemaId' => $contactInfoSchemaId, + 'objectId' => $ctx['objectId'], + 'timestamp' => date('Y-m-d H:i:s'), ] ); - - try { - // Handle contactgegevens as contactpersoon (backward compatibility). - $contactSvc->handleContactpersoonUpdate( - contactPersonObject: $object, - oldContactPersonObject: $oldObject - ); - - $logger->info( - 'Stackiq: Successfully processed contactgegevens update (as contactpersoon)', - [ - 'objectId' => $objectId, - 'timestamp' => date('Y-m-d H:i:s'), - ] - ); - } catch (\Exception $e) { - $logger->error( - 'Stackiq: Failed to process contactgegevens update', - [ - 'objectId' => $objectId, - 'exception' => $e->getMessage(), - 'file' => $e->getFile(), - 'line' => $e->getLine(), - 'trace' => $e->getTraceAsString(), - ] - ); - }//end try - - return; - }//end if - - // Handle gebruik updates. - $gebruikSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'usage'); - $gebruikSchemaIdInt = (int)$gebruikSchemaId; - - if ($gebruikSchemaId !== null && $objectSchemaIdInt === $gebruikSchemaIdInt) { - $logger->info( - 'Stackiq: Matched gebruik schema - processing update', + } catch (\Exception $e) { + $ctx['logger']->error( + $failed, [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'configuredSchemaId' => $gebruikSchemaId, + 'objectId' => $ctx['objectId'], + 'exception' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'trace' => $e->getTraceAsString(), ] ); - - $this->runGebruikSync(object: $object, phase: 'update', logger: $logger); - return; - }//end if - - // Log if we don't handle this schema type. - $logger->debug( - 'Stackiq: Object update not handled - focusing only on organisatie, contactpersonen, and gebruik', - [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'schemaIdInt' => $objectSchemaIdInt, - 'schemaIdType' => gettype($objectSchemaId), - 'registerId' => $objectRegisterId, - 'handledSchemas' => [ - 'organization' => $organisationSchemaId, - 'contactPerson' => $contactSchemaId, - 'contactgegevens' => $contactInfoSchemaId, - 'usage' => $gebruikSchemaId, - ], - ] - ); - }//end handleObjectUpdated() + }//end try + }//end runContactAction() /** * Handles object deletion events * * @param ObjectDeletedEvent $event The deletion event - * @param ContactpersoonService $contactSvc The contact person service - * @param SettingsService $settingsService The settings service - * @param LoggerInterface $logger The logger instance + * @param array $services The contactSvc, settings and logger services. * * @return void * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * * @spec openspec/specs/method-decomposition/spec.md */ - private function handleObjectDeleted( - ObjectDeletedEvent $event, - ContactpersoonService $contactSvc, - SettingsService $settingsService, - LoggerInterface $logger, - ): void { + private function handleObjectDeleted(ObjectDeletedEvent $event, array $services): void { $object = $event->getObject(); if ($object === null) { - $logger->warning('Stackiq: ObjectDeletedEvent received with null object'); + $services['logger']->warning('Stackiq: ObjectDeletedEvent received with null object'); return; } - $objectSchemaId = $object->getSchema(); - $objectId = $object->getUuid(); - $objectRegisterId = $object->getRegister(); - - $logger->info( + $ctx = $this->objectContext(object: $object, services: $services); + $ctx['logger']->info( 'Stackiq: Processing object deletion', [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'registerId' => $objectRegisterId, + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'registerId' => $ctx['registerId'], 'objectData' => $object->getObject(), ] ); - // Check if this is an organization deletion. - $organisationSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'organization'); - $orgSchemaIdInt = (int)$organisationSchemaId; - $objectSchemaIdInt = (int)$objectSchemaId; - - if ($organisationSchemaId !== null && $objectSchemaIdInt === $orgSchemaIdInt) { - $logger->info('Stackiq: Processing organization deletion', ['objectId' => $objectId]); - $this->runOrganizationSync(object: $object, phase: 'deletion', logger: $logger); - return; - }//end if - - // Handle contactpersoon deletion. - $contactSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'contactPerson'); - $cntSchemaIdInt = (int)$contactSchemaId; - - if ($contactSchemaId !== null && $objectSchemaIdInt === $cntSchemaIdInt) { - $logger->info( - 'Stackiq: Matched contactpersoon schema - processing deletion', - [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'configuredSchemaId' => $contactSchemaId, - ] - ); - - try { - $contactSvc->handleContactDeletion($object); - - $logger->info( - 'Stackiq: Successfully processed contactpersoon deletion', - [ - 'objectId' => $objectId, - 'timestamp' => date('Y-m-d H:i:s'), - ] - ); - } catch (\Exception $e) { - $logger->error( - 'Stackiq: Failed to process contactpersoon deletion', - [ - 'objectId' => $objectId, - 'exception' => $e->getMessage(), - 'file' => $e->getFile(), - 'line' => $e->getLine(), - 'trace' => $e->getTraceAsString(), - ] - ); - }//end try - - return; - }//end if - - // Handle contactgegevens deletion (backward compatibility). - $contactInfoSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'contactgegevens'); - $infoSchemaIdInt = (int)$contactInfoSchemaId; - - if ($contactInfoSchemaId !== null && $objectSchemaIdInt === $infoSchemaIdInt) { - $logger->info( - 'Stackiq: Matched contactgegevens schema - processing deletion (backward compatibility)', + $match = $this->firstMatchingSchema(ctx: $ctx, kinds: ['organization', 'contactPerson', 'contactgegevens', 'usage']); + match ($match['kind']) { + 'organization' => $this->onOrganisationDeleted(ctx: $ctx), + 'contactPerson', 'contactgegevens' => $this->runContactAction( + ctx: $ctx, + action: ['phase' => 'deletion', 'kind' => $match['kind'], 'configured' => $match['ids'][$match['kind']]] + ), + 'usage' => $this->onUsageDeleted(ctx: $ctx, configured: $match['ids']['usage']), + default => $ctx['logger']->debug( + 'Stackiq: Object deletion not handled - focusing only on organisatie, contactpersonen, and gebruik', [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'configuredSchemaId' => $contactInfoSchemaId, + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'registerId' => $ctx['registerId'], + 'handledSchemas' => $match['ids'], ] - ); - - try { - $contactSvc->handleContactDeletion($object); - - $logger->info( - 'Stackiq: Successfully processed contactgegevens deletion', - [ - 'objectId' => $objectId, - 'timestamp' => date('Y-m-d H:i:s'), - ] - ); - } catch (\Exception $e) { - $logger->error( - 'Stackiq: Failed to process contactgegevens deletion', - [ - 'objectId' => $objectId, - 'exception' => $e->getMessage(), - 'file' => $e->getFile(), - 'line' => $e->getLine(), - 'trace' => $e->getTraceAsString(), - ] - ); - }//end try - - return; - }//end if - - // Handle gebruik deletion. - $gebruikSchemaId = $settingsService->getSchemaIdForObjectType(objectType: 'usage'); - $gebruikSchemaIdInt = (int)$gebruikSchemaId; - - if ($gebruikSchemaId !== null && $objectSchemaIdInt === $gebruikSchemaIdInt) { - $objectData = $object->getObject(); + ), + }; + }//end handleObjectDeleted() - $logger->info( - 'Stackiq: Matched gebruik schema - processing deletion', - [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'configuredSchemaId' => $gebruikSchemaId, - 'consumer' => $objectData['consumer']['name'] ?? 'Unknown', - 'product' => $objectData['product']['name'] ?? 'Unknown', - ] - ); + /** + * A deleted organisation gets synced. + * + * @param array $ctx The object context. + * + * @return void + */ + private function onOrganisationDeleted(array $ctx): void { + $ctx['logger']->info('Stackiq: Processing organization deletion', ['objectId' => $ctx['objectId']]); + $this->runOrganizationSync(object: $ctx['object'], phase: 'deletion', logger: $ctx['logger']); + }//end onOrganisationDeleted() - // For deletions, we mainly log the event since the object is being removed. - // No specific cleanup needed for gebruik objects currently. - $logger->info( - 'Stackiq: Gebruik object deleted - no specific cleanup required', - [ - 'objectId' => $objectId, - 'timestamp' => date('Y-m-d H:i:s'), - ] - ); - return; - }//end if + /** + * A deleted usage is only logged; it needs no clean-up. + * + * @param array $ctx The object context. + * @param int|null $configured The configured usage schema id. + * + * @return void + */ + private function onUsageDeleted(array $ctx, ?int $configured): void { + $objectData = $ctx['object']->getObject(); + $ctx['logger']->info( + 'Stackiq: Matched gebruik schema - processing deletion', + [ + 'objectId' => $ctx['objectId'], + 'schemaId' => $ctx['schemaId'], + 'configuredSchemaId' => $configured, + 'consumer' => $objectData['consumer']['name'] ?? 'Unknown', + 'product' => $objectData['product']['name'] ?? 'Unknown', + ] + ); - // Log if we don't handle this schema type. - $logger->debug( - 'Stackiq: Object deletion not handled - focusing only on organisatie, contactpersonen, and gebruik', + $ctx['logger']->info( + 'Stackiq: Gebruik object deleted - no specific cleanup required', [ - 'objectId' => $objectId, - 'schemaId' => $objectSchemaId, - 'registerId' => $objectRegisterId, - 'handledSchemas' => [ - 'organization' => $organisationSchemaId, - 'contactPerson' => $contactSchemaId, - 'contactgegevens' => $contactInfoSchemaId, - 'usage' => $gebruikSchemaId, - ], + 'objectId' => $ctx['objectId'], + 'timestamp' => date('Y-m-d H:i:s'), ] ); - }//end handleObjectDeleted() + }//end onUsageDeleted() }//end class diff --git a/tests/Unit/EventListener/StackiqEventListenerGoldenTest.php b/tests/Unit/EventListener/StackiqEventListenerGoldenTest.php new file mode 100644 index 000000000..f32a8f15d --- /dev/null +++ b/tests/Unit/EventListener/StackiqEventListenerGoldenTest.php @@ -0,0 +1,360 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * @link https://github.com/ConductionNL/stackiq + * + * @spec openspec/specs/method-decomposition/spec.md + */ + +declare(strict_types=1); + +namespace OCA\Stackiq\Tests\Unit\EventListener; + +use OCA\OpenRegister\Db\ObjectEntity; +use OCA\OpenRegister\Event\ObjectCreatedEvent; +use OCA\OpenRegister\Event\ObjectDeletedEvent; +use OCA\OpenRegister\Event\ObjectUpdatedEvent; +use OCA\Stackiq\EventListener\StackiqEventListener; +use OCA\Stackiq\Service\ContactpersoonService; +use OCA\Stackiq\Service\GebruikSyncService; +use OCA\Stackiq\Service\OrganizationSyncService; +use OCA\Stackiq\Service\SettingsService; +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Psr\Log\AbstractLogger; +use Psr\Log\LoggerInterface; + +/** + * Golden cases for StackiqEventListener::handle(). + * + * @covers \OCA\Stackiq\EventListener\StackiqEventListener + * + * @spec openspec/specs/method-decomposition/spec.md + */ +class StackiqEventListenerGoldenTest extends TestCase { + + /** + * The configured catalog schema ids. + */ + private const SCHEMAS = ['organization' => 1, 'contactPerson' => 2, 'contactgegevens' => 3, 'usage' => 4]; + + /** + * Context keys whose values depend on the clock or the run. + */ + private const VOLATILE = ['timestamp', 'trace', 'file', 'line']; + + /** + * Everything the doubles saw, in order. + * + * @var array + */ + private array $trace = []; + + /** + * Per-case behaviour of the doubles. + * + * @var array + */ + private array $plan = []; + + /** + * The cases: event kind, schema, data, old data and the doubles' behaviour. + * + * @return array}> + */ + public static function cases(): array { + $active = ['name' => 'Gemeente A', 'status' => 'Actief']; + $inactive = ['name' => 'Gemeente A', 'status' => 'inactief']; + $usage = ['consumer' => ['name' => 'Gemeente A'], 'product' => ['name' => 'Zaaksysteem']]; + return [ + 'created organisation active' => ['created', '1', $active, null, []], + 'created organisation active english' => ['created', '1', ['status' => 'ACTIVE'], null, []], + 'created organisation inactive' => ['created', '1', $inactive, null, []], + 'created organisation no status' => ['created', '1', [], null, []], + 'created organisation sync fails' => ['created', '1', $active, null, ['orgSyncThrows' => true]], + 'created contact person' => ['created', '2', ['email' => 'a@a.nl'], null, []], + 'created contact person fails' => ['created', '2', ['email' => 'a@a.nl'], null, ['contactThrows' => true]], + 'created contactgegevens' => ['created', '3', [], null, []], + 'created usage' => ['created', '4', $usage, null, []], + 'created usage sync fails' => ['created', '4', $usage, null, ['usageSyncThrows' => true]], + 'created other schema' => ['created', '9', ['x' => 1], null, []], + 'created, no schemas configured' => ['created', '1', $active, null, ['noSchemas' => true]], + 'created, schema id as string' => ['created', '01', $active, null, []], + 'created, two types share a schema' => ['created', '4', ['email' => 'a@a.nl'], null, ['schemas' => ['organization' => 1, 'contactPerson' => 4, 'contactgegevens' => 3, 'usage' => 4]]], + 'updated organisation activated' => ['updated', '1', $active, $inactive, []], + 'updated organisation, no old object' => ['updated', '1', $active, null, []], + 'updated organisation still active' => ['updated', '1', $active, $active, []], + 'updated organisation deactivated' => ['updated', '1', $inactive, $active, []], + 'updated organisation, refetch fails' => ['updated', '1', $active, $inactive, ['findThrows' => true]], + 'updated organisation, sync fails' => ['updated', '1', $active, $inactive, ['orgSyncThrows' => true]], + 'updated organisation, schema \'01\'' => ['updated', '01', $active, $inactive, []], + 'updated contact person' => ['updated', '2', ['email' => 'a@a.nl'], ['email' => 'b@a.nl'], []], + 'updated contact person fails' => ['updated', '2', ['email' => 'a@a.nl'], null, ['contactThrows' => true]], + 'updated contact person, Error escapes' => ['updated', '2', ['email' => 'a@a.nl'], null, ['contactThrows' => 'error']], + 'updated contactgegevens' => ['updated', '3', ['email' => 'a@a.nl'], null, []], + 'updated contactgegevens fails' => ['updated', '3', ['email' => 'a@a.nl'], null, ['contactThrows' => true]], + 'updated usage' => ['updated', '4', $usage, null, []], + 'updated other schema' => ['updated', '9', ['x' => 1], null, []], + 'updated, no schemas configured' => ['updated', '2', [], null, ['noSchemas' => true]], + 'deleted organisation' => ['deleted', '1', $active, null, []], + 'deleted organisation, sync fails' => ['deleted', '1', $active, null, ['orgSyncThrows' => true]], + 'deleted contact person' => ['deleted', '2', ['email' => 'a@a.nl'], null, []], + 'deleted contact person fails' => ['deleted', '2', ['email' => 'a@a.nl'], null, ['contactThrows' => true]], + 'deleted contactgegevens' => ['deleted', '3', [], null, []], + 'deleted contactgegevens fails' => ['deleted', '3', [], null, ['contactThrows' => true]], + 'deleted usage' => ['deleted', '4', $usage, null, []], + 'deleted usage without names' => ['deleted', '4', [], null, []], + 'deleted other schema' => ['deleted', '9', ['x' => 1], null, []], + 'deleted, no schemas configured' => ['deleted', '4', [], null, ['noSchemas' => true]], + ]; + }//end cases() + + /** + * Each case matches its recording. + * + * @param string $kind created, updated or deleted. + * @param string $schema The object's schema id. + * @param array $data The object data. + * @param array|null $oldData The previous object data, for an update. + * @param array $plan The behaviour of the doubles. + * + * @return void + * + * @dataProvider cases + */ + public function testHandleMatchesTheRecording(string $kind, string $schema, array $data, ?array $oldData, array $plan): void { + $this->plan = $plan; + $this->trace = []; + $object = $this->entity(uuid: 'obj-1', schema: $schema, data: $data); + $events = [ + 'created' => fn () => new ObjectCreatedEvent($object), + 'updated' => fn () => new ObjectUpdatedEvent($object, $oldData === null ? null : $this->entity(uuid: 'obj-1', schema: $schema, data: $oldData)), + 'deleted' => fn () => new ObjectDeletedEvent($object), + ]; + + try { + (new StackiqEventListener($this->container()))->handle($events[$kind]()); + } catch (\Throwable $e) { + $this->trace[] = ['escaped', get_class($e), $e->getMessage()]; + } + + $this->check(key: $this->dataName(), value: $this->trace); + }//end testHandleMatchesTheRecording() + + /** + * An object entity double. + * + * @param string $uuid The uuid. + * @param string $schema The schema id. + * @param array $data The data. + * + * @return ObjectEntity + */ + private function entity(string $uuid, string $schema, array $data): ObjectEntity { + $entity = $this->createMock(ObjectEntity::class); + $entity->method('getUuid')->willReturn($uuid); + $entity->method('getSchema')->willReturn($schema); + $entity->method('getRegister')->willReturn('5'); + $entity->method('getObject')->willReturn($data); + return $entity; + }//end entity() + + /** + * A container with recording doubles for every service the listener resolves. + * + * @return ContainerInterface + */ + private function container(): ContainerInterface { + $settings = $this->createMock(SettingsService::class); + $settings->method('getSchemaIdForObjectType')->willReturnCallback( + function (string $objectType): ?int { + $this->trace[] = ['settings.getSchemaIdForObjectType', $objectType]; + if (isset($this->plan['noSchemas']) === true) { + return null; + } + + return ($this->plan['schemas'] ?? self::SCHEMAS)[$objectType] ?? null; + } + ); + $settings->method('getVoorzieningenConfig')->willReturnCallback( + function (): array { + $this->trace[] = ['settings.getVoorzieningenConfig']; + return ['register' => '5', 'organisatie_schema' => '1']; + } + ); + + $contacts = $this->createMock(ContactpersoonService::class); + foreach (['processContactpersoon', 'handleContactpersoonUpdate', 'handleContactDeletion'] as $method) { + $contacts->method($method)->willReturnCallback( + function (...$args) use ($method) { + $this->trace[] = ['contacts.' . $method, array_map(fn ($arg) => is_object($arg) === true ? $arg->getUuid() : $arg, $args)]; + if (($this->plan['contactThrows'] ?? null) === 'error') { + throw new \Error('contact broke'); + } + + if (isset($this->plan['contactThrows']) === true) { + throw new \RuntimeException('contact failed'); + } + + return true; + } + ); + } + + $orgSync = $this->createMock(OrganizationSyncService::class); + $orgSync->method('processSpecificOrganization')->willReturnCallback( + function ($object): array { + $this->trace[] = ['orgSync.processSpecificOrganization', $object->getUuid(), $object->getObject()]; + if (isset($this->plan['orgSyncThrows']) === true) { + throw new \RuntimeException('org sync failed'); + } + + return ['organizationsProcessed' => 1]; + } + ); + + $usageSync = $this->createMock(GebruikSyncService::class); + $usageSync->method('processSpecificGebruik')->willReturnCallback( + function ($object): array { + $this->trace[] = ['usageSync.processSpecificGebruik', $object->getUuid()]; + if (isset($this->plan['usageSyncThrows']) === true) { + throw new \RuntimeException('usage sync failed'); + } + + return ['processed' => 1]; + } + ); + + $objects = new class($this) { + /** + * @param StackiqEventListenerGoldenTest $test The test, for the trace. + */ + public function __construct(private StackiqEventListenerGoldenTest $test) { + } + + /** + * @param mixed ...$args The lookup, by name. + * + * @return ObjectEntity + */ + public function find(...$args): ObjectEntity { + return $this->test->refetch(args: $args); + } + }; + + $services = [ + LoggerInterface::class => $this->logger(), + ContactpersoonService::class => $contacts, + SettingsService::class => $settings, + 'OCA\Stackiq\Service\OrganizationSyncService' => $orgSync, + GebruikSyncService::class => $usageSync, + 'OCA\OpenRegister\Service\ObjectService' => $objects, + ]; + $container = $this->createMock(ContainerInterface::class); + $container->method('get')->willReturnCallback( + function (string $id) use ($services) { + $this->trace[] = ['container.get', $id]; + return $services[$id]; + } + ); + + return $container; + }//end container() + + /** + * Record a refetch of the organisation and answer it. + * + * @param array $args The find() arguments, by name. + * + * @return ObjectEntity The refetched organisation. + */ + public function refetch(array $args): ObjectEntity { + $this->trace[] = ['objects.find', $args]; + if (isset($this->plan['findThrows']) === true) { + throw new \RuntimeException('find failed'); + } + + return $this->entity(uuid: 'obj-1', schema: '1', data: ['status' => 'actief', 'contactpersonen' => [['email' => 'a@a.nl'], ['email' => 'b@a.nl']]]); + }//end refetch() + + /** + * A logger that records every line, with volatile values masked. + * + * @return LoggerInterface + */ + private function logger(): LoggerInterface { + $trace = &$this->trace; + return new class($trace, self::VOLATILE) extends AbstractLogger { + /** + * @param array $trace The shared trace. + * @param array $volatile The keys to mask. + */ + public function __construct(private array &$trace, private array $volatile) { + } + + /** + * @param mixed $level The level. + * @param string|\Stringable $message The message. + * @param array $context The context. + * + * @return void + */ + public function log($level, string|\Stringable $message, array $context = []): void { + foreach ($this->volatile as $key) { + if (array_key_exists($key, $context) === true) { + $context[$key] = '(' . $key . ')'; + } + } + + if (isset($context['eventType']) === true) { + $context['eventType'] = preg_replace('/Mock\w+/', 'Mock', (string) $context['eventType']); + } + + $this->trace[] = ['log.' . $level, (string) $message, $context]; + } + }; + }//end logger() + + /** + * Compare a case with the golden file, or record it. + * + * @param string $key The case. + * @param array $value What the case observed. + * + * @return void + */ + private function check(string $key, array $value): void { + $json = json_decode(json_encode($value, JSON_PARTIAL_OUTPUT_ON_ERROR), true); + $file = __DIR__ . '/golden/stackiqEventListener.json'; + $saved = []; + if (file_exists($file) === true) { + $saved = json_decode((string) file_get_contents($file), true); + } + + if (getenv('RECORD_GOLDEN') !== false) { + $saved[$key] = $json; + if (is_dir(dirname($file)) === false) { + mkdir(dirname($file)); + } + + file_put_contents($file, json_encode($saved, (JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)) . "\n"); + $this->addToAssertionCount(count: 1); + return; + } + + $this->assertArrayHasKey(key: $key, array: $saved, message: 'No golden for ' . $key); + $this->assertSame(expected: $saved[$key], actual: $json); + }//end check() +}//end class diff --git a/tests/Unit/EventListener/StackiqEventListenerTest.php b/tests/Unit/EventListener/StackiqEventListenerTest.php deleted file mode 100644 index 42215db86..000000000 --- a/tests/Unit/EventListener/StackiqEventListenerTest.php +++ /dev/null @@ -1,387 +0,0 @@ - - * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 - * @link https://github.com/ConductionNL/stackiq - * @version 1.0.0 - */ -class StackiqEventListenerTest extends TestCase { - /** - * Mock of the StackiqService - * - * @var StackiqService|MockObject - */ - private StackiqService|MockObject $softwareCatalogueService; - - /** - * Mock of the LoggerInterface - * - * @var LoggerInterface|MockObject - */ - private LoggerInterface|MockObject $logger; - - /** - * The event listener instance under test - * - * @var StackiqEventListener - */ - private StackiqEventListener $eventListener; - - /** - * Set up the test environment before each test - * - * @return void - */ - protected function setUp(): void { - parent::setUp(); - - // The StackiqEventListener was refactored after these tests - // were written: handle() now dispatches via SettingsService schema-id - // lookups (handleObjectCreated/Updated/Deleted private dispatchers) - // rather than the direct handleNewContact/handleNewGebruiker/etc. - // service methods these tests assert. The tests need to be rewritten - // against the new dispatch flow and additional collaborators - // (SettingsService, AppManager, IUserManager, etc.) — tracked as a - // follow-up. See https://github.com/ConductionNL/stackiq - $this->markTestSkipped( - 'Stale against current StackiqEventListener — needs ' - . 'rewrite against new SettingsService-driven dispatch. ' - . 'Tracked as follow-up issue.' - ); - - $this->softwareCatalogueService = $this->createMock(StackiqService::class); - $this->logger = $this->createMock(LoggerInterface::class); - - $this->eventListener = new StackiqEventListener( - $this->softwareCatalogueService, - $this->logger - ); - } - - /** - * Test handling organization creation event - * - * @return void - */ - public function testHandleOrganizationCreatedEvent(): void { - // Create mock ObjectEntity for organization (schema ID 1) - $organization = $this->createMock(ObjectEntity::class); - $organization->method('getSchema')->willReturn(1); - - // Create ObjectCreatedEvent - $event = new ObjectCreatedEvent($organization); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('handleNewOrganization') - ->with($organization); - - $this->softwareCatalogueService - ->expects($this->once()) - ->method('sendOrganizationWelcomeEmail') - ->with($organization); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling contact creation event - * - * @return void - */ - public function testHandleContactCreatedEvent(): void { - // Create mock ObjectEntity for contact (schema ID 2) - $contact = $this->createMock(ObjectEntity::class); - $contact->method('getSchema')->willReturn(2); - - // Create ObjectCreatedEvent - $event = new ObjectCreatedEvent($contact); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('handleNewContact') - ->with($contact); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling gebruiker (user) creation event - * - * @return void - */ - public function testHandleGebruikerCreatedEvent(): void { - // Create mock ObjectEntity for gebruiker (schema ID 3) - $user = $this->createMock(ObjectEntity::class); - $user->method('getSchema')->willReturn(3); - - // Create ObjectCreatedEvent - $event = new ObjectCreatedEvent($user); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('handleNewGebruiker') - ->with($user); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling contact update event - * - * @return void - */ - public function testHandleContactUpdatedEvent(): void { - // Create mock ObjectEntity for contact (schema ID 2) - $newContact = $this->createMock(ObjectEntity::class); - $newContact->method('getSchema')->willReturn(2); - - $oldContact = $this->createMock(ObjectEntity::class); - - // Create ObjectUpdatedEvent - $event = new ObjectUpdatedEvent($newContact, $oldContact); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('handleContactUpdate') - ->with($newContact); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling gebruiker (user) update event - * - * @return void - */ - public function testHandleGebruikerUpdatedEvent(): void { - // Create mock ObjectEntity for gebruiker (schema ID 3) - $newUser = $this->createMock(ObjectEntity::class); - $newUser->method('getSchema')->willReturn(3); - - $oldUser = $this->createMock(ObjectEntity::class); - - // Create ObjectUpdatedEvent - $event = new ObjectUpdatedEvent($newUser, $oldUser); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('handleGebruikerUpdate') - ->with($newUser, $oldUser); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling contact deletion event - * - * @return void - */ - public function testHandleContactDeletedEvent(): void { - // Create mock ObjectEntity for contact (schema ID 2) - $contact = $this->createMock(ObjectEntity::class); - $contact->method('getSchema')->willReturn(2); - - // Create ObjectDeletedEvent - $event = new ObjectDeletedEvent($contact); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('handleContactDeletion') - ->with($contact); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling gebruiker (user) deletion event - should block user - * - * @return void - */ - public function testHandleGebruikerDeletedEvent(): void { - // Create mock ObjectEntity for gebruiker (schema ID 3) - $user = $this->createMock(ObjectEntity::class); - $user->method('getSchema')->willReturn(3); - - // Create ObjectDeletedEvent - $event = new ObjectDeletedEvent($user); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('blockUserForGebruiker') - ->with($user); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling gebruiker (user) locking event - * - * @return void - */ - public function testHandleGebruikerLockedEvent(): void { - // Create mock ObjectEntity for gebruiker (schema ID 3) - $user = $this->createMock(ObjectEntity::class); - $user->method('getSchema')->willReturn(3); - - // Create ObjectLockedEvent - $event = new ObjectLockedEvent($user); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('temporarilyBlockUserForGebruiker') - ->with($user); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * Test handling gebruiker (user) unlocking event - * - * @return void - */ - public function testHandleGebruikerUnlockedEvent(): void { - // Create mock ObjectEntity for gebruiker (schema ID 3) - $user = $this->createMock(ObjectEntity::class); - $user->method('getSchema')->willReturn(3); - - // Create ObjectUnlockedEvent - $event = new ObjectUnlockedEvent($user); - - // Set expectations for service calls - $this->softwareCatalogueService - ->expects($this->once()) - ->method('restoreUserAccessForGebruiker') - ->with($user); - - // Handle the event - $this->eventListener->handle($event); - } - - /** - * An object-reverted event reaches the listener without driving - * StackiqService. - * - * The two cases that stood here asserted - * `syncUserWithRevertedContact()` / `updateUserFromRevertedGebruiker()` - * were called once each. `StackiqEventListener` does not call - * them — it never did — and both service methods were log-only stubs with - * no caller, removed with this change. The assertion that survives is the - * true one: the revert path must not blow up, and must not reach a - * capability the app does not implement. - * - * @return void - */ - public function testHandleRevertedEventDoesNotDriveTheCatalogueService(): void { - $contact = $this->createMock(ObjectEntity::class); - $contact->method('getSchema')->willReturn(2); - - $this->softwareCatalogueService - ->expects($this->never()) - ->method('handleContactUpdate'); - - $this->eventListener->handle( - new ObjectRevertedEvent($contact, new \DateTime('2024-01-01 12:00:00')) - ); - } - - /** - * Test handling events with null objects - * - * @return void - */ - public function testHandleEventWithUnmatchedSchema(): void { - // Create a mock ObjectEntity with a schema that doesn't match any configured schema - $object = $this->createMock(ObjectEntity::class); - $object->method('getSchema')->willReturn(999999); - $object->method('getUuid')->willReturn('test-uuid'); - $object->method('getRegister')->willReturn(1); - - // Create ObjectCreatedEvent with a valid object but unmatched schema - $event = new ObjectCreatedEvent($object); - - // No service methods should be called since schema doesn't match - $this->softwareCatalogueService - ->expects($this->never()) - ->method($this->anything()); - - // Handle the event - should return early since schema doesn't match - $this->eventListener->handle($event); - } - - /** - * Test exception handling during event processing - * - * @return void - */ - public function testExceptionHandlingDuringEventProcessing(): void { - // Create mock ObjectEntity for organization (schema ID 1) - $organization = $this->createMock(ObjectEntity::class); - $organization->method('getSchema')->willReturn(1); - - // Create ObjectCreatedEvent - $event = new ObjectCreatedEvent($organization); - - // Mock service to throw exception - $exception = new \Exception('Service error'); - $this->softwareCatalogueService - ->method('handleNewOrganization') - ->willThrowException($exception); - - // Expect logger to be called with error - $this->logger - ->expects($this->once()) - ->method('error') - ->with( - 'Failed to handle new organization: Service error', - [ - 'exception' => $exception, - 'object' => $organization - ] - ); - - // Handle the event - $this->eventListener->handle($event); - } -} diff --git a/tests/Unit/EventListener/golden/stackiqEventListener.json b/tests/Unit/EventListener/golden/stackiqEventListener.json new file mode 100644 index 000000000..2b50aea6f --- /dev/null +++ b/tests/Unit/EventListener/golden/stackiqEventListener.json @@ -0,0 +1,3326 @@ +{ + "created organisation active": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "{\"name\":\"Gemeente A\",\"status\":\"Actief\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 1 + } + ], + [ + "log.info", + "Stackiq: Processing active organization creation", + { + "objectId": "obj-1", + "status": "actief" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "name": "Gemeente A", + "status": "Actief" + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization creation", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "created organisation active english": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "{\"status\":\"ACTIVE\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 1 + } + ], + [ + "log.info", + "Stackiq: Processing active organization creation", + { + "objectId": "obj-1", + "status": "active" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "status": "ACTIVE" + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization creation", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "created organisation inactive": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "{\"name\":\"Gemeente A\",\"status\":\"inactief\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 1 + } + ], + [ + "log.debug", + "Stackiq: Skipping non-active organization creation", + { + "objectId": "obj-1", + "status": "inactief" + } + ] + ], + "created organisation no status": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "[]" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 1 + } + ], + [ + "log.debug", + "Stackiq: Skipping non-active organization creation", + { + "objectId": "obj-1", + "status": "" + } + ] + ], + "created organisation sync fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "{\"name\":\"Gemeente A\",\"status\":\"Actief\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 1 + } + ], + [ + "log.info", + "Stackiq: Processing active organization creation", + { + "objectId": "obj-1", + "status": "actief" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "name": "Gemeente A", + "status": "Actief" + } + ], + [ + "log.error", + "Stackiq: Failed to process organization creation", + { + "objectId": "obj-1", + "exception": "org sync failed", + "file": "(file)", + "line": "(line)" + } + ] + ], + "created contact person": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "registerId": "5", + "objectData": "{\"email\":\"a@a.nl\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 2 + } + ], + [ + "log.info", + "Stackiq: Processing contactpersoon creation", + { + "objectId": "obj-1" + } + ], + [ + "contacts.processContactpersoon", + [ + "obj-1", + false + ] + ] + ], + "created contact person fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "registerId": "5", + "objectData": "{\"email\":\"a@a.nl\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 2 + } + ], + [ + "log.info", + "Stackiq: Processing contactpersoon creation", + { + "objectId": "obj-1" + } + ], + [ + "contacts.processContactpersoon", + [ + "obj-1", + false + ] + ], + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "log.error", + "Stackiq: Error in event handler", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "exception": "contact failed", + "file": "(file)", + "line": "(line)", + "trace": "(trace)" + } + ] + ], + "created contactgegevens": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "3", + "schemaIdInt": 3, + "registerId": "5", + "objectData": "[]" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 3 + } + ], + [ + "log.info", + "Stackiq: Processing contactgegevens creation (deprecated)", + { + "objectId": "obj-1" + } + ] + ], + "created usage": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "4", + "schemaIdInt": 4, + "registerId": "5", + "objectData": "{\"consumer\":{\"name\":\"Gemeente A\"},\"product\":{\"name\":\"Zaaksysteem\"}}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 4 + } + ], + [ + "log.info", + "Stackiq: Processing gebruik creation", + { + "objectId": "obj-1" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\GebruikSyncService" + ], + [ + "usageSync.processSpecificGebruik", + "obj-1" + ], + [ + "log.info", + "Stackiq: Successfully processed gebruik creation", + { + "objectId": "obj-1", + "processResult": { + "processed": 1 + } + } + ] + ], + "created usage sync fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "4", + "schemaIdInt": 4, + "registerId": "5", + "objectData": "{\"consumer\":{\"name\":\"Gemeente A\"},\"product\":{\"name\":\"Zaaksysteem\"}}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 4 + } + ], + [ + "log.info", + "Stackiq: Processing gebruik creation", + { + "objectId": "obj-1" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\GebruikSyncService" + ], + [ + "usageSync.processSpecificGebruik", + "obj-1" + ], + [ + "log.error", + "Stackiq: Failed to process gebruik creation", + { + "objectId": "obj-1", + "exception": "usage sync failed", + "file": "(file)", + "line": "(line)" + } + ] + ], + "created other schema": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "9", + "schemaIdInt": 9, + "registerId": "5", + "objectData": "{\"x\":1}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 9 + } + ], + [ + "log.debug", + "Stackiq: Object creation not handled - not a supported object type", + { + "objectId": "obj-1", + "schemaId": 9, + "registerId": "5", + "supportedSchemas": { + "organization": 1, + "contactPerson": 2, + "contactgegevens": 3, + "usage": 4 + } + } + ] + ], + "created, no schemas configured": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "{\"name\":\"Gemeente A\",\"status\":\"Actief\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": null, + "contactpersoonSchemaId": null, + "contactgegevensSchemaId": null, + "gebruikSchemaId": null, + "objectSchemaId": 1 + } + ], + [ + "log.debug", + "Stackiq: Object creation not handled - not a supported object type", + { + "objectId": "obj-1", + "schemaId": 1, + "registerId": "5", + "supportedSchemas": { + "organization": null, + "contactPerson": null, + "contactgegevens": null, + "usage": null + } + } + ] + ], + "created, schema id as string": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "01", + "schemaIdInt": 1, + "registerId": "5", + "objectData": "{\"name\":\"Gemeente A\",\"status\":\"Actief\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 2, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 1 + } + ], + [ + "log.info", + "Stackiq: Processing active organization creation", + { + "objectId": "obj-1", + "status": "actief" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "name": "Gemeente A", + "status": "Actief" + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization creation", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "updated organisation activated": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "1", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "actief", + "oldStatus": "inactief", + "statusChanged": true, + "isActief": true, + "willProcess": true + } + ], + [ + "log.info", + "Stackiq: Processing active organization update", + { + "objectId": "obj-1", + "status": "actief", + "schemaId": "1" + } + ], + [ + "settings.getVoorzieningenConfig" + ], + [ + "container.get", + "OCA\\OpenRegister\\Service\\ObjectService" + ], + [ + "objects.find", + { + "id": "obj-1", + "register": "5", + "schema": "1", + "_extend": [ + "contactpersonen" + ], + "_rbac": false, + "_multitenancy": false + } + ], + [ + "log.info", + "Stackiq: Refetched organization with contactpersonen", + { + "objectId": "obj-1", + "contactpersonenCount": 2 + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "status": "actief", + "contactpersonen": [ + { + "email": "a@a.nl" + }, + { + "email": "b@a.nl" + } + ] + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization update", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "updated organisation, no old object": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "1", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "actief", + "oldStatus": "", + "statusChanged": true, + "isActief": true, + "willProcess": true + } + ], + [ + "log.info", + "Stackiq: Processing active organization update", + { + "objectId": "obj-1", + "status": "actief", + "schemaId": "1" + } + ], + [ + "settings.getVoorzieningenConfig" + ], + [ + "container.get", + "OCA\\OpenRegister\\Service\\ObjectService" + ], + [ + "objects.find", + { + "id": "obj-1", + "register": "5", + "schema": "1", + "_extend": [ + "contactpersonen" + ], + "_rbac": false, + "_multitenancy": false + } + ], + [ + "log.info", + "Stackiq: Refetched organization with contactpersonen", + { + "objectId": "obj-1", + "contactpersonenCount": 2 + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "status": "actief", + "contactpersonen": [ + { + "email": "a@a.nl" + }, + { + "email": "b@a.nl" + } + ] + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization update", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "updated organisation still active": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "1", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "actief", + "oldStatus": "actief", + "statusChanged": false, + "isActief": true, + "willProcess": false + } + ], + [ + "log.debug", + "Stackiq: Skipping non-active organization update", + { + "objectId": "obj-1", + "status": "actief", + "schemaId": "1" + } + ] + ], + "updated organisation deactivated": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "1", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "inactief", + "oldStatus": "actief", + "statusChanged": true, + "isActief": false, + "willProcess": false + } + ], + [ + "log.debug", + "Stackiq: Skipping non-active organization update", + { + "objectId": "obj-1", + "status": "inactief", + "schemaId": "1" + } + ] + ], + "updated organisation, refetch fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "1", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "actief", + "oldStatus": "inactief", + "statusChanged": true, + "isActief": true, + "willProcess": true + } + ], + [ + "log.info", + "Stackiq: Processing active organization update", + { + "objectId": "obj-1", + "status": "actief", + "schemaId": "1" + } + ], + [ + "settings.getVoorzieningenConfig" + ], + [ + "container.get", + "OCA\\OpenRegister\\Service\\ObjectService" + ], + [ + "objects.find", + { + "id": "obj-1", + "register": "5", + "schema": "1", + "_extend": [ + "contactpersonen" + ], + "_rbac": false, + "_multitenancy": false + } + ], + [ + "log.error", + "Stackiq: Failed to refetch organization with contactpersonen", + { + "objectId": "obj-1", + "exception": "find failed", + "file": "(file)", + "line": "(line)" + } + ] + ], + "updated organisation, sync fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "1", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "1", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "actief", + "oldStatus": "inactief", + "statusChanged": true, + "isActief": true, + "willProcess": true + } + ], + [ + "log.info", + "Stackiq: Processing active organization update", + { + "objectId": "obj-1", + "status": "actief", + "schemaId": "1" + } + ], + [ + "settings.getVoorzieningenConfig" + ], + [ + "container.get", + "OCA\\OpenRegister\\Service\\ObjectService" + ], + [ + "objects.find", + { + "id": "obj-1", + "register": "5", + "schema": "1", + "_extend": [ + "contactpersonen" + ], + "_rbac": false, + "_multitenancy": false + } + ], + [ + "log.info", + "Stackiq: Refetched organization with contactpersonen", + { + "objectId": "obj-1", + "contactpersonenCount": 2 + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "status": "actief", + "contactpersonen": [ + { + "email": "a@a.nl" + }, + { + "email": "b@a.nl" + } + ] + } + ], + [ + "log.error", + "Stackiq: Failed to process organization update", + { + "objectId": "obj-1", + "exception": "org sync failed", + "file": "(file)", + "line": "(line)" + } + ] + ], + "updated contact person": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "2", + "objectSchemaIdInt": 2, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "log.info", + "Stackiq: Matched contactpersoon schema - processing update", + { + "objectId": "obj-1", + "schemaId": "2", + "configuredSchemaId": 2 + } + ], + [ + "contacts.handleContactpersoonUpdate", + [ + "obj-1", + "obj-1" + ] + ], + [ + "log.info", + "Stackiq: Successfully processed contactpersoon update", + { + "objectId": "obj-1", + "timestamp": "(timestamp)" + } + ] + ], + "updated contact person fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "2", + "objectSchemaIdInt": 2, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "log.info", + "Stackiq: Matched contactpersoon schema - processing update", + { + "objectId": "obj-1", + "schemaId": "2", + "configuredSchemaId": 2 + } + ], + [ + "contacts.handleContactpersoonUpdate", + [ + "obj-1", + null + ] + ], + [ + "log.error", + "Stackiq: Failed to process contactpersoon update", + { + "objectId": "obj-1", + "exception": "contact failed", + "file": "(file)", + "line": "(line)", + "trace": "(trace)" + } + ] + ], + "updated contactgegevens": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "3", + "schemaIdInt": 3, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "3", + "objectSchemaIdInt": 3, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "log.info", + "Stackiq: Matched contactgegevens schema - processing update (backward compatibility)", + { + "objectId": "obj-1", + "schemaId": "3", + "configuredSchemaId": 3 + } + ], + [ + "contacts.handleContactpersoonUpdate", + [ + "obj-1", + null + ] + ], + [ + "log.info", + "Stackiq: Successfully processed contactgegevens update (as contactpersoon)", + { + "objectId": "obj-1", + "timestamp": "(timestamp)" + } + ] + ], + "updated contactgegevens fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "3", + "schemaIdInt": 3, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "3", + "objectSchemaIdInt": 3, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "log.info", + "Stackiq: Matched contactgegevens schema - processing update (backward compatibility)", + { + "objectId": "obj-1", + "schemaId": "3", + "configuredSchemaId": 3 + } + ], + [ + "contacts.handleContactpersoonUpdate", + [ + "obj-1", + null + ] + ], + [ + "log.error", + "Stackiq: Failed to process contactgegevens update", + { + "objectId": "obj-1", + "exception": "contact failed", + "file": "(file)", + "line": "(line)", + "trace": "(trace)" + } + ] + ], + "updated usage": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "4", + "schemaIdInt": 4, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "4", + "objectSchemaIdInt": 4, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.info", + "Stackiq: Matched gebruik schema - processing update", + { + "objectId": "obj-1", + "schemaId": "4", + "configuredSchemaId": 4 + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\GebruikSyncService" + ], + [ + "usageSync.processSpecificGebruik", + "obj-1" + ], + [ + "log.info", + "Stackiq: Successfully processed gebruik update", + { + "objectId": "obj-1", + "processResult": { + "processed": 1 + } + } + ] + ], + "updated other schema": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "9", + "schemaIdInt": 9, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "9", + "objectSchemaIdInt": 9, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Object update not handled - focusing only on organisatie, contactpersonen, and gebruik", + { + "objectId": "obj-1", + "schemaId": "9", + "schemaIdInt": 9, + "schemaIdType": "string", + "registerId": "5", + "handledSchemas": { + "organization": 1, + "contactPerson": 2, + "contactgegevens": 3, + "usage": 4 + } + } + ] + ], + "updated, no schemas configured": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": null, + "organisatieSchemaIdInt": 0 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "2", + "objectSchemaIdInt": 2, + "organisatieSchemaId": null, + "organisatieSchemaIdInt": 0, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Object update not handled - focusing only on organisatie, contactpersonen, and gebruik", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "schemaIdType": "string", + "registerId": "5", + "handledSchemas": { + "organization": null, + "contactPerson": null, + "contactgegevens": null, + "usage": null + } + } + ] + ], + "deleted organisation": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "1", + "registerId": "5", + "objectData": { + "name": "Gemeente A", + "status": "Actief" + } + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.info", + "Stackiq: Processing organization deletion", + { + "objectId": "obj-1" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "name": "Gemeente A", + "status": "Actief" + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization deletion", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "deleted organisation, sync fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "1", + "registerId": "5", + "objectData": { + "name": "Gemeente A", + "status": "Actief" + } + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.info", + "Stackiq: Processing organization deletion", + { + "objectId": "obj-1" + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "name": "Gemeente A", + "status": "Actief" + } + ], + [ + "log.error", + "Stackiq: Failed to process organization deletion", + { + "objectId": "obj-1", + "exception": "org sync failed", + "file": "(file)", + "line": "(line)" + } + ] + ], + "deleted contact person": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "2", + "registerId": "5", + "objectData": { + "email": "a@a.nl" + } + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "log.info", + "Stackiq: Matched contactpersoon schema - processing deletion", + { + "objectId": "obj-1", + "schemaId": "2", + "configuredSchemaId": 2 + } + ], + [ + "contacts.handleContactDeletion", + [ + "obj-1" + ] + ], + [ + "log.info", + "Stackiq: Successfully processed contactpersoon deletion", + { + "objectId": "obj-1", + "timestamp": "(timestamp)" + } + ] + ], + "deleted contact person fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "2", + "registerId": "5", + "objectData": { + "email": "a@a.nl" + } + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "log.info", + "Stackiq: Matched contactpersoon schema - processing deletion", + { + "objectId": "obj-1", + "schemaId": "2", + "configuredSchemaId": 2 + } + ], + [ + "contacts.handleContactDeletion", + [ + "obj-1" + ] + ], + [ + "log.error", + "Stackiq: Failed to process contactpersoon deletion", + { + "objectId": "obj-1", + "exception": "contact failed", + "file": "(file)", + "line": "(line)", + "trace": "(trace)" + } + ] + ], + "deleted contactgegevens": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "3", + "registerId": "5", + "objectData": [] + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "log.info", + "Stackiq: Matched contactgegevens schema - processing deletion (backward compatibility)", + { + "objectId": "obj-1", + "schemaId": "3", + "configuredSchemaId": 3 + } + ], + [ + "contacts.handleContactDeletion", + [ + "obj-1" + ] + ], + [ + "log.info", + "Stackiq: Successfully processed contactgegevens deletion", + { + "objectId": "obj-1", + "timestamp": "(timestamp)" + } + ] + ], + "deleted contactgegevens fails": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "3", + "registerId": "5", + "objectData": [] + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "log.info", + "Stackiq: Matched contactgegevens schema - processing deletion (backward compatibility)", + { + "objectId": "obj-1", + "schemaId": "3", + "configuredSchemaId": 3 + } + ], + [ + "contacts.handleContactDeletion", + [ + "obj-1" + ] + ], + [ + "log.error", + "Stackiq: Failed to process contactgegevens deletion", + { + "objectId": "obj-1", + "exception": "contact failed", + "file": "(file)", + "line": "(line)", + "trace": "(trace)" + } + ] + ], + "deleted usage": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "4", + "registerId": "5", + "objectData": { + "consumer": { + "name": "Gemeente A" + }, + "product": { + "name": "Zaaksysteem" + } + } + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.info", + "Stackiq: Matched gebruik schema - processing deletion", + { + "objectId": "obj-1", + "schemaId": "4", + "configuredSchemaId": 4, + "consumer": "Gemeente A", + "product": "Zaaksysteem" + } + ], + [ + "log.info", + "Stackiq: Gebruik object deleted - no specific cleanup required", + { + "objectId": "obj-1", + "timestamp": "(timestamp)" + } + ] + ], + "deleted usage without names": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "4", + "registerId": "5", + "objectData": [] + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.info", + "Stackiq: Matched gebruik schema - processing deletion", + { + "objectId": "obj-1", + "schemaId": "4", + "configuredSchemaId": 4, + "consumer": "Unknown", + "product": "Unknown" + } + ], + [ + "log.info", + "Stackiq: Gebruik object deleted - no specific cleanup required", + { + "objectId": "obj-1", + "timestamp": "(timestamp)" + } + ] + ], + "deleted other schema": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "9", + "registerId": "5", + "objectData": { + "x": 1 + } + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Object deletion not handled - focusing only on organisatie, contactpersonen, and gebruik", + { + "objectId": "obj-1", + "schemaId": "9", + "registerId": "5", + "handledSchemas": { + "organization": 1, + "contactPerson": 2, + "contactgegevens": 3, + "usage": 4 + } + } + ] + ], + "deleted, no schemas configured": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectDeletedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object deletion", + { + "objectId": "obj-1", + "schemaId": "4", + "registerId": "5", + "objectData": [] + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Object deletion not handled - focusing only on organisatie, contactpersonen, and gebruik", + { + "objectId": "obj-1", + "schemaId": "4", + "registerId": "5", + "handledSchemas": { + "organization": null, + "contactPerson": null, + "contactgegevens": null, + "usage": null + } + } + ] + ], + "created, two types share a schema": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectCreatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object creation", + { + "objectId": "obj-1", + "schemaId": "4", + "schemaIdInt": 4, + "registerId": "5", + "objectData": "{\"email\":\"a@a.nl\"}" + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "settings.getSchemaIdForObjectType", + "contactgegevens" + ], + [ + "settings.getSchemaIdForObjectType", + "usage" + ], + [ + "log.debug", + "Stackiq: Configuration lookup results", + { + "organisatieSchemaId": 1, + "contactpersoonSchemaId": 4, + "contactgegevensSchemaId": 3, + "gebruikSchemaId": 4, + "objectSchemaId": 4 + } + ], + [ + "log.info", + "Stackiq: Processing contactpersoon creation", + { + "objectId": "obj-1" + } + ], + [ + "contacts.processContactpersoon", + [ + "obj-1", + false + ] + ] + ], + "updated organisation, schema '01'": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "01", + "schemaIdInt": 1, + "registerId": "5", + "hasOldObject": true + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "01", + "objectSchemaIdInt": 1, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": true + } + ], + [ + "log.debug", + "Organization status check", + { + "app": "stackiq", + "objectId": "obj-1", + "status": "actief", + "oldStatus": "inactief", + "statusChanged": true, + "isActief": true, + "willProcess": true + } + ], + [ + "log.info", + "Stackiq: Processing active organization update", + { + "objectId": "obj-1", + "status": "actief", + "schemaId": "01" + } + ], + [ + "settings.getVoorzieningenConfig" + ], + [ + "container.get", + "OCA\\OpenRegister\\Service\\ObjectService" + ], + [ + "objects.find", + { + "id": "obj-1", + "register": "5", + "schema": "1", + "_extend": [ + "contactpersonen" + ], + "_rbac": false, + "_multitenancy": false + } + ], + [ + "log.info", + "Stackiq: Refetched organization with contactpersonen", + { + "objectId": "obj-1", + "contactpersonenCount": 2 + } + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\OrganizationSyncService" + ], + [ + "orgSync.processSpecificOrganization", + "obj-1", + { + "status": "actief", + "contactpersonen": [ + { + "email": "a@a.nl" + }, + { + "email": "b@a.nl" + } + ] + } + ], + [ + "log.info", + "Stackiq: Successfully processed organization update", + { + "objectId": "obj-1", + "processResult": { + "organizationsProcessed": 1 + } + } + ] + ], + "updated contact person, Error escapes": [ + [ + "container.get", + "Psr\\Log\\LoggerInterface" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\ContactpersoonService" + ], + [ + "container.get", + "OCA\\Stackiq\\Service\\SettingsService" + ], + [ + "log.info", + "Stackiq: Processing event", + { + "eventType": "OCA\\OpenRegister\\Event\\ObjectUpdatedEvent", + "timestamp": "(timestamp)" + } + ], + [ + "log.info", + "Stackiq: Processing object update", + { + "objectId": "obj-1", + "schemaId": "2", + "schemaIdInt": 2, + "registerId": "5", + "hasOldObject": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "organization" + ], + [ + "log.debug", + "Got organisation schema ID", + { + "app": "stackiq", + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1 + } + ], + [ + "log.debug", + "Organization schema check", + { + "app": "stackiq", + "objectSchemaId": "2", + "objectSchemaIdInt": 2, + "organisatieSchemaId": 1, + "organisatieSchemaIdInt": 1, + "matches": false + } + ], + [ + "settings.getSchemaIdForObjectType", + "contactPerson" + ], + [ + "log.info", + "Stackiq: Matched contactpersoon schema - processing update", + { + "objectId": "obj-1", + "schemaId": "2", + "configuredSchemaId": 2 + } + ], + [ + "contacts.handleContactpersoonUpdate", + [ + "obj-1", + null + ] + ], + [ + "escaped", + "Error", + "contact broke" + ] + ] +}