feat(CPuls): Enhance CPuls entity with new fields, tooltips, and options; add localization for German and English

- Added new fields to CPuls entity including status, syncStatus, kiAnalyse, and others.
- Implemented localization for CPuls in German (de_DE) and English (en_US).
- Introduced new API actions for team activation and completion of CPuls.
- Created hooks to update team statistics and manage document counts.
- Added new entity definitions and metadata for CPulsTeamZuordnung and Team.
- Implemented validation logic in formulas to prevent completion of unclean Puls.
- Updated layouts for detail and list views of CPuls.
- Enhanced user entity with absence tracking fields.
- Added scopes for CPuls and CPulsTeamZuordnung.
This commit is contained in:
2026-02-13 10:09:19 +01:00
parent 0faf1c0657
commit e1a963ffab
22 changed files with 1073 additions and 374 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
<?php
namespace Espo\Custom\Api\CPuls;
use Espo\Core\Api\Action;
use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
class AbschliessenFuerTeam implements Action
{
public function __construct(
private \Espo\ORM\EntityManager $entityManager,
private \Espo\Core\Acl\Table $acl,
private \Espo\Entities\User $user,
private \Espo\Core\Utils\Log $log
) {}
public function process(Request $request): Response
{
$pulsId = $request->getRouteParam('id');
$data = $request->getParsedBody();
$teamId = $data->teamId ?? null;
if (!$pulsId || !$teamId) {
throw new BadRequest('pulsId oder teamId fehlt');
}
// 1. Validierung: Ist User in diesem Team?
$userTeams = $this->user->getLinkMultipleIdList('teams');
if (!in_array($teamId, $userTeams)) {
throw new Forbidden('User nicht in angegebenem Team');
}
// 2. Lade Puls
$puls = $this->entityManager->getEntity('CPuls', $pulsId);
if (!$puls) {
throw new NotFound('Puls nicht gefunden');
}
// 3. Validierung: syncStatus = clean?
if ($puls->get('syncStatus') !== 'clean') {
throw new BadRequest('Puls hat neue Dokumente (unclean) - bitte warten Sie auf die KI-Analyse');
}
// 4. Finde Zuordnung
$zuordnung = $this->entityManager
->getRDBRepository('CPulsTeamZuordnung')
->where([
'pulsId' => $pulsId,
'teamId' => $teamId,
'aktiv' => true
])
->findOne();
if (!$zuordnung) {
throw new NotFound('Team-Zuordnung nicht gefunden oder nicht aktiv');
}
// 5. Bereits abgeschlossen?
if ($zuordnung->get('abgeschlossen')) {
return Response::json([
'success' => true,
'message' => 'Bereits abgeschlossen',
'alreadyCompleted' => true
]);
}
// 6. Abschluss setzen
$zuordnung->set([
'abgeschlossen' => true,
'abgeschlossenAm' => date('Y-m-d H:i:s'),
'abgeschlossenVonId' => $this->user->getId()
]);
$this->entityManager->saveEntity($zuordnung);
// 6.5. FIRST-READ-CLOSES: Finalisiere Block bei erstem Abschluss
if (!$puls->get('finalisiert')) {
$puls->set([
'finalisiert' => true,
'finalisierungsGrund' => 'Erstes Team',
'finalisiertAm' => date('Y-m-d H:i:s'),
'finalisiertVonId' => $this->user->getId()
]);
$this->log->info("Block finalisiert durch erstes Team (Team {$teamId}, User {$this->user->getId()})");
}
// 7. Prüfe: Alle Teams abgeschlossen?
$offeneTeams = $this->entityManager
->getRDBRepository('CPulsTeamZuordnung')
->where([
'pulsId' => $pulsId,
'aktiv' => true,
'abgeschlossen' => false
])
->count();
// 8. Update Puls-Status
if ($offeneTeams === 0) {
$puls->set('status', 'Abgeschlossen');
} else {
$puls->set('status', 'Teilweise abgeschlossen');
}
$this->entityManager->saveEntity($puls);
$this->log->info("Team {$teamId} hat Puls {$pulsId} abgeschlossen");
return Response::json([
'success' => true,
'status' => $puls->get('status'),
'finalisiert' => $puls->get('finalisiert'),
'offeneTeams' => $offeneTeams
]);
}
}

View File

@@ -0,0 +1,99 @@
<?php
namespace Espo\Custom\Api\CPuls;
use Espo\Core\Api\Action;
use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\NotFound;
class AktiviereTeams implements Action
{
public function __construct(
private \Espo\ORM\EntityManager $entityManager,
private \Espo\Core\Utils\Log $log
) {}
public function process(Request $request): Response
{
$id = $request->getRouteParam('id');
if (!$id) {
throw new BadRequest('ID fehlt');
}
$puls = $this->entityManager->getEntity('CPuls', $id);
if (!$puls) {
throw new NotFound('Puls nicht gefunden');
}
$data = $request->getParsedBody();
// 1. Update Puls
$puls->set([
'kiAnalyse' => $data->kiAnalyse ?? null,
'zusammenfassung' => $data->zusammenfassung ?? null,
'status' => $data->status ?? 'Bereit',
'syncStatus' => $data->syncStatus ?? 'clean'
]);
$this->entityManager->saveEntity($puls);
// 2. Lösche alte Zuordnungen (soft delete - setze inaktiv)
$this->entityManager
->getQueryBuilder()
->update()
->in('CPulsTeamZuordnung')
->set(['aktiv' => false])
->where(['pulsId' => $id])
->execute();
// 3. Erstelle neue Zuordnungen
if (isset($data->teams) && is_array($data->teams)) {
foreach ($data->teams as $teamData) {
$teamId = $teamData->teamId ?? null;
if (!$teamId) {
$this->log->warning("Team-ID fehlt in teams-Array");
continue;
}
// Prüfe ob bereits existiert
$existing = $this->entityManager
->getRDBRepository('CPulsTeamZuordnung')
->where([
'pulsId' => $id,
'teamId' => $teamId
])
->findOne();
if ($existing) {
// Reaktiviere
$existing->set([
'aktiv' => true,
'abgeschlossen' => false,
'prioritaet' => $teamData->prioritaet ?? 'Normal'
]);
$this->entityManager->saveEntity($existing);
} else {
// Erstelle neu
$zuordnung = $this->entityManager->createEntity('CPulsTeamZuordnung', [
'pulsId' => $id,
'teamId' => $teamId,
'aktiv' => true,
'abgeschlossen' => false,
'prioritaet' => $teamData->prioritaet ?? 'Normal'
]);
}
}
}
$this->log->info("Teams aktiviert für Puls {$id}");
return Response::json([
'success' => true,
'pulsId' => $id
]);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Espo\Custom\Hooks\CPuls;
use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\BeforeSave;
class UpdateTeamStats implements BeforeSave
{
public function __construct(
private \Espo\ORM\EntityManager $entityManager
) {}
public function beforeSave(Entity $entity, array $options): void
{
// Zähle Dokumente
if ($entity->isNew() || $entity->isAttributeChanged('id')) {
$dokumenteCount = $this->entityManager
->getRDBRepository('CDokumente')
->where(['pulsId' => $entity->getId()])
->count();
$entity->set('anzahlDokumente', $dokumenteCount);
}
// Zähle Team-Zuordnungen
$zuordnungen = $this->entityManager
->getRDBRepository('CPulsTeamZuordnung')
->where(['pulsId' => $entity->getId()])
->find();
$aktiv = 0;
$abgeschlossen = 0;
foreach ($zuordnungen as $z) {
if ($z->get('aktiv')) {
$aktiv++;
if ($z->get('abgeschlossen')) {
$abgeschlossen++;
}
}
}
$entity->set('anzahlTeamsAktiv', $aktiv);
$entity->set('anzahlTeamsAbgeschlossen', $abgeschlossen);
}
}

View File

@@ -1,9 +1,58 @@
{
"links": {
"calls": "Anrufe",
"tasks": "Aufgaben"
},
"labels": {
"Create CPuls": "Puls erstellen"
"Create CPuls": "Puls erstellen",
"CPuls": "Puls",
"cPuls": "Pulse"
},
"fields": {
"name": "Bezeichnung",
"status": "Status",
"syncStatus": "Synchronisations-Status",
"kiAnalyse": "KI-Analyse",
"zusammenfassung": "Zusammenfassung",
"anzahlDokumente": "Anzahl Dokumente",
"anzahlTeamsAktiv": "Teams (aktiv)",
"anzahlTeamsAbgeschlossen": "Teams (abgeschlossen)",
"finalisiert": "Finalisiert",
"finalisierungsGrund": "Finalisierungsgrund",
"finalisiertAm": "Finalisiert am",
"finalisiertVon": "Finalisiert von",
"parent": "Vorgang",
"dokumente": "Dokumente",
"teamZuordnungen": "Team-Zuordnungen"
},
"links": {
"parent": "Vorgang",
"dokumente": "Dokumente",
"teamZuordnungen": "Team-Zuordnungen"
},
"tooltips": {
"syncStatus": "clean = KI-Analyse aktuell | unclean = Neue Dokumente, Analyse ausstehend",
"kiAnalyse": "Automatisch generierte Zusammenfassung durch KI-Middleware",
"zusammenfassung": "Kurze Zusammenfassung für Listen-Ansicht",
"finalisiert": "Block wurde geschlossen - neue Dokumente erzeugen automatisch einen neuen Block (First-Read-Closes Prinzip)",
"finalisierungsGrund": "Grund der Finalisierung: Erstes Team = Team hat abgeschlossen | Manuell = Admin-Aktion | Automatisch = System-Regel"
},
"options": {
"status": {
"Neu": "Neu",
"In Verarbeitung": "In Verarbeitung",
"Bereit": "Bereit",
"In Review": "In Review",
"Teilweise abgeschlossen": "Teilweise abgeschlossen",
"Abgeschlossen": "Abgeschlossen"
},
"syncStatus": {
"clean": "Aktuell",
"unclean": "Ausstehend"
},
"finalisierungsGrund": {
"Erstes Team": "Erstes Team",
"Manuell": "Manuell",
"Automatisch": "Automatisch"
}
},
"presetFilters": {
"meineOffenen": "Meine offenen Pulse"
}
}
}

View File

@@ -0,0 +1,32 @@
{
"labels": {
"Create CPulsTeamZuordnung": "Team-Zuordnung erstellen",
"CPulsTeamZuordnung": "Puls Team-Zuordnung",
"cPulsTeamZuordnung": "Puls Team-Zuordnungen"
},
"fields": {
"name": "Name",
"puls": "Puls",
"team": "Team",
"aktiv": "Aktiv",
"abgeschlossen": "Abgeschlossen",
"abgeschlossenAm": "Abgeschlossen am",
"abgeschlossenVon": "Abgeschlossen von",
"prioritaet": "Priorität"
},
"links": {
"puls": "Puls",
"team": "Team",
"abgeschlossenVon": "Abgeschlossen von"
},
"tooltips": {
"aktiv": "Ist diese Team-Zuordnung aktiv? Inaktive werden nicht angezeigt."
},
"options": {
"prioritaet": {
"Niedrig": "Niedrig",
"Normal": "Normal",
"Hoch": "Hoch"
}
}
}

View File

@@ -1,12 +1,58 @@
{
"fields": {
},
"links": {
"meetings": "Meetings",
"calls": "Calls",
"tasks": "Tasks"
},
"labels": {
"Create CPuls": "Create Puls"
}
}
{
"labels": {
"Create CPuls": "Create Pulse",
"CPuls": "Pulse",
"cPuls": "Pulses"
},
"fields": {
"name": "Name",
"status": "Status",
"syncStatus": "Sync Status",
"kiAnalyse": "AI Analysis",
"zusammenfassung": "Summary",
"anzahlDokumente": "Number of Documents",
"anzahlTeamsAktiv": "Teams (active)",
"anzahlTeamsAbgeschlossen": "Teams (completed)",
"finalisiert": "Finalized",
"finalisierungsGrund": "Finalization Reason",
"finalisiertAm": "Finalized At",
"finalisiertVon": "Finalized By",
"parent": "Parent Record",
"dokumente": "Documents",
"teamZuordnungen": "Team Assignments"
},
"links": {
"parent": "Parent Record",
"dokumente": "Documents",
"teamZuordnungen": "Team Assignments"
},
"tooltips": {
"syncStatus": "clean = AI analysis up-to-date | unclean = New documents, analysis pending",
"kiAnalyse": "Automatically generated summary by AI middleware",
"zusammenfassung": "Short summary for list views",
"finalisiert": "Block has been closed - new documents will automatically create a new block (First-Read-Closes principle)",
"finalisierungsGrund": "Reason for finalization: First Team = Team completed | Manual = Admin action | Automatic = System rule"
},
"options": {
"status": {
"Neu": "New",
"In Verarbeitung": "Processing",
"Bereit": "Ready",
"In Review": "In Review",
"Teilweise abgeschlossen": "Partially Completed",
"Abgeschlossen": "Completed"
},
"syncStatus": {
"clean": "Up-to-date",
"unclean": "Pending"
},
"finalisierungsGrund": {
"Erstes Team": "First Team",
"Manuell": "Manual",
"Automatisch": "Automatic"
}
},
"presetFilters": {
"meineOffenen": "My Open Pulses"
}
}

View File

@@ -0,0 +1,17 @@
{
"teamZuordnungen": {
"index": 0,
"sticked": true,
"style": "info",
"label": "Team-Zuordnungen"
},
"dokumente": {
"index": 1,
"sticked": false,
"label": "Dokumente"
},
"stream": {
"index": 2,
"sticked": false
}
}

View File

@@ -0,0 +1,47 @@
[
{
"label": "Übersicht",
"rows": [
[
{"name": "name"},
{"name": "status"}
],
[
{"name": "syncStatus"},
{"name": "parent"}
],
[
{"name": "anzahlDokumente"},
{"name": "anzahlTeamsAktiv"}
],
[
{"name": "finalisiert"},
{"name": "finalisierungsGrund"}
],
[
{"name": "zusammenfassung", "span": 2}
]
]
},
{
"label": "KI-Analyse",
"rows": [
[
{"name": "kiAnalyse", "span": 2}
]
]
},
{
"label": "System",
"rows": [
[
{"name": "createdAt"},
{"name": "modifiedAt"}
],
[
{"name": "createdBy"},
{"name": "modifiedBy"}
]
]
}
]

View File

@@ -0,0 +1,8 @@
[
{"name": "name", "width": 30},
{"name": "status", "width": 15},
{"name": "syncStatus", "width": 10},
{"name": "parent", "width": 20},
{"name": "anzahlDokumente", "width": 10},
{"name": "createdAt", "width": 15}
]

View File

@@ -0,0 +1,14 @@
{
"routes": [
{
"route": "/CPuls/:id/aktiviere-teams",
"method": "put",
"actionClassName": "Espo\\Custom\\Api\\CPuls\\AktiviereTeams"
},
{
"route": "/CPuls/:id/abschliessen-fuer-team",
"method": "post",
"actionClassName": "Espo\\Custom\\Api\\CPuls\\AbschliessenFuerTeam"
}
]
}

View File

@@ -1,37 +1,18 @@
{
"controller": "controllers/record",
"boolFilterList": [
"onlyMy"
],
"sidePanels": {
"detail": [
{
"name": "activities",
"reference": "activities"
},
{
"name": "history",
"reference": "history"
},
{
"name": "tasks",
"reference": "tasks"
}
]
"controller": "controllers/record",
"iconClass": "fas fa-heartbeat",
"color": "#e74c3c",
"filterList": [
"meineOffenen",
{
"name": "bereit"
},
"bottomPanels": {
"detail": [
{
"name": "activities",
"reference": "activities",
"disabled": true
},
{
"name": "history",
"reference": "history",
"disabled": true
}
]
},
"iconClass": "fas fa-heart-pulse"
}
{
"name": "inReview"
}
],
"boolFilterList": [
"onlyMy"
],
"defaultFilterPreset": "meineOffenen"
}

View File

@@ -105,6 +105,11 @@
"default": "pending_sync",
"tooltip": true,
"isCustom": true
},
"puls": {
"type": "link",
"entity": "CPuls",
"isCustom": true
}
},
"links": {
@@ -138,6 +143,12 @@
"skipOrmDefs": true,
"utility": true
},
"puls": {
"type": "belongsTo",
"entity": "CPuls",
"foreign": "dokumente",
"isCustom": true
},
"contactsvmhdokumente": {
"type": "hasMany",
"relationName": "cDokumenteContact",

View File

@@ -3,10 +3,97 @@
"name": {
"type": "varchar",
"required": true,
"pattern": "$noBadCharacters"
"maxLength": 255,
"trim": true,
"isCustom": true
},
"description": {
"type": "text"
"status": {
"type": "enum",
"options": [
"Neu",
"In Verarbeitung",
"Bereit",
"In Review",
"Teilweise abgeschlossen",
"Abgeschlossen"
],
"default": "Neu",
"required": true,
"isCustom": true,
"style": {
"Neu": "default",
"In Verarbeitung": "primary",
"Bereit": "success",
"In Review": "warning",
"Teilweise abgeschlossen": "info",
"Abgeschlossen": "success"
}
},
"syncStatus": {
"type": "enum",
"options": ["clean", "unclean"],
"default": "unclean",
"required": true,
"isCustom": true,
"tooltip": true
},
"kiAnalyse": {
"type": "text",
"isCustom": true,
"tooltip": true
},
"zusammenfassung": {
"type": "varchar",
"maxLength": 500,
"isCustom": true,
"tooltip": true
},
"anzahlDokumente": {
"type": "int",
"readOnly": true,
"notStorable": false,
"isCustom": true
},
"anzahlTeamsAktiv": {
"type": "int",
"readOnly": true,
"notStorable": false,
"isCustom": true
},
"anzahlTeamsAbgeschlossen": {
"type": "int",
"readOnly": true,
"notStorable": false,
"isCustom": true
},
"finalisiert": {
"type": "bool",
"default": false,
"readOnly": true,
"isCustom": true,
"tooltip": true
},
"finalisierungsGrund": {
"type": "enum",
"options": [
"Erstes Team",
"Manuell",
"Automatisch"
],
"readOnly": true,
"isCustom": true,
"tooltip": true
},
"finalisiertAm": {
"type": "datetime",
"readOnly": true,
"isCustom": true
},
"finalisiertVon": {
"type": "link",
"entity": "User",
"readOnly": true,
"isCustom": true
},
"createdAt": {
"type": "datetime",
@@ -18,25 +105,43 @@
},
"createdBy": {
"type": "link",
"readOnly": true,
"view": "views/fields/user"
"entity": "User",
"readOnly": true
},
"modifiedBy": {
"type": "link",
"readOnly": true,
"view": "views/fields/user"
"entity": "User",
"readOnly": true
},
"assignedUser": {
"type": "link",
"required": false,
"view": "views/fields/assigned-user"
"entity": "User",
"isCustom": true
},
"teams": {
"type": "linkMultiple",
"view": "views/fields/teams"
"isCustom": true
}
},
"links": {
"parent": {
"type": "belongsToParent",
"entityList": [
"CVmhRumungsklage",
"CMietinkasso",
"CKuendigung"
]
},
"dokumente": {
"type": "hasMany",
"entity": "CDokumente",
"foreign": "puls"
},
"teamZuordnungen": {
"type": "hasMany",
"entity": "CPulsTeamZuordnung",
"foreign": "puls"
},
"createdBy": {
"type": "belongsTo",
"entity": "User"
@@ -49,62 +154,37 @@
"type": "belongsTo",
"entity": "User"
},
"finalisiertVon": {
"type": "belongsTo",
"entity": "User"
},
"teams": {
"type": "hasMany",
"entity": "Team",
"relationName": "entityTeam",
"layoutRelationshipsDisabled": true
},
"meetings": {
"type": "hasMany",
"entity": "Meeting",
"foreign": "parent"
},
"calls": {
"type": "hasMany",
"entity": "Call",
"foreign": "parent"
},
"tasks": {
"type": "hasChildren",
"entity": "Task",
"foreign": "parent"
},
"emails": {
"type": "hasChildren",
"entity": "Email",
"foreign": "parent",
"relationName": "EntityTeam",
"layoutRelationshipsDisabled": true
}
},
"collection": {
"orderBy": "createdAt",
"order": "desc"
"order": "desc",
"textFilterFields": ["name", "zusammenfassung"]
},
"indexes": {
"name": {
"columns": [
"name",
"deleted"
]
"parent": {
"columns": ["parentType", "parentId"]
},
"assignedUser": {
"columns": [
"assignedUserId",
"deleted"
]
"status": {
"columns": ["status"]
},
"syncStatus": {
"columns": ["syncStatus"]
},
"finalisiert": {
"columns": ["finalisiert"]
},
"createdAt": {
"columns": [
"createdAt"
]
},
"createdAtId": {
"unique": true,
"columns": [
"createdAt",
"id"
]
"columns": ["createdAt"]
}
}
}

View File

@@ -0,0 +1,100 @@
{
"fields": {
"name": {
"type": "varchar",
"notStorable": true,
"select": {
"select": "CONCAT:(team.name, ' - ', puls.name)"
},
"orderBy": {
"order": [
["team.name", "{direction}"]
]
}
},
"puls": {
"type": "link",
"entity": "CPuls",
"required": true,
"isCustom": true
},
"team": {
"type": "link",
"entity": "Team",
"required": true,
"isCustom": true
},
"aktiv": {
"type": "bool",
"default": true,
"isCustom": true,
"tooltip": true
},
"abgeschlossen": {
"type": "bool",
"default": false,
"isCustom": true
},
"abgeschlossenAm": {
"type": "datetime",
"readOnly": true,
"isCustom": true
},
"abgeschlossenVon": {
"type": "link",
"entity": "User",
"readOnly": true,
"isCustom": true
},
"prioritaet": {
"type": "enum",
"options": ["Niedrig", "Normal", "Hoch"],
"default": "Normal",
"isCustom": true,
"style": {
"Niedrig": "default",
"Normal": "primary",
"Hoch": "danger"
}
},
"createdAt": {
"type": "datetime",
"readOnly": true
},
"modifiedAt": {
"type": "datetime",
"readOnly": true
}
},
"links": {
"puls": {
"type": "belongsTo",
"entity": "CPuls",
"foreign": "teamZuordnungen"
},
"team": {
"type": "belongsTo",
"entity": "Team"
},
"abgeschlossenVon": {
"type": "belongsTo",
"entity": "User"
}
},
"collection": {
"orderBy": "createdAt",
"order": "desc"
},
"indexes": {
"pulsTeam": {
"columns": ["pulsId", "teamId"],
"unique": true
},
"aktiv": {
"columns": ["aktiv"]
},
"abgeschlossen": {
"columns": ["abgeschlossen"]
}
}
}

View File

@@ -0,0 +1,16 @@
{
"fields": {
"teamKategorie": {
"type": "enum",
"options": [
"Anwalt",
"Mandatsbetreuung",
"Zwangsvollstreckung",
"Sonstiges"
],
"default": "Sonstiges",
"isCustom": true,
"tooltip": true
}
}
}

View File

@@ -2,6 +2,23 @@
"fields": {
"cCallQueues": {
"type": "linkOne"
},
"abwesend": {
"type": "bool",
"default": false,
"isCustom": true,
"tooltip": true
},
"abwesendBis": {
"type": "date",
"isCustom": true,
"tooltip": true
},
"vertretung": {
"type": "link",
"entity": "User",
"isCustom": true,
"tooltip": true
}
},
"links": {
@@ -10,6 +27,11 @@
"foreign": "user",
"entity": "CCallQueues",
"isCustom": true
},
"vertretung": {
"type": "belongsTo",
"entity": "User",
"isCustom": true
}
}
}

View File

@@ -0,0 +1,3 @@
{
"beforeSaveApiScript": "// Verhindere Abschluss bei unclean Status\nif (\n (status == 'Abgeschlossen' || entity\\isAttributeChanged('status'))\n && syncStatus == 'unclean'\n) {\n recordService\\throwBadRequest('Puls kann nicht abgeschlossen werden: Neue Dokumente vorhanden (Status: unclean). Bitte warten Sie auf die KI-Analyse.');\n}\n\n// Verhindere Änderungen an finalisiertem Puls\nif (\n finalisiert == true\n && entity\\isAttributeChanged('finalisiert') == false\n && (entity\\isAttributeChanged('status') || entity\\isAttributeChanged('syncStatus'))\n) {\n recordService\\throwBadRequest('Puls ist finalisiert. Neue Dokumente erzeugen automatisch einen neuen Block.');\n}"
}

View File

@@ -2,22 +2,16 @@
"entity": true,
"layouts": true,
"tab": true,
"acl": true,
"aclPortal": true,
"aclPortalLevelList": [
"all",
"account",
"contact",
"own",
"no"
],
"acl": "recordAllTeamOwnNo",
"aclPortal": false,
"customizable": true,
"importable": true,
"importable": false,
"notifications": true,
"stream": true,
"disabled": false,
"type": "BasePlus",
"type": "Base",
"module": "Custom",
"object": true,
"isCustom": true
}
"isCustom": true,
"calendar": false
}

View File

@@ -0,0 +1,13 @@
{
"entity": true,
"tab": false,
"acl": "recordAllTeamNo",
"aclPortal": false,
"customizable": true,
"stream": false,
"disabled": false,
"type": "Base",
"module": "Custom",
"object": true,
"isCustom": true
}