Implement UpdateLastSyncFromDocuments hook; adjust syncStatus logic; update layout and metadata for dokumentes relationship
This commit is contained in:
@@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
namespace Espo\Custom\Hooks\CAdvowareAkten;
|
||||||
|
|
||||||
|
use Espo\ORM\Entity;
|
||||||
|
use Espo\ORM\Repository\Option\SaveOptions;
|
||||||
|
use Espo\Core\Hook\Hook\BeforeSave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook: Aktualisiert lastSync basierend auf dem neuesten lastSyncTimestamp
|
||||||
|
* der verknüpften Dokumente
|
||||||
|
*/
|
||||||
|
class UpdateLastSyncFromDocuments implements BeforeSave
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private \Espo\ORM\EntityManager $entityManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function beforeSave(Entity $entity, SaveOptions $options): void
|
||||||
|
{
|
||||||
|
// Überspringe, wenn skipHooks gesetzt ist (verhindert Loops)
|
||||||
|
if ($options->get('skipHooks')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur wenn Entity bereits existiert (nicht bei Create)
|
||||||
|
if ($entity->isNew()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Hole das neueste lastSyncTimestamp aller verknüpften Dokumente
|
||||||
|
$query = $this->entityManager->getQueryBuilder()
|
||||||
|
->select([
|
||||||
|
'MAX:lastSyncTimestamp' => 'maxLastSync',
|
||||||
|
'COUNT:id' => 'dokumentCount'
|
||||||
|
])
|
||||||
|
->from('CDokumente')
|
||||||
|
->where([
|
||||||
|
'cAdvowareAktenId' => $entity->getId(),
|
||||||
|
'deleted' => false,
|
||||||
|
'lastSyncTimestamp!=' => null
|
||||||
|
])
|
||||||
|
->build();
|
||||||
|
|
||||||
|
$pdoStatement = $this->entityManager->getQueryExecutor()->execute($query);
|
||||||
|
$result = $pdoStatement->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($result && $result['maxLastSync']) {
|
||||||
|
// Setze lastSync auf den neuesten Sync-Timestamp
|
||||||
|
$entity->set('lastSync', $result['maxLastSync']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Berechne auch syncStatus basierend auf verknüpften Dokumenten
|
||||||
|
$this->updateSyncStatus($entity);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Fehler loggen, aber nicht werfen (um Save nicht zu blockieren)
|
||||||
|
$GLOBALS['log']->error('CAdvowareAkten UpdateLastSyncFromDocuments Hook Error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aktualisiert syncStatus basierend auf den Status der verknüpften Dokumente
|
||||||
|
*/
|
||||||
|
private function updateSyncStatus(Entity $entity): void
|
||||||
|
{
|
||||||
|
$query = $this->entityManager->getQueryBuilder()
|
||||||
|
->select(['syncStatus'])
|
||||||
|
->from('CDokumente')
|
||||||
|
->where([
|
||||||
|
'cAdvowareAktenId' => $entity->getId(),
|
||||||
|
'deleted' => false
|
||||||
|
])
|
||||||
|
->build();
|
||||||
|
|
||||||
|
$pdoStatement = $this->entityManager->getQueryExecutor()->execute($query);
|
||||||
|
$rows = $pdoStatement->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Wenn keine Dokumente verknüpft, setze auf "unclean"
|
||||||
|
if (empty($rows)) {
|
||||||
|
$entity->set('syncStatus', 'unclean');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfe, ob irgendein Dokument "new" oder "unclean" ist
|
||||||
|
$hasUnsynced = false;
|
||||||
|
$hasFailed = false;
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$status = $row['syncStatus'] ?? null;
|
||||||
|
|
||||||
|
if ($status === 'failed') {
|
||||||
|
$hasFailed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status === 'new' || $status === 'unclean' || $status === null || $status === '') {
|
||||||
|
$hasUnsynced = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setze globalen Status
|
||||||
|
if ($hasFailed) {
|
||||||
|
$entity->set('syncStatus', 'failed');
|
||||||
|
} elseif ($hasUnsynced) {
|
||||||
|
$entity->set('syncStatus', 'unclean');
|
||||||
|
} else {
|
||||||
|
// Alle Dokumente sind "synced"
|
||||||
|
$entity->set('syncStatus', 'synced');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,11 +34,11 @@ class UpdateJunctionSyncStatus implements AfterSave
|
|||||||
$entity->set('syncStatus', 'unclean');
|
$entity->set('syncStatus', 'unclean');
|
||||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
// Also update the parent AdvowareAkte
|
// Trigger parent AdvowareAkte update (will update syncStatus and lastSync via its own hook)
|
||||||
$akte = $this->entityManager->getEntity('CAdvowareAkten', $entity->get('cAdvowareAktenId'));
|
$akte = $this->entityManager->getEntityById('CAdvowareAkten', $entity->get('cAdvowareAktenId'));
|
||||||
if ($akte) {
|
if ($akte) {
|
||||||
$akte->set('syncStatus', 'unclean');
|
// Just touch the entity to trigger beforeSave hook
|
||||||
$this->entityManager->saveEntity($akte, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
"tabLabel": "Dokumente"
|
"tabLabel": "Dokumente"
|
||||||
},
|
},
|
||||||
"dokumentes": {
|
"dokumentes": {
|
||||||
"index": 1
|
"index": 1,
|
||||||
|
"view": "views/record/panels/relationship",
|
||||||
|
"layout": "listForAdvowareAkten"
|
||||||
},
|
},
|
||||||
"_tabBreak_1": {
|
"_tabBreak_1": {
|
||||||
"index": 2,
|
"index": 2,
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"link": true,
|
||||||
|
"width": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "advowareArt",
|
||||||
|
"align": "left",
|
||||||
|
"width": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "advowareBemerkung",
|
||||||
|
"align": "left",
|
||||||
|
"notSortable": true,
|
||||||
|
"width": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "syncStatus",
|
||||||
|
"align": "left",
|
||||||
|
"width": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lastSyncTimestamp",
|
||||||
|
"align": "left",
|
||||||
|
"width": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dokument",
|
||||||
|
"notSortable": true,
|
||||||
|
"align": "left",
|
||||||
|
"width": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createdAt",
|
||||||
|
"align": "left",
|
||||||
|
"width": 13
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -104,36 +104,6 @@
|
|||||||
"tooltip": true,
|
"tooltip": true,
|
||||||
"isCustom": true
|
"isCustom": true
|
||||||
},
|
},
|
||||||
"dokumenteHnr": {
|
|
||||||
"type": "int",
|
|
||||||
"notStorable": true,
|
|
||||||
"utility": true,
|
|
||||||
"disabled": true
|
|
||||||
},
|
|
||||||
"dokumenteSyncstatus": {
|
|
||||||
"type": "enum",
|
|
||||||
"options": [
|
|
||||||
"new",
|
|
||||||
"unclean",
|
|
||||||
"synced",
|
|
||||||
"failed"
|
|
||||||
],
|
|
||||||
"notStorable": true,
|
|
||||||
"utility": true,
|
|
||||||
"disabled": true
|
|
||||||
},
|
|
||||||
"dokumenteLastSync": {
|
|
||||||
"type": "datetime",
|
|
||||||
"notStorable": true,
|
|
||||||
"utility": true,
|
|
||||||
"disabled": true
|
|
||||||
},
|
|
||||||
"dokumenteSyncedHash": {
|
|
||||||
"type": "varchar",
|
|
||||||
"notStorable": true,
|
|
||||||
"utility": true,
|
|
||||||
"disabled": true
|
|
||||||
},
|
|
||||||
"dokumentes": {
|
"dokumentes": {
|
||||||
"type": "linkMultiple",
|
"type": "linkMultiple",
|
||||||
"layoutDetailDisabled": false,
|
"layoutDetailDisabled": false,
|
||||||
@@ -143,7 +113,6 @@
|
|||||||
"importDisabled": false,
|
"importDisabled": false,
|
||||||
"exportDisabled": false,
|
"exportDisabled": false,
|
||||||
"customizationDisabled": false,
|
"customizationDisabled": false,
|
||||||
"disabled": true,
|
|
||||||
"isCustom": true
|
"isCustom": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -78,6 +78,7 @@
|
|||||||
"hnr": {
|
"hnr": {
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"tooltip": true,
|
"tooltip": true,
|
||||||
|
"disableFormatting": true,
|
||||||
"isCustom": true
|
"isCustom": true
|
||||||
},
|
},
|
||||||
"syncStatus": {
|
"syncStatus": {
|
||||||
@@ -108,8 +109,10 @@
|
|||||||
},
|
},
|
||||||
"usn": {
|
"usn": {
|
||||||
"type": "int",
|
"type": "int",
|
||||||
|
"dbType": "bigint",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"tooltip": true,
|
"tooltip": true,
|
||||||
|
"disableFormatting": true,
|
||||||
"isCustom": true
|
"isCustom": true
|
||||||
},
|
},
|
||||||
"dateipfad": {
|
"dateipfad": {
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ return [
|
|||||||
0 => 'youtube.com',
|
0 => 'youtube.com',
|
||||||
1 => 'google.com'
|
1 => 'google.com'
|
||||||
],
|
],
|
||||||
'microtime' => 1774472414.650919,
|
'microtime' => 1774473866.020977,
|
||||||
'siteUrl' => 'https://crm.bitbylaw.com',
|
'siteUrl' => 'https://crm.bitbylaw.com',
|
||||||
'fullTextSearchMinLength' => 4,
|
'fullTextSearchMinLength' => 4,
|
||||||
'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws',
|
'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
'cacheTimestamp' => 1774472414,
|
'cacheTimestamp' => 1774473866,
|
||||||
'microtimeState' => 1774472414.878455,
|
'microtimeState' => 1774473866.194744,
|
||||||
'currencyRates' => [
|
'currencyRates' => [
|
||||||
'EUR' => 1.0
|
'EUR' => 1.0
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user