Compare commits
47 Commits
9ab8f8b4bf
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bad25216b | |||
| 412c25f184 | |||
| fa3c92379f | |||
| 2a18e62528 | |||
| bd29d6e9b4 | |||
| a0d9d1133a | |||
| 297d2765bd | |||
| 260186d148 | |||
| 5a61bd550c | |||
| 0841543d8e | |||
| cca6d288eb | |||
| 8e7bb9f141 | |||
| 6ac852b42a | |||
| 661943987f | |||
| bb44fd0277 | |||
| c151505c22 | |||
| 35d165a4b6 | |||
| 4a302542b7 | |||
| 7d55075490 | |||
| 867da15823 | |||
| 0abd37d7a5 | |||
| 7abd2122fe | |||
| cb3da68673 | |||
| ea4738d9eb | |||
| 672645673f | |||
| 22665948e4 | |||
| 0b829e9dfe | |||
| faffe3d874 | |||
| bf0f596ad4 | |||
| 3ecc6275bc | |||
| d0397e475e | |||
| 51d9f7fa22 | |||
| 80dc3b40d3 | |||
| e15dd14cab | |||
| 54d66da52d | |||
| ae359048af | |||
| c678660ad6 | |||
| c952fc40bc | |||
| b2c391539d | |||
| e7b14406fb | |||
| 4707925917 | |||
| c2c9cfe709 | |||
| 9411337939 | |||
| 986cafcfd6 | |||
| c12577f4f8 | |||
| f7b1adc015 | |||
| 0f307c7eca |
@@ -53,7 +53,7 @@ class NotInternal implements Validator
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->hostCheck->isNotInternalHost($value)) {
|
||||
if (!$this->hostCheck->isHostAndNotInternal($value)) {
|
||||
return Failure::create();
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class NotInternal implements Validator
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->urlCheck->isNotInternalUrl($value)) {
|
||||
if (!$this->urlCheck->isUrlAndNotIternal($value)) {
|
||||
return Failure::create();
|
||||
}
|
||||
|
||||
|
||||
@@ -178,7 +178,9 @@ class MassUpdate implements MassAction
|
||||
|
||||
private function clearRoleCache(string $id): void
|
||||
{
|
||||
$this->fileManager->removeFile('data/cache/application/acl/' . $id . '.php');
|
||||
$part = basename($id);
|
||||
|
||||
$this->fileManager->removeFile("data/cache/application/acl/$part.php");
|
||||
}
|
||||
|
||||
private function clearPortalRolesCache(): void
|
||||
|
||||
@@ -76,7 +76,7 @@ class BeforeSaveValidateHosts implements SaveHook
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->hostCheck->isNotInternalHost($host)) {
|
||||
if (!$this->hostCheck->isHostAndNotInternal($host)) {
|
||||
$message = $this->composeErrorMessage($host, $address);
|
||||
|
||||
throw new Forbidden($message);
|
||||
@@ -97,7 +97,11 @@ class BeforeSaveValidateHosts implements SaveHook
|
||||
|
||||
$address = $host . ':' . $port;
|
||||
|
||||
if (!$this->hostCheck->isNotInternalHost($host)) {
|
||||
if (in_array($address, $this->getAllowedAddressList())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->hostCheck->isHostAndNotInternal($host)) {
|
||||
$message = $this->composeErrorMessage($host, $address);
|
||||
|
||||
throw new Forbidden($message);
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Espo\Classes\TemplateHelpers;
|
||||
use Espo\Core\Htmlizer\Helper;
|
||||
use Espo\Core\Htmlizer\Helper\Data;
|
||||
use Espo\Core\Htmlizer\Helper\Result;
|
||||
use Michelf\MarkdownExtra as MarkdownTransformer;
|
||||
use Espo\Core\Utils\Markdown\Markdown;
|
||||
|
||||
class MarkdownText implements Helper
|
||||
{
|
||||
@@ -44,7 +44,7 @@ class MarkdownText implements Helper
|
||||
return Result::createEmpty();
|
||||
}
|
||||
|
||||
$transformed = MarkdownTransformer::defaultTransform($value);
|
||||
$transformed = Markdown::transform($value);
|
||||
|
||||
return Result::createSafeString($transformed);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class Clearer
|
||||
return;
|
||||
}
|
||||
|
||||
$part = $user->getId() . '.php';
|
||||
$part = basename($user->getId() . '.php');
|
||||
|
||||
$this->fileManager->remove('data/cache/application/acl/' . $part);
|
||||
$this->fileManager->remove('data/cache/application/aclMap/' . $part);
|
||||
@@ -77,7 +77,7 @@ class Clearer
|
||||
->find();
|
||||
|
||||
foreach ($portals as $portal) {
|
||||
$part = $portal->getId() . '/' . $user->getId() . '.php';
|
||||
$part = basename($portal->getId()) . '/' . basename($user->getId() . '.php');
|
||||
|
||||
$this->fileManager->remove('data/cache/application/aclPortal/' . $part);
|
||||
$this->fileManager->remove('data/cache/application/aclPortalMap/' . $part);
|
||||
|
||||
@@ -115,7 +115,8 @@ class EspoUploadDir implements Storage, Local
|
||||
protected function getFilePath(Attachment $attachment)
|
||||
{
|
||||
$sourceId = $attachment->getSourceId();
|
||||
$file = basename($sourceId);
|
||||
|
||||
return 'data/upload/' . $sourceId;
|
||||
return 'data/upload/' . $file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use Espo\Core\Formula\EvaluatedArgumentList;
|
||||
use Espo\Core\Formula\Exceptions\BadArgumentType;
|
||||
use Espo\Core\Formula\Exceptions\TooFewArguments;
|
||||
use Espo\Core\Formula\Func;
|
||||
use Michelf\Markdown;
|
||||
use Espo\Core\Utils\Markdown\Markdown;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
@@ -52,6 +52,6 @@ class TransformType implements Func
|
||||
throw BadArgumentType::create(1, 'string');
|
||||
}
|
||||
|
||||
return Markdown::defaultTransform($string);
|
||||
return Markdown::transform($string);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class Service
|
||||
if (
|
||||
$params->getHost() &&
|
||||
!$this->addressUtil->isAllowedAddress($params) &&
|
||||
!$this->hostCheck->isNotInternalHost($params->getHost())
|
||||
!$this->hostCheck->isHostAndNotInternal($params->getHost())
|
||||
) {
|
||||
throw new Forbidden("Not allowed internal host.");
|
||||
}
|
||||
@@ -124,7 +124,7 @@ class Service
|
||||
if (
|
||||
$params->getHost() &&
|
||||
!$this->addressUtil->isAllowedAddress($params) &&
|
||||
!$this->hostCheck->isNotInternalHost($params->getHost())
|
||||
!$this->hostCheck->isHostAndNotInternal($params->getHost())
|
||||
) {
|
||||
throw new Forbidden("Not allowed internal host.");
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ class Service
|
||||
if (
|
||||
$params->getHost() &&
|
||||
!$this->addressUtil->isAllowedAddress($params) &&
|
||||
!$this->hostCheck->isNotInternalHost($params->getHost())
|
||||
!$this->hostCheck->isHostAndNotInternal($params->getHost())
|
||||
) {
|
||||
throw new Forbidden("Not allowed internal host.");
|
||||
}
|
||||
@@ -144,7 +144,7 @@ class Service
|
||||
if (
|
||||
$params->getHost() &&
|
||||
!$this->addressUtil->isAllowedAddress($params) &&
|
||||
!$this->hostCheck->isNotInternalHost($params->getHost())
|
||||
!$this->hostCheck->isHostAndNotInternal($params->getHost())
|
||||
) {
|
||||
throw new Forbidden("Not allowed host.");
|
||||
}
|
||||
|
||||
@@ -49,7 +49,9 @@ class Starter extends StarterBase
|
||||
SystemConfig $systemConfig,
|
||||
ApplicationState $applicationState
|
||||
) {
|
||||
$routeCacheFile = 'data/cache/application/slim-routes-portal-' . $applicationState->getPortalId() . '.php';
|
||||
$part = basename($applicationState->getPortalId());
|
||||
|
||||
$routeCacheFile = 'data/cache/application/slim-routes-portal-' . $part . '.php';
|
||||
|
||||
parent::__construct(
|
||||
$requestProcessor,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Copyright (C) 2014-2026 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -27,26 +27,24 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Utils\Database\Dbal\Platforms\Keywords;
|
||||
namespace Espo\Core\Utils\Markdown;
|
||||
|
||||
use Doctrine\DBAL\Platforms\Keywords\MariaDBKeywords;
|
||||
use Michelf\Markdown as MarkdownParser;
|
||||
|
||||
/**
|
||||
* 'LEAD' happened to be a reserved words on some environments.
|
||||
* @internal
|
||||
*/
|
||||
final class MariaDb102Keywords extends MariaDBKeywords
|
||||
class Markdown
|
||||
{
|
||||
/** @deprecated */
|
||||
public function getName(): string
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function transform(string $text): string
|
||||
{
|
||||
return 'MariaDb102';
|
||||
}
|
||||
$parser = new MarkdownParser();
|
||||
$parser->no_markup = true;
|
||||
$parser->no_entities = true;
|
||||
|
||||
protected function getKeywords(): array
|
||||
{
|
||||
return [
|
||||
...parent::getKeywords(),
|
||||
'LEAD',
|
||||
];
|
||||
return $parser->transform($text);
|
||||
}
|
||||
}
|
||||
@@ -32,30 +32,35 @@ namespace Espo\Core\Utils\Security;
|
||||
use const DNS_A;
|
||||
use const FILTER_FLAG_NO_PRIV_RANGE;
|
||||
use const FILTER_FLAG_NO_RES_RANGE;
|
||||
use const FILTER_FLAG_HOSTNAME;
|
||||
use const FILTER_VALIDATE_DOMAIN;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
|
||||
class HostCheck
|
||||
{
|
||||
public function isNotInternalHost(string $host): bool
|
||||
/**
|
||||
* Validates the string is a host and it's not internal.
|
||||
* If not a host, returns false.
|
||||
*
|
||||
* @since 9.3.4
|
||||
*/
|
||||
public function isHostAndNotInternal(string $host): bool
|
||||
{
|
||||
$records = dns_get_record($host, DNS_A);
|
||||
|
||||
if (filter_var($host, FILTER_VALIDATE_IP)) {
|
||||
return $this->ipAddressIsNotInternal($host);
|
||||
}
|
||||
|
||||
if (!$records) {
|
||||
return true;
|
||||
if (!$this->isDomainHost($host)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
/** @var ?string $idAddress */
|
||||
$idAddress = $record['ip'] ?? null;
|
||||
$ipAddresses = $this->getHostIpAddresses($host);
|
||||
|
||||
if (!$idAddress) {
|
||||
return false;
|
||||
}
|
||||
if ($ipAddresses === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($ipAddresses as $idAddress) {
|
||||
if (!$this->ipAddressIsNotInternal($idAddress)) {
|
||||
return false;
|
||||
}
|
||||
@@ -64,7 +69,66 @@ class HostCheck
|
||||
return true;
|
||||
}
|
||||
|
||||
private function ipAddressIsNotInternal(string $ipAddress): bool
|
||||
/**
|
||||
* @internal
|
||||
* @since 9.3.4
|
||||
*/
|
||||
public function isDomainHost(string $host): bool
|
||||
{
|
||||
$normalized = $this->normalizeIpAddress($host);
|
||||
|
||||
if ($normalized !== false && filter_var($normalized, FILTER_VALIDATE_IP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!filter_var($host, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->hasNoNumericItem($host)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filter_var($host, FILTER_VALIDATE_DOMAIN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @internal
|
||||
* @since 9.3.4
|
||||
*/
|
||||
public function getHostIpAddresses(string $host): array
|
||||
{
|
||||
$records = dns_get_record($host, DNS_A);
|
||||
|
||||
if (!$records) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$output = [];
|
||||
|
||||
foreach ($records as $record) {
|
||||
/** @var ?string $idAddress */
|
||||
$idAddress = $record['ip'] ?? null;
|
||||
|
||||
if (!$idAddress) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[] = $idAddress;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function ipAddressIsNotInternal(string $ipAddress): bool
|
||||
{
|
||||
return (bool) filter_var(
|
||||
$ipAddress,
|
||||
@@ -72,4 +136,90 @@ class HostCheck
|
||||
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since 9.3.4. Use `isHostAndNotInternal`.
|
||||
* @todo Remove in 9.4.0.
|
||||
*/
|
||||
public function isNotInternalHost(string $host): bool
|
||||
{
|
||||
return $this->isHostAndNotInternal($host);
|
||||
}
|
||||
|
||||
private function normalizeIpAddress(string $ip): string|false
|
||||
{
|
||||
if (!str_contains($ip, '.')) {
|
||||
return self::normalizePart($ip);
|
||||
}
|
||||
|
||||
$parts = explode('.', $ip);
|
||||
|
||||
if (count($parts) !== 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
if (preg_match('/^0x[0-9a-f]+$/i', $part)) {
|
||||
$num = hexdec($part);
|
||||
} else if (preg_match('/^0[0-7]+$/', $part) && $part !== '0') {
|
||||
$num = octdec($part);
|
||||
} else if (ctype_digit($part)) {
|
||||
$num = (int)$part;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($num < 0 || $num > 255) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result[] = $num;
|
||||
}
|
||||
|
||||
return implode('.', $result);
|
||||
}
|
||||
|
||||
private static function normalizePart(string $ip): string|false
|
||||
{
|
||||
if (preg_match('/^0x[0-9a-f]+$/i', $ip)) {
|
||||
$num = hexdec($ip);
|
||||
} elseif (preg_match('/^0[0-7]+$/', $ip) && $ip !== '0') {
|
||||
$num = octdec($ip);
|
||||
} elseif (ctype_digit($ip)) {
|
||||
$num = (int) $ip;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($num < 0 || $num > 0xFFFFFFFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$num = (int) $num;
|
||||
|
||||
return long2ip($num);
|
||||
}
|
||||
|
||||
|
||||
private function hasNoNumericItem(string $host): bool
|
||||
{
|
||||
$hasNoNumeric = false;
|
||||
|
||||
foreach (explode('.', $host) as $it) {
|
||||
if (!is_numeric($it) && !self::isHex($it)) {
|
||||
$hasNoNumeric = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $hasNoNumeric;
|
||||
}
|
||||
|
||||
private function isHex(string $value): bool
|
||||
{
|
||||
return preg_match('/^0x[0-9a-fA-F]+$/', $value) === 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
|
||||
namespace Espo\Core\Utils\Security;
|
||||
|
||||
use const FILTER_VALIDATE_URL;
|
||||
use const PHP_URL_HOST;
|
||||
|
||||
class UrlCheck
|
||||
{
|
||||
public function __construct(
|
||||
@@ -44,9 +41,11 @@ class UrlCheck
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a URL does not follow to an internal host.
|
||||
* Checks whether it's a URL, and it does not follow to an internal host.
|
||||
*
|
||||
* @since 9.3.4
|
||||
*/
|
||||
public function isNotInternalUrl(string $url): bool
|
||||
public function isUrlAndNotIternal(string $url): bool
|
||||
{
|
||||
if (!$this->isUrl($url)) {
|
||||
return false;
|
||||
@@ -58,6 +57,118 @@ class UrlCheck
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->hostCheck->isNotInternalHost($host);
|
||||
return $this->hostCheck->isHostAndNotInternal($host);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?string[] Null if not a domain name or not a URL.
|
||||
* @internal
|
||||
* @since 9.3.4
|
||||
*/
|
||||
public function getCurlResolve(string $url): ?array
|
||||
{
|
||||
if (!$this->isUrl($url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$host = parse_url($url, PHP_URL_HOST);
|
||||
$port = parse_url($url, PHP_URL_PORT);
|
||||
$scheme = parse_url($url, PHP_URL_SCHEME);
|
||||
|
||||
if ($port === null && $scheme) {
|
||||
$port = match (strtolower($scheme)) {
|
||||
'http' => 80,
|
||||
'https'=> 443,
|
||||
'ftp' => 21,
|
||||
'ssh' => 22,
|
||||
'smtp' => 25,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
if ($port === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!is_string($host)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (filter_var($host, FILTER_VALIDATE_IP)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->hostCheck->isDomainHost($host)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$ipAddresses = $this->hostCheck->getHostIpAddresses($host);
|
||||
|
||||
$output = [];
|
||||
|
||||
foreach ($ipAddresses as $ipAddress) {
|
||||
$ipPart = $ipAddress;
|
||||
|
||||
if (filter_var($ipAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
$ipPart = "[$ipPart]";
|
||||
}
|
||||
|
||||
$output[] = "$host:$port:$ipPart";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since 9.3.4. Use `isUrlAndNotIternal`.
|
||||
* @todo Remove in 9.5.0.
|
||||
*/
|
||||
public function isNotInternalUrl(string $url): bool
|
||||
{
|
||||
return $this->isUrlAndNotIternal($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $resolve
|
||||
* @param string[] $allowed An allowed address list in the `{host}:{port}` format.
|
||||
* @internal
|
||||
*/
|
||||
public function validateCurlResolveNotInternal(array $resolve, array $allowed = []): bool
|
||||
{
|
||||
if ($resolve === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ipAddresses = [];
|
||||
|
||||
foreach ($resolve as $item) {
|
||||
$arr = explode(':', $item, 3);
|
||||
|
||||
if (count($arr) < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ipAddress = $arr[2];
|
||||
$port = $arr[1];
|
||||
$domain = $arr[0];
|
||||
|
||||
if (in_array("$ipAddress:$port", $allowed) || in_array("$domain:$port", $allowed)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (str_starts_with($ipAddress, '[') && str_ends_with($ipAddress, ']')) {
|
||||
$ipAddress = substr($ipAddress, 1, -1);
|
||||
}
|
||||
|
||||
$ipAddresses[] = $ipAddress;
|
||||
}
|
||||
|
||||
foreach ($ipAddresses as $ipAddress) {
|
||||
if (!$this->hostCheck->ipAddressIsNotInternal($ipAddress)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,13 @@ class TemplateFileManager
|
||||
?string $entityType = null
|
||||
): string {
|
||||
|
||||
$type = basename($type);
|
||||
$language = basename($language);
|
||||
$name = basename($name);
|
||||
|
||||
if ($entityType) {
|
||||
$entityType = basename($entityType);
|
||||
|
||||
return "custom/Espo/Custom/Resources/templates/{$type}/{$language}/{$entityType}/{$name}.tpl";
|
||||
}
|
||||
|
||||
@@ -152,7 +158,13 @@ class TemplateFileManager
|
||||
?string $entityType = null
|
||||
): string {
|
||||
|
||||
$type = basename($type);
|
||||
$language = basename($language);
|
||||
$name = basename($name);
|
||||
|
||||
if ($entityType) {
|
||||
$entityType = basename($entityType);
|
||||
|
||||
return "templates/{$type}/{$language}/{$entityType}/{$name}.tpl";
|
||||
}
|
||||
|
||||
|
||||
@@ -95,11 +95,24 @@ class Sender
|
||||
|
||||
if (
|
||||
!$this->addressUtil->isAllowedUrl($url) &&
|
||||
!$this->urlCheck->isNotInternalUrl($url)
|
||||
!$this->urlCheck->isUrlAndNotIternal($url)
|
||||
) {
|
||||
throw new Error("URL '$url' points to an internal host, not allowed.");
|
||||
}
|
||||
|
||||
$resolve = $this->urlCheck->getCurlResolve($url);
|
||||
|
||||
if ($resolve === []) {
|
||||
throw new Error("Could not resolve the host.");
|
||||
}
|
||||
|
||||
/** @var string[] $allowedAddressList */
|
||||
$allowedAddressList = $this->config->get('webhookAllowedAddressList') ?? [];
|
||||
|
||||
if ($resolve !== null && !$this->urlCheck->validateCurlResolveNotInternal($resolve, $allowedAddressList)) {
|
||||
throw new Error("Forbidden host.");
|
||||
}
|
||||
|
||||
$handler = curl_init($url);
|
||||
|
||||
if ($handler === false) {
|
||||
@@ -118,6 +131,10 @@ class Sender
|
||||
curl_setopt($handler, \CURLOPT_HTTPHEADER, $headerList);
|
||||
curl_setopt($handler, \CURLOPT_POSTFIELDS, $payload);
|
||||
|
||||
if ($resolve) {
|
||||
curl_setopt($handler, CURLOPT_RESOLVE, $resolve);
|
||||
}
|
||||
|
||||
curl_exec($handler);
|
||||
|
||||
$code = curl_getinfo($handler, \CURLINFO_HTTP_CODE);
|
||||
|
||||
@@ -95,7 +95,7 @@ class Attachment implements EntryPoint
|
||||
$response
|
||||
->setHeader('Content-Length', (string) $size)
|
||||
->setHeader('Cache-Control', 'private, max-age=864000, immutable')
|
||||
->setHeader('Content-Security-Policy', "default-src 'self'")
|
||||
->setHeader('Content-Security-Policy', "default-src 'self'; script-src 'none'; object-src 'none';")
|
||||
->setBody($stream);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class Download implements EntryPoint
|
||||
if (in_array($type, $inlineMimeTypeList)) {
|
||||
$disposition = 'inline';
|
||||
|
||||
$response->setHeader('Content-Security-Policy', "default-src 'self'");
|
||||
$response->setHeader('Content-Security-Policy', "default-src 'self'; script-src 'none'; object-src 'none';");
|
||||
}
|
||||
|
||||
$response->setHeader('Content-Description', 'File Transfer');
|
||||
|
||||
@@ -153,7 +153,7 @@ class Image implements EntryPoint
|
||||
$response
|
||||
->setHeader('Content-Disposition', 'inline;filename="' . $fileName . '"')
|
||||
->setHeader('Content-Length', (string) $fileSize)
|
||||
->setHeader('Content-Security-Policy', "default-src 'self'");
|
||||
->setHeader('Content-Security-Policy', "default-src 'self'; script-src 'none'; object-src 'none';");
|
||||
|
||||
if (!$noCacheHeaders) {
|
||||
$response->setHeader('Cache-Control', 'private, max-age=864000, immutable');
|
||||
@@ -174,7 +174,9 @@ class Image implements EntryPoint
|
||||
|
||||
$sourceId = $attachment->getSourceId();
|
||||
|
||||
$cacheFilePath = "data/upload/thumbs/{$sourceId}_$size";
|
||||
$file = basename("{$sourceId}_$size");
|
||||
|
||||
$cacheFilePath = "data/upload/thumbs/$file";
|
||||
|
||||
if ($useCache && $this->fileManager->isFile($cacheFilePath)) {
|
||||
return $this->fileManager->getContents($cacheFilePath);
|
||||
|
||||
@@ -89,7 +89,9 @@ class RemoveFile implements AfterRemove
|
||||
$sizeList = array_keys($this->metadata->get(['app', 'image', 'sizes']) ?? []);
|
||||
|
||||
foreach ($sizeList as $size) {
|
||||
$filePath = "data/upload/thumbs/{$entity->getSourceId()}_{$size}";
|
||||
$file = basename("{$entity->getSourceId()}_$size");
|
||||
|
||||
$filePath = "data/upload/thumbs/$file";
|
||||
|
||||
if ($this->fileManager->isFile($filePath)) {
|
||||
$this->fileManager->removeFile($filePath);
|
||||
|
||||
@@ -1,380 +1,380 @@
|
||||
{
|
||||
"labels": {
|
||||
"Enabled": "Povoleno",
|
||||
"Disabled": "Zakázáno",
|
||||
"System": "Systém",
|
||||
"Users": "Uživatelé",
|
||||
"Customization": "Přizpůsobení",
|
||||
"Available Fields": "Dostupná pole",
|
||||
"Layout": "Vzhled",
|
||||
"Entity Manager": "Správa entit",
|
||||
"Add Panel": "Přidat panel",
|
||||
"Add Field": "Přidat pole",
|
||||
"Settings": "Nastavení",
|
||||
"Scheduled Jobs": "Naplánované akce",
|
||||
"Upgrade": "Aktualizace",
|
||||
"Clear Cache": "Vyčistit cache",
|
||||
"Rebuild": "Přestavět",
|
||||
"Teams": "Týmy",
|
||||
"Roles": "Role",
|
||||
"Portal": "Portál",
|
||||
"Portals": "Portály",
|
||||
"Portal Roles": "Role portálu",
|
||||
"Outbound Emails": "Odchozí emaily",
|
||||
"Group Email Accounts": "Skupinové e-mailové účty",
|
||||
"Personal Email Accounts": "Osobní e-mailové účty",
|
||||
"Inbound Emails": "Příchozí emaily",
|
||||
"Email Templates": "Šablony emailů",
|
||||
"Layout Manager": "Správa layoutu",
|
||||
"User Interface": "Uživatelské rozhraní",
|
||||
"Auth Tokens": "Autentizační tokeny",
|
||||
"Authentication": "Autentizace",
|
||||
"Currency": "Měna",
|
||||
"Integrations": "Integrace",
|
||||
"Extensions": "Rozšíření",
|
||||
"Upload": "Nahrát",
|
||||
"Installing...": "Instaluji...",
|
||||
"Upgrading...": "Upgraduji...",
|
||||
"Upgraded successfully": "Úspěšně upgradováno",
|
||||
"Installed successfully": "Úspěšně nainstalováno",
|
||||
"Ready for upgrade": "Připraveno k upgradu",
|
||||
"Run Upgrade": "Spustit upgrade",
|
||||
"Install": "Instalovat",
|
||||
"Ready for installation": "Připraveno k instalaci",
|
||||
"Uninstalling...": "Odebírám...",
|
||||
"Uninstalled": "Odebráno",
|
||||
"Create Entity": "Vytvořit entitu",
|
||||
"Edit Entity": "Upravit entitu",
|
||||
"Create Link": "Vytvořit vazbu",
|
||||
"Edit Link": "Upravit link",
|
||||
"Notifications": "Upozornění",
|
||||
"Jobs": "Joby",
|
||||
"Reset to Default": "Obnovit do základního nastavení",
|
||||
"Email Filters": "E-mailové filtry",
|
||||
"Portal Users": "Uživatelé portálu",
|
||||
"Action History": "Historie akcí",
|
||||
"Label Manager": "Správce labelů",
|
||||
"Auth Log": "Log autentizace",
|
||||
"Lead Capture": "Zachycení potenciálů",
|
||||
"Attachments": "Přílohy",
|
||||
"API Users": "API uživatelé",
|
||||
"Template Manager": "Správce šablon",
|
||||
"System Requirements": "Požadavky na systém",
|
||||
"PHP Settings": "Nastavení PHP",
|
||||
"Database Settings": "Nastavení databáze",
|
||||
"Permissions": "Oprávnění",
|
||||
"Success": "Úspěch",
|
||||
"Fail": "Selhání",
|
||||
"is recommended": "je doporučeno",
|
||||
"extension is missing": "rozšíření chybí",
|
||||
"PDF Templates": "PDF Šablony",
|
||||
"Webhooks": "Webhooky",
|
||||
"Dashboard Templates": "Šablony hlavních panelů",
|
||||
"Email Addresses": "Emailové adresy",
|
||||
"Phone Numbers": "Telefonní čísla",
|
||||
"Layout Sets": "Sady vzhledů",
|
||||
"Messaging": "Zprávy",
|
||||
"Misc": "Vedlejší",
|
||||
"Job Settings": "Nastavení jobů",
|
||||
"Configuration Instructions": "Instrukce k nastavení",
|
||||
"Formula Sandbox": "Pískoviště pro formula skripty",
|
||||
"Working Time Calendars": "Kalendáře pracovní doby",
|
||||
"Group Email Folders": "Složky skupinových e-mailů",
|
||||
"Authentication Providers": "Poskytovatelé autentizace",
|
||||
"Setup": "Nastavení",
|
||||
"App Log": "Log aplikace",
|
||||
"Address Countries": "Seznam zemí",
|
||||
"App Secrets": "Tajemství aplikace",
|
||||
"OAuth Providers": "OAuth poskytovatelé"
|
||||
},
|
||||
"layouts": {
|
||||
"list": "Seznam",
|
||||
"listSmall": "Seznam (malý)",
|
||||
"detailSmall": "Detail (malý)",
|
||||
"filters": "Vyhledávací filtry",
|
||||
"massUpdate": "Hromadný update",
|
||||
"relationships": "Vztah",
|
||||
"sidePanelsDetail": "Boční panely (Detail)",
|
||||
"sidePanelsEdit": "Boční panely (Upravit)",
|
||||
"sidePanelsDetailSmall": "Boční panely (Detail malé)",
|
||||
"sidePanelsEditSmall": "Boční panely (Upravit malé)",
|
||||
"detailPortal": "Detail (Portál)",
|
||||
"detailSmallPortal": "Detail (Small, Portál)",
|
||||
"listSmallPortal": "Seznam malý (Portál)",
|
||||
"listPortal": "Seznam (portál)",
|
||||
"relationshipsPortal": "Panely vztahů (Portál)",
|
||||
"defaultSidePanel": "Pole bočního panelu",
|
||||
"bottomPanelsDetail": "Spodní panely",
|
||||
"bottomPanelsEdit": "Spodní panely (Upravit)",
|
||||
"bottomPanelsDetailSmall": "Spodní panely (Detail malé)",
|
||||
"bottomPanelsEditSmall": "Spodní panely (Upravit malé)"
|
||||
},
|
||||
"fieldTypes": {
|
||||
"address": "Adresa",
|
||||
"array": "Pole",
|
||||
"foreign": "Cizí pole",
|
||||
"duration": "Trvání",
|
||||
"password": "Heslo",
|
||||
"personName": "Jméno osoby",
|
||||
"autoincrement": "Číslo (automaticky zvyšované)",
|
||||
"bool": "Ano/Ne",
|
||||
"currency": "Měna",
|
||||
"date": "Datum",
|
||||
"enum": "Výběr",
|
||||
"enumInt": "Výběr (číslo)",
|
||||
"enumFloat": "Výběr (desetinné číslo)",
|
||||
"float": "Číslo (desetinné)",
|
||||
"link": "Vazba",
|
||||
"linkMultiple": "Vazba (vícenásobná)",
|
||||
"linkParent": "Vazba (rodič)",
|
||||
"phone": "Telefon",
|
||||
"url": "URL adresa",
|
||||
"file": "Soubor",
|
||||
"image": "Obrázek",
|
||||
"multiEnum": "Výběr (vícenásobný)",
|
||||
"attachmentMultiple": "Více příloh",
|
||||
"rangeInt": "Rozsah (celé číslo)",
|
||||
"rangeFloat": "Rozsah (desetinné číslo)",
|
||||
"rangeCurrency": "Rozsah (měna)",
|
||||
"wysiwyg": "WYSIWYG editor",
|
||||
"map": "Mapa",
|
||||
"currencyConverted": "Měna (převedená)",
|
||||
"colorpicker": "Výběr barvy",
|
||||
"int": "Číslo (celé)",
|
||||
"number": "Číslo faktury",
|
||||
"jsonArray": "JSON pole",
|
||||
"jsonObject": "JSON objekt",
|
||||
"datetime": "Datum a čas",
|
||||
"datetimeOptional": "Datum/Datum a čas",
|
||||
"checklist": "Ano/Ne (seznam)",
|
||||
"linkOne": "Vazba (jednonásobná)",
|
||||
"barcode": "Čárový kód",
|
||||
"urlMultiple": "URL adresy (více)",
|
||||
"base": "Výchozí",
|
||||
"decimal": "Desetinné číslo"
|
||||
},
|
||||
"fields": {
|
||||
"type": "Typ",
|
||||
"name": "Jméno",
|
||||
"label": "Popisek",
|
||||
"required": "Povinné",
|
||||
"default": "Výchozí",
|
||||
"maxLength": "Maximální délka",
|
||||
"options": "Možnosti",
|
||||
"after": "Po (pole)",
|
||||
"before": "Před (pole)",
|
||||
"link": "Odkaz",
|
||||
"field": "Pole",
|
||||
"min": "Minimum",
|
||||
"max": "Maximum",
|
||||
"translation": "Překlad",
|
||||
"previewSize": "Velikost náhledu",
|
||||
"defaultType": "Výchozí typ",
|
||||
"seeMoreDisabled": "Zakázat ořez textu",
|
||||
"entityList": "Seznam entit",
|
||||
"isSorted": "Je seřazeno (abecedně)",
|
||||
"audited": "Auditováno",
|
||||
"trim": "Oříznout",
|
||||
"height": "Výška (px)",
|
||||
"minHeight": "Minimální výška (px)",
|
||||
"provider": "Poskytovatel",
|
||||
"typeList": "Seznam typů",
|
||||
"lengthOfCut": "Délka řezu",
|
||||
"sourceList": "Seznam zdrojů",
|
||||
"tooltipText": "Text nápovědy",
|
||||
"prefix": "Předpona",
|
||||
"nextNumber": "Další číslo",
|
||||
"padLength": "Délka výplně",
|
||||
"disableFormatting": "Zakázat formátování",
|
||||
"dynamicLogicVisible": "Podmínky, za kterých je pole viditelné",
|
||||
"dynamicLogicReadOnly": "Podmínky, za kterých je pole jenom pro čtení",
|
||||
"dynamicLogicRequired": "Podmínky, za kterých je pole povinné",
|
||||
"dynamicLogicOptions": "Podmíněné možnosti",
|
||||
"probabilityMap": "Pravděpodobnosti fáze (%)",
|
||||
"readOnly": "Pouze ke čtení",
|
||||
"noEmptyString": "Neprázdný řetězec",
|
||||
"maxFileSize": "Maximální velikost souboru (Mb)",
|
||||
"isPersonalData": "Jsou osobní údaje",
|
||||
"useIframe": "Použít iframe",
|
||||
"useNumericFormat": "Použít číselný formát",
|
||||
"strip": "Odstranit",
|
||||
"cutHeight": "Oříznout výšku (px)",
|
||||
"minuteStep": "Minutový krok",
|
||||
"inlineEditDisabled": "Zakázat samostatnou úpravu",
|
||||
"displayAsLabel": "Zobrazit jako štítek",
|
||||
"allowCustomOptions": "Povolit vlastní možnosti",
|
||||
"maxCount": "Maximální počet položek",
|
||||
"displayRawText": "Zobrazit holý text (bez označení)",
|
||||
"notActualOptions": "Neopravdové možnosti",
|
||||
"accept": "Přijmout",
|
||||
"displayAsList": "Zobrazit jako seznam",
|
||||
"viewMap": "Zobrazit mapu",
|
||||
"codeType": "Typ kódu",
|
||||
"lastChar": "Poslední znak",
|
||||
"listPreviewSize": "Velikost náhledu seznamu",
|
||||
"onlyDefaultCurrency": "Pouze výchozí měna",
|
||||
"dynamicLogicInvalid": "Podmínky, které pole dělají neplatným",
|
||||
"conversionDisabled": "Konverze zakázána",
|
||||
"decimalPlaces": "Počet desetinných míst",
|
||||
"pattern": "Vzor",
|
||||
"globalRestrictions": "Globální omezení",
|
||||
"decimal": "Desetinné",
|
||||
"optionsReference": "Odkaz na možnosti",
|
||||
"copyToClipboard": "Tlačítko na zkopírování do schránky",
|
||||
"rows": "Počet řádků textové oblasti",
|
||||
"readOnlyAfterCreate": "Pouze ke čtení po vytvoření",
|
||||
"createButton": "Tlačítko pro vytváření",
|
||||
"autocompleteOnEmpty": "Doplňování při prázdném poli",
|
||||
"relateOnImport": "Provázat při importu",
|
||||
"aclScope": "Entita pro acl",
|
||||
"onlyAdmin": "Pouze pro administrátory",
|
||||
"activeOptions": "Aktivní možnosti",
|
||||
"labelType": "Typ zobrazení",
|
||||
"preview": "Náhled",
|
||||
"attachmentField": "Pole pro přílohu",
|
||||
"dynamicLogicReadOnlySaved": "Podmínky, za kterých je pole jenom pro čtení (po uložení)",
|
||||
"notStorable": "Neuložitelné",
|
||||
"itemsEditable": "Upravitelné položky"
|
||||
},
|
||||
"messages": {
|
||||
"selectEntityType": "Vybrat entitu v levém menu.",
|
||||
"selectUpgradePackage": "Vybrat upgrade balíček",
|
||||
"selectLayout": "Vybrat požadovaný layout v levém menu a upravit ho.",
|
||||
"selectExtensionPackage": "Vybrat soubor s rozšířením",
|
||||
"extensionInstalled": "Rozšíření {name} {version} bylo nainstalováno.",
|
||||
"installExtension": "Rozšíření {name} {version} je připraveno k instalaci.",
|
||||
"upgradeBackup": "Doporučujeme zálohovat soubory a data EspoCRM před upgradem.",
|
||||
"thousandSeparatorEqualsDecimalMark": "Oddělovač tisíců nemůže být stejný jako desetinný symbol.",
|
||||
"userHasNoEmailAddress": "Uživatel nemá emailovou adresu.",
|
||||
"uninstallConfirmation": "Opravdu odinstalovat vybrané rozšíření?",
|
||||
"cronIsNotConfigured": "Naplánované úlohy nejsou spuštěny. Příchozí e-maily, oznámení a připomenutí proto nefungují. Postupujte podle [pokynů](https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab) k nastavení úlohy cron.",
|
||||
"newExtensionVersionIsAvailable": "Je k dispozici nová verze {latestName} {latestVersion}.",
|
||||
"upgradeVersion": "EspoCRM bude upgradováno na verzi <strong>{version}</strong>. Toto může chvíli trvat.",
|
||||
"upgradeDone": "EspoCRM bylo upgradováno na verzi <strong>{version}</strong>.",
|
||||
"downloadUpgradePackage": "Stáhnout upgradovací balíčky na [tomto]({url}) odkaze.",
|
||||
"upgradeInfo": "Přečtěte si [dokumentaci]({url}) o tom, jak upgradovat instanci AutoCRM.",
|
||||
"upgradeRecommendation": "Tento způsob upgradu se nedoporučuje. Je lepší upgradovat z CLI.",
|
||||
"newVersionIsAvailable": "K dispozici je nová verze AutoCRM {latestVersion}. Při aktualizaci instance postupujte podle [pokynů](https://www.espocrm.com/documentation/administration/upgrading/).",
|
||||
"formulaFunctions": "Funkce formula skriptů",
|
||||
"rebuildRequired": "Musíte spustit znovu rebuild z CLI.",
|
||||
"cronIsDisabled": "Cron je zakázán",
|
||||
"cacheIsDisabled": "Cache je zakázána"
|
||||
},
|
||||
"descriptions": {
|
||||
"settings": "Systémová nastavení aplikace.",
|
||||
"scheduledJob": "Činnosti vykonávané CRONem.",
|
||||
"upgrade": "Upgradovat EspoCRM.",
|
||||
"clearCache": "Vyčistit veškerou cache.",
|
||||
"rebuild": "Přestavět backend a vyčistit cache.",
|
||||
"users": "Správa uživatelů.",
|
||||
"teams": "Správa týmů.",
|
||||
"roles": "Správa rolí.",
|
||||
"portals": "Správa portálů.",
|
||||
"portalRoles": "Role pro portál.",
|
||||
"outboundEmails": "Nastavení SMTP pro odchozí emaily.",
|
||||
"groupEmailAccounts": "Skupinové IMAP emailové účty. Import emailů",
|
||||
"personalEmailAccounts": "E-mailové účty uživatelů.",
|
||||
"emailTemplates": "Šablony pro odchozí emaily.",
|
||||
"import": "Importovat data z CSV souboru.",
|
||||
"layoutManager": "Přizpůsobit layouty (seznam, detail, upravit, hledat, hromadný update).",
|
||||
"userInterface": "Nastavit uživatelské rozhraní.",
|
||||
"authTokens": "Aktivní autentizační sessions. IP adresa a datum posledního přístupu.",
|
||||
"authentication": "Nastavení autentizace.",
|
||||
"currency": "Nastavení měn a kurzů.",
|
||||
"extensions": "Instalovat a odebrat rozšíření.",
|
||||
"integrations": "Integrace se službami třetích stran.",
|
||||
"notifications": "Nastavení In-app a emailových upozornění.",
|
||||
"inboundEmails": "Nastavení příchozích mailů",
|
||||
"portalUsers": "Uživatelé portálu.",
|
||||
"entityManager": "Vytvořit vlastní entity, úpravit existující. Správa polí a vztahů.",
|
||||
"emailFilters": "E-mailové zprávy, které odpovídají zadanému filtru, nebudou importovány.",
|
||||
"actionHistory": "Protokol akcí uživatelů.",
|
||||
"labelManager": "Upravit popisky",
|
||||
"authLog": "Historie přihlášení.",
|
||||
"attachments": "Všechny přílohy souborů uložené v systému.",
|
||||
"templateManager": "Přizpůsobte si šablony zpráv.",
|
||||
"systemRequirements": "Systémové požadavky na AutoCRM.",
|
||||
"apiUsers": "Oddělte uživatele pro účely integrace.",
|
||||
"jobs": "Spustit akce na pozadí.",
|
||||
"pdfTemplates": "Šablony pro tisk do PDF.",
|
||||
"webhooks": "Správa webhooků.",
|
||||
"dashboardTemplates": "Umožňuje přidávat dashboardy uživatelům.",
|
||||
"phoneNumbers": "Všechna telefonní čísla uložená v systému.",
|
||||
"emailAddresses": "Všechny e-mailové adresy uložené v systému.",
|
||||
"layoutSets": "Kolekce layoutů, které lze přiřadit týmům a portálům.",
|
||||
"jobsSettings": "Nastavení zpracování jobů. Joby vykonávají úkoly na pozadí.",
|
||||
"sms": "Nastavení SMS.",
|
||||
"formulaSandbox": "Pískoviště pro testování formula skriptů bez ukládání změn.",
|
||||
"workingTimeCalendars": "Pracovní plány.",
|
||||
"groupEmailFolders": "Složky sdílené pro týmy",
|
||||
"authenticationProviders": "Další poskytovatelé autentizace pro portály.",
|
||||
"appLog": "Log aplikace.",
|
||||
"addressCountries": "Dostupné země pro políčka typu 'adresa'.",
|
||||
"appSecrets": "Pro ukládání citlivých informací jako jsou API klíče, hesla, a jiná tajemství.",
|
||||
"leadCapture": "Koncové body pro zachycení potenciálů a webové formuláře.",
|
||||
"oAuthProviders": "OAuth poskytovatelé pro integrace."
|
||||
},
|
||||
"options": {
|
||||
"previewSize": {
|
||||
"x-small": "Extra-malý",
|
||||
"small": "Malý",
|
||||
"medium": "Střední",
|
||||
"large": "Velký",
|
||||
"": "Prázdné"
|
||||
},
|
||||
"labelType": {
|
||||
"state": "Stav",
|
||||
"regular": "Výchozí"
|
||||
}
|
||||
},
|
||||
"logicalOperators": {
|
||||
"and": "a zároveň",
|
||||
"or": "nebo",
|
||||
"not": "negace"
|
||||
},
|
||||
"systemRequirements": {
|
||||
"requiredPhpVersion": "Požadovaná verze PHP",
|
||||
"requiredMysqlVersion": "Požadovaná verze MySQL",
|
||||
"host": "Jméno hostitele",
|
||||
"dbname": "Název databáze",
|
||||
"user": "Uživatel",
|
||||
"writable": "Zapisovatelné",
|
||||
"readable": "Čitelné",
|
||||
"requiredMariadbVersion": "Požadovaná verze MariaDB",
|
||||
"requiredPostgresqlVersion": "Požadovaná verze PostgreSQL"
|
||||
},
|
||||
"templates": {
|
||||
"accessInfo": "Přístupové údaje",
|
||||
"accessInfoPortal": "Přístupové údaje na portály",
|
||||
"assignment": "Úkol",
|
||||
"mention": "Zmínka",
|
||||
"notePost": "Poznámka k příspěvku",
|
||||
"notePostNoParent": "Poznámka k příspěvku (bez rodiče)",
|
||||
"noteStatus": "Poznámka k aktualizaci stavu",
|
||||
"passwordChangeLink": "Odkaz na změnu hesla",
|
||||
"noteEmailReceived": "Poznámka o přijatém e-mailu",
|
||||
"twoFactorCode": "Dvoufaktorový kód"
|
||||
},
|
||||
"strings": {
|
||||
"rebuildRequired": "Rebuild je vyžadován."
|
||||
},
|
||||
"keywords": {
|
||||
"settings": "nastavení",
|
||||
"userInterface": "uživatelské rozhraní",
|
||||
"scheduledJob": "naplánovaná akce",
|
||||
"integrations": "integrace",
|
||||
"authLog": "log autentizace",
|
||||
"authTokens": "autentizační tokeny",
|
||||
"entityManager": "správce entit",
|
||||
"templateManager": "správce šablon",
|
||||
"jobs": "úlohy",
|
||||
"authentication": "autentizace",
|
||||
"labelManager": "správce popisků",
|
||||
"appSecrets": "tajemství aplikace",
|
||||
"leadCapture": "zachycení potenciálů"
|
||||
},
|
||||
"tooltips": {
|
||||
"tabUrl": "URL záložky",
|
||||
"tabUrlAclScope": "ACL rozsah pro záložku URL"
|
||||
}
|
||||
}
|
||||
{
|
||||
"labels": {
|
||||
"Enabled": "Povoleno",
|
||||
"Disabled": "Zakázáno",
|
||||
"System": "Systém",
|
||||
"Users": "Uživatelé",
|
||||
"Customization": "Přizpůsobení",
|
||||
"Available Fields": "Dostupná pole",
|
||||
"Layout": "Vzhled",
|
||||
"Entity Manager": "Správa entit",
|
||||
"Add Panel": "Přidat panel",
|
||||
"Add Field": "Přidat pole",
|
||||
"Settings": "Nastavení",
|
||||
"Scheduled Jobs": "Naplánované akce",
|
||||
"Upgrade": "Aktualizace",
|
||||
"Clear Cache": "Vyčistit cache",
|
||||
"Rebuild": "Přestavět",
|
||||
"Teams": "Týmy",
|
||||
"Roles": "Role",
|
||||
"Portal": "Portál",
|
||||
"Portals": "Portály",
|
||||
"Portal Roles": "Role portálu",
|
||||
"Outbound Emails": "Odchozí emaily",
|
||||
"Group Email Accounts": "Skupinové e-mailové účty",
|
||||
"Personal Email Accounts": "Osobní e-mailové účty",
|
||||
"Inbound Emails": "Příchozí emaily",
|
||||
"Email Templates": "Šablony emailů",
|
||||
"Layout Manager": "Správa layoutu",
|
||||
"User Interface": "Uživatelské rozhraní",
|
||||
"Auth Tokens": "Autentizační tokeny",
|
||||
"Authentication": "Autentizace",
|
||||
"Currency": "Měna",
|
||||
"Integrations": "Integrace",
|
||||
"Extensions": "Rozšíření",
|
||||
"Upload": "Nahrát",
|
||||
"Installing...": "Instaluji...",
|
||||
"Upgrading...": "Upgraduji...",
|
||||
"Upgraded successfully": "Úspěšně upgradováno",
|
||||
"Installed successfully": "Úspěšně nainstalováno",
|
||||
"Ready for upgrade": "Připraveno k upgradu",
|
||||
"Run Upgrade": "Spustit upgrade",
|
||||
"Install": "Instalovat",
|
||||
"Ready for installation": "Připraveno k instalaci",
|
||||
"Uninstalling...": "Odebírám...",
|
||||
"Uninstalled": "Odebráno",
|
||||
"Create Entity": "Vytvořit entitu",
|
||||
"Edit Entity": "Upravit entitu",
|
||||
"Create Link": "Vytvořit vazbu",
|
||||
"Edit Link": "Upravit link",
|
||||
"Notifications": "Upozornění",
|
||||
"Jobs": "Joby",
|
||||
"Reset to Default": "Obnovit do základního nastavení",
|
||||
"Email Filters": "E-mailové filtry",
|
||||
"Portal Users": "Uživatelé portálu",
|
||||
"Action History": "Historie akcí",
|
||||
"Label Manager": "Správce labelů",
|
||||
"Auth Log": "Log autentizace",
|
||||
"Lead Capture": "Zachycení potenciálů",
|
||||
"Attachments": "Přílohy",
|
||||
"API Users": "API uživatelé",
|
||||
"Template Manager": "Správce šablon",
|
||||
"System Requirements": "Požadavky na systém",
|
||||
"PHP Settings": "Nastavení PHP",
|
||||
"Database Settings": "Nastavení databáze",
|
||||
"Permissions": "Oprávnění",
|
||||
"Success": "Úspěch",
|
||||
"Fail": "Selhání",
|
||||
"is recommended": "je doporučeno",
|
||||
"extension is missing": "rozšíření chybí",
|
||||
"PDF Templates": "PDF Šablony",
|
||||
"Webhooks": "Webhooky",
|
||||
"Dashboard Templates": "Šablony hlavních panelů",
|
||||
"Email Addresses": "Emailové adresy",
|
||||
"Phone Numbers": "Telefonní čísla",
|
||||
"Layout Sets": "Sady vzhledů",
|
||||
"Messaging": "Zprávy",
|
||||
"Misc": "Vedlejší",
|
||||
"Job Settings": "Nastavení jobů",
|
||||
"Configuration Instructions": "Instrukce k nastavení",
|
||||
"Formula Sandbox": "Pískoviště pro formula skripty",
|
||||
"Working Time Calendars": "Kalendáře pracovní doby",
|
||||
"Group Email Folders": "Složky skupinových e-mailů",
|
||||
"Authentication Providers": "Poskytovatelé autentizace",
|
||||
"Setup": "Nastavení",
|
||||
"App Log": "Log aplikace",
|
||||
"Address Countries": "Seznam zemí",
|
||||
"App Secrets": "Tajemství aplikace",
|
||||
"OAuth Providers": "OAuth poskytovatelé"
|
||||
},
|
||||
"layouts": {
|
||||
"list": "Seznam",
|
||||
"listSmall": "Seznam (malý)",
|
||||
"detailSmall": "Detail (malý)",
|
||||
"filters": "Vyhledávací filtry",
|
||||
"massUpdate": "Hromadný update",
|
||||
"relationships": "Vztah",
|
||||
"sidePanelsDetail": "Boční panely (Detail)",
|
||||
"sidePanelsEdit": "Boční panely (Upravit)",
|
||||
"sidePanelsDetailSmall": "Boční panely (Detail malé)",
|
||||
"sidePanelsEditSmall": "Boční panely (Upravit malé)",
|
||||
"detailPortal": "Detail (Portál)",
|
||||
"detailSmallPortal": "Detail (Small, Portál)",
|
||||
"listSmallPortal": "Seznam malý (Portál)",
|
||||
"listPortal": "Seznam (portál)",
|
||||
"relationshipsPortal": "Panely vztahů (Portál)",
|
||||
"defaultSidePanel": "Pole bočního panelu",
|
||||
"bottomPanelsDetail": "Spodní panely",
|
||||
"bottomPanelsEdit": "Spodní panely (Upravit)",
|
||||
"bottomPanelsDetailSmall": "Spodní panely (Detail malé)",
|
||||
"bottomPanelsEditSmall": "Spodní panely (Upravit malé)"
|
||||
},
|
||||
"fieldTypes": {
|
||||
"address": "Adresa",
|
||||
"array": "Pole",
|
||||
"foreign": "Cizí pole",
|
||||
"duration": "Trvání",
|
||||
"password": "Heslo",
|
||||
"personName": "Jméno osoby",
|
||||
"autoincrement": "Číslo (automaticky zvyšované)",
|
||||
"bool": "Ano/Ne",
|
||||
"currency": "Měna",
|
||||
"date": "Datum",
|
||||
"enum": "Výběr",
|
||||
"enumInt": "Výběr (číslo)",
|
||||
"enumFloat": "Výběr (desetinné číslo)",
|
||||
"float": "Číslo (desetinné)",
|
||||
"link": "Vazba",
|
||||
"linkMultiple": "Vazba (vícenásobná)",
|
||||
"linkParent": "Vazba (rodič)",
|
||||
"phone": "Telefon",
|
||||
"url": "URL adresa",
|
||||
"file": "Soubor",
|
||||
"image": "Obrázek",
|
||||
"multiEnum": "Výběr (vícenásobný)",
|
||||
"attachmentMultiple": "Více příloh",
|
||||
"rangeInt": "Rozsah (celé číslo)",
|
||||
"rangeFloat": "Rozsah (desetinné číslo)",
|
||||
"rangeCurrency": "Rozsah (měna)",
|
||||
"wysiwyg": "WYSIWYG editor",
|
||||
"map": "Mapa",
|
||||
"currencyConverted": "Měna (převedená)",
|
||||
"colorpicker": "Výběr barvy",
|
||||
"int": "Číslo (celé)",
|
||||
"number": "Číslo faktury",
|
||||
"jsonArray": "JSON pole",
|
||||
"jsonObject": "JSON objekt",
|
||||
"datetime": "Datum a čas",
|
||||
"datetimeOptional": "Datum/Datum a čas",
|
||||
"checklist": "Ano/Ne (seznam)",
|
||||
"linkOne": "Vazba (jednonásobná)",
|
||||
"barcode": "Čárový kód",
|
||||
"urlMultiple": "URL adresy (více)",
|
||||
"base": "Výchozí",
|
||||
"decimal": "Desetinné číslo"
|
||||
},
|
||||
"fields": {
|
||||
"type": "Typ",
|
||||
"name": "Jméno",
|
||||
"label": "Popisek",
|
||||
"required": "Povinné",
|
||||
"default": "Výchozí",
|
||||
"maxLength": "Maximální délka",
|
||||
"options": "Možnosti",
|
||||
"after": "Po (pole)",
|
||||
"before": "Před (pole)",
|
||||
"link": "Odkaz",
|
||||
"field": "Pole",
|
||||
"min": "Minimum",
|
||||
"max": "Maximum",
|
||||
"translation": "Překlad",
|
||||
"previewSize": "Velikost náhledu",
|
||||
"defaultType": "Výchozí typ",
|
||||
"seeMoreDisabled": "Zakázat ořez textu",
|
||||
"entityList": "Seznam entit",
|
||||
"isSorted": "Je seřazeno (abecedně)",
|
||||
"audited": "Auditováno",
|
||||
"trim": "Oříznout",
|
||||
"height": "Výška (px)",
|
||||
"minHeight": "Minimální výška (px)",
|
||||
"provider": "Poskytovatel",
|
||||
"typeList": "Seznam typů",
|
||||
"lengthOfCut": "Délka řezu",
|
||||
"sourceList": "Seznam zdrojů",
|
||||
"tooltipText": "Text nápovědy",
|
||||
"prefix": "Předpona",
|
||||
"nextNumber": "Další číslo",
|
||||
"padLength": "Délka výplně",
|
||||
"disableFormatting": "Zakázat formátování",
|
||||
"dynamicLogicVisible": "Podmínky, za kterých je pole viditelné",
|
||||
"dynamicLogicReadOnly": "Podmínky, za kterých je pole jenom pro čtení",
|
||||
"dynamicLogicRequired": "Podmínky, za kterých je pole povinné",
|
||||
"dynamicLogicOptions": "Podmíněné možnosti",
|
||||
"probabilityMap": "Pravděpodobnosti fáze (%)",
|
||||
"readOnly": "Pouze ke čtení",
|
||||
"noEmptyString": "Neprázdný řetězec",
|
||||
"maxFileSize": "Maximální velikost souboru (Mb)",
|
||||
"isPersonalData": "Jsou osobní údaje",
|
||||
"useIframe": "Použít iframe",
|
||||
"useNumericFormat": "Použít číselný formát",
|
||||
"strip": "Odstranit",
|
||||
"cutHeight": "Oříznout výšku (px)",
|
||||
"minuteStep": "Minutový krok",
|
||||
"inlineEditDisabled": "Zakázat samostatnou úpravu",
|
||||
"displayAsLabel": "Zobrazit jako štítek",
|
||||
"allowCustomOptions": "Povolit vlastní možnosti",
|
||||
"maxCount": "Maximální počet položek",
|
||||
"displayRawText": "Zobrazit holý text (bez označení)",
|
||||
"notActualOptions": "Neopravdové možnosti",
|
||||
"accept": "Přijmout",
|
||||
"displayAsList": "Zobrazit jako seznam",
|
||||
"viewMap": "Zobrazit mapu",
|
||||
"codeType": "Typ kódu",
|
||||
"lastChar": "Poslední znak",
|
||||
"listPreviewSize": "Velikost náhledu seznamu",
|
||||
"onlyDefaultCurrency": "Pouze výchozí měna",
|
||||
"dynamicLogicInvalid": "Podmínky, které pole dělají neplatným",
|
||||
"conversionDisabled": "Konverze zakázána",
|
||||
"decimalPlaces": "Počet desetinných míst",
|
||||
"pattern": "Vzor",
|
||||
"globalRestrictions": "Globální omezení",
|
||||
"decimal": "Desetinné",
|
||||
"optionsReference": "Odkaz na možnosti",
|
||||
"copyToClipboard": "Tlačítko na zkopírování do schránky",
|
||||
"rows": "Počet řádků textové oblasti",
|
||||
"readOnlyAfterCreate": "Pouze ke čtení po vytvoření",
|
||||
"createButton": "Tlačítko pro vytváření",
|
||||
"autocompleteOnEmpty": "Doplňování při prázdném poli",
|
||||
"relateOnImport": "Provázat při importu",
|
||||
"aclScope": "Entita pro acl",
|
||||
"onlyAdmin": "Pouze pro administrátory",
|
||||
"activeOptions": "Aktivní možnosti",
|
||||
"labelType": "Typ zobrazení",
|
||||
"preview": "Náhled",
|
||||
"attachmentField": "Pole pro přílohu",
|
||||
"dynamicLogicReadOnlySaved": "Podmínky, za kterých je pole jenom pro čtení (po uložení)",
|
||||
"notStorable": "Neuložitelné",
|
||||
"itemsEditable": "Upravitelné položky"
|
||||
},
|
||||
"messages": {
|
||||
"selectEntityType": "Vybrat entitu v levém menu.",
|
||||
"selectUpgradePackage": "Vybrat upgrade balíček",
|
||||
"selectLayout": "Vybrat požadovaný layout v levém menu a upravit ho.",
|
||||
"selectExtensionPackage": "Vybrat soubor s rozšířením",
|
||||
"extensionInstalled": "Rozšíření {name} {version} bylo nainstalováno.",
|
||||
"installExtension": "Rozšíření {name} {version} je připraveno k instalaci.",
|
||||
"upgradeBackup": "Doporučujeme zálohovat soubory a data EspoCRM před upgradem.",
|
||||
"thousandSeparatorEqualsDecimalMark": "Oddělovač tisíců nemůže být stejný jako desetinný symbol.",
|
||||
"userHasNoEmailAddress": "Uživatel nemá emailovou adresu.",
|
||||
"uninstallConfirmation": "Opravdu odinstalovat vybrané rozšíření?",
|
||||
"cronIsNotConfigured": "Naplánované úlohy nejsou spuštěny. Příchozí e-maily, oznámení a připomenutí proto nefungují. Postupujte podle [pokynů](https://www.espocrm.com/documentation/administration/server-configuration/#user-content-setup-a-crontab) k nastavení úlohy cron.",
|
||||
"newExtensionVersionIsAvailable": "Je k dispozici nová verze {latestName} {latestVersion}.",
|
||||
"upgradeVersion": "EspoCRM bude upgradováno na verzi <strong>{version}</strong>. Toto může chvíli trvat.",
|
||||
"upgradeDone": "EspoCRM bylo upgradováno na verzi <strong>{version}</strong>.",
|
||||
"downloadUpgradePackage": "Stáhnout upgradovací balíčky na [tomto]({url}) odkaze.",
|
||||
"upgradeInfo": "Přečtěte si [dokumentaci]({url}) o tom, jak upgradovat instanci EspoCRM.",
|
||||
"upgradeRecommendation": "Tento způsob upgradu se nedoporučuje. Je lepší upgradovat z CLI.",
|
||||
"newVersionIsAvailable": "K dispozici je nová verze EspoCRM {latestVersion}. Při aktualizaci instance postupujte podle [pokynů](https://www.espocrm.com/documentation/administration/upgrading/).",
|
||||
"formulaFunctions": "Funkce formula skriptů",
|
||||
"rebuildRequired": "Musíte spustit znovu rebuild z CLI.",
|
||||
"cronIsDisabled": "Cron je zakázán",
|
||||
"cacheIsDisabled": "Cache je zakázána"
|
||||
},
|
||||
"descriptions": {
|
||||
"settings": "Systémová nastavení aplikace.",
|
||||
"scheduledJob": "Činnosti vykonávané CRONem.",
|
||||
"upgrade": "Upgradovat EspoCRM.",
|
||||
"clearCache": "Vyčistit veškerou cache.",
|
||||
"rebuild": "Přestavět backend a vyčistit cache.",
|
||||
"users": "Správa uživatelů.",
|
||||
"teams": "Správa týmů.",
|
||||
"roles": "Správa rolí.",
|
||||
"portals": "Správa portálů.",
|
||||
"portalRoles": "Role pro portál.",
|
||||
"outboundEmails": "Nastavení SMTP pro odchozí emaily.",
|
||||
"groupEmailAccounts": "Skupinové IMAP emailové účty. Import emailů",
|
||||
"personalEmailAccounts": "E-mailové účty uživatelů.",
|
||||
"emailTemplates": "Šablony pro odchozí emaily.",
|
||||
"import": "Importovat data z CSV souboru.",
|
||||
"layoutManager": "Přizpůsobit layouty (seznam, detail, upravit, hledat, hromadný update).",
|
||||
"userInterface": "Nastavit uživatelské rozhraní.",
|
||||
"authTokens": "Aktivní autentizační sessions. IP adresa a datum posledního přístupu.",
|
||||
"authentication": "Nastavení autentizace.",
|
||||
"currency": "Nastavení měn a kurzů.",
|
||||
"extensions": "Instalovat a odebrat rozšíření.",
|
||||
"integrations": "Integrace se službami třetích stran.",
|
||||
"notifications": "Nastavení In-app a emailových upozornění.",
|
||||
"inboundEmails": "Nastavení příchozích mailů",
|
||||
"portalUsers": "Uživatelé portálu.",
|
||||
"entityManager": "Vytvořit vlastní entity, úpravit existující. Správa polí a vztahů.",
|
||||
"emailFilters": "E-mailové zprávy, které odpovídají zadanému filtru, nebudou importovány.",
|
||||
"actionHistory": "Protokol akcí uživatelů.",
|
||||
"labelManager": "Upravit popisky",
|
||||
"authLog": "Historie přihlášení.",
|
||||
"attachments": "Všechny přílohy souborů uložené v systému.",
|
||||
"templateManager": "Přizpůsobte si šablony zpráv.",
|
||||
"systemRequirements": "Systémové požadavky na EspoCRM.",
|
||||
"apiUsers": "Oddělte uživatele pro účely integrace.",
|
||||
"jobs": "Spustit akce na pozadí.",
|
||||
"pdfTemplates": "Šablony pro tisk do PDF.",
|
||||
"webhooks": "Správa webhooků.",
|
||||
"dashboardTemplates": "Umožňuje přidávat dashboardy uživatelům.",
|
||||
"phoneNumbers": "Všechna telefonní čísla uložená v systému.",
|
||||
"emailAddresses": "Všechny e-mailové adresy uložené v systému.",
|
||||
"layoutSets": "Kolekce layoutů, které lze přiřadit týmům a portálům.",
|
||||
"jobsSettings": "Nastavení zpracování jobů. Joby vykonávají úkoly na pozadí.",
|
||||
"sms": "Nastavení SMS.",
|
||||
"formulaSandbox": "Pískoviště pro testování formula skriptů bez ukládání změn.",
|
||||
"workingTimeCalendars": "Pracovní plány.",
|
||||
"groupEmailFolders": "Složky sdílené pro týmy",
|
||||
"authenticationProviders": "Další poskytovatelé autentizace pro portály.",
|
||||
"appLog": "Log aplikace.",
|
||||
"addressCountries": "Dostupné země pro políčka typu 'adresa'.",
|
||||
"appSecrets": "Pro ukládání citlivých informací jako jsou API klíče, hesla, a jiná tajemství.",
|
||||
"leadCapture": "Koncové body pro zachycení potenciálů a webové formuláře.",
|
||||
"oAuthProviders": "OAuth poskytovatelé pro integrace."
|
||||
},
|
||||
"options": {
|
||||
"previewSize": {
|
||||
"x-small": "Extra-malý",
|
||||
"small": "Malý",
|
||||
"medium": "Střední",
|
||||
"large": "Velký",
|
||||
"": "Prázdné"
|
||||
},
|
||||
"labelType": {
|
||||
"state": "Stav",
|
||||
"regular": "Výchozí"
|
||||
}
|
||||
},
|
||||
"logicalOperators": {
|
||||
"and": "a zároveň",
|
||||
"or": "nebo",
|
||||
"not": "negace"
|
||||
},
|
||||
"systemRequirements": {
|
||||
"requiredPhpVersion": "Požadovaná verze PHP",
|
||||
"requiredMysqlVersion": "Požadovaná verze MySQL",
|
||||
"host": "Jméno hostitele",
|
||||
"dbname": "Název databáze",
|
||||
"user": "Uživatel",
|
||||
"writable": "Zapisovatelné",
|
||||
"readable": "Čitelné",
|
||||
"requiredMariadbVersion": "Požadovaná verze MariaDB",
|
||||
"requiredPostgresqlVersion": "Požadovaná verze PostgreSQL"
|
||||
},
|
||||
"templates": {
|
||||
"accessInfo": "Přístupové údaje",
|
||||
"accessInfoPortal": "Přístupové údaje na portály",
|
||||
"assignment": "Úkol",
|
||||
"mention": "Zmínka",
|
||||
"notePost": "Poznámka k příspěvku",
|
||||
"notePostNoParent": "Poznámka k příspěvku (bez rodiče)",
|
||||
"noteStatus": "Poznámka k aktualizaci stavu",
|
||||
"passwordChangeLink": "Odkaz na změnu hesla",
|
||||
"noteEmailReceived": "Poznámka o přijatém e-mailu",
|
||||
"twoFactorCode": "Dvoufaktorový kód"
|
||||
},
|
||||
"strings": {
|
||||
"rebuildRequired": "Rebuild je vyžadován."
|
||||
},
|
||||
"keywords": {
|
||||
"settings": "nastavení",
|
||||
"userInterface": "uživatelské rozhraní",
|
||||
"scheduledJob": "naplánovaná akce",
|
||||
"integrations": "integrace",
|
||||
"authLog": "log autentizace",
|
||||
"authTokens": "autentizační tokeny",
|
||||
"entityManager": "správce entit",
|
||||
"templateManager": "správce šablon",
|
||||
"jobs": "úlohy",
|
||||
"authentication": "autentizace",
|
||||
"labelManager": "správce popisků",
|
||||
"appSecrets": "tajemství aplikace",
|
||||
"leadCapture": "zachycení potenciálů"
|
||||
},
|
||||
"tooltips": {
|
||||
"tabUrl": "URL záložky",
|
||||
"tabUrlAclScope": "ACL rozsah pro záložku URL"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,313 +1,313 @@
|
||||
{
|
||||
"fields": {
|
||||
"useCache": "Použít cache",
|
||||
"dateFormat": "Formát data",
|
||||
"timeFormat": "Formát času",
|
||||
"timeZone": "Časové pásmo",
|
||||
"weekStart": "První den v týdnu",
|
||||
"thousandSeparator": "Oddělovač tisíců",
|
||||
"decimalMark": "Desetinný oddělovač",
|
||||
"defaultCurrency": "Výchozí měna",
|
||||
"baseCurrency": "Bázová měna",
|
||||
"currencyRates": "Kurzy měn",
|
||||
"currencyList": "Seznam měn",
|
||||
"language": "Jazyk",
|
||||
"companyLogo": "Logo společnosti",
|
||||
"ldapPort": "LDAP Port",
|
||||
"ldapAuth": "LDAP Auth",
|
||||
"ldapSecurity": "Zabezpečení",
|
||||
"ldapPassword": "Heslo",
|
||||
"outboundEmailFromName": "Od (jméno)",
|
||||
"outboundEmailIsShared": "Sdílení",
|
||||
"recordsPerPage": "Záznamy na stránku",
|
||||
"recordsPerPageSmall": "Záznamy na stránku (malý)",
|
||||
"tabList": "Seznam záložek",
|
||||
"quickCreateList": "Rychlé odkazy",
|
||||
"exportDelimiter": "Export oddělovač",
|
||||
"globalSearchEntityList": "Seznam entit globálního vyhledávání",
|
||||
"authenticationMethod": "Autentizační metoda",
|
||||
"ldapHost": "LDAP Host",
|
||||
"ldapAccountCanonicalForm": "LDAP Account Canonical Form",
|
||||
"ldapAccountDomainName": "Název domény účtu",
|
||||
"ldapTryUsernameSplit": "Zkuste rozdělit uživatelské jméno",
|
||||
"ldapCreateEspoUser": "Vytvořit uživatele v EspoCRM",
|
||||
"ldapUserLoginFilter": "Filtr uživatelského přihlášení",
|
||||
"ldapAccountDomainNameShort": "Account Domain Name krátké",
|
||||
"ldapOptReferrals": "Volit doporučení",
|
||||
"exportDisabled": "Zakázat export (povolen pouze správce)",
|
||||
"b2cMode": "Režm B2C",
|
||||
"avatarsDisabled": "Zakázat avatary",
|
||||
"displayListViewRecordCount": "Zobrazit celkový počet (v zobrazení seznamu)",
|
||||
"theme": "Téma",
|
||||
"userThemesDisabled": "Zakázat uživatelské motivy",
|
||||
"emailMessageMaxSize": "Maximální velikost emailu (Mb)",
|
||||
"personalEmailMaxPortionSize": "Maximální velikost emailové části pro načítání osobních účtů",
|
||||
"inboundEmailMaxPortionSize": "Maximální velikost emailové části pro načítání skupinových účtů",
|
||||
"authTokenLifetime": "Životnost ověřovacího tokenu (hodiny)",
|
||||
"authTokenMaxIdleTime": "Maximální doba nečinnosti ověřovacího tokenu (hodiny)",
|
||||
"dashboardLayout": "Rozvržení Dashboardu (výchozí)",
|
||||
"siteUrl": "URL stránky",
|
||||
"addressPreview": "Náhled adresy",
|
||||
"addressFormat": "Formát adresy",
|
||||
"notificationSoundsDisabled": "Zakázat zvuky oznámení",
|
||||
"applicationName": "Název aplikace",
|
||||
"ldapUsername": "Uživatelské jméno",
|
||||
"ldapBindRequiresDn": "Přiřazení vyžaduje Dn",
|
||||
"ldapBaseDn": "Bázové Dn",
|
||||
"ldapUserNameAttribute": "Atribut uživatelského jména",
|
||||
"ldapUserObjectClass": "Třída objektu uživatele",
|
||||
"ldapUserTitleAttribute": "Atribut názvu uživatele",
|
||||
"ldapUserFirstNameAttribute": "Atribut křestního jména uživatele",
|
||||
"ldapUserLastNameAttribute": "Atribut příjmení uživatele",
|
||||
"ldapUserEmailAddressAttribute": "Atribut emailové adresy uživatele",
|
||||
"ldapUserTeams": "Týmy uživatele",
|
||||
"ldapUserDefaultTeam": "Výchozí tým uživatele",
|
||||
"ldapUserPhoneNumberAttribute": "Atribut telefonního čísla uživatele",
|
||||
"assignmentNotificationsEntityList": "Entity k upozornění podle přiřazení",
|
||||
"assignmentEmailNotifications": "Poslat emailová upozornění podle přiřazení",
|
||||
"assignmentEmailNotificationsEntityList": "Entity k upozornění emailem podle přiřazení",
|
||||
"streamEmailNotifications": "Oznámení o aktualizacích ve streamu pro interní uživatele",
|
||||
"portalStreamEmailNotifications": "Oznámení o aktualizacích ve streamu pro uživatele portálu",
|
||||
"streamEmailNotificationsEntityList": "Rozsahy emailových oznámení o streamu",
|
||||
"calendarEntityList": "Seznam entit kalendáře",
|
||||
"mentionEmailNotifications": "Zasílejte emailová oznámení o nových příspěvcích",
|
||||
"massEmailDisableMandatoryOptOutLink": "Zakázat povinný odkaz pro odhlášení",
|
||||
"activitiesEntityList": "Seznam entit aktivit",
|
||||
"historyEntityList": "Seznam entit historie",
|
||||
"currencyFormat": "Formát měny",
|
||||
"currencyDecimalPlaces": "Počet desetinných míst měny",
|
||||
"followCreatedEntities": "Sledovat vytvořené entity",
|
||||
"aclAllowDeleteCreated": "Povolit odebrání vytvořených záznamů",
|
||||
"adminNotifications": "Systémová oznámení v administračním panelu",
|
||||
"adminNotificationsNewVersion": "Zobrazit oznámení, až bude k dispozici nová verze CRM",
|
||||
"massEmailMaxPerHourCount": "Maximální počet e-mailů odeslaných za hodinu",
|
||||
"maxEmailAccountCount": "Maximální počet osobních emailových účtů na uživatele",
|
||||
"streamEmailNotificationsTypeList": "Na co upozorňovat",
|
||||
"authTokenPreventConcurrent": "Pouze jeden ověřovací token na uživatele",
|
||||
"scopeColorsDisabled": "Zakázat barvy rozsahu",
|
||||
"tabColorsDisabled": "Zakázat barvy záložek",
|
||||
"tabIconsDisabled": "Zakázat ikony na kartě",
|
||||
"textFilterUseContainsForVarchar": "Při filtrování polí varchar používat operátor „obsahuje“",
|
||||
"emailAddressIsOptedOutByDefault": "Označit nové emailové adresy jako odhlášené",
|
||||
"outboundEmailBccAddress": "Adresa BCC pro externí klienty",
|
||||
"adminNotificationsNewExtensionVersion": "Zobrazit oznámení, když jsou k dispozici nové verze rozšíření",
|
||||
"cleanupDeletedRecords": "Vyčistit smazané záznamy",
|
||||
"ldapPortalUserLdapAuth": "Pro uživatele portálu použijte ověřování LDAP",
|
||||
"ldapPortalUserPortals": "Výchozí portály pro uživatele portálu",
|
||||
"ldapPortalUserRoles": "Výchozí role pro uživatele portálu",
|
||||
"fiscalYearShift": "Začátek fiskálního roku",
|
||||
"jobRunInParallel": "Úlohy běží paralelně",
|
||||
"jobMaxPortion": "Maximální velikost části úloh",
|
||||
"jobPoolConcurrencyNumber": "Číslo souběhu úloh",
|
||||
"daemonInterval": "Interval démona",
|
||||
"daemonMaxProcessNumber": "Maximální počet procesů démona",
|
||||
"daemonProcessTimeout": "Timeout procesu démona",
|
||||
"addressCityList": "Seznam měst při našeptávání políčka adresa",
|
||||
"addressStateList": "Seznam států pro našeptávání adres",
|
||||
"cronDisabled": "Zakázat Cron",
|
||||
"maintenanceMode": "Režim údržby",
|
||||
"useWebSocket": "Použít WebSocket",
|
||||
"emailNotificationsDelay": "Zpoždění e-mailových oznámení (v sekundách)",
|
||||
"massEmailOpenTracking": "Sledování otevření emailů",
|
||||
"passwordRecoveryDisabled": "Zakázat obnovení hesla",
|
||||
"passwordRecoveryForAdminDisabled": "Zakázat obnovení hesla pro uživatele správce",
|
||||
"passwordGenerateLength": "Délka vygenerovaných hesel",
|
||||
"passwordStrengthLength": "Minimální délka hesla",
|
||||
"passwordStrengthLetterCount": "Počet písmen požadovaných v hesle",
|
||||
"passwordStrengthNumberCount": "Počet číslic požadovaných v hesle",
|
||||
"passwordStrengthBothCases": "Zabraňte vystavení e-mailové adresy ve formuláři pro obnovení hesla",
|
||||
"auth2FA": "Povolit dvoufaktorové ověřování",
|
||||
"auth2FAMethodList": "Dostupné metody dvoufaktorové autorizace",
|
||||
"personNameFormat": "Formát jména osoby",
|
||||
"newNotificationCountInTitle": "Zobrazit nové číslo oznámení v názvu stránky",
|
||||
"massEmailVerp": "Použít VERP",
|
||||
"emailAddressLookupEntityTypeList": "Rozsahy vyhledávání emailových adres",
|
||||
"busyRangesEntityList": "Seznam volných / zaneprázdněných entit",
|
||||
"passwordRecoveryForInternalUsersDisabled": "Zakázat obnovení hesla pro uživatele",
|
||||
"passwordRecoveryNoExposure": "Zabraňte vystavení emailové adresy ve formuláři pro obnovení hesla",
|
||||
"auth2FAForced": "Přimět uživatele k nastavení dvoufaktorové autorizace",
|
||||
"smsProvider": "Poskytovatel SMS",
|
||||
"outboundSmsFromNumber": "SMS z čísla",
|
||||
"recordsPerPageSelect": "Záznamy na stránku (Výběr)",
|
||||
"attachmentUploadMaxSize": "Maximální velikost přílohy (Mb)",
|
||||
"attachmentUploadChunkSize": "Velikost části nahrávání příloh (Mb)",
|
||||
"workingTimeCalendar": "Pracovní kalendář",
|
||||
"oidcClientId": "OIDC ID klienta",
|
||||
"oidcClientSecret": "OIDC tajný klíč klienta",
|
||||
"oidcAuthorizationRedirectUri": "OIDC URI přesměrování autorizace",
|
||||
"oidcAuthorizationEndpoint": "OIDC koncový bod autorizace",
|
||||
"oidcTokenEndpoint": "OIDC koncový bod tokenu",
|
||||
"oidcJwksEndpoint": "OIDC koncový bod JSON Web Key Set",
|
||||
"oidcJwtSignatureAlgorithmList": "OIDC povolené podpisové algoritmy JWT",
|
||||
"oidcScopes": "OIDC rozsahy",
|
||||
"oidcGroupClaim": "OIDC nárok skupiny",
|
||||
"oidcCreateUser": "OIDC vytvořit uživatele",
|
||||
"oidcUsernameClaim": "OIDC nárok uživatelského jména",
|
||||
"oidcTeams": "OIDC týmy",
|
||||
"oidcSync": "OIDC synchronizace",
|
||||
"oidcSyncTeams": "OIDC synchronizace týmů",
|
||||
"oidcFallback": "OIDC záložní přihlášení",
|
||||
"oidcAllowRegularUserFallback": "OIDC povolit záložní přihlášení běžným uživatelům",
|
||||
"oidcAllowAdminUser": "OIDC povolit přihlášení správcům",
|
||||
"oidcLogoutUrl": "OIDC URL odhlášení",
|
||||
"pdfEngine": "PDF generátor",
|
||||
"recordsPerPageKanban": "Záznamy na stránku (Kanban)",
|
||||
"auth2FAInPortal": "Povolit dvoufaktorové ověřování v portálech",
|
||||
"massEmailMaxPerBatchCount": "Maximální počet e-mailů odeslaných za dávku",
|
||||
"phoneNumberNumericSearch": "Číselné vyhledávání telefonních čísel",
|
||||
"phoneNumberInternational": "Mezinárodní telefonní čísla",
|
||||
"phoneNumberPreferredCountryList": "Upřednostňované země pro telefonního čísla",
|
||||
"jobForceUtc": "Vynutit UTC pro úlohy",
|
||||
"emailAddressSelectEntityTypeList": "Rozsahy výběru emailových adres",
|
||||
"phoneNumberExtensions": "Přípony telefonních čísel",
|
||||
"oidcAuthorizationPrompt": "OIDC výzva k autorizaci",
|
||||
"quickSearchFullTextAppendWildcard": "Rychlé vyhledávání přidat wildcard symbol",
|
||||
"authIpAddressCheck": "Omezovat přístup na základě IP adresy",
|
||||
"authIpAddressWhitelist": "Whitelist IP adres",
|
||||
"authIpAddressCheckExcludedUsers": "Uživatelé vyřazení z kontroly",
|
||||
"streamEmailWithContentEntityTypeList": "Entity s obsahem emailu v poznámkách streamu",
|
||||
"emailScheduledBatchCount": "Maximální počet naplánovaných e-mailů odeslaných za dávku",
|
||||
"passwordStrengthSpecialCharacterCount": "Počet speciálních znaků požadovaných v hesle",
|
||||
"availableReactions": "Dostupné reakce",
|
||||
"outboundEmailFromAddress": "Odesílatelská emailová adresa",
|
||||
"oidcUserInfoEndpoint": "OIDC koncový bod informací o uživateli",
|
||||
"baselineRole": "Základní role"
|
||||
},
|
||||
"tooltips": {
|
||||
"recordsPerPage": "Počet záznamů původně zobrazených v zobrazení seznamu.",
|
||||
"recordsPerPageSmall": "Počet záznamů v panelu vztahů.",
|
||||
"followCreatedEntities": "Pokud uživatel vytvoří záznam, bude jej sledovat automaticky.",
|
||||
"ldapUsername": "Úplné uživatelské jméno systému, které umožňuje vyhledávat další uživatele. Např. \"CN = uživatel systému LDAP, OU = uživatelé, OU = espocrm, DC = test, DC = lan\".",
|
||||
"ldapPassword": "Heslo pro přístup k serveru LDAP.",
|
||||
"ldapAuth": "Přístup k pověření serveru LDAP.",
|
||||
"ldapUserNameAttribute": "Atribut k identifikaci uživatele. \nNapř. „userPrincipalName“ nebo „sAMAccountName“ pro Active Directory, „uid“ pro OpenLDAP.",
|
||||
"ldapUserObjectClass": "Atribut ObjectClass pro vyhledávání uživatelů. Např. „osoba“ pro AD, „inetOrgPerson“ pro OpenLDAP.",
|
||||
"ldapBindRequiresDn": "Možnost formátovat uživatelské jméno ve formuláři DN.",
|
||||
"ldapBaseDn": "Výchozí základní DN používané pro vyhledávání uživatelů. Např. \"OU = uživatelé, OU = espocrm, DC = test, DC = lan\".",
|
||||
"ldapTryUsernameSplit": "Možnost rozdělit uživatelské jméno na doménu.",
|
||||
"ldapOptReferrals": "pokud by měla být sledována doporučení klientovi LDAP.",
|
||||
"ldapCreateEspoUser": "Tato možnost umožňuje AutoCRM vytvořit uživatele z LDAP.",
|
||||
"ldapUserFirstNameAttribute": "Atribut LDAP, který se používá k určení křestního jména uživatele. Např. \"křestní jméno\".",
|
||||
"ldapUserLastNameAttribute": "Atribut LDAP, který se používá k určení příjmení uživatele. Např. \"sn\".",
|
||||
"ldapUserTitleAttribute": "LDAP atribut pro titul uživatele.",
|
||||
"ldapUserEmailAddressAttribute": "Atribut LDAP, který se používá k určení e-mailové adresy uživatele. Např. \"pošta\".",
|
||||
"ldapUserPhoneNumberAttribute": "LDAP atribut pro telefonní číslo uživatele.",
|
||||
"ldapUserLoginFilter": "Filtr, který umožňuje omezit uživatele, kteří mohou používat AutoCRM. Např. \"memberOf = CN = espoGroup, OU = groups, OU = espocrm, DC = test, DC = lan\".",
|
||||
"ldapAccountDomainName": "Doména, která se používá k autorizaci k serveru LDAP.",
|
||||
"ldapAccountDomainNameShort": "Krátká doména, která se používá k autorizaci k serveru LDAP.",
|
||||
"ldapUserTeams": "LDAP týmy pro uživatele.",
|
||||
"ldapUserDefaultTeam": "Výchozí tým pro vytvořeného uživatele. Další informace najdete v uživatelském profilu.",
|
||||
"b2cMode": "Ve výchozím nastavení je AutoCRM přizpůsoben pro B2B. Můžete jej přepnout na B2C.",
|
||||
"aclStrictMode": "Povoleno: Přístup k rozsahům bude zakázán, pokud není uveden v rolích. \nZakázán: Přístup k rozsahům bude povolen, pokud není uveden v rolích.",
|
||||
"outboundEmailIsShared": "Povolit posílání emailů uživatelům pomocí SMTP.",
|
||||
"streamEmailNotificationsEntityList": "Emailová upozornění na aktualizace streamu sledovaných záznamů. Uživatelé budou dostávat e-mailová oznámení pouze pro určené typy entit.",
|
||||
"authTokenPreventConcurrent": "Uživatelé nebudou moci být přihlášeni na více zařízeních současně.",
|
||||
"ldapPortalUserLdapAuth": "Umožněte uživatelům portálu používat autentizaci LDAP namísto autentizace Auto.",
|
||||
"ldapPortalUserPortals": "Výchozí portály pro vytvořeného uživatele portálu",
|
||||
"ldapPortalUserRoles": "Výchozí role pro vytvořeného uživatele portálu",
|
||||
"jobPoolConcurrencyNumber": "Maximální počet procesů spuštěných současně.",
|
||||
"cronDisabled": "Cron se nespustí.",
|
||||
"maintenanceMode": "Do systému budou mít přístup pouze správci.",
|
||||
"ldapAccountCanonicalForm": "Typ kanonického formuláře vašeho účtu. K dispozici jsou 4 možnosti: \n- „Dn“ - formulář ve formátu „CN = tester, OU = espocrm, DC = test, DC = lan“. - „Uživatelské jméno“ - formulář „tester“ .- „Zpětné lomítko“ - formulář „SPOLEČNOST \\ tester“. - „Principal“ - formulář „tester@company.com“.",
|
||||
"massEmailVerp": "Variabilní zpětná cesta obálky. Pro lepší zpracování odražených zpráv. Ujistěte se, že to váš poskytovatel SMTP podporuje.",
|
||||
"addressStateList": "Návrhy států pro adresní pole.",
|
||||
"addressCityList": "Návrhy měst pro adresní pole.",
|
||||
"addressCountryList": "Návrhy zemí pro adresní pole.",
|
||||
"exportDisabled": "Zakázat export pro běžné uživatele.",
|
||||
"siteUrl": "URL vašeho CRM systému.",
|
||||
"useCache": "Nedoporučuje se deaktivovat, pokud se nejedná o účely vývoje.",
|
||||
"useWebSocket": "WebSocket umožňuje obousměrnou interaktivní komunikaci mezi serverem a prohlížečem. Vyžaduje nastavení démonu WebSocket na vašem serveru. Pro více informací se podívejte do dokumentace.",
|
||||
"emailNotificationsDelay": "Zprávu lze upravit ve stanoveném časovém rámci před odesláním oznámení.",
|
||||
"recordsPerPageSelect": "Počet záznamů na stránku ve výběru.",
|
||||
"workingTimeCalendar": "Pracovní kalendář pro zobrazení pracovní doby.",
|
||||
"oidcFallback": "Povolit záložní přihlášení.",
|
||||
"oidcCreateUser": "Automaticky vytvářet nové uživatele z OIDC.",
|
||||
"oidcSync": "Synchronizovat uživatelské údaje z OIDC.",
|
||||
"oidcSyncTeams": "Synchronizovat týmy z OIDC.",
|
||||
"oidcUsernameClaim": "OIDC nárok pro uživatelské jméno.",
|
||||
"oidcTeams": "OIDC týmy pro uživatele.",
|
||||
"recordsPerPageKanban": "Počet záznamů na stránku v Kanban zobrazení.",
|
||||
"jobForceUtc": "Použije časové pásmo UTC pro plánované úlohy. Jinak bude použito časové pásmo nastavené v nastavení.",
|
||||
"authIpAddressCheckExcludedUsers": "Uživatelé, kteří se budou moci přihlásit z jakéhokoli místa.",
|
||||
"authIpAddressWhitelist": "Seznam IP adres nebo rozsahů v notaci CIDR.\n\nPortály nejsou omezeny.",
|
||||
"oidcGroupClaim": "OIDC nárok pro skupinové informace.",
|
||||
"outboundEmailFromAddress": "Systémová emailová adresa.",
|
||||
"baselineRole": "Základní role definuje minimální úroveň přístupových práv pro všechny uživatele. Tato role je automaticky aplikována na všechny uživatele bez ohledu na jejich ostatní role.",
|
||||
"displayListViewRecordCount": "Zobrazit celkový počet záznamů v zobrazení seznamu.",
|
||||
"currencyList": "Dostupné měny v systému.",
|
||||
"activitiesEntityList": "Entity, které se považují za aktivity.",
|
||||
"historyEntityList": "Entity, které se považují za historii.",
|
||||
"calendarEntityList": "Entity zobrazené v kalendáři.",
|
||||
"globalSearchEntityList": "Entity dostupné v globálním vyhledávání.",
|
||||
"passwordRecoveryForInternalUsersDisabled": "Obnovit heslo budou moci pouze uživatelé portálu.",
|
||||
"passwordRecoveryNoExposure": "Nebude možné určit, zda je v systému zaregistrována konkrétní e-mailová adresa.",
|
||||
"emailAddressLookupEntityTypeList": "Pro automatické vyplňování emailových adres.",
|
||||
"emailAddressSelectEntityTypeList": "Rozsahy pro výběr emailových adres.",
|
||||
"busyRangesEntityList": "Co se bude brát v úvahu při zobrazování časových období zaneprázdnění v plánovači a časové ose.",
|
||||
"emailMessageMaxSize": "Všechny příchozí emaily přesahující stanovenou velikost budou načteny bez těla a příloh.",
|
||||
"authTokenLifetime": "Definuje, jak dlouho mohou existovat tokeny. \n0 - znamená žádné vypršení platnosti.",
|
||||
"authTokenMaxIdleTime": "Definuje, jak dlouho mohou existovat poslední přístupové tokeny. \n0 - znamená žádné vypršení platnosti.",
|
||||
"userThemesDisabled": "Pokud je zaškrtnuto, uživatelé nebudou moci vybrat jiné téma.",
|
||||
"currencyDecimalPlaces": "Počet desetinných míst. Pokud jsou prázdné, zobrazí se všechna neprázdná desetinná místa.",
|
||||
"aclAllowDeleteCreated": "Uživatelé budou moci odebrat záznamy, které vytvořili, i když nemají přístup k odstranění.",
|
||||
"textFilterUseContainsForVarchar": "Pokud není zaškrtnuto, použije se operátor „začíná na“. Můžete použít zástupný znak '%'.",
|
||||
"emailAddressIsOptedOutByDefault": "Při vytváření nového záznamu bude emailová adresa označena jako odhlášena.",
|
||||
"cleanupDeletedRecords": "Odebrané záznamy budou po chvíli z databáze odstraněny.",
|
||||
"jobRunInParallel": "Úlohy budou prováděny paralelně.",
|
||||
"jobMaxPortion": "Maximální počet zpracovaných úloh na jedno provedení.",
|
||||
"daemonInterval": "Interval spouštění démona v sekundách.",
|
||||
"daemonMaxProcessNumber": "Maximální počet procesů cron běžících současně.",
|
||||
"daemonProcessTimeout": "Maximální doba provedení (v sekundách) přidělená jednomu procesu cron.",
|
||||
"oidcLogoutUrl": "URL pro odhlášení z OIDC poskytovatele.",
|
||||
"quickSearchFullTextAppendWildcard": "Připojte zástupný znak k dotazu automatického dokončování, pokud je povoleno fulltextové vyhledávání. Snižuje to výkon vyhledávání."
|
||||
},
|
||||
"labels": {
|
||||
"System": "Systém",
|
||||
"Locale": "Lokalizace",
|
||||
"Configuration": "Konfigurace",
|
||||
"In-app Notifications": "In-app notifikace",
|
||||
"Email Notifications": "Email notifikace",
|
||||
"Currency Settings": "Nastavení měn",
|
||||
"Currency Rates": "Kurzy měn",
|
||||
"Mass Email": "Hromadný email",
|
||||
"Test Connection": "Test připojení",
|
||||
"Connecting": "Připojování...",
|
||||
"Activities": "Aktivity",
|
||||
"Admin Notifications": "Oznámení správce",
|
||||
"Search": "Vyhledat",
|
||||
"Misc": "Vedlejší",
|
||||
"Passwords": "Hesla",
|
||||
"2-Factor Authentication": "Dvoufaktorové ověřování",
|
||||
"Group Tab": "Skupina záložek",
|
||||
"Attachments": "Přílohy",
|
||||
"IdP Group": "IdP skupina",
|
||||
"Divider": "Oddělovač",
|
||||
"General": "Obecné",
|
||||
"Navbar": "Navigační panel",
|
||||
"Phone Numbers": "Telefonní čísla",
|
||||
"Access": "Přístup",
|
||||
"Strength": "Síla",
|
||||
"Recovery": "Obnovení",
|
||||
"Scheduled Send": "Naplánované odeslání"
|
||||
},
|
||||
"messages": {
|
||||
"ldapTestConnection": "Připojení bylo úspěšně navázáno.",
|
||||
"confirmBaselineRoleChange": "Opravdu chcete změnit základní roli? Tato změna ovlivní přístupová práva všech uživatelů."
|
||||
},
|
||||
"options": {
|
||||
"streamEmailNotificationsTypeList": {
|
||||
"Post": "Příspěvky",
|
||||
"Status": "Aktualizace stavu",
|
||||
"EmailReceived": "Přijaté emaily"
|
||||
},
|
||||
"personNameFormat": {
|
||||
"firstLast": "Jméno Příjmení",
|
||||
"lastFirst": "Příjmení Jméno",
|
||||
"firstMiddleLast": "Jméno Prostřední jméno Příjmení",
|
||||
"lastFirstMiddle": "Příjmení Jméno Prostřední jméno"
|
||||
},
|
||||
"auth2FAMethodList": {
|
||||
"Email": "E-mail"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"fields": {
|
||||
"useCache": "Použít cache",
|
||||
"dateFormat": "Formát data",
|
||||
"timeFormat": "Formát času",
|
||||
"timeZone": "Časové pásmo",
|
||||
"weekStart": "První den v týdnu",
|
||||
"thousandSeparator": "Oddělovač tisíců",
|
||||
"decimalMark": "Desetinný oddělovač",
|
||||
"defaultCurrency": "Výchozí měna",
|
||||
"baseCurrency": "Bázová měna",
|
||||
"currencyRates": "Kurzy měn",
|
||||
"currencyList": "Seznam měn",
|
||||
"language": "Jazyk",
|
||||
"companyLogo": "Logo společnosti",
|
||||
"ldapPort": "LDAP Port",
|
||||
"ldapAuth": "LDAP Auth",
|
||||
"ldapSecurity": "Zabezpečení",
|
||||
"ldapPassword": "Heslo",
|
||||
"outboundEmailFromName": "Od (jméno)",
|
||||
"outboundEmailIsShared": "Sdílení",
|
||||
"recordsPerPage": "Záznamy na stránku",
|
||||
"recordsPerPageSmall": "Záznamy na stránku (malý)",
|
||||
"tabList": "Seznam záložek",
|
||||
"quickCreateList": "Rychlé odkazy",
|
||||
"exportDelimiter": "Export oddělovač",
|
||||
"globalSearchEntityList": "Seznam entit globálního vyhledávání",
|
||||
"authenticationMethod": "Autentizační metoda",
|
||||
"ldapHost": "LDAP Host",
|
||||
"ldapAccountCanonicalForm": "LDAP Account Canonical Form",
|
||||
"ldapAccountDomainName": "Název domény účtu",
|
||||
"ldapTryUsernameSplit": "Zkuste rozdělit uživatelské jméno",
|
||||
"ldapCreateEspoUser": "Vytvořit uživatele v EspoCRM",
|
||||
"ldapUserLoginFilter": "Filtr uživatelského přihlášení",
|
||||
"ldapAccountDomainNameShort": "Account Domain Name krátké",
|
||||
"ldapOptReferrals": "Volit doporučení",
|
||||
"exportDisabled": "Zakázat export (povolen pouze správce)",
|
||||
"b2cMode": "Režm B2C",
|
||||
"avatarsDisabled": "Zakázat avatary",
|
||||
"displayListViewRecordCount": "Zobrazit celkový počet (v zobrazení seznamu)",
|
||||
"theme": "Téma",
|
||||
"userThemesDisabled": "Zakázat uživatelské motivy",
|
||||
"emailMessageMaxSize": "Maximální velikost emailu (Mb)",
|
||||
"personalEmailMaxPortionSize": "Maximální velikost emailové části pro načítání osobních účtů",
|
||||
"inboundEmailMaxPortionSize": "Maximální velikost emailové části pro načítání skupinových účtů",
|
||||
"authTokenLifetime": "Životnost ověřovacího tokenu (hodiny)",
|
||||
"authTokenMaxIdleTime": "Maximální doba nečinnosti ověřovacího tokenu (hodiny)",
|
||||
"dashboardLayout": "Rozvržení Dashboardu (výchozí)",
|
||||
"siteUrl": "URL stránky",
|
||||
"addressPreview": "Náhled adresy",
|
||||
"addressFormat": "Formát adresy",
|
||||
"notificationSoundsDisabled": "Zakázat zvuky oznámení",
|
||||
"applicationName": "Název aplikace",
|
||||
"ldapUsername": "Uživatelské jméno",
|
||||
"ldapBindRequiresDn": "Přiřazení vyžaduje Dn",
|
||||
"ldapBaseDn": "Bázové Dn",
|
||||
"ldapUserNameAttribute": "Atribut uživatelského jména",
|
||||
"ldapUserObjectClass": "Třída objektu uživatele",
|
||||
"ldapUserTitleAttribute": "Atribut názvu uživatele",
|
||||
"ldapUserFirstNameAttribute": "Atribut křestního jména uživatele",
|
||||
"ldapUserLastNameAttribute": "Atribut příjmení uživatele",
|
||||
"ldapUserEmailAddressAttribute": "Atribut emailové adresy uživatele",
|
||||
"ldapUserTeams": "Týmy uživatele",
|
||||
"ldapUserDefaultTeam": "Výchozí tým uživatele",
|
||||
"ldapUserPhoneNumberAttribute": "Atribut telefonního čísla uživatele",
|
||||
"assignmentNotificationsEntityList": "Entity k upozornění podle přiřazení",
|
||||
"assignmentEmailNotifications": "Poslat emailová upozornění podle přiřazení",
|
||||
"assignmentEmailNotificationsEntityList": "Entity k upozornění emailem podle přiřazení",
|
||||
"streamEmailNotifications": "Oznámení o aktualizacích ve streamu pro interní uživatele",
|
||||
"portalStreamEmailNotifications": "Oznámení o aktualizacích ve streamu pro uživatele portálu",
|
||||
"streamEmailNotificationsEntityList": "Rozsahy emailových oznámení o streamu",
|
||||
"calendarEntityList": "Seznam entit kalendáře",
|
||||
"mentionEmailNotifications": "Zasílejte emailová oznámení o nových příspěvcích",
|
||||
"massEmailDisableMandatoryOptOutLink": "Zakázat povinný odkaz pro odhlášení",
|
||||
"activitiesEntityList": "Seznam entit aktivit",
|
||||
"historyEntityList": "Seznam entit historie",
|
||||
"currencyFormat": "Formát měny",
|
||||
"currencyDecimalPlaces": "Počet desetinných míst měny",
|
||||
"followCreatedEntities": "Sledovat vytvořené entity",
|
||||
"aclAllowDeleteCreated": "Povolit odebrání vytvořených záznamů",
|
||||
"adminNotifications": "Systémová oznámení v administračním panelu",
|
||||
"adminNotificationsNewVersion": "Zobrazit oznámení, až bude k dispozici nová verze CRM",
|
||||
"massEmailMaxPerHourCount": "Maximální počet e-mailů odeslaných za hodinu",
|
||||
"maxEmailAccountCount": "Maximální počet osobních emailových účtů na uživatele",
|
||||
"streamEmailNotificationsTypeList": "Na co upozorňovat",
|
||||
"authTokenPreventConcurrent": "Pouze jeden ověřovací token na uživatele",
|
||||
"scopeColorsDisabled": "Zakázat barvy rozsahu",
|
||||
"tabColorsDisabled": "Zakázat barvy záložek",
|
||||
"tabIconsDisabled": "Zakázat ikony na kartě",
|
||||
"textFilterUseContainsForVarchar": "Při filtrování polí varchar používat operátor „obsahuje“",
|
||||
"emailAddressIsOptedOutByDefault": "Označit nové emailové adresy jako odhlášené",
|
||||
"outboundEmailBccAddress": "Adresa BCC pro externí klienty",
|
||||
"adminNotificationsNewExtensionVersion": "Zobrazit oznámení, když jsou k dispozici nové verze rozšíření",
|
||||
"cleanupDeletedRecords": "Vyčistit smazané záznamy",
|
||||
"ldapPortalUserLdapAuth": "Pro uživatele portálu použijte ověřování LDAP",
|
||||
"ldapPortalUserPortals": "Výchozí portály pro uživatele portálu",
|
||||
"ldapPortalUserRoles": "Výchozí role pro uživatele portálu",
|
||||
"fiscalYearShift": "Začátek fiskálního roku",
|
||||
"jobRunInParallel": "Úlohy běží paralelně",
|
||||
"jobMaxPortion": "Maximální velikost části úloh",
|
||||
"jobPoolConcurrencyNumber": "Číslo souběhu úloh",
|
||||
"daemonInterval": "Interval démona",
|
||||
"daemonMaxProcessNumber": "Maximální počet procesů démona",
|
||||
"daemonProcessTimeout": "Timeout procesu démona",
|
||||
"addressCityList": "Seznam měst při našeptávání políčka adresa",
|
||||
"addressStateList": "Seznam států pro našeptávání adres",
|
||||
"cronDisabled": "Zakázat Cron",
|
||||
"maintenanceMode": "Režim údržby",
|
||||
"useWebSocket": "Použít WebSocket",
|
||||
"emailNotificationsDelay": "Zpoždění e-mailových oznámení (v sekundách)",
|
||||
"massEmailOpenTracking": "Sledování otevření emailů",
|
||||
"passwordRecoveryDisabled": "Zakázat obnovení hesla",
|
||||
"passwordRecoveryForAdminDisabled": "Zakázat obnovení hesla pro uživatele správce",
|
||||
"passwordGenerateLength": "Délka vygenerovaných hesel",
|
||||
"passwordStrengthLength": "Minimální délka hesla",
|
||||
"passwordStrengthLetterCount": "Počet písmen požadovaných v hesle",
|
||||
"passwordStrengthNumberCount": "Počet číslic požadovaných v hesle",
|
||||
"passwordStrengthBothCases": "Zabraňte vystavení e-mailové adresy ve formuláři pro obnovení hesla",
|
||||
"auth2FA": "Povolit dvoufaktorové ověřování",
|
||||
"auth2FAMethodList": "Dostupné metody dvoufaktorové autorizace",
|
||||
"personNameFormat": "Formát jména osoby",
|
||||
"newNotificationCountInTitle": "Zobrazit nové číslo oznámení v názvu stránky",
|
||||
"massEmailVerp": "Použít VERP",
|
||||
"emailAddressLookupEntityTypeList": "Rozsahy vyhledávání emailových adres",
|
||||
"busyRangesEntityList": "Seznam volných / zaneprázdněných entit",
|
||||
"passwordRecoveryForInternalUsersDisabled": "Zakázat obnovení hesla pro uživatele",
|
||||
"passwordRecoveryNoExposure": "Zabraňte vystavení emailové adresy ve formuláři pro obnovení hesla",
|
||||
"auth2FAForced": "Přimět uživatele k nastavení dvoufaktorové autorizace",
|
||||
"smsProvider": "Poskytovatel SMS",
|
||||
"outboundSmsFromNumber": "SMS z čísla",
|
||||
"recordsPerPageSelect": "Záznamy na stránku (Výběr)",
|
||||
"attachmentUploadMaxSize": "Maximální velikost přílohy (Mb)",
|
||||
"attachmentUploadChunkSize": "Velikost části nahrávání příloh (Mb)",
|
||||
"workingTimeCalendar": "Pracovní kalendář",
|
||||
"oidcClientId": "OIDC ID klienta",
|
||||
"oidcClientSecret": "OIDC tajný klíč klienta",
|
||||
"oidcAuthorizationRedirectUri": "OIDC URI přesměrování autorizace",
|
||||
"oidcAuthorizationEndpoint": "OIDC koncový bod autorizace",
|
||||
"oidcTokenEndpoint": "OIDC koncový bod tokenu",
|
||||
"oidcJwksEndpoint": "OIDC koncový bod JSON Web Key Set",
|
||||
"oidcJwtSignatureAlgorithmList": "OIDC povolené podpisové algoritmy JWT",
|
||||
"oidcScopes": "OIDC rozsahy",
|
||||
"oidcGroupClaim": "OIDC nárok skupiny",
|
||||
"oidcCreateUser": "OIDC vytvořit uživatele",
|
||||
"oidcUsernameClaim": "OIDC nárok uživatelského jména",
|
||||
"oidcTeams": "OIDC týmy",
|
||||
"oidcSync": "OIDC synchronizace",
|
||||
"oidcSyncTeams": "OIDC synchronizace týmů",
|
||||
"oidcFallback": "OIDC záložní přihlášení",
|
||||
"oidcAllowRegularUserFallback": "OIDC povolit záložní přihlášení běžným uživatelům",
|
||||
"oidcAllowAdminUser": "OIDC povolit přihlášení správcům",
|
||||
"oidcLogoutUrl": "OIDC URL odhlášení",
|
||||
"pdfEngine": "PDF generátor",
|
||||
"recordsPerPageKanban": "Záznamy na stránku (Kanban)",
|
||||
"auth2FAInPortal": "Povolit dvoufaktorové ověřování v portálech",
|
||||
"massEmailMaxPerBatchCount": "Maximální počet e-mailů odeslaných za dávku",
|
||||
"phoneNumberNumericSearch": "Číselné vyhledávání telefonních čísel",
|
||||
"phoneNumberInternational": "Mezinárodní telefonní čísla",
|
||||
"phoneNumberPreferredCountryList": "Upřednostňované země pro telefonního čísla",
|
||||
"jobForceUtc": "Vynutit UTC pro úlohy",
|
||||
"emailAddressSelectEntityTypeList": "Rozsahy výběru emailových adres",
|
||||
"phoneNumberExtensions": "Přípony telefonních čísel",
|
||||
"oidcAuthorizationPrompt": "OIDC výzva k autorizaci",
|
||||
"quickSearchFullTextAppendWildcard": "Rychlé vyhledávání přidat wildcard symbol",
|
||||
"authIpAddressCheck": "Omezovat přístup na základě IP adresy",
|
||||
"authIpAddressWhitelist": "Whitelist IP adres",
|
||||
"authIpAddressCheckExcludedUsers": "Uživatelé vyřazení z kontroly",
|
||||
"streamEmailWithContentEntityTypeList": "Entity s obsahem emailu v poznámkách streamu",
|
||||
"emailScheduledBatchCount": "Maximální počet naplánovaných e-mailů odeslaných za dávku",
|
||||
"passwordStrengthSpecialCharacterCount": "Počet speciálních znaků požadovaných v hesle",
|
||||
"availableReactions": "Dostupné reakce",
|
||||
"outboundEmailFromAddress": "Odesílatelská emailová adresa",
|
||||
"oidcUserInfoEndpoint": "OIDC koncový bod informací o uživateli",
|
||||
"baselineRole": "Základní role"
|
||||
},
|
||||
"tooltips": {
|
||||
"recordsPerPage": "Počet záznamů původně zobrazených v zobrazení seznamu.",
|
||||
"recordsPerPageSmall": "Počet záznamů v panelu vztahů.",
|
||||
"followCreatedEntities": "Pokud uživatel vytvoří záznam, bude jej sledovat automaticky.",
|
||||
"ldapUsername": "Úplné uživatelské jméno systému, které umožňuje vyhledávat další uživatele. Např. \"CN = uživatel systému LDAP, OU = uživatelé, OU = espocrm, DC = test, DC = lan\".",
|
||||
"ldapPassword": "Heslo pro přístup k serveru LDAP.",
|
||||
"ldapAuth": "Přístup k pověření serveru LDAP.",
|
||||
"ldapUserNameAttribute": "Atribut k identifikaci uživatele. \nNapř. „userPrincipalName“ nebo „sAMAccountName“ pro Active Directory, „uid“ pro OpenLDAP.",
|
||||
"ldapUserObjectClass": "Atribut ObjectClass pro vyhledávání uživatelů. Např. „osoba“ pro AD, „inetOrgPerson“ pro OpenLDAP.",
|
||||
"ldapBindRequiresDn": "Možnost formátovat uživatelské jméno ve formuláři DN.",
|
||||
"ldapBaseDn": "Výchozí základní DN používané pro vyhledávání uživatelů. Např. \"OU = uživatelé, OU = espocrm, DC = test, DC = lan\".",
|
||||
"ldapTryUsernameSplit": "Možnost rozdělit uživatelské jméno na doménu.",
|
||||
"ldapOptReferrals": "pokud by měla být sledována doporučení klientovi LDAP.",
|
||||
"ldapCreateEspoUser": "Tato možnost umožňuje EspoCRM vytvořit uživatele z LDAP.",
|
||||
"ldapUserFirstNameAttribute": "Atribut LDAP, který se používá k určení křestního jména uživatele. Např. \"křestní jméno\".",
|
||||
"ldapUserLastNameAttribute": "Atribut LDAP, který se používá k určení příjmení uživatele. Např. \"sn\".",
|
||||
"ldapUserTitleAttribute": "LDAP atribut pro titul uživatele.",
|
||||
"ldapUserEmailAddressAttribute": "Atribut LDAP, který se používá k určení e-mailové adresy uživatele. Např. \"pošta\".",
|
||||
"ldapUserPhoneNumberAttribute": "LDAP atribut pro telefonní číslo uživatele.",
|
||||
"ldapUserLoginFilter": "Filtr, který umožňuje omezit uživatele, kteří mohou používat EspoCRM. Např. \"memberOf = CN = espoGroup, OU = groups, OU = espocrm, DC = test, DC = lan\".",
|
||||
"ldapAccountDomainName": "Doména, která se používá k autorizaci k serveru LDAP.",
|
||||
"ldapAccountDomainNameShort": "Krátká doména, která se používá k autorizaci k serveru LDAP.",
|
||||
"ldapUserTeams": "LDAP týmy pro uživatele.",
|
||||
"ldapUserDefaultTeam": "Výchozí tým pro vytvořeného uživatele. Další informace najdete v uživatelském profilu.",
|
||||
"b2cMode": "Ve výchozím nastavení je EspoCRM přizpůsoben pro B2B. Můžete jej přepnout na B2C.",
|
||||
"aclStrictMode": "Povoleno: Přístup k rozsahům bude zakázán, pokud není uveden v rolích. \nZakázán: Přístup k rozsahům bude povolen, pokud není uveden v rolích.",
|
||||
"outboundEmailIsShared": "Povolit posílání emailů uživatelům pomocí SMTP.",
|
||||
"streamEmailNotificationsEntityList": "Emailová upozornění na aktualizace streamu sledovaných záznamů. Uživatelé budou dostávat e-mailová oznámení pouze pro určené typy entit.",
|
||||
"authTokenPreventConcurrent": "Uživatelé nebudou moci být přihlášeni na více zařízeních současně.",
|
||||
"ldapPortalUserLdapAuth": "Umožněte uživatelům portálu používat autentizaci LDAP namísto autentizace Auto.",
|
||||
"ldapPortalUserPortals": "Výchozí portály pro vytvořeného uživatele portálu",
|
||||
"ldapPortalUserRoles": "Výchozí role pro vytvořeného uživatele portálu",
|
||||
"jobPoolConcurrencyNumber": "Maximální počet procesů spuštěných současně.",
|
||||
"cronDisabled": "Cron se nespustí.",
|
||||
"maintenanceMode": "Do systému budou mít přístup pouze správci.",
|
||||
"ldapAccountCanonicalForm": "Typ kanonického formuláře vašeho účtu. K dispozici jsou 4 možnosti: \n- „Dn“ - formulář ve formátu „CN = tester, OU = espocrm, DC = test, DC = lan“. - „Uživatelské jméno“ - formulář „tester“ .- „Zpětné lomítko“ - formulář „SPOLEČNOST \\ tester“. - „Principal“ - formulář „tester@company.com“.",
|
||||
"massEmailVerp": "Variabilní zpětná cesta obálky. Pro lepší zpracování odražených zpráv. Ujistěte se, že to váš poskytovatel SMTP podporuje.",
|
||||
"addressStateList": "Návrhy států pro adresní pole.",
|
||||
"addressCityList": "Návrhy měst pro adresní pole.",
|
||||
"addressCountryList": "Návrhy zemí pro adresní pole.",
|
||||
"exportDisabled": "Zakázat export pro běžné uživatele.",
|
||||
"siteUrl": "URL vašeho CRM systému.",
|
||||
"useCache": "Nedoporučuje se deaktivovat, pokud se nejedná o účely vývoje.",
|
||||
"useWebSocket": "WebSocket umožňuje obousměrnou interaktivní komunikaci mezi serverem a prohlížečem. Vyžaduje nastavení démonu WebSocket na vašem serveru. Pro více informací se podívejte do dokumentace.",
|
||||
"emailNotificationsDelay": "Zprávu lze upravit ve stanoveném časovém rámci před odesláním oznámení.",
|
||||
"recordsPerPageSelect": "Počet záznamů na stránku ve výběru.",
|
||||
"workingTimeCalendar": "Pracovní kalendář pro zobrazení pracovní doby.",
|
||||
"oidcFallback": "Povolit záložní přihlášení.",
|
||||
"oidcCreateUser": "Automaticky vytvářet nové uživatele z OIDC.",
|
||||
"oidcSync": "Synchronizovat uživatelské údaje z OIDC.",
|
||||
"oidcSyncTeams": "Synchronizovat týmy z OIDC.",
|
||||
"oidcUsernameClaim": "OIDC nárok pro uživatelské jméno.",
|
||||
"oidcTeams": "OIDC týmy pro uživatele.",
|
||||
"recordsPerPageKanban": "Počet záznamů na stránku v Kanban zobrazení.",
|
||||
"jobForceUtc": "Použije časové pásmo UTC pro plánované úlohy. Jinak bude použito časové pásmo nastavené v nastavení.",
|
||||
"authIpAddressCheckExcludedUsers": "Uživatelé, kteří se budou moci přihlásit z jakéhokoli místa.",
|
||||
"authIpAddressWhitelist": "Seznam IP adres nebo rozsahů v notaci CIDR.\n\nPortály nejsou omezeny.",
|
||||
"oidcGroupClaim": "OIDC nárok pro skupinové informace.",
|
||||
"outboundEmailFromAddress": "Systémová emailová adresa.",
|
||||
"baselineRole": "Základní role definuje minimální úroveň přístupových práv pro všechny uživatele. Tato role je automaticky aplikována na všechny uživatele bez ohledu na jejich ostatní role.",
|
||||
"displayListViewRecordCount": "Zobrazit celkový počet záznamů v zobrazení seznamu.",
|
||||
"currencyList": "Dostupné měny v systému.",
|
||||
"activitiesEntityList": "Entity, které se považují za aktivity.",
|
||||
"historyEntityList": "Entity, které se považují za historii.",
|
||||
"calendarEntityList": "Entity zobrazené v kalendáři.",
|
||||
"globalSearchEntityList": "Entity dostupné v globálním vyhledávání.",
|
||||
"passwordRecoveryForInternalUsersDisabled": "Obnovit heslo budou moci pouze uživatelé portálu.",
|
||||
"passwordRecoveryNoExposure": "Nebude možné určit, zda je v systému zaregistrována konkrétní e-mailová adresa.",
|
||||
"emailAddressLookupEntityTypeList": "Pro automatické vyplňování emailových adres.",
|
||||
"emailAddressSelectEntityTypeList": "Rozsahy pro výběr emailových adres.",
|
||||
"busyRangesEntityList": "Co se bude brát v úvahu při zobrazování časových období zaneprázdnění v plánovači a časové ose.",
|
||||
"emailMessageMaxSize": "Všechny příchozí emaily přesahující stanovenou velikost budou načteny bez těla a příloh.",
|
||||
"authTokenLifetime": "Definuje, jak dlouho mohou existovat tokeny. \n0 - znamená žádné vypršení platnosti.",
|
||||
"authTokenMaxIdleTime": "Definuje, jak dlouho mohou existovat poslední přístupové tokeny. \n0 - znamená žádné vypršení platnosti.",
|
||||
"userThemesDisabled": "Pokud je zaškrtnuto, uživatelé nebudou moci vybrat jiné téma.",
|
||||
"currencyDecimalPlaces": "Počet desetinných míst. Pokud jsou prázdné, zobrazí se všechna neprázdná desetinná místa.",
|
||||
"aclAllowDeleteCreated": "Uživatelé budou moci odebrat záznamy, které vytvořili, i když nemají přístup k odstranění.",
|
||||
"textFilterUseContainsForVarchar": "Pokud není zaškrtnuto, použije se operátor „začíná na“. Můžete použít zástupný znak '%'.",
|
||||
"emailAddressIsOptedOutByDefault": "Při vytváření nového záznamu bude emailová adresa označena jako odhlášena.",
|
||||
"cleanupDeletedRecords": "Odebrané záznamy budou po chvíli z databáze odstraněny.",
|
||||
"jobRunInParallel": "Úlohy budou prováděny paralelně.",
|
||||
"jobMaxPortion": "Maximální počet zpracovaných úloh na jedno provedení.",
|
||||
"daemonInterval": "Interval spouštění démona v sekundách.",
|
||||
"daemonMaxProcessNumber": "Maximální počet procesů cron běžících současně.",
|
||||
"daemonProcessTimeout": "Maximální doba provedení (v sekundách) přidělená jednomu procesu cron.",
|
||||
"oidcLogoutUrl": "URL pro odhlášení z OIDC poskytovatele.",
|
||||
"quickSearchFullTextAppendWildcard": "Připojte zástupný znak k dotazu automatického dokončování, pokud je povoleno fulltextové vyhledávání. Snižuje to výkon vyhledávání."
|
||||
},
|
||||
"labels": {
|
||||
"System": "Systém",
|
||||
"Locale": "Lokalizace",
|
||||
"Configuration": "Konfigurace",
|
||||
"In-app Notifications": "In-app notifikace",
|
||||
"Email Notifications": "Email notifikace",
|
||||
"Currency Settings": "Nastavení měn",
|
||||
"Currency Rates": "Kurzy měn",
|
||||
"Mass Email": "Hromadný email",
|
||||
"Test Connection": "Test připojení",
|
||||
"Connecting": "Připojování...",
|
||||
"Activities": "Aktivity",
|
||||
"Admin Notifications": "Oznámení správce",
|
||||
"Search": "Vyhledat",
|
||||
"Misc": "Vedlejší",
|
||||
"Passwords": "Hesla",
|
||||
"2-Factor Authentication": "Dvoufaktorové ověřování",
|
||||
"Group Tab": "Skupina záložek",
|
||||
"Attachments": "Přílohy",
|
||||
"IdP Group": "IdP skupina",
|
||||
"Divider": "Oddělovač",
|
||||
"General": "Obecné",
|
||||
"Navbar": "Navigační panel",
|
||||
"Phone Numbers": "Telefonní čísla",
|
||||
"Access": "Přístup",
|
||||
"Strength": "Síla",
|
||||
"Recovery": "Obnovení",
|
||||
"Scheduled Send": "Naplánované odeslání"
|
||||
},
|
||||
"messages": {
|
||||
"ldapTestConnection": "Připojení bylo úspěšně navázáno.",
|
||||
"confirmBaselineRoleChange": "Opravdu chcete změnit základní roli? Tato změna ovlivní přístupová práva všech uživatelů."
|
||||
},
|
||||
"options": {
|
||||
"streamEmailNotificationsTypeList": {
|
||||
"Post": "Příspěvky",
|
||||
"Status": "Aktualizace stavu",
|
||||
"EmailReceived": "Přijaté emaily"
|
||||
},
|
||||
"personNameFormat": {
|
||||
"firstLast": "Jméno Příjmení",
|
||||
"lastFirst": "Příjmení Jméno",
|
||||
"firstMiddleLast": "Jméno Prostřední jméno Příjmení",
|
||||
"lastFirstMiddle": "Příjmení Jméno Prostřední jméno"
|
||||
},
|
||||
"auth2FAMethodList": {
|
||||
"Email": "E-mail"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class UploadUrlService
|
||||
*/
|
||||
public function uploadImage(string $url, FieldData $data): Attachment
|
||||
{
|
||||
if (!$this->urlCheck->isNotInternalUrl($url)) {
|
||||
if (!$this->urlCheck->isUrlAndNotIternal($url)) {
|
||||
throw new ForbiddenSilent("Not allowed URL.");
|
||||
}
|
||||
|
||||
@@ -114,9 +114,20 @@ class UploadUrlService
|
||||
/**
|
||||
* @param non-empty-string $url
|
||||
* @return ?array{string, string} A type and contents.
|
||||
* @throws ForbiddenSilent
|
||||
*/
|
||||
private function getImageDataByUrl(string $url): ?array
|
||||
{
|
||||
$resolve = $this->urlCheck->getCurlResolve($url);
|
||||
|
||||
if ($resolve === []) {
|
||||
throw new ForbiddenSilent("Could not resolve the host.");
|
||||
}
|
||||
|
||||
if ($resolve !== null && !$this->urlCheck->validateCurlResolveNotInternal($resolve)) {
|
||||
throw new ForbiddenSilent("Forbidden host.");
|
||||
}
|
||||
|
||||
$type = null;
|
||||
|
||||
if (!function_exists('curl_init')) {
|
||||
@@ -144,6 +155,10 @@ class UploadUrlService
|
||||
$opts[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTPS | \CURLPROTO_HTTP;
|
||||
$opts[\CURLOPT_REDIR_PROTOCOLS] = \CURLPROTO_HTTPS;
|
||||
|
||||
if ($resolve) {
|
||||
$opts[CURLOPT_RESOLVE] = $resolve;
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, $opts);
|
||||
|
||||
@@ -36,8 +36,11 @@ use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Entities\Attachment;
|
||||
use Espo\Entities\Email;
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Tools\Email\ImportEmlService;
|
||||
|
||||
/**
|
||||
@@ -49,6 +52,7 @@ class PostImportEml implements Action
|
||||
private Acl $acl,
|
||||
private User $user,
|
||||
private ImportEmlService $service,
|
||||
private EntityManager $entityManager,
|
||||
) {}
|
||||
|
||||
public function process(Request $request): Response
|
||||
@@ -61,11 +65,32 @@ class PostImportEml implements Action
|
||||
throw new BadRequest("No 'fileId'.");
|
||||
}
|
||||
|
||||
$email = $this->service->import($fileId, $this->user->getId());
|
||||
$attachment = $this->getAttachment($fileId);
|
||||
|
||||
$email = $this->service->import($attachment, $this->user->getId());
|
||||
|
||||
return ResponseComposer::json(['id' => $email->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
* @throws Forbidden
|
||||
*/
|
||||
private function getAttachment(string $fileId): Attachment
|
||||
{
|
||||
$attachment = $this->entityManager->getRDBRepositoryByClass(Attachment::class)->getById($fileId);
|
||||
|
||||
if (!$attachment) {
|
||||
throw new NotFound("Attachment not found.");
|
||||
}
|
||||
|
||||
if (!$this->acl->checkEntityRead($attachment)) {
|
||||
throw new Forbidden("No access to attachment.");
|
||||
}
|
||||
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
*/
|
||||
|
||||
@@ -115,7 +115,7 @@ class PostSendTest implements Action
|
||||
|
||||
if (
|
||||
!$this->addressUtil->isAllowedAddress($smtpParams) &&
|
||||
!$this->hostCheck->isNotInternalHost($server)
|
||||
!$this->hostCheck->isHostAndNotInternal($server)
|
||||
) {
|
||||
throw new Forbidden("Not allowed internal host.");
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace Espo\Tools\Email;
|
||||
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\Core\Exceptions\Error;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\FileStorage\Manager;
|
||||
use Espo\Core\Mail\Exceptions\ImapError;
|
||||
use Espo\Core\Mail\Importer;
|
||||
@@ -56,16 +55,13 @@ class ImportEmlService
|
||||
/**
|
||||
* Import an EML.
|
||||
*
|
||||
* @param string $fileId An attachment ID.
|
||||
* @param ?string $userId A user ID to relate an email with.
|
||||
* @return Email An Email.
|
||||
* @throws NotFound
|
||||
* @throws Error
|
||||
* @throws Conflict
|
||||
*/
|
||||
public function import(string $fileId, ?string $userId = null): Email
|
||||
public function import(Attachment $attachment, ?string $userId = null): Email
|
||||
{
|
||||
$attachment = $this->getAttachment($fileId);
|
||||
$contents = $this->fileStorageManager->getContents($attachment);
|
||||
|
||||
try {
|
||||
@@ -93,20 +89,6 @@ class ImportEmlService
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
private function getAttachment(string $fileId): Attachment
|
||||
{
|
||||
$attachment = $this->entityManager->getRDBRepositoryByClass(Attachment::class)->getById($fileId);
|
||||
|
||||
if (!$attachment) {
|
||||
throw new NotFound("Attachment not found.");
|
||||
}
|
||||
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Conflict
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@ use Espo\Core\Notification\EmailNotificationHandler;
|
||||
use Espo\Core\Mail\SenderParams;
|
||||
use Espo\Core\Utils\Config\ApplicationConfig;
|
||||
use Espo\Core\Utils\DateTime as DateTimeUtil;
|
||||
use Espo\Core\Utils\Markdown\Markdown;
|
||||
use Espo\Entities\Note;
|
||||
use Espo\ORM\Collection;
|
||||
use Espo\Repositories\Portal as PortalRepository;
|
||||
@@ -58,8 +59,6 @@ use Espo\Core\Utils\TemplateFileManager;
|
||||
use Espo\Core\Utils\Util;
|
||||
use Espo\Tools\Stream\NoteAccessControl;
|
||||
|
||||
use Michelf\Markdown;
|
||||
|
||||
use Exception;
|
||||
use DateTime;
|
||||
use Throwable;
|
||||
@@ -325,11 +324,10 @@ class Processor
|
||||
|
||||
$data['userName'] = $note->get('createdByName');
|
||||
|
||||
$post = Markdown::defaultTransform(
|
||||
$note->get('post') ?? ''
|
||||
);
|
||||
$post = $note->getPost() ?? '';
|
||||
|
||||
$data['post'] = $post;
|
||||
|
||||
$data['post'] = Markdown::transform($post);
|
||||
|
||||
$subjectTpl = $this->templateFileManager->getTemplate('mention', 'subject');
|
||||
$bodyTpl = $this->templateFileManager->getTemplate('mention', 'body');
|
||||
@@ -486,9 +484,7 @@ class Processor
|
||||
|
||||
$data['userName'] = $note->get('createdByName');
|
||||
|
||||
$post = Markdown::defaultTransform($note->getPost() ?? '');
|
||||
|
||||
$data['post'] = $post;
|
||||
$data['post'] = Markdown::transform($note->getPost() ?? '');
|
||||
|
||||
$parent = null;
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/*! espocrm 2026-03-10 */
|
||||
/*! espocrm 2026-03-24 */
|
||||
define("modules/crm/views/scheduler/scheduler",["exports","view","vis-data","vis-timeline","moment","jquery"],function(t,e,a,s,n,r){Object.defineProperty(t,"__esModule",{value:!0});t.default=void 0;e=i(e);n=i(n);r=i(r);function i(t){return t&&t.__esModule?t:{default:t}}class o extends e.default{templateContent=`
|
||||
<div class="timeline"></div>
|
||||
<link href="{{basePath}}client/modules/crm/css/vis.css" rel="stylesheet">
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -334,6 +334,19 @@ cat custom/docs/ESPOCRM_BEST_PRACTICES.md | grep -A 200 "Troubleshooting"
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Architektur-Update (26. März 2026)
|
||||
|
||||
**Änderungen:**
|
||||
- ✅ `CAIKnowledge` entfernt (Hooks, Controller, i18n, Metadata)
|
||||
- ✅ `CAICollections` / `CAICollectionCDokumente` entfernt
|
||||
- ✅ `CAdvowareAkten` entfernt → ersetzt durch `CAkten`
|
||||
- ✅ AI-Sync-Architektur: CDokumente → CAkten (direkte n:1, kein Junction Table)
|
||||
- ✅ Neues Feld `aiProvider` auf CAkten (ragflow/xai, Default: ragflow)
|
||||
- ✅ Hook-Chain: UpdateJunctionSyncStatus → UpdateLastSyncFromDocuments
|
||||
- ✅ ESPOCRM_BEST_PRACTICES.md auf v2.5 aktualisiert
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Reorganisation (9. März 2026)
|
||||
|
||||
**Änderungen:**
|
||||
@@ -356,6 +369,6 @@ cat custom/docs/ESPOCRM_BEST_PRACTICES.md | grep -A 200 "Troubleshooting"
|
||||
|
||||
---
|
||||
|
||||
**Letzte Aktualisierung:** 9. März 2026
|
||||
**Letzte Aktualisierung:** 26. März 2026
|
||||
|
||||
**Für Fragen:** Siehe `custom/docs/ESPOCRM_BEST_PRACTICES.md`
|
||||
|
||||
71
custom/Espo/Custom/Api/JunctionData/GetDokumentes.php
Normal file
71
custom/Espo/Custom/Api/JunctionData/GetDokumentes.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Custom\Api\JunctionData;
|
||||
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* GET /api/v1/JunctionData/CAIKnowledge/:knowledgeId/dokumentes
|
||||
*
|
||||
* Returns all documents linked to a knowledge entry with junction table data
|
||||
*/
|
||||
class GetDokumentes implements Action
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$knowledgeId = $request->getRouteParam('knowledgeId');
|
||||
|
||||
if (!$knowledgeId) {
|
||||
throw new BadRequest('Knowledge ID is required');
|
||||
}
|
||||
|
||||
// Verify knowledge exists
|
||||
$knowledge = $this->entityManager->getEntityById('CAIKnowledge', $knowledgeId);
|
||||
if (!$knowledge) {
|
||||
throw new NotFound('Knowledge entry not found');
|
||||
}
|
||||
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
j.id as junctionId,
|
||||
j.c_a_i_knowledge_id as cAIKnowledgeId,
|
||||
j.c_dokumente_id as cDokumenteId,
|
||||
j.ai_document_id as aiDocumentId,
|
||||
j.syncstatus,
|
||||
j.last_sync as lastSync,
|
||||
d.id as documentId,
|
||||
d.name as documentName,
|
||||
d.blake3hash as blake3hash,
|
||||
d.created_at as documentCreatedAt,
|
||||
d.modified_at as documentModifiedAt
|
||||
FROM c_a_i_knowledge_dokumente j
|
||||
INNER JOIN c_dokumente d ON j.c_dokumente_id = d.id
|
||||
WHERE j.c_a_i_knowledge_id = :knowledgeId
|
||||
AND j.deleted = 0
|
||||
AND d.deleted = 0
|
||||
ORDER BY j.id DESC
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute(['knowledgeId' => $knowledgeId]);
|
||||
|
||||
$results = $sth->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
return ResponseComposer::json([
|
||||
'total' => count($results),
|
||||
'list' => $results
|
||||
]);
|
||||
}
|
||||
}
|
||||
178
custom/Espo/Custom/Api/JunctionData/LinkDokument.php
Normal file
178
custom/Espo/Custom/Api/JunctionData/LinkDokument.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Custom\Api\JunctionData;
|
||||
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Exceptions\Conflict;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* POST /api/v1/JunctionData/CAIKnowledge/:knowledgeId/dokumentes/:documentId
|
||||
*
|
||||
* Creates or updates relationship with junction table data
|
||||
* This endpoint links the entities AND sets junction columns in one call
|
||||
*/
|
||||
class LinkDokument implements Action
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$knowledgeId = $request->getRouteParam('knowledgeId');
|
||||
$documentId = $request->getRouteParam('documentId');
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$knowledgeId || !$documentId) {
|
||||
throw new BadRequest('Knowledge ID and Document ID are required');
|
||||
}
|
||||
|
||||
// Verify entities exist
|
||||
$knowledge = $this->entityManager->getEntityById('CAIKnowledge', $knowledgeId);
|
||||
if (!$knowledge) {
|
||||
throw new NotFound('Knowledge entry not found');
|
||||
}
|
||||
|
||||
$document = $this->entityManager->getEntityById('CDokumente', $documentId);
|
||||
if (!$document) {
|
||||
throw new NotFound('Document not found');
|
||||
}
|
||||
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
// Check if link already exists
|
||||
$existing = $this->checkIfLinked($knowledgeId, $documentId);
|
||||
|
||||
if ($existing) {
|
||||
// Link exists - update junction columns
|
||||
return $this->updateExisting($knowledgeId, $documentId, $data);
|
||||
}
|
||||
|
||||
// Create new link via ORM (triggers hooks like DokumenteSyncStatus)
|
||||
$this->entityManager->getRDBRepository('CAIKnowledge')
|
||||
->getRelation($knowledge, 'dokumentes')
|
||||
->relate($document);
|
||||
|
||||
// Now set junction columns if provided
|
||||
if (!empty((array)$data)) {
|
||||
return $this->updateExisting($knowledgeId, $documentId, $data);
|
||||
}
|
||||
|
||||
// Return created entry
|
||||
$result = $this->getJunctionEntry($knowledgeId, $documentId);
|
||||
|
||||
return ResponseComposer::json($result);
|
||||
}
|
||||
|
||||
private function checkIfLinked(string $knowledgeId, string $documentId): bool
|
||||
{
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT COUNT(*) as count
|
||||
FROM c_a_i_knowledge_dokumente
|
||||
WHERE c_a_i_knowledge_id = :knowledgeId
|
||||
AND c_dokumente_id = :documentId
|
||||
AND deleted = 0
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute([
|
||||
'knowledgeId' => $knowledgeId,
|
||||
'documentId' => $documentId
|
||||
]);
|
||||
|
||||
$result = $sth->fetch(\PDO::FETCH_ASSOC);
|
||||
return $result['count'] > 0;
|
||||
}
|
||||
|
||||
private function updateExisting(string $knowledgeId, string $documentId, \stdClass $data): Response
|
||||
{
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
// Build dynamic UPDATE SET clause
|
||||
$setClauses = [];
|
||||
$params = [
|
||||
'knowledgeId' => $knowledgeId,
|
||||
'documentId' => $documentId
|
||||
];
|
||||
|
||||
if (isset($data->aiDocumentId)) {
|
||||
$setClauses[] = "ai_document_id = :aiDocumentId";
|
||||
$params['aiDocumentId'] = $data->aiDocumentId;
|
||||
}
|
||||
|
||||
if (isset($data->syncstatus)) {
|
||||
$allowedStatuses = ['new', 'unclean', 'synced', 'failed', 'unsupported'];
|
||||
if (!in_array($data->syncstatus, $allowedStatuses)) {
|
||||
throw new BadRequest('Invalid syncstatus value. Allowed: ' . implode(', ', $allowedStatuses));
|
||||
}
|
||||
$setClauses[] = "syncstatus = :syncstatus";
|
||||
$params['syncstatus'] = $data->syncstatus;
|
||||
}
|
||||
|
||||
if (isset($data->lastSync)) {
|
||||
$setClauses[] = "last_sync = :lastSync";
|
||||
$params['lastSync'] = $data->lastSync;
|
||||
} elseif (isset($data->updateLastSync) && $data->updateLastSync === true) {
|
||||
$setClauses[] = "last_sync = NOW()";
|
||||
}
|
||||
|
||||
if (!empty($setClauses)) {
|
||||
$sql = "
|
||||
UPDATE c_a_i_knowledge_dokumente
|
||||
SET " . implode(', ', $setClauses) . "
|
||||
WHERE c_a_i_knowledge_id = :knowledgeId
|
||||
AND c_dokumente_id = :documentId
|
||||
AND deleted = 0
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute($params);
|
||||
}
|
||||
|
||||
// Return updated data
|
||||
$result = $this->getJunctionEntry($knowledgeId, $documentId);
|
||||
|
||||
return ResponseComposer::json($result);
|
||||
}
|
||||
|
||||
private function getJunctionEntry(string $knowledgeId, string $documentId): array
|
||||
{
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
id as junctionId,
|
||||
c_a_i_knowledge_id as cAIKnowledgeId,
|
||||
c_dokumente_id as cDokumenteId,
|
||||
ai_document_id as aiDocumentId,
|
||||
syncstatus,
|
||||
last_sync as lastSync
|
||||
FROM c_a_i_knowledge_dokumente
|
||||
WHERE c_a_i_knowledge_id = :knowledgeId
|
||||
AND c_dokumente_id = :documentId
|
||||
AND deleted = 0
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute([
|
||||
'knowledgeId' => $knowledgeId,
|
||||
'documentId' => $documentId
|
||||
]);
|
||||
|
||||
$result = $sth->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$result) {
|
||||
throw new NotFound('Junction entry not found');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
123
custom/Espo/Custom/Api/JunctionData/UpdateJunction.php
Normal file
123
custom/Espo/Custom/Api/JunctionData/UpdateJunction.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Custom\Api\JunctionData;
|
||||
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* PUT /api/v1/JunctionData/CAIKnowledge/:knowledgeId/dokumentes/:documentId
|
||||
*
|
||||
* Updates junction table columns for an existing relationship
|
||||
*/
|
||||
class UpdateJunction implements Action
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$knowledgeId = $request->getRouteParam('knowledgeId');
|
||||
$documentId = $request->getRouteParam('documentId');
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!$knowledgeId || !$documentId) {
|
||||
throw new BadRequest('Knowledge ID and Document ID are required');
|
||||
}
|
||||
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
// Build dynamic UPDATE SET clause
|
||||
$setClauses = [];
|
||||
$params = [
|
||||
'knowledgeId' => $knowledgeId,
|
||||
'documentId' => $documentId
|
||||
];
|
||||
|
||||
if (isset($data->aiDocumentId)) {
|
||||
$setClauses[] = "ai_document_id = :aiDocumentId";
|
||||
$params['aiDocumentId'] = $data->aiDocumentId;
|
||||
}
|
||||
|
||||
if (isset($data->syncstatus)) {
|
||||
$allowedStatuses = ['new', 'unclean', 'synced', 'failed', 'unsupported'];
|
||||
if (!in_array($data->syncstatus, $allowedStatuses)) {
|
||||
throw new BadRequest('Invalid syncstatus value. Allowed: ' . implode(', ', $allowedStatuses));
|
||||
}
|
||||
$setClauses[] = "syncstatus = :syncstatus";
|
||||
$params['syncstatus'] = $data->syncstatus;
|
||||
}
|
||||
|
||||
if (isset($data->lastSync)) {
|
||||
$setClauses[] = "last_sync = :lastSync";
|
||||
$params['lastSync'] = $data->lastSync;
|
||||
} elseif (isset($data->updateLastSync) && $data->updateLastSync === true) {
|
||||
$setClauses[] = "last_sync = NOW()";
|
||||
}
|
||||
|
||||
if (empty($setClauses)) {
|
||||
throw new BadRequest('No fields to update. Provide at least one of: aiDocumentId, syncstatus, lastSync');
|
||||
}
|
||||
|
||||
$sql = "
|
||||
UPDATE c_a_i_knowledge_dokumente
|
||||
SET " . implode(', ', $setClauses) . "
|
||||
WHERE c_a_i_knowledge_id = :knowledgeId
|
||||
AND c_dokumente_id = :documentId
|
||||
AND deleted = 0
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute($params);
|
||||
|
||||
$affectedRows = $sth->rowCount();
|
||||
|
||||
if ($affectedRows === 0) {
|
||||
throw new NotFound('Junction entry not found or no changes made');
|
||||
}
|
||||
|
||||
// Return updated data
|
||||
$result = $this->getJunctionEntry($knowledgeId, $documentId);
|
||||
|
||||
return ResponseComposer::json($result);
|
||||
}
|
||||
|
||||
private function getJunctionEntry(string $knowledgeId, string $documentId): array
|
||||
{
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
|
||||
$sql = "
|
||||
SELECT
|
||||
id as junctionId,
|
||||
c_a_i_knowledge_id as cAIKnowledgeId,
|
||||
c_dokumente_id as cDokumenteId,
|
||||
ai_document_id as aiDocumentId,
|
||||
syncstatus,
|
||||
last_sync as lastSync
|
||||
FROM c_a_i_knowledge_dokumente
|
||||
WHERE c_a_i_knowledge_id = :knowledgeId
|
||||
AND c_dokumente_id = :documentId
|
||||
AND deleted = 0
|
||||
";
|
||||
|
||||
$sth = $pdo->prepare($sql);
|
||||
$sth->execute([
|
||||
'knowledgeId' => $knowledgeId,
|
||||
'documentId' => $documentId
|
||||
]);
|
||||
|
||||
$result = $sth->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$result) {
|
||||
throw new NotFound('Junction entry not found');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Custom\Controllers;
|
||||
|
||||
class CAICollection extends \Espo\Core\Templates\Controllers\BasePlus
|
||||
{
|
||||
}
|
||||
7
custom/Espo/Custom/Controllers/CAkten.php
Normal file
7
custom/Espo/Custom/Controllers/CAkten.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Custom\Controllers;
|
||||
|
||||
class CAkten extends \Espo\Core\Templates\Controllers\BasePlus
|
||||
{
|
||||
}
|
||||
21
custom/Espo/Custom/Controllers/CAktenCDokumente.php
Normal file
21
custom/Espo/Custom/Controllers/CAktenCDokumente.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Controllers;
|
||||
|
||||
use Espo\Core\Controllers\Record;
|
||||
|
||||
/**
|
||||
* Junction Controller: CAkten ↔ CDokumente
|
||||
*
|
||||
* Provides REST API access to the Akten-Dokumente relationship.
|
||||
*
|
||||
* Available endpoints:
|
||||
* GET /api/v1/CAktenCDokumente
|
||||
* GET /api/v1/CAktenCDokumente/{id}
|
||||
* POST /api/v1/CAktenCDokumente
|
||||
* PUT /api/v1/CAktenCDokumente/{id}
|
||||
* DELETE /api/v1/CAktenCDokumente/{id}
|
||||
*/
|
||||
class CAktenCDokumente extends Record
|
||||
{
|
||||
// Inherits all CRUD operations from Record controller
|
||||
}
|
||||
19
custom/Espo/Custom/Hooks/CAkten/PropagateDocumentsUp.php
Normal file
19
custom/Espo/Custom/Hooks/CAkten/PropagateDocumentsUp.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CAkten;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
|
||||
/**
|
||||
* DEPRECATED / DEAD CODE — dieser Hook war in der falschen Namespace.
|
||||
*
|
||||
* CAkten-Hooks feuern bei CAkten-Saves, nicht bei CDokumente-Saves.
|
||||
* Die Logik wurde in Hooks/CDokumente/PropagateDocumentsUp.php verschoben.
|
||||
*/
|
||||
class PropagateDocumentsUp implements AfterSave
|
||||
{
|
||||
public function afterSave(Entity $entity, \Espo\ORM\Repository\Option\SaveOptions $options): void
|
||||
{
|
||||
// intentionally empty — see Hooks/CDokumente/PropagateDocumentsUp.php
|
||||
}
|
||||
}
|
||||
128
custom/Espo/Custom/Hooks/CAkten/UpdateLastSyncFromDocuments.php
Normal file
128
custom/Espo/Custom/Hooks/CAkten/UpdateLastSyncFromDocuments.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CAkten;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
use Espo\Core\Hook\Hook\BeforeSave;
|
||||
|
||||
/**
|
||||
* Hook: Aktualisiert lastSync + syncStatus (Advoware) und aiLastSync + aiSyncStatus (AI)
|
||||
* basierend auf dem neuesten Timestamp und schlechtesten Status der verknüpften Dokumente.
|
||||
*/
|
||||
class UpdateLastSyncFromDocuments implements BeforeSave
|
||||
{
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function beforeSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
if ($options->get('skipHooks')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($entity->isNew()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = $this->entityManager->getPDO();
|
||||
$aktenId = $entity->getId();
|
||||
|
||||
// Single aggregation row — CASE inside MAX() avoids the mixed-aggregate bug.
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT
|
||||
MAX(last_sync_timestamp) AS maxAdvLastSync,
|
||||
MAX(ai_last_sync) AS maxAiLastSync,
|
||||
MAX(CASE
|
||||
WHEN sync_status = 'failed' THEN 2
|
||||
WHEN sync_status IN ('new','unclean')
|
||||
OR sync_status IS NULL OR sync_status = '' THEN 1
|
||||
ELSE 0
|
||||
END) AS advWorstLevel,
|
||||
MAX(CASE
|
||||
WHEN ai_sync_status = 'failed' THEN 2
|
||||
WHEN ai_sync_status IN ('new','unclean')
|
||||
OR ai_sync_status IS NULL OR ai_sync_status = '' THEN 1
|
||||
ELSE 0
|
||||
END) AS aiWorstLevel,
|
||||
-- ai_sync_status = unclean triggers graphParsingStatus
|
||||
SUM(CASE WHEN ai_sync_status = 'unclean' THEN 1 ELSE 0 END) AS aiUncleanCount,
|
||||
-- aiParsingStatus buckets
|
||||
SUM(CASE WHEN ai_parsing_status = 'parsing' THEN 1 ELSE 0 END) AS parseParsingCount,
|
||||
SUM(CASE WHEN ai_parsing_status = 'complete' THEN 1 ELSE 0 END) AS parseCompleteCount,
|
||||
SUM(CASE WHEN ai_parsing_status = 'failed' THEN 1 ELSE 0 END) AS parseFailedCount,
|
||||
COUNT(*) AS docCount
|
||||
FROM c_dokumente
|
||||
WHERE c_akten_id = :aktenId AND deleted = 0"
|
||||
);
|
||||
$stmt->execute([':aktenId' => $aktenId]);
|
||||
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$row || (int)$row['docCount'] === 0) {
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
$entity->set('aiParsingStatus', 'unknown');
|
||||
return;
|
||||
}
|
||||
|
||||
$docCount = (int)$row['docCount'];
|
||||
|
||||
// ── Timestamps ─────────────────────────────────────────────────
|
||||
if (!empty($row['maxAdvLastSync'])) {
|
||||
$entity->set('lastSync', $row['maxAdvLastSync']);
|
||||
}
|
||||
if (!empty($row['maxAiLastSync'])) {
|
||||
$entity->set('aiLastSync', $row['maxAiLastSync']);
|
||||
}
|
||||
|
||||
// ── Advoware Sync Status (worst-case) ──────────────────────────
|
||||
$advLevel = (int)($row['advWorstLevel'] ?? 0);
|
||||
if ($advLevel >= 2) {
|
||||
$entity->set('syncStatus', 'failed');
|
||||
} elseif ($advLevel === 1) {
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
} else {
|
||||
$entity->set('syncStatus', 'synced');
|
||||
}
|
||||
|
||||
// ── AI Sync Status (worst-case) ────────────────────────────────
|
||||
$aiLevel = (int)($row['aiWorstLevel'] ?? 0);
|
||||
if ($aiLevel >= 2) {
|
||||
$entity->set('aiSyncStatus', 'failed');
|
||||
} elseif ($aiLevel === 1) {
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
} else {
|
||||
$entity->set('aiSyncStatus', 'synced');
|
||||
}
|
||||
|
||||
// ── AI Parsing Status (aggregated across all documents) ─────────
|
||||
// Priority: parsing > unknown > complete_with_failures > complete
|
||||
$parseParsing = (int)($row['parseParsingCount'] ?? 0);
|
||||
$parseComplete = (int)($row['parseCompleteCount'] ?? 0);
|
||||
$parseFailed = (int)($row['parseFailedCount'] ?? 0);
|
||||
$parseUnknown = $docCount - $parseParsing - $parseComplete - $parseFailed;
|
||||
|
||||
if ($parseParsing > 0) {
|
||||
$entity->set('aiParsingStatus', 'parsing');
|
||||
} elseif ($parseUnknown > 0) {
|
||||
$entity->set('aiParsingStatus', 'unknown');
|
||||
} elseif ($parseFailed > 0) {
|
||||
// No unknown/parsing left, but some failures
|
||||
$entity->set('aiParsingStatus', 'complete_with_failures');
|
||||
} else {
|
||||
$entity->set('aiParsingStatus', 'complete');
|
||||
}
|
||||
|
||||
// ── Graph Parsing Status (only auto-set to unclean, never reset) ─
|
||||
// If any document's AI sync status is currently unclean → graph is stale.
|
||||
// Any other transition (back to complete, etc.) must be done manually.
|
||||
if ((int)($row['aiUncleanCount'] ?? 0) > 0) {
|
||||
$entity->set('graphParsingStatus', 'unclean');
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CAkten UpdateLastSyncFromDocuments Hook Error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,21 @@
|
||||
namespace Espo\Custom\Hooks\CDokumente;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
use Espo\Core\Hook\Hook\BeforeSave;
|
||||
|
||||
class CDokumente extends \Espo\Core\Hooks\Base
|
||||
/**
|
||||
* Hook: Berechnet Dokumenten-Hashes und setzt fileStatus
|
||||
*
|
||||
* Verwendet Blake3 als Hash-Algorithmus für optimale Performance
|
||||
*/
|
||||
class CDokumente implements BeforeSave
|
||||
{
|
||||
public function beforeSave(Entity $entity, array $options = [])
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function beforeSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
// Problem: isAttributeChanged('dokument') erkennt Datei-Änderungen nicht,
|
||||
// da EspoCRM Datei-Uploads nicht als Feld-Änderung markiert.
|
||||
@@ -14,43 +25,43 @@ class CDokumente extends \Espo\Core\Hooks\Base
|
||||
// um sicherzustellen, dass Hashes bei Datei-Änderungen berechnet werden.
|
||||
// Optimierung wäre wünschenswert, aber nicht möglich mit aktueller API.
|
||||
|
||||
$dokument = $entity->get('dokument');
|
||||
$dokumentId = $entity->get('dokumentId');
|
||||
|
||||
if (!$dokument) {
|
||||
if (!$dokumentId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_object($dokument)) {
|
||||
$attachment = $dokument;
|
||||
} else {
|
||||
$attachment = $this->getEntityManager()->getEntity('Attachment', $dokument);
|
||||
}
|
||||
// Verwende EntityManager zur korrekten Relation-Verwaltung
|
||||
$attachment = $this->entityManager->getEntityById('Attachment', $dokumentId);
|
||||
|
||||
if (!$attachment) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filePath = 'data/upload/' . $attachment->get('id');
|
||||
$filePath = 'data/upload/' . $attachment->getId();
|
||||
if (!file_exists($filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Berechne neue Hashes
|
||||
$newMd5 = hash_file('md5', $filePath);
|
||||
$newSha256 = hash_file('sha256', $filePath);
|
||||
// Berechne Blake3 Hash
|
||||
$fileContent = file_get_contents($filePath);
|
||||
if ($fileContent === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Blake3 Hashing - schneller als SHA3 und kryptographisch sicher
|
||||
$newBlake3 = blake3($fileContent);
|
||||
|
||||
// Setze Hashes
|
||||
$entity->set('md5sum', $newMd5);
|
||||
$entity->set('sha256', $newSha256);
|
||||
// Setze Hash
|
||||
$entity->set('blake3hash', $newBlake3);
|
||||
|
||||
// Bestimme Status
|
||||
if ($entity->isNew()) {
|
||||
$entity->set('fileStatus', 'new');
|
||||
} else {
|
||||
$oldMd5 = $entity->getFetched('md5sum');
|
||||
$oldSha256 = $entity->getFetched('sha256');
|
||||
$oldBlake3 = $entity->getFetched('blake3hash');
|
||||
|
||||
if ($oldMd5 !== $newMd5 || $oldSha256 !== $newSha256) {
|
||||
if ($oldBlake3 !== $newBlake3) {
|
||||
$entity->set('fileStatus', 'changed');
|
||||
} else {
|
||||
$entity->set('fileStatus', 'synced');
|
||||
|
||||
90
custom/Espo/Custom/Hooks/CDokumente/PropagateDocumentsUp.php
Normal file
90
custom/Espo/Custom/Hooks/CDokumente/PropagateDocumentsUp.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CDokumente;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
|
||||
/**
|
||||
* Hook: Propagiert Dokumenten-Verlinkung von CDokumente nach oben zu Räumungsklage/Mietinkasso.
|
||||
*
|
||||
* Wenn ein Dokument direkt einer Akte zugewiesen wird (cAktenId gesetzt oder geändert):
|
||||
* → verknüpfe das Dokument auch via M2M mit der verbundenen Räumungsklage / dem Mietinkasso.
|
||||
*
|
||||
* Damit ist sichergestellt, dass über alle Einstiegspunkte (direktes CAkten-Panel,
|
||||
* cAktenId-Feld) die Beziehung vollständig ist.
|
||||
*/
|
||||
class PropagateDocumentsUp implements AfterSave
|
||||
{
|
||||
private static array $processing = [];
|
||||
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function afterSave(Entity $entity, \Espo\ORM\Repository\Option\SaveOptions $options): void
|
||||
{
|
||||
if ($options->get('skipHooks')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$akteId = $entity->get('cAktenId');
|
||||
if (!$akteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Nur wenn cAktenId neu gesetzt oder geändert wurde
|
||||
if (!$entity->isNew() && !$entity->isAttributeChanged('cAktenId')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$key = $akteId . '-' . $entity->getId() . '-propagate-up';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
$akte = $this->entityManager->getEntity('CAkten', $akteId);
|
||||
if (!$akte) {
|
||||
return;
|
||||
}
|
||||
|
||||
$raumungsklage = $this->entityManager
|
||||
->getRDBRepository('CAkten')
|
||||
->getRelation($akte, 'vmhRumungsklage')
|
||||
->findOne();
|
||||
|
||||
if ($raumungsklage) {
|
||||
$this->relateDocument($raumungsklage, 'dokumentesvmhraumungsklage', $entity);
|
||||
}
|
||||
|
||||
$mietinkasso = $this->entityManager
|
||||
->getRDBRepository('CAkten')
|
||||
->getRelation($akte, 'mietinkasso')
|
||||
->findOne();
|
||||
|
||||
if ($mietinkasso) {
|
||||
$this->relateDocument($mietinkasso, 'dokumentesmietinkasso', $entity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CDokumente PropagateDocumentsUp Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
private function relateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
$isRelated = $relation
|
||||
->where(['id' => $document->getId()])
|
||||
->findOne();
|
||||
|
||||
if (!$isRelated) {
|
||||
$relation->relate($document);
|
||||
}
|
||||
}
|
||||
}
|
||||
193
custom/Espo/Custom/Hooks/CDokumente/SyncStatusOnRelate.php
Normal file
193
custom/Espo/Custom/Hooks/CDokumente/SyncStatusOnRelate.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CDokumente;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterRelate;
|
||||
use Espo\Core\Hook\Hook\AfterUnrelate;
|
||||
use Espo\ORM\Repository\Option\RelateOptions;
|
||||
use Espo\ORM\Repository\Option\UnrelateOptions;
|
||||
|
||||
/**
|
||||
* Hook: Sync-Status-Aktualisierung wenn ein Dokument über die CDokumente-Panels
|
||||
* mit einer Räumungsklage oder einem Mietinkasso verknüpft oder entknüpft wird.
|
||||
*
|
||||
* Auslöser (von CDokumente-Seite aus):
|
||||
* - afterRelate 'vmhRumungsklagesdokumente' → Räumungsklage verknüpft
|
||||
* - afterRelate 'mietinkassosdokumente' → Mietinkasso verknüpft
|
||||
* - afterUnrelate 'vmhRumungsklagesdokumente' → Räumungsklage entknüpft
|
||||
* - afterUnrelate 'mietinkassosdokumente' → Mietinkasso entknüpft
|
||||
*
|
||||
* Wenn die Verknüpfung von der Räumungsklage/Mietinkasso-Seite kommt, feuern
|
||||
* stattdessen CVmhRumungsklage/CMietinkasso::PropagateDocuments — dieses Hook
|
||||
* feuert dann NICHT (EspoCRM feuert afterRelate nur auf der aufrufenden Seite).
|
||||
*/
|
||||
class SyncStatusOnRelate implements AfterRelate, AfterUnrelate
|
||||
{
|
||||
/** Relation → [parentEntityType, advowareAktenRelation, aiKnowledgeRelation] */
|
||||
private const RELATION_MAP = [
|
||||
'vmhRumungsklagesdokumente' => ['CVmhRumungsklage', 'advowareAkten', 'aIKnowledge'],
|
||||
'mietinkassosdokumente' => ['CMietinkasso', 'advowareAkten', 'aIKnowledge'],
|
||||
];
|
||||
|
||||
/** @var array<string, bool> */
|
||||
private static array $processing = [];
|
||||
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public function afterRelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
array $columnData,
|
||||
RelateOptions $options
|
||||
): void {
|
||||
if (!isset(self::RELATION_MAP[$relationName])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-' . $relationName . '-relate';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
[, $aktenRelation, $aiKnowledgeRelation] = self::RELATION_MAP[$relationName];
|
||||
|
||||
// AdvowareAkten über die Parent-Entity ermitteln
|
||||
$advowareAkten = $this->entityManager
|
||||
->getRDBRepository($foreignEntity->getEntityType())
|
||||
->getRelation($foreignEntity, $aktenRelation)
|
||||
->findOne();
|
||||
|
||||
if ($advowareAkten) {
|
||||
$entity->set('cAktenId', $advowareAkten->getId());
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
$entity->set('aiParsingStatus', 'unknown');
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
$this->triggerAkteUpdate($advowareAkten->getId());
|
||||
} else {
|
||||
// Kein Akte-Link — trotzdem Sync-Status auf unclean setzen
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
$entity->set('aiParsingStatus', 'unknown');
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
}
|
||||
|
||||
// AIKnowledge-Verknüpfung propagieren
|
||||
$aiKnowledge = $this->entityManager
|
||||
->getRDBRepository($foreignEntity->getEntityType())
|
||||
->getRelation($foreignEntity, $aiKnowledgeRelation)
|
||||
->findOne();
|
||||
|
||||
if ($aiKnowledge) {
|
||||
$this->relateIfNotAlready($aiKnowledge, 'dokumentes', $entity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error(
|
||||
'CDokumente SyncStatusOnRelate afterRelate (' . $relationName . ') Error: ' . $e->getMessage()
|
||||
);
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public function afterUnrelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
UnrelateOptions $options
|
||||
): void {
|
||||
if (!isset(self::RELATION_MAP[$relationName])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-' . $relationName . '-unrelate';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
[, $aktenRelation, $aiKnowledgeRelation] = self::RELATION_MAP[$relationName];
|
||||
|
||||
// Alte Akte ermitteln
|
||||
$advowareAkten = $this->entityManager
|
||||
->getRDBRepository($foreignEntity->getEntityType())
|
||||
->getRelation($foreignEntity, $aktenRelation)
|
||||
->findOne();
|
||||
|
||||
$oldAkteId = null;
|
||||
|
||||
if ($advowareAkten && $entity->get('cAktenId') === $advowareAkten->getId()) {
|
||||
$oldAkteId = $advowareAkten->getId();
|
||||
$entity->set('cAktenId', null);
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
}
|
||||
|
||||
if ($oldAkteId) {
|
||||
$this->triggerAkteUpdate($oldAkteId);
|
||||
}
|
||||
|
||||
// AIKnowledge-Verknüpfung entfernen
|
||||
$aiKnowledge = $this->entityManager
|
||||
->getRDBRepository($foreignEntity->getEntityType())
|
||||
->getRelation($foreignEntity, $aiKnowledgeRelation)
|
||||
->findOne();
|
||||
|
||||
if ($aiKnowledge) {
|
||||
$this->unrelateIfExists($aiKnowledge, 'dokumentes', $entity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error(
|
||||
'CDokumente SyncStatusOnRelate afterUnrelate (' . $relationName . ') Error: ' . $e->getMessage()
|
||||
);
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private function triggerAkteUpdate(string $akteId): void
|
||||
{
|
||||
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||
if ($akte) {
|
||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
private function relateIfNotAlready(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
$isRelated = $relation->where(['id' => $document->getId()])->findOne();
|
||||
if (!$isRelated) {
|
||||
$relation->relate($document);
|
||||
}
|
||||
}
|
||||
|
||||
private function unrelateIfExists(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
$isRelated = $relation->where(['id' => $document->getId()])->findOne();
|
||||
if ($isRelated) {
|
||||
$relation->unrelate($document);
|
||||
}
|
||||
}
|
||||
}
|
||||
134
custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php
Normal file
134
custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CDokumente;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\Repository\Option\RemoveOptions;
|
||||
use Espo\ORM\Repository\Option\SaveOptions;
|
||||
use Espo\Core\Hook\Hook\AfterRemove;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
|
||||
/**
|
||||
* Hook: Bei Änderung, Verlinkung oder Löschung eines Dokuments syncStatus und
|
||||
* aiSyncStatus auf "unclean" setzen und die verknüpfte CAkten-Entity aktualisieren.
|
||||
*
|
||||
* Auslöser:
|
||||
* - afterSave: Feldänderungen (name, description, file, …)
|
||||
* - afterSave: Neues Dokument mit cAktenId
|
||||
* - afterSave: cAktenId-Änderung (Verlinkung / Entlinkung über CAkten-Panel)
|
||||
* - afterRemove: Gelöschtes Dokument → verknüpfte Akte neu berechnen
|
||||
*/
|
||||
class UpdateJunctionSyncStatus implements AfterSave, AfterRemove
|
||||
{
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function afterSave(Entity $entity, SaveOptions $options): void
|
||||
{
|
||||
// Kein Re-Eintritt wenn dieser Hook selbst gespeichert hat
|
||||
if ($options->get('skipHooks')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Fall 1: Neues Dokument → verknüpfte Akte neu berechnen
|
||||
if ($entity->isNew()) {
|
||||
if ($entity->get('cAktenId')) {
|
||||
$this->triggerAkteUpdate($entity->get('cAktenId'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall 2: cAktenId geändert (Dokument verlinkt oder entlinkt)
|
||||
if ($entity->isAttributeChanged('cAktenId')) {
|
||||
$oldAktenId = $entity->getFetched('cAktenId');
|
||||
$newAktenId = $entity->get('cAktenId');
|
||||
|
||||
// Dokument der neuen Akte zugewiesen → als unclean markieren
|
||||
if ($newAktenId) {
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
$entity->set('aiParsingStatus', 'unknown');
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
$this->triggerAkteUpdate($newAktenId);
|
||||
}
|
||||
|
||||
// Alte Akte ebenfalls neu berechnen (Dokument entfernt)
|
||||
if ($oldAktenId && $oldAktenId !== $newAktenId) {
|
||||
$this->triggerAkteUpdate($oldAktenId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall 3: Relevante Feldänderungen (Datei, Name, Beschreibung, …)
|
||||
if ($this->hasRelevantChanges($entity)) {
|
||||
if (!$entity->get('cAktenId')) {
|
||||
return;
|
||||
}
|
||||
$entity->set('syncStatus', 'unclean');
|
||||
$entity->set('aiSyncStatus', 'unclean');
|
||||
$entity->set('aiParsingStatus', 'unknown');
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
$this->triggerAkteUpdate($entity->get('cAktenId'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall 4: aiParsingStatus geändert (z.B. durch externen Parsing-Service)
|
||||
// → Akte neu berechnen, aber KEIN unclean setzen (Inhalt ist unverändert)
|
||||
if ($entity->isAttributeChanged('aiParsingStatus') && $entity->get('cAktenId')) {
|
||||
$this->triggerAkteUpdate($entity->get('cAktenId'));
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CDokumente UpdateJunctionSyncStatus afterSave Error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function afterRemove(Entity $entity, RemoveOptions $options): void
|
||||
{
|
||||
$akteId = $entity->get('cAktenId');
|
||||
if (!$akteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->triggerAkteUpdate($akteId);
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CDokumente UpdateJunctionSyncStatus afterRemove Error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Speichert die CAkten-Entity neu, damit UpdateLastSyncFromDocuments
|
||||
* den Sync-Status aller verknüpften Dokumente neu aggregiert.
|
||||
*/
|
||||
private function triggerAkteUpdate(string $akteId): void
|
||||
{
|
||||
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||
if ($akte) {
|
||||
// silent=true → keine Audit-Einträge; kein skipHooks → UpdateLastSyncFromDocuments läuft
|
||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
private function hasRelevantChanges(Entity $entity): bool
|
||||
{
|
||||
$relevantFields = [
|
||||
'name',
|
||||
'description',
|
||||
'dokument',
|
||||
'dokumentId',
|
||||
'preview',
|
||||
'previewId',
|
||||
'fileStatus',
|
||||
];
|
||||
|
||||
foreach ($relevantFields as $field) {
|
||||
if ($entity->isAttributeChanged($field)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
134
custom/Espo/Custom/Hooks/CKuendigung/CreateAdvowareAkte.php
Normal file
134
custom/Espo/Custom/Hooks/CKuendigung/CreateAdvowareAkte.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CKuendigung;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterSave;
|
||||
|
||||
/**
|
||||
* Hook: Erstellt automatisch AdvowareAkte für Kündigung
|
||||
*
|
||||
* Wenn eine Kündigung erstellt/gespeichert wird:
|
||||
* - Prüfe ob bereits eine AdvowareAkte vorhanden ist (über verknüpfte Räumungsklage)
|
||||
* - Wenn nein: Erstelle neue AdvowareAkte und verknüpfe sie
|
||||
*/
|
||||
class CreateAdvowareAkte implements AfterSave
|
||||
{
|
||||
private static array $processing = [];
|
||||
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager,
|
||||
private \Espo\Core\InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
public function afterSave(
|
||||
Entity $entity,
|
||||
\Espo\ORM\Repository\Option\SaveOptions $options
|
||||
): void {
|
||||
// Skip if silent or during hooks
|
||||
if ($options->get('silent') || $options->get('skipHooks')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vermeide Loops
|
||||
$key = $entity->getId() . '-create-akte';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
// Prüfe ob Kündigung bereits eine AdvowareAkte hat
|
||||
$existingAkteId = $entity->get('advowareAktenId');
|
||||
|
||||
if ($existingAkteId) {
|
||||
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Kündigung already has AdvowareAkte: {$existingAkteId}");
|
||||
unset(self::$processing[$key]);
|
||||
return; // Bereits vorhanden
|
||||
}
|
||||
|
||||
// Prüfe ob verknüpfte Räumungsklagen eine Akte haben
|
||||
$raeumungsklagen = $this->entityManager
|
||||
->getRDBRepository('CKuendigung')
|
||||
->getRelation($entity, 'vmhRumungsklages')
|
||||
->find();
|
||||
|
||||
foreach ($raeumungsklagen as $rk) {
|
||||
$rkAkteId = $rk->get('advowareAktenId');
|
||||
if ($rkAkteId) {
|
||||
// Übernehme Akte von Räumungsklage
|
||||
$entity->set('advowareAktenId', $rkAkteId);
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
// Synchronisiere Aktennummer
|
||||
$akte = $this->entityManager->getEntity('CAkten', $rkAkteId);
|
||||
if ($akte) {
|
||||
$this->syncAktennummer($entity, $akte);
|
||||
}
|
||||
|
||||
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Using AdvowareAkte from Räumungsklage: {$rkAkteId}");
|
||||
unset(self::$processing[$key]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Keine Akte gefunden -> Erstelle neue
|
||||
$this->createNewAkte($entity);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CKuendigung CreateAdvowareAkte Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
private function createNewAkte(Entity $kuendigung): void
|
||||
{
|
||||
// Hole Aktennummer aus Kündigung (falls vorhanden)
|
||||
$aktennummer = $kuendigung->get('aktennr');
|
||||
if (!$aktennummer) {
|
||||
$aktennummer = time();
|
||||
}
|
||||
|
||||
// Erstelle AdvowareAkte (aktenzeichen bleibt leer)
|
||||
$akteData = [
|
||||
'name' => 'Advoware Akte - ' . $kuendigung->get('name'),
|
||||
'aktennummer' => $aktennummer,
|
||||
'syncStatus' => 'unclean',
|
||||
'assignedUserId' => $kuendigung->get('assignedUserId')
|
||||
];
|
||||
|
||||
// Copy teams
|
||||
$teamsIds = $kuendigung->getLinkMultipleIdList('teams');
|
||||
if (!empty($teamsIds)) {
|
||||
$akteData['teamsIds'] = $teamsIds;
|
||||
}
|
||||
|
||||
$akte = $this->entityManager->createEntity('CAkten', $akteData);
|
||||
|
||||
if ($akte) {
|
||||
// Verknüpfe mit Kündigung
|
||||
$kuendigung->set('advowareAktenId', $akte->getId());
|
||||
$this->entityManager->saveEntity($kuendigung, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
// Synchronisiere Aktennummer zurück zur Kündigung (falls leer war)
|
||||
if (!$kuendigung->get('aktennr') && $akte->get('aktennummer')) {
|
||||
$kuendigung->set('aktennr', $akte->get('aktennummer'));
|
||||
$this->entityManager->saveEntity($kuendigung, ['silent' => true, 'skipHooks' => true]);
|
||||
}
|
||||
|
||||
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Created new AdvowareAkte: {$akte->getId()}");
|
||||
} else {
|
||||
$GLOBALS['log']->error('CKuendigung CreateAdvowareAkte: Failed to create AdvowareAkte');
|
||||
}
|
||||
}
|
||||
|
||||
private function syncAktennummer(Entity $kuendigung, Entity $akte): void
|
||||
{
|
||||
// Synchronisiere nur Aktennummer (nicht Aktenzeichen, das ist in der Beziehung)
|
||||
if (!$kuendigung->get('aktennr') && $akte->get('aktennummer')) {
|
||||
$kuendigung->set('aktennr', $akte->get('aktennummer'));
|
||||
$this->entityManager->saveEntity($kuendigung, ['silent' => true, 'skipHooks' => true]);
|
||||
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Synchronized Aktennummer");
|
||||
}
|
||||
}
|
||||
}
|
||||
84
custom/Espo/Custom/Hooks/CKuendigung/SyncAdvowareAkte.php
Normal file
84
custom/Espo/Custom/Hooks/CKuendigung/SyncAdvowareAkte.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CKuendigung;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterRelate;
|
||||
|
||||
/**
|
||||
* Hook: Synchronisiert AdvowareAkte zwischen Kündigung und Räumungsklage
|
||||
*
|
||||
* Wenn eine Kündigung mit einer Räumungsklage verknüpft wird:
|
||||
* - Prüfe ob Räumungsklage eine AdvowareAkte hat
|
||||
* - Wenn ja, verknüpfe diese Akte auch mit der Kündigung
|
||||
* - Übernehme/Synchronisiere Aktennummer und Aktenzeichen
|
||||
*/
|
||||
class SyncAdvowareAkte implements AfterRelate
|
||||
{
|
||||
private static array $processing = [];
|
||||
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function afterRelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
array $columnData,
|
||||
\Espo\ORM\Repository\Option\RelateOptions $options
|
||||
): void {
|
||||
// Nur für vmhRumungsklages-Beziehung (wenn Räumungsklage zu Kündigung hinzugefügt wird)
|
||||
if ($relationName !== 'vmhRumungsklages') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vermeide Loops
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-sync-akte';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
// $entity = CKuendigung
|
||||
// $foreignEntity = CVmhRumungsklage
|
||||
|
||||
// Hole AdvowareAkte von der Räumungsklage (hasOne relationship - get via field)
|
||||
$advowareAkteId = $foreignEntity->get('advowareAktenId');
|
||||
|
||||
if ($advowareAkteId) {
|
||||
$advowareAkte = $this->entityManager->getEntity('CAkten', $advowareAkteId);
|
||||
|
||||
if ($advowareAkte) {
|
||||
$GLOBALS['log']->info("CKuendigung SyncAdvowareAkte: Found AdvowareAkte {$advowareAkte->getId()} on Räumungsklage {$foreignEntity->getId()}");
|
||||
|
||||
// Prüfe ob Kündigung bereits eine andere Akte hat
|
||||
$existingAktenId = $entity->get('advowareAktenId');
|
||||
|
||||
if ($existingAktenId && $existingAktenId !== $advowareAkteId) {
|
||||
$GLOBALS['log']->warning("CKuendigung SyncAdvowareAkte: Kündigung already has different AdvowareAkte {$existingAktenId}, will replace with {$advowareAkteId}");
|
||||
}
|
||||
|
||||
// Verknüpfe AdvowareAkte mit Kündigung (belongsTo relationship - set field directly)
|
||||
$entity->set('advowareAktenId', $advowareAkteId);
|
||||
|
||||
// Synchronisiere nur Aktennummer (Aktenzeichen kommt über Beziehung)
|
||||
if (!$entity->get('aktennr') && $advowareAkte->get('aktennummer')) {
|
||||
$entity->set('aktennr', $advowareAkte->get('aktennummer'));
|
||||
}
|
||||
|
||||
// Save once with all changes
|
||||
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||
$GLOBALS['log']->info("CKuendigung SyncAdvowareAkte: Successfully linked AdvowareAkte and synchronized Aktennummer to Kündigung");
|
||||
}
|
||||
} else {
|
||||
$GLOBALS['log']->info("CKuendigung SyncAdvowareAkte: Räumungsklage {$foreignEntity->getId()} has no AdvowareAkte yet");
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CKuendigung SyncAdvowareAkte Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
171
custom/Espo/Custom/Hooks/CMietinkasso/PropagateDocuments.php
Normal file
171
custom/Espo/Custom/Hooks/CMietinkasso/PropagateDocuments.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CMietinkasso;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterRelate;
|
||||
use Espo\Core\Hook\Hook\AfterUnrelate;
|
||||
|
||||
/**
|
||||
* Hook: Propagiert Dokumenten-Verknüpfungen von Mietinkasso zu AdvowareAkten und AIKnowledge
|
||||
*
|
||||
* - Wenn Dokument mit Mietinkasso verknüpft wird → verknüpfe auch mit AdvowareAkten + AIKnowledge
|
||||
* - Wenn Dokument von Mietinkasso entknüpft wird → entknüpfe auch von AdvowareAkten + AIKnowledge
|
||||
*/
|
||||
class PropagateDocuments implements AfterRelate, AfterUnrelate
|
||||
{
|
||||
private static array $processing = [];
|
||||
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function afterRelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
array $columnData,
|
||||
\Espo\ORM\Repository\Option\RelateOptions $options
|
||||
): void {
|
||||
// Nur für dokumentesmietinkasso-Beziehung
|
||||
if ($relationName !== 'dokumentesmietinkasso') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vermeide Loops
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-relate';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
// Hole verbundene AdvowareAkten
|
||||
$advowareAkten = $this->entityManager
|
||||
->getRDBRepository('CMietinkasso')
|
||||
->getRelation($entity, 'advowareAkten')
|
||||
->findOne();
|
||||
|
||||
// Set direct belongsTo relationship on document
|
||||
if ($advowareAkten) {
|
||||
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
||||
$foreignEntity->set('syncStatus', 'unclean'); // Advoware-Sync ausstehend
|
||||
$foreignEntity->set('aiSyncStatus', 'unclean'); // AI-Sync ausstehend
|
||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
||||
$akte = $this->entityManager->getEntityById('CAkten', $advowareAkten->getId());
|
||||
if ($akte) {
|
||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
// Hole verbundene AIKnowledge
|
||||
$aIKnowledge = $this->entityManager
|
||||
->getRDBRepository('CMietinkasso')
|
||||
->getRelation($entity, 'aIKnowledge')
|
||||
->findOne();
|
||||
|
||||
// Verknüpfe Dokument mit AIKnowledge
|
||||
if ($aIKnowledge) {
|
||||
$this->relateDocument($aIKnowledge, 'dokumentes', $foreignEntity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CMietinkasso PropagateDocuments (relate) Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
public function afterUnrelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
\Espo\ORM\Repository\Option\UnrelateOptions $options
|
||||
): void {
|
||||
// Nur für dokumentesmietinkasso-Beziehung
|
||||
if ($relationName !== 'dokumentesmietinkasso') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vermeide Loops
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-unrelate';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
// Hole verbundene AdvowareAkten
|
||||
$advowareAkten = $this->entityManager
|
||||
->getRDBRepository('CMietinkasso')
|
||||
->getRelation($entity, 'advowareAkten')
|
||||
->findOne();
|
||||
|
||||
// Remove direct belongsTo relationship from document
|
||||
if ($advowareAkten && $foreignEntity->get('cAktenId') === $advowareAkten->getId()) {
|
||||
$akteId = $advowareAkten->getId(); // Vor dem Löschen merken
|
||||
$foreignEntity->set('cAktenId', null);
|
||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
// Akte über Entlinkung informieren → syncStatus neu berechnen
|
||||
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||
if ($akte) {
|
||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
// Hole verbundene AIKnowledge
|
||||
$aIKnowledge = $this->entityManager
|
||||
->getRDBRepository('CMietinkasso')
|
||||
->getRelation($entity, 'aIKnowledge')
|
||||
->findOne();
|
||||
|
||||
// Entknüpfe Dokument von AIKnowledge
|
||||
if ($aIKnowledge) {
|
||||
$this->unrelateDocument($aIKnowledge, 'dokumentes', $foreignEntity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CMietinkasso PropagateDocuments (unrelate) Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsfunktion: Verknüpfe Dokument (nur wenn nicht bereits verknüpft)
|
||||
*/
|
||||
private function relateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
// Prüfe ob bereits verknüpft
|
||||
$isRelated = $relation
|
||||
->where(['id' => $document->getId()])
|
||||
->findOne();
|
||||
|
||||
if (!$isRelated) {
|
||||
$relation->relate($document);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsfunktion: Entknüpfe Dokument
|
||||
*/
|
||||
private function unrelateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
// Prüfe ob verknüpft
|
||||
$isRelated = $relation
|
||||
->where(['id' => $document->getId()])
|
||||
->findOne();
|
||||
|
||||
if ($isRelated) {
|
||||
$relation->unrelate($document);
|
||||
}
|
||||
}
|
||||
}
|
||||
171
custom/Espo/Custom/Hooks/CVmhRumungsklage/PropagateDocuments.php
Normal file
171
custom/Espo/Custom/Hooks/CVmhRumungsklage/PropagateDocuments.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
namespace Espo\Custom\Hooks\CVmhRumungsklage;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Core\Hook\Hook\AfterRelate;
|
||||
use Espo\Core\Hook\Hook\AfterUnrelate;
|
||||
|
||||
/**
|
||||
* Hook: Propagiert Dokumenten-Verknüpfungen von Räumungsklage zu AdvowareAkten und AIKnowledge
|
||||
*
|
||||
* - Wenn Dokument mit Räumungsklage verknüpft wird → verknüpfe auch mit AdvowareAkten + AIKnowledge
|
||||
* - Wenn Dokument von Räumungsklage entknüpft wird → entknüpfe auch von AdvowareAkten + AIKnowledge
|
||||
*/
|
||||
class PropagateDocuments implements AfterRelate, AfterUnrelate
|
||||
{
|
||||
private static array $processing = [];
|
||||
|
||||
public function __construct(
|
||||
private \Espo\ORM\EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
public function afterRelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
array $columnData,
|
||||
\Espo\ORM\Repository\Option\RelateOptions $options
|
||||
): void {
|
||||
// Nur für dokumentesvmhraumungsklage-Beziehung
|
||||
if ($relationName !== 'dokumentesvmhraumungsklage') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vermeide Loops
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-relate';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
// Hole verbundene AdvowareAkten
|
||||
$advowareAkten = $this->entityManager
|
||||
->getRDBRepository('CVmhRumungsklage')
|
||||
->getRelation($entity, 'advowareAkten')
|
||||
->findOne();
|
||||
|
||||
// Set direct belongsTo relationship on document
|
||||
if ($advowareAkten) {
|
||||
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
||||
$foreignEntity->set('syncStatus', 'unclean'); // Advoware-Sync ausstehend
|
||||
$foreignEntity->set('aiSyncStatus', 'unclean'); // AI-Sync ausstehend
|
||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
||||
$akte = $this->entityManager->getEntityById('CAkten', $advowareAkten->getId());
|
||||
if ($akte) {
|
||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
// Hole verbundene AIKnowledge
|
||||
$aIKnowledge = $this->entityManager
|
||||
->getRDBRepository('CVmhRumungsklage')
|
||||
->getRelation($entity, 'aIKnowledge')
|
||||
->findOne();
|
||||
|
||||
// Verknüpfe Dokument mit AIKnowledge
|
||||
if ($aIKnowledge) {
|
||||
$this->relateDocument($aIKnowledge, 'dokumentes', $foreignEntity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CVmhRumungsklage PropagateDocuments (relate) Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
public function afterUnrelate(
|
||||
Entity $entity,
|
||||
string $relationName,
|
||||
Entity $foreignEntity,
|
||||
\Espo\ORM\Repository\Option\UnrelateOptions $options
|
||||
): void {
|
||||
// Nur für dokumentesvmhraumungsklage-Beziehung
|
||||
if ($relationName !== 'dokumentesvmhraumungsklage') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vermeide Loops
|
||||
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-unrelate';
|
||||
if (isset(self::$processing[$key])) {
|
||||
return;
|
||||
}
|
||||
self::$processing[$key] = true;
|
||||
|
||||
try {
|
||||
// Hole verbundene AdvowareAkten
|
||||
$advowareAkten = $this->entityManager
|
||||
->getRDBRepository('CVmhRumungsklage')
|
||||
->getRelation($entity, 'advowareAkten')
|
||||
->findOne();
|
||||
|
||||
// Remove direct belongsTo relationship from document
|
||||
if ($advowareAkten && $foreignEntity->get('cAktenId') === $advowareAkten->getId()) {
|
||||
$akteId = $advowareAkten->getId(); // Vor dem Löschen merken
|
||||
$foreignEntity->set('cAktenId', null);
|
||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||
|
||||
// Akte über Entlinkung informieren → syncStatus neu berechnen
|
||||
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||
if ($akte) {
|
||||
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
// Hole verbundene AIKnowledge
|
||||
$aIKnowledge = $this->entityManager
|
||||
->getRDBRepository('CVmhRumungsklage')
|
||||
->getRelation($entity, 'aIKnowledge')
|
||||
->findOne();
|
||||
|
||||
// Entknüpfe Dokument von AIKnowledge
|
||||
if ($aIKnowledge) {
|
||||
$this->unrelateDocument($aIKnowledge, 'dokumentes', $foreignEntity);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$GLOBALS['log']->error('CVmhRumungsklage PropagateDocuments (unrelate) Error: ' . $e->getMessage());
|
||||
} finally {
|
||||
unset(self::$processing[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsfunktion: Verknüpfe Dokument (nur wenn nicht bereits verknüpft)
|
||||
*/
|
||||
private function relateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
// Prüfe ob bereits verknüpft
|
||||
$isRelated = $relation
|
||||
->where(['id' => $document->getId()])
|
||||
->findOne();
|
||||
|
||||
if (!$isRelated) {
|
||||
$relation->relate($document);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsfunktion: Entknüpfe Dokument
|
||||
*/
|
||||
private function unrelateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
||||
{
|
||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||
|
||||
// Prüfe ob verknüpft
|
||||
$isRelated = $relation
|
||||
->where(['id' => $document->getId()])
|
||||
->findOne();
|
||||
|
||||
if ($isRelated) {
|
||||
$relation->unrelate($document);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "مهام"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "إنشاء {الكيانTypeTranslated}"
|
||||
"Create CAkten": "إنشاء {الكيانTypeTranslated}"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Задачи"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Създаване на Advoware Akte"
|
||||
"Create CAdvowareAkten": "Създаване на Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Задачи"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Създаване на AI Collection"
|
||||
"Create CAkten": "Създаване на Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Úkoly"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Vytvořit Advoware Akte"
|
||||
"Create CAdvowareAkten": "Vytvořit Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Úkoly"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Vytvořit AI Collection"
|
||||
"Create CAkten": "Vytvořit Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Opgaver"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Opret Advoware Akte "
|
||||
"Create CAdvowareAkten": "Opret Advoware Akten "
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Opgaver"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Opret AI Collection "
|
||||
"Create CAkten": "Opret Advoware Akten "
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"fields": {
|
||||
"cAdvowareAkte": "Advoware-Akte",
|
||||
"cAdvowareAkteId": "Advoware-Akte ID",
|
||||
"cAdvowareAkteName": "Advoware-Akte Name",
|
||||
"xaiCollectionId": "x.AI Collection ID",
|
||||
"syncStatus": "Sync-Status",
|
||||
"lastSync": "Letzte Synchronisation",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cmietinkassoId": "Mietinkasso ID",
|
||||
"cmietinkassoName": "Mietinkasso Name",
|
||||
"cvmhRumungsklage": "Räumungsklage",
|
||||
"cvmhRumungsklageId": "Räumungsklage ID",
|
||||
"cvmhRumungsklageName": "Räumungsklage Name"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Termine",
|
||||
"calls": "Anrufe",
|
||||
"tasks": "Aufgaben",
|
||||
"cDokumente": "Dokumente",
|
||||
"cAdvowareAkte": "Advoware-Akte",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cvmhRumungsklage": "Räumungsklage"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "AI Collection erstellen"
|
||||
},
|
||||
"tooltips": {
|
||||
"xaiCollectionId": "Collection ID für x.AI Synchronisation",
|
||||
"syncStatus": "Status der x.AI-Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert",
|
||||
"lastSync": "Zeitpunkt der letzten Synchronisation mit x.AI"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"pending_sync": "Warte auf Sync",
|
||||
"clean": "Synchronisiert",
|
||||
"unclean": "Änderungen ausstehend",
|
||||
"failed": "Fehlgeschlagen",
|
||||
"no_sync": "Kein Sync"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAICollectionCDokumente": "AI-Collection-Dokument-Verknüpfung erstellen",
|
||||
"CAICollectionCDokumente": "AI-Collection-Dokument-Verknüpfungen"
|
||||
},
|
||||
"fields": {
|
||||
"cAICollection": "AI-Collection",
|
||||
"cAICollectionId": "AI-Collection ID",
|
||||
"cDokumente": "Dokument",
|
||||
"cDokumenteId": "Dokument ID",
|
||||
"xaifileid": "XAI File ID",
|
||||
"syncStatus": "Sync-Status",
|
||||
"deleted": "Gelöscht"
|
||||
},
|
||||
"links": {
|
||||
"cAICollection": "AI-Collection",
|
||||
"cDokumente": "Dokument"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"new": "Neu",
|
||||
"changed": "Geändert",
|
||||
"synced": "Synchronisiert",
|
||||
"deleted": "Gelöscht"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"xaifileid": "Externe XAI File ID für dieses Dokument",
|
||||
"syncStatus": "Synchronisierungsstatus mit XAI"
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,47 @@
|
||||
{
|
||||
"fields": {
|
||||
"advowareAktenzeichen": "Advoware Aktenzeichen",
|
||||
"aktennr": "Advoware Identifikator",
|
||||
"syncStatus": "Sync-Status",
|
||||
"lastSync": "Letzte Synchronisation",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cmietinkassoId": "Mietinkasso ID",
|
||||
"cmietinkassoName": "Mietinkasso Name",
|
||||
"cvmhRumungsklage": "Räumungsklage",
|
||||
"cvmhRumungsklageId": "Räumungsklage ID",
|
||||
"cvmhRumungsklageName": "Räumungsklage Name"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Termine",
|
||||
"calls": "Anrufe",
|
||||
"tasks": "Aufgaben",
|
||||
"cDokumente": "Dokumente",
|
||||
"cAICollection": "AI Collection",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cvmhRumungsklage": "Räumungsklage"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Advoware Akte erstellen"
|
||||
},
|
||||
"tooltips": {
|
||||
"advowareAktenzeichen": "Aktenzeichen aus dem Advoware-System",
|
||||
"aktennr": "Eindeutige Aktennummer aus Advoware",
|
||||
"syncStatus": "Status der Advoware-Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert",
|
||||
"lastSync": "Zeitpunkt der letzten Synchronisation mit Advoware"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"pending_sync": "Warte auf Sync",
|
||||
"clean": "Synchronisiert",
|
||||
"unclean": "Änderungen ausstehend",
|
||||
"failed": "Fehlgeschlagen",
|
||||
"no_sync": "Kein Sync"
|
||||
"links": {
|
||||
"calls": "Anrufe",
|
||||
"tasks": "Aufgaben",
|
||||
"vmhRumungsklage": "Räumungsklagen",
|
||||
"mietinkasso": "Mietinkasso",
|
||||
"kuendigungen": "Kündigungen",
|
||||
"dokumentes": "Dokumente"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Advoware Akten erstellen"
|
||||
},
|
||||
"fields": {
|
||||
"vmhRumungsklage": "Räumungsklagen",
|
||||
"mietinkasso": "Mietinkasso",
|
||||
"aktenzeichen": "Aktenzeichen",
|
||||
"aktennummer": "Aktennummer",
|
||||
"syncStatus": "Sync-Status",
|
||||
"lastSync": "Letzte Synchronisation",
|
||||
"aktivierungsstatus": "Aktivierungsstatus",
|
||||
"dokumentes": "Dokumente",
|
||||
"dokumenteHnr": "HNR",
|
||||
"dokumenteSyncstatus": "Sync-Status",
|
||||
"dokumenteLastSync": "Letzter Sync",
|
||||
"dokumenteSyncedHash": "Sync-Hash"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"synced": "Synchronisiert",
|
||||
"unclean": "Nicht synchronisiert",
|
||||
"pending_sync": "Synchronisierung ausstehend",
|
||||
"failed": "Fehlgeschlagen"
|
||||
},
|
||||
"aktivierungsstatus": {
|
||||
"new": "Neu",
|
||||
"import": "Import",
|
||||
"active": "Aktiv",
|
||||
"paused": "Pausiert",
|
||||
"deactivated": "Deaktiviert"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"syncStatus": "Globaler Synchronisationsstatus: synced = Alle Dokumente synchronisiert, unclean = Mindestens ein Dokument ist neu oder hat Änderungen, pending_sync = Synchronisierung wurde gestartet aber noch nicht abgeschlossen, failed = Synchronisierung fehlgeschlagen. Wird automatisch basierend auf den Dokumenten-Status aktualisiert.",
|
||||
"lastSync": "Zeitpunkt der letzten erfolgreichen Synchronisation aller Dokumente",
|
||||
"aktivierungsstatus": "Aktivierungsstatus der Akte: new = Neu angelegt, import = Aus Advoware importiert, active = Aktiv synchronisiert, paused = Synchronisation pausiert, deactivated = Synchronisation deaktiviert"
|
||||
}
|
||||
}
|
||||
}
|
||||
99
custom/Espo/Custom/Resources/i18n/de_DE/CAkten.json
Normal file
99
custom/Espo/Custom/Resources/i18n/de_DE/CAkten.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"links": {
|
||||
"calls": "Anrufe",
|
||||
"tasks": "Aufgaben",
|
||||
"vmhRumungsklage": "Räumungsklagen",
|
||||
"mietinkasso": "Mietinkasso",
|
||||
"kuendigungen": "Kündigungen",
|
||||
"dokumentes": "Dokumente"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAkten": "Erstellen Akten"
|
||||
},
|
||||
"fields": {
|
||||
"vmhRumungsklage": "Räumungsklagen",
|
||||
"mietinkasso": "Mietinkasso",
|
||||
"aktenzeichen": "Aktenzeichen",
|
||||
"aktennummer": "Aktennummer",
|
||||
"syncStatus": "Advoware Sync-Status",
|
||||
"lastSync": "Advoware Letzter Sync",
|
||||
"aktivierungsstatus": "Advoware Aktivierungsstatus",
|
||||
"aiCollectionId": "AI Collection-ID",
|
||||
"aiAktivierungsstatus": "AI Aktivierungsstatus",
|
||||
"aiSyncStatus": "AI Sync-Status",
|
||||
"aiLastSync": "AI Letzter Sync",
|
||||
"aiProvider": "AI Anbieter",
|
||||
"globalSyncStatus": "Globaler Sync-Status",
|
||||
"globalLastSync": "Globaler letzter Sync",
|
||||
"syncSchalter": "Sync aktiv",
|
||||
"dokumentes": "Dokumente",
|
||||
"rubrum": "Rubrum",
|
||||
"aiParsingStatus": "AI Parsing-Status",
|
||||
"graphParsingStatus": "Graph Parsing-Status"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"synced": "Synchronisiert",
|
||||
"unclean": "Nicht synchronisiert",
|
||||
"pending_sync": "Synchronisierung ausstehend",
|
||||
"failed": "Fehlgeschlagen"
|
||||
},
|
||||
"aktivierungsstatus": {
|
||||
"new": "Neu",
|
||||
"import": "Import",
|
||||
"active": "Aktiv",
|
||||
"paused": "Pausiert",
|
||||
"deactivated": "Deaktiviert"
|
||||
},
|
||||
"aiAktivierungsstatus": {
|
||||
"new": "Neu",
|
||||
"import": "Import",
|
||||
"active": "Aktiv",
|
||||
"paused": "Pausiert",
|
||||
"deactivated": "Deaktiviert"
|
||||
},
|
||||
"aiSyncStatus": {
|
||||
"synced": "Synchronisiert",
|
||||
"unclean": "Nicht synchronisiert",
|
||||
"pending_sync": "Synchronisierung ausstehend",
|
||||
"failed": "Fehlgeschlagen"
|
||||
},
|
||||
"aiProvider": {
|
||||
"ragflow": "RAGflow",
|
||||
"xai": "xAI"
|
||||
},
|
||||
"globalSyncStatus": {
|
||||
"synced": "Synchronisiert",
|
||||
"unclean": "Nicht synchronisiert",
|
||||
"pending_sync": "Synchronisierung ausstehend",
|
||||
"failed": "Fehlgeschlagen"
|
||||
},
|
||||
"aiParsingStatus": {
|
||||
"unknown": "Unbekannt",
|
||||
"parsing": "In Verarbeitung",
|
||||
"complete": "Abgeschlossen",
|
||||
"complete_with_failures": "Abgeschlossen mit Fehlern"
|
||||
},
|
||||
"graphParsingStatus": {
|
||||
"no_graph": "Kein Graph",
|
||||
"parsing": "In Verarbeitung",
|
||||
"complete": "Abgeschlossen",
|
||||
"unclean": "Veraltet"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"syncStatus": "Advoware-Synchronisationsstatus: synced = Alle Dokumente synchronisiert, unclean = Mindestens ein Dokument ist neu oder hat Änderungen, pending_sync = Synchronisierung ausstehend, failed = Fehlgeschlagen.",
|
||||
"lastSync": "Zeitpunkt der letzten erfolgreichen Advoware-Synchronisation",
|
||||
"aktivierungsstatus": "Advoware Aktivierungsstatus: new = Neu angelegt, import = Aus Advoware importiert, active = Aktiv synchronisiert, paused = Pausiert, deactivated = Deaktiviert",
|
||||
"aiCollectionId": "Eindeutige ID der KI-Datenbank/Collection für diese Akte",
|
||||
"aiAktivierungsstatus": "KI-Sync Aktivierungsstatus: new = Neu, import = Importiert, active = Aktiv synchronisiert, paused = Pausiert, deactivated = Deaktiviert",
|
||||
"aiSyncStatus": "KI-Synchronisationsstatus: synced = Alle Dokumente synchronisiert, unclean = Änderungen vorhanden, pending_sync = Ausstehend, failed = Fehlgeschlagen",
|
||||
"aiLastSync": "Zeitpunkt der letzten erfolgreichen KI-Synchronisation",
|
||||
"advowareSyncEnabled": "Advoware-Synchronisation für diese Akte aktivieren oder deaktivieren",
|
||||
"aiSyncEnabled": "KI-Synchronisation für diese Akte aktivieren oder deaktivieren",
|
||||
"globalSyncStatus": "Übergreifender Sync-Status über alle Synchronisationssysteme",
|
||||
"globalLastSync": "Zeitpunkt des letzten Sync-Vorgangs über alle Systeme",
|
||||
"syncSchalter": "Globaler Sync-Schalter: aktiviert oder deaktiviert alle Synchronisationen für diese Akte",
|
||||
"rubrum": "Rubrum der Akte aus Advoware (Kurzbezeichnung der Parteien)"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAdvowareAktenCDokumente": "Advoware-Dokument-Verknüpfung erstellen",
|
||||
"CAdvowareAktenCDokumente": "Advoware-Dokument-Verknüpfungen"
|
||||
"Create CAktenCDokumente": "Advoware-Dokument-Verknüpfung erstellen",
|
||||
"CAktenCDokumente": "Advoware-Dokument-Verknüpfungen"
|
||||
},
|
||||
"fields": {
|
||||
"cAdvowareAkten": "Advoware-Akte",
|
||||
"cAdvowareAktenId": "Advoware-Akte ID",
|
||||
"cAkten": "Akte",
|
||||
"cAktenId": "Akten-ID",
|
||||
"cDokumente": "Dokument",
|
||||
"cDokumenteId": "Dokument ID",
|
||||
"hnr": "HNR",
|
||||
"syncStatus": "Sync-Status",
|
||||
"syncedHash": "Sync-Hash",
|
||||
"deleted": "Gelöscht"
|
||||
},
|
||||
"links": {
|
||||
"cAdvowareAkten": "Advoware-Akte",
|
||||
"cAkten": "Akte",
|
||||
"cDokumente": "Dokument"
|
||||
},
|
||||
"options": {
|
||||
@@ -26,6 +27,7 @@
|
||||
},
|
||||
"tooltips": {
|
||||
"hnr": "Advoware HNR Referenz für dieses Dokument",
|
||||
"syncStatus": "Synchronisierungsstatus mit Advoware"
|
||||
"syncStatus": "Synchronisierungsstatus mit Advoware",
|
||||
"syncedHash": "Hash-Wert des zuletzt synchronisierten Dokument-Zustands (zur Änderungserkennung)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,15 @@
|
||||
"fields": {
|
||||
"dokument": "Download",
|
||||
"preview": "Vorschau",
|
||||
"ydocumentuuid": "Y-Document-UUID",
|
||||
"md5sum": "MD5-Prüfsumme",
|
||||
"sha256": "SHA256-Prüfsumme",
|
||||
"aktennr": "Advoware Identifikator",
|
||||
"advowareLastSync": "Advoware letzte Synchronisation",
|
||||
"syncStatus": "Sync-Status",
|
||||
"xaiId": "x.AI ID",
|
||||
"xaiCollections": "x.AI Collections",
|
||||
"xaiSyncStatus": "Sync-Status",
|
||||
"fileStatus": "Datei-Status",
|
||||
"blake3hash": "Blake3-Hash",
|
||||
"hnr": "HNR (Advoware)",
|
||||
"syncStatus": "Advoware Sync-Status",
|
||||
"syncedHash": "Advoware Sync-Hash",
|
||||
"usn": "USN",
|
||||
"dateipfad": "Dateipfad",
|
||||
"lastSyncTimestamp": "Advoware Letzter Sync",
|
||||
"advowareArt": "Advoware Art",
|
||||
"advowareBemerkung": "Advoware Bemerkung",
|
||||
"contactsvmhdokumente": "Freigegebene Nutzer",
|
||||
"vmhMietverhltnisesDokumente": "Mietverhältnisse",
|
||||
"vmhErstgespraechsdokumente": "Erstgespräche",
|
||||
@@ -20,7 +19,19 @@
|
||||
"beteiligte2dokumente": "Beteiligte",
|
||||
"mietobjekt2dokumente": "Mietobjekte",
|
||||
"mietinkassosdokumente": "Mietinkasso",
|
||||
"kndigungensdokumente": "Kündigungen"
|
||||
"kndigungensdokumente": "Kündigungen",
|
||||
"aiKnowledgeAiDocumentId": "AI Document ID",
|
||||
"aiKnowledgeSyncstatus": "AI Sync-Status",
|
||||
"aiKnowledgeLastSync": "AI Letzter Sync",
|
||||
"cAkten": "Akte",
|
||||
"cAktenId": "Akten-ID",
|
||||
"cAktenName": "Aktenname",
|
||||
"aiCollectionId": "AI Collection-ID",
|
||||
"aiSyncHash": "AI Sync-Hash",
|
||||
"aiSyncStatus": "AI Sync-Status",
|
||||
"aiLastSync": "AI Letzter Sync",
|
||||
"aiFileId": "AI File-ID",
|
||||
"aiParsingStatus": "AI Parsing-Status"
|
||||
},
|
||||
"links": {
|
||||
"contactsvmhdokumente": "Freigegebene Nutzer",
|
||||
@@ -32,40 +43,47 @@
|
||||
"mietobjekt2dokumente": "Mietobjekte",
|
||||
"mietinkassosdokumente": "Mietinkasso",
|
||||
"kndigungensdokumente": "Kündigungen",
|
||||
"cAICollections": "AI Collections",
|
||||
"cAdvowareAkten": "Advoware-Akten"
|
||||
"cAkten": "Akte"
|
||||
},
|
||||
"labels": {
|
||||
"Create CDokumente": "Dokument erstellen"
|
||||
},
|
||||
"tooltips": {
|
||||
"aktennr": "Eindeutige Dokument-Nummer aus Advoware",
|
||||
"advowareLastSync": "Zeitpunkt der letzten Synchronisation mit Advoware",
|
||||
"syncStatus": "Status der Advoware-Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert",
|
||||
"xaiId": "Eindeutige ID für x.AI Synchronisation",
|
||||
"xaiCollections": "Liste der x.AI Collections für dieses Dokument",
|
||||
"xaiSyncStatus": "Status der x.AI Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert",
|
||||
"fileStatus": "Status der Datei: new = neu hochgeladen, changed = geändert, synced = synchronisiert"
|
||||
"blake3hash": "Kryptografischer Blake3-Hash der Datei (schneller und sicherer als MD5/SHA256)",
|
||||
"hnr": "Hierarchische Referenznummer in Advoware",
|
||||
"syncStatus": "Advoware Sync-Status: new=neu, unclean=geändert, synced=synchronisiert, failed=Fehler, unsupported=nicht unterstützt",
|
||||
"syncedHash": "Hash-Wert bei letzter erfolgreicher Advoware-Synchronisation",
|
||||
"usn": "Update Sequence Number - Versionsnummer für Synchronisation",
|
||||
"dateipfad": "Windows-Dateipfad des Dokuments in Advoware",
|
||||
"lastSyncTimestamp": "Zeitstempel der letzten erfolgreichen Advoware-Synchronisation",
|
||||
"advowareArt": "Dokumententyp/Art wie in Advoware klassifiziert",
|
||||
"advowareBemerkung": "Bemerkungsfeld aus Advoware - wird bei Sync übernommen",
|
||||
"aiCollectionId": "ID der KI-Collection, in der dieses Dokument indexiert ist",
|
||||
"aiSyncHash": "Hash-Wert bei letzter erfolgreicher KI-Synchronisation",
|
||||
"aiSyncStatus": "Synchronisationsstatus mit der KI-Datenbank: new=neu, unclean=geändert, synced=synchronisiert, failed=Fehler, unsupported=nicht unterstützt",
|
||||
"aiLastSync": "Zeitstempel der letzten erfolgreichen KI-Synchronisation",
|
||||
"aiFileId": "Datei-ID in der KI-Datenbank nach erfolgter Synchronisation"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"pending_sync": "Warte auf Sync",
|
||||
"clean": "Synchronisiert",
|
||||
"unclean": "Änderungen ausstehend",
|
||||
"failed": "Fehlgeschlagen",
|
||||
"no_sync": "Kein Sync"
|
||||
},
|
||||
"xaiSyncStatus": {
|
||||
"pending_sync": "Warte auf Sync",
|
||||
"clean": "Synchronisiert",
|
||||
"unclean": "Abweichungen",
|
||||
"failed": "Fehlgeschlagen",
|
||||
"no_sync": "Kein Sync"
|
||||
},
|
||||
"fileStatus": {
|
||||
"new": "Neu",
|
||||
"changed": "Geändert",
|
||||
"synced": "Synchronisiert"
|
||||
"unclean": "Geändert",
|
||||
"synced": "Synchronisiert",
|
||||
"failed": "Fehler",
|
||||
"unsupported": "Nicht unterstützt"
|
||||
},
|
||||
"aiSyncStatus": {
|
||||
"new": "Neu",
|
||||
"unclean": "Geändert",
|
||||
"synced": "Synchronisiert",
|
||||
"failed": "Fehler",
|
||||
"unsupported": "Nicht unterstützt"
|
||||
},
|
||||
"aiParsingStatus": {
|
||||
"unknown": "Unbekannt",
|
||||
"parsing": "In Verarbeitung",
|
||||
"complete": "Abgeschlossen",
|
||||
"failed": "Fehlgeschlagen"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
"gekuendigte": "Mieter",
|
||||
"dokumenteskuendigung": "Dokumente",
|
||||
"contactsKuendigung": "Portal-Freigaben",
|
||||
"advowareAkten": "Advoware Akte",
|
||||
"vmhRumungsklages": "Räumungsklagen",
|
||||
"pulse": "Pulse"
|
||||
},
|
||||
"labels": {
|
||||
@@ -32,7 +34,7 @@
|
||||
"modifiedBy": "Geändert von",
|
||||
"freigeschalteteNutzer": "Freigeschaltete Nutzer",
|
||||
"collaborators": "Mitarbeiter",
|
||||
"advowareAktenzeichen": "Advoware Aktenzeichen",
|
||||
"advowareAkten": "Advoware Akte",
|
||||
"aktennr": "Advoware Identifikator",
|
||||
"advowareLastSync": "Letzter Sync",
|
||||
"syncStatus": "Sync Status",
|
||||
@@ -104,7 +106,6 @@
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"advowareAktenzeichen": "Aktenzeichen aus Advoware für die Synchronisation",
|
||||
"aktennr": "Eindeutige Kündigungs-Nummer aus Advoware",
|
||||
"syncStatus": "Status der Advoware-Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert",
|
||||
"sendungsverfolgungsnummer": "Sendungsverfolgungsnummer für Einschreiben",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"vmhMietverhltnises": "Mietverhältnisse",
|
||||
"contactsMietinkasso": "Freigegebene Nutzer",
|
||||
"dokumentesmietinkasso": "Dokumente",
|
||||
"gerichtsrubrum": "Gerichtsrubrum",
|
||||
"gegenstandswert": "Gegenstandswert",
|
||||
"kuendigungsservice": "Kündigungsservice",
|
||||
"aussergerichtlicheGebuehren13": "Außergerichtliche Gebühren 1,3",
|
||||
@@ -14,8 +13,7 @@
|
||||
"freigeschalteteNutzer": "Freigeschaltete Nutzer (veraltet)",
|
||||
"collaborators": "Mitarbeiter",
|
||||
"vmhVermietersMIK": "Vermieter",
|
||||
"cAdvowareAkte": "Advoware-Akte",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Termine",
|
||||
@@ -30,14 +28,12 @@
|
||||
"collaborators": "Mitarbeiter",
|
||||
"vmhVermietersMIK": "Vermieter",
|
||||
"pulse": "Pulse",
|
||||
"cAdvowareAkte": "Advoware-Akte",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"labels": {
|
||||
"Create CMietinkasso": "Mietinkasso erstellen"
|
||||
},
|
||||
"tooltips": {
|
||||
"gerichtsrubrum": "Rubrum des Gerichtsverfahrens",
|
||||
"gegenstandswert": "Wert des Streitgegenstands",
|
||||
"kuendigungsservice": "Kündigungsservice aktiviert"
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
"freigeschalteteNutzer": "Freigeschaltete Nutzer (veraltet)",
|
||||
"collaborators": "Mitarbeiter",
|
||||
"vmhVermietersRKL": "Vermieter",
|
||||
"cAdvowareAkte": "Advoware-Akte",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Termine",
|
||||
@@ -25,14 +24,14 @@
|
||||
"klaeger": "Kläger",
|
||||
"beklagte": "Beklagte",
|
||||
"vmhMietverhltnises": "Mietverhältnisse",
|
||||
"kuendigungen": "Kündigungen",
|
||||
"contactsRumungsklage": "Freigegebene Nutzer",
|
||||
"dokumentesvmhraumungsklage": "Dokumente",
|
||||
"freigeschalteteNutzer": "Freigeschaltete Nutzer (veraltet)",
|
||||
"collaborators": "Mitarbeiter",
|
||||
"vmhVermietersRKL": "Vermieter",
|
||||
"pulse": "Pulse",
|
||||
"cAdvowareAkte": "Advoware-Akte",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"labels": {
|
||||
"Create CVmhRumungsklage": "Räumungsklage erstellen"
|
||||
|
||||
@@ -4,5 +4,11 @@
|
||||
},
|
||||
"labels": {
|
||||
"Log": "Log"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"CAkten": "Akten"
|
||||
},
|
||||
"scopeNames": {
|
||||
"CAkten": "Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Εργασίες"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Δημιουργία Advoware Akte"
|
||||
"Create CAdvowareAkten": "Δημιουργία Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Εργασίες"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Δημιουργία AI Collection"
|
||||
"Create CAkten": "Δημιουργία Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"fields": {
|
||||
"cAdvowareAkte": "Advoware File",
|
||||
"cAdvowareAkteId": "Advoware File ID",
|
||||
"cAdvowareAkteName": "Advoware File Name",
|
||||
"xaiCollectionId": "x.AI Collection ID",
|
||||
"syncStatus": "Sync Status",
|
||||
"lastSync": "Last Sync",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cmietinkassoId": "Mietinkasso ID",
|
||||
"cmietinkassoName": "Mietinkasso Name",
|
||||
"cvmhRumungsklage": "Räumungsklage",
|
||||
"cvmhRumungsklageId": "Räumungsklage ID",
|
||||
"cvmhRumungsklageName": "Räumungsklage Name"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"cDokumente": "Documents",
|
||||
"cAdvowareAkte": "Advoware File",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cvmhRumungsklage": "Räumungsklage"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Create AI Collection"
|
||||
},
|
||||
"tooltips": {
|
||||
"xaiCollectionId": "Collection ID for x.AI synchronization",
|
||||
"syncStatus": "x.AI synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized",
|
||||
"lastSync": "Time of last synchronization with x.AI"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"pending_sync": "Waiting for Sync",
|
||||
"clean": "Synchronized",
|
||||
"unclean": "Changes Pending",
|
||||
"failed": "Failed",
|
||||
"no_sync": "No Sync"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAICollectionCDokumente": "Create AI Collection Document Link",
|
||||
"CAICollectionCDokumente": "AI Collection Document Links"
|
||||
},
|
||||
"fields": {
|
||||
"cAICollection": "AI Collection",
|
||||
"cAICollectionId": "AI Collection ID",
|
||||
"cDokumente": "Document",
|
||||
"cDokumenteId": "Document ID",
|
||||
"xaifileid": "XAI File ID",
|
||||
"syncStatus": "Sync Status",
|
||||
"deleted": "Deleted"
|
||||
},
|
||||
"links": {
|
||||
"cAICollection": "AI Collection",
|
||||
"cDokumente": "Document"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"new": "New",
|
||||
"changed": "Changed",
|
||||
"synced": "Synced",
|
||||
"deleted": "Deleted"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"xaifileid": "External XAI file ID for this document",
|
||||
"syncStatus": "Synchronization status with XAI"
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,48 @@
|
||||
{
|
||||
"fields": {
|
||||
"advowareAktenzeichen": "Advoware Case Number",
|
||||
"aktennr": "Advoware Identifier",
|
||||
"syncStatus": "Sync Status",
|
||||
"lastSync": "Last Sync",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cmietinkassoId": "Mietinkasso ID",
|
||||
"cmietinkassoName": "Mietinkasso Name",
|
||||
"cvmhRumungsklage": "Räumungsklage",
|
||||
"cvmhRumungsklageId": "Räumungsklage ID",
|
||||
"cvmhRumungsklageName": "Räumungsklage Name"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"cDokumente": "Documents",
|
||||
"cAICollection": "AI Collection",
|
||||
"cmietinkasso": "Mietinkasso",
|
||||
"cvmhRumungsklage": "Räumungsklage"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Create Advoware Akte"
|
||||
},
|
||||
"tooltips": {
|
||||
"advowareAktenzeichen": "Case number from Advoware system",
|
||||
"aktennr": "Unique case number from Advoware",
|
||||
"syncStatus": "Advoware synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized",
|
||||
"lastSync": "Time of last synchronization with Advoware"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"pending_sync": "Waiting for Sync",
|
||||
"clean": "Synchronized",
|
||||
"unclean": "Changes Pending",
|
||||
"failed": "Failed",
|
||||
"no_sync": "No Sync"
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"fields": {
|
||||
"vmhRumungsklage": "Räumungsklagen",
|
||||
"mietinkasso": "Mietinkasso",
|
||||
"aktenzeichen": "Aktenzeichen",
|
||||
"aktennummer": "Aktennummer",
|
||||
"syncStatus": "Sync Status",
|
||||
"lastSync": "Last Synchronization",
|
||||
"aktivierungsstatus": "Activation Status",
|
||||
"dokumentes": "Dokumente",
|
||||
"dokumenteHnr": "HNR",
|
||||
"dokumenteSyncstatus": "Sync Status",
|
||||
"dokumenteLastSync": "Last Sync",
|
||||
"dokumenteSyncedHash": "Sync Hash"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"vmhRumungsklage": "Räumungsklagen",
|
||||
"mietinkasso": "Mietinkasso",
|
||||
"kuendigungen": "Terminations",
|
||||
"dokumentes": "Dokumente"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Create Advoware Akten"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"synced": "Synchronized",
|
||||
"unclean": "Not Synchronized",
|
||||
"pending_sync": "Synchronization Pending",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"aktivierungsstatus": {
|
||||
"new": "New",
|
||||
"import": "Import",
|
||||
"active": "Active",
|
||||
"paused": "Paused",
|
||||
"deactivated": "Deactivated"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"syncStatus": "Global synchronization status: synced = All documents synchronized, unclean = At least one document is new or has changes, pending_sync = Synchronization started but not yet completed, failed = Synchronization failed. Updated automatically based on document status.",
|
||||
"lastSync": "Timestamp of the last successful synchronization of all documents",
|
||||
"aktivierungsstatus": "Activation status of the file: new = Newly created, import = Imported from Advoware, active = Actively synchronized, paused = Synchronization paused, deactivated = Synchronization deactivated"
|
||||
}
|
||||
}
|
||||
100
custom/Espo/Custom/Resources/i18n/en_US/CAkten.json
Normal file
100
custom/Espo/Custom/Resources/i18n/en_US/CAkten.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"vmhRumungsklage": "Eviction Lawsuits",
|
||||
"mietinkasso": "Rent Collection",
|
||||
"kuendigungen": "Terminations",
|
||||
"dokumentes": "Documents"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAkten": "Erstellen Akten"
|
||||
},
|
||||
"fields": {
|
||||
"vmhRumungsklage": "Eviction Lawsuit",
|
||||
"mietinkasso": "Rent Collection",
|
||||
"aktenzeichen": "File Reference",
|
||||
"aktennummer": "File Number",
|
||||
"syncStatus": "Advoware Sync Status",
|
||||
"lastSync": "Advoware Last Sync",
|
||||
"aktivierungsstatus": "Advoware Activation Status",
|
||||
"aiCollectionId": "AI Collection ID",
|
||||
"aiAktivierungsstatus": "AI Activation Status",
|
||||
"aiSyncStatus": "AI Sync Status",
|
||||
"aiLastSync": "AI Last Sync",
|
||||
"aiProvider": "AI Provider",
|
||||
"globalSyncStatus": "Global Sync Status",
|
||||
"globalLastSync": "Global Last Sync",
|
||||
"syncSchalter": "Sync Active",
|
||||
"dokumentes": "Documents",
|
||||
"rubrum": "Rubrum",
|
||||
"aiParsingStatus": "AI Parsing Status",
|
||||
"graphParsingStatus": "Graph Parsing Status"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"synced": "Synchronized",
|
||||
"unclean": "Not Synchronized",
|
||||
"pending_sync": "Synchronization Pending",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"aktivierungsstatus": {
|
||||
"new": "New",
|
||||
"import": "Import",
|
||||
"active": "Active",
|
||||
"paused": "Paused",
|
||||
"deactivated": "Deactivated"
|
||||
},
|
||||
"aiAktivierungsstatus": {
|
||||
"new": "New",
|
||||
"import": "Import",
|
||||
"active": "Active",
|
||||
"paused": "Paused",
|
||||
"deactivated": "Deactivated"
|
||||
},
|
||||
"aiSyncStatus": {
|
||||
"synced": "Synchronized",
|
||||
"unclean": "Not Synchronized",
|
||||
"pending_sync": "Synchronization Pending",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"aiProvider": {
|
||||
"ragflow": "RAGflow",
|
||||
"xai": "xAI"
|
||||
},
|
||||
"globalSyncStatus": {
|
||||
"synced": "Synchronized",
|
||||
"unclean": "Not Synchronized",
|
||||
"pending_sync": "Synchronization Pending",
|
||||
"failed": "Failed"
|
||||
},
|
||||
"aiParsingStatus": {
|
||||
"unknown": "Unknown",
|
||||
"parsing": "Parsing",
|
||||
"complete": "Complete",
|
||||
"complete_with_failures": "Complete with Failures"
|
||||
},
|
||||
"graphParsingStatus": {
|
||||
"no_graph": "No Graph",
|
||||
"parsing": "Parsing",
|
||||
"complete": "Complete",
|
||||
"unclean": "Stale"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"syncStatus": "Advoware sync status: synced = All documents synchronized, unclean = At least one document changed, pending_sync = Pending, failed = Failed.",
|
||||
"lastSync": "Timestamp of last successful Advoware synchronization",
|
||||
"aktivierungsstatus": "Advoware activation status: new = Newly created, import = Imported from Advoware, active = Actively synchronized, paused = Paused, deactivated = Deactivated",
|
||||
"aiCollectionId": "Unique ID of the AI database/collection for this file",
|
||||
"aiAktivierungsstatus": "AI sync activation status: new = New, import = Imported, active = Actively synchronized, paused = Paused, deactivated = Deactivated",
|
||||
"aiSyncStatus": "AI sync status: synced = All documents synchronized, unclean = Changes pending, pending_sync = Pending, failed = Failed",
|
||||
"aiLastSync": "Timestamp of last successful AI synchronization",
|
||||
"advowareSyncEnabled": "Enable or disable Advoware synchronization for this file",
|
||||
"aiSyncEnabled": "Enable or disable AI synchronization for this file",
|
||||
"globalSyncStatus": "Overall sync status across all synchronization systems",
|
||||
"globalLastSync": "Timestamp of last sync across all systems",
|
||||
"syncSchalter": "Global sync switch: enables or disables all synchronizations for this file",
|
||||
"rubrum": "Rubrum of the file from Advoware (short designation of parties)"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAdvowareAktenCDokumente": "Create Advoware Document Link",
|
||||
"CAdvowareAktenCDokumente": "Advoware Document Links"
|
||||
"Create CAktenCDokumente": "Create Advoware Document Link",
|
||||
"CAktenCDokumente": "Advoware Document Links"
|
||||
},
|
||||
"fields": {
|
||||
"cAdvowareAkten": "Advoware File",
|
||||
"cAdvowareAktenId": "Advoware File ID",
|
||||
"cAkten": "File",
|
||||
"cAktenId": "File ID",
|
||||
"cDokumente": "Document",
|
||||
"cDokumenteId": "Document ID",
|
||||
"hnr": "HNR",
|
||||
"syncStatus": "Sync Status",
|
||||
"syncedHash": "Sync Hash",
|
||||
"deleted": "Deleted"
|
||||
},
|
||||
"links": {
|
||||
"cAdvowareAkten": "Advoware File",
|
||||
"cAkten": "File",
|
||||
"cDokumente": "Document"
|
||||
},
|
||||
"options": {
|
||||
@@ -26,6 +27,7 @@
|
||||
},
|
||||
"tooltips": {
|
||||
"hnr": "Advoware HNR reference for this document",
|
||||
"syncStatus": "Synchronization status with Advoware"
|
||||
"syncStatus": "Synchronization status with Advoware",
|
||||
"syncedHash": "Hash value of the last synchronized document state (for change detection)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,37 @@
|
||||
{
|
||||
"fields": {
|
||||
"dokument": "Download",
|
||||
"ydocumentuuid": "Y-Document-UUID",
|
||||
"preview": "Preview",
|
||||
"hnr": "HNR (Advoware)",
|
||||
"syncStatus": "Advoware Sync Status",
|
||||
"syncedHash": "Advoware Sync Hash",
|
||||
"usn": "USN",
|
||||
"dateipfad": "File Path",
|
||||
"lastSyncTimestamp": "Advoware Last Sync",
|
||||
"advowareArt": "Advoware Type",
|
||||
"advowareBemerkung": "Advoware Remarks",
|
||||
"contactsvmhdokumente": "Portal Users",
|
||||
"vmhMietverhltnisesDokumente": "Tenancies",
|
||||
"vmhErstgespraechsdokumente": "Initial Consultations",
|
||||
"vmhRumungsklagesdokumente": "Eviction Lawsuits",
|
||||
"kuendigungDokumente": "Terminations",
|
||||
"md5sum": "MD5 Checksum",
|
||||
"sha256": "SHA256 Checksum",
|
||||
"blake3hash": "Blake3 Hash",
|
||||
"beteiligte2dokumente": "Parties",
|
||||
"mietobjekt2dokumente": "Properties",
|
||||
"mietinkassosdokumente": "Rent Collection",
|
||||
"kndigungensdokumente": "Terminations",
|
||||
"aktennr": "Advoware Identifier",
|
||||
"advowareLastSync": "Advoware Last Sync",
|
||||
"syncStatus": "Sync Status",
|
||||
"xaiId": "x.AI ID",
|
||||
"xaiCollections": "x.AI Collections",
|
||||
"xaiSyncStatus": "Sync Status",
|
||||
"fileStatus": "File Status"
|
||||
"aiKnowledgeAiDocumentId": "AI Document ID",
|
||||
"aiKnowledgeSyncstatus": "AI Sync Status",
|
||||
"aiKnowledgeLastSync": "AI Last Sync",
|
||||
"cAkten": "File",
|
||||
"cAktenId": "File ID",
|
||||
"cAktenName": "File Name",
|
||||
"aiCollectionId": "AI Collection ID",
|
||||
"aiSyncHash": "AI Sync Hash",
|
||||
"aiSyncStatus": "AI Sync Status",
|
||||
"aiLastSync": "AI Last Sync",
|
||||
"aiFileId": "AI File ID",
|
||||
"aiParsingStatus": "AI Parsing Status"
|
||||
},
|
||||
"links": {
|
||||
"contactsvmhdokumente": "Portal Users",
|
||||
@@ -32,43 +43,53 @@
|
||||
"mietobjekt2dokumente": "Properties",
|
||||
"mietinkassosdokumente": "Rent Collection",
|
||||
"kndigungensdokumente": "Terminations",
|
||||
"cAICollections": "AI Collections",
|
||||
"cAdvowareAkten": "Advoware Files"
|
||||
"cAkten": "File"
|
||||
},
|
||||
"labels": {
|
||||
"Create CDokumente": "Create Dokument"
|
||||
},
|
||||
"layouts": {
|
||||
"listRaeumungsKl": "List (RaeumungsKl)"
|
||||
"listRaeumungsKl": "List (RaeumungsKl)",
|
||||
"listForAdvowareAkten": "List for Advoware Akten",
|
||||
"listForAIKnowledge": "List for AI Knowledge",
|
||||
"listForAkten": "List for Akten"
|
||||
},
|
||||
"tooltips": {
|
||||
"aktennr": "Unique document number from Advoware",
|
||||
"advowareLastSync": "Time of last synchronization with Advoware",
|
||||
"syncStatus": "Advoware synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized",
|
||||
"xaiId": "Unique ID for x.AI synchronization",
|
||||
"xaiCollections": "List of x.AI collections for this document",
|
||||
"xaiSyncStatus": "x.AI synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized",
|
||||
"fileStatus": "File status: new = newly uploaded, changed = modified, synced = synchronized"
|
||||
"blake3hash": "Cryptographic Blake3 hash of the file (faster and more secure than MD5/SHA256)",
|
||||
"hnr": "Hierarchical reference number in Advoware",
|
||||
"syncStatus": "Advoware sync status: new=new, unclean=changed, synced=synchronized, failed=error, unsupported=not supported",
|
||||
"syncedHash": "Hash value at last successful Advoware synchronization",
|
||||
"usn": "Update Sequence Number - Version number for synchronization",
|
||||
"dateipfad": "Windows file path of the document in Advoware",
|
||||
"lastSyncTimestamp": "Timestamp of last successful Advoware synchronization",
|
||||
"advowareArt": "Document type/kind as classified in Advoware",
|
||||
"advowareBemerkung": "Remarks field from Advoware - synced automatically",
|
||||
"aiCollectionId": "ID of the AI collection in which this document is indexed",
|
||||
"aiSyncHash": "Hash value at last successful AI synchronization",
|
||||
"aiSyncStatus": "AI sync status: new=new, unclean=changed, synced=synchronized, failed=error, unsupported=not supported",
|
||||
"aiLastSync": "Timestamp of last successful AI synchronization",
|
||||
"aiFileId": "File ID in the AI database after successful synchronization"
|
||||
},
|
||||
"options": {
|
||||
"syncStatus": {
|
||||
"pending_sync": "Waiting for Sync",
|
||||
"clean": "Synchronized",
|
||||
"unclean": "Changes Pending",
|
||||
"failed": "Failed",
|
||||
"no_sync": "No Sync"
|
||||
},
|
||||
"xaiSyncStatus": {
|
||||
"pending_sync": "Waiting for Sync",
|
||||
"clean": "Synchronized",
|
||||
"unclean": "Changes Pending",
|
||||
"failed": "Failed",
|
||||
"no_sync": "No Sync"
|
||||
},
|
||||
"fileStatus": {
|
||||
"new": "New",
|
||||
"changed": "Changed",
|
||||
"synced": "Synchronized"
|
||||
"unclean": "Changed",
|
||||
"synced": "Synchronized",
|
||||
"failed": "Failed",
|
||||
"unsupported": "Unsupported"
|
||||
},
|
||||
"aiSyncStatus": {
|
||||
"new": "New",
|
||||
"unclean": "Changed",
|
||||
"synced": "Synchronized",
|
||||
"failed": "Failed",
|
||||
"unsupported": "Unsupported"
|
||||
},
|
||||
"aiParsingStatus": {
|
||||
"unknown": "Unknown",
|
||||
"parsing": "Parsing",
|
||||
"complete": "Complete",
|
||||
"failed": "Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"modifiedBy": "Modified By",
|
||||
"freigeschalteteNutzer": "Authorized Users",
|
||||
"collaborators": "Collaborators",
|
||||
"advowareAktenzeichen": "Advoware File Number",
|
||||
"advowareAkten": "Advoware File",
|
||||
"aktennr": "Case Number",
|
||||
"advowareLastSync": "Last Sync",
|
||||
"syncStatus": "Sync Status",
|
||||
@@ -44,6 +44,8 @@
|
||||
"gekuendigte": "Tenant",
|
||||
"dokumenteskuendigung": "Documents",
|
||||
"contactsKuendigung": "Portal Access",
|
||||
"advowareAkten": "Advoware Case File",
|
||||
"vmhRumungsklages": "Eviction Lawsuits",
|
||||
"pulse": "Pulses"
|
||||
},
|
||||
"labels": {
|
||||
@@ -103,7 +105,6 @@
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
"advowareAktenzeichen": "File number from Advoware for synchronization",
|
||||
"aktennr": "Case number from Advoware",
|
||||
"syncStatus": "Advoware synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized",
|
||||
"sendungsverfolgungsnummer": "Tracking number for registered mail",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
"vmhMietverhltnises": "Tenancies",
|
||||
"contactsMietinkasso": "Portal Users",
|
||||
"dokumentesmietinkasso": "Documents",
|
||||
"gerichtsrubrum": "Court Rubrum",
|
||||
"gegenstandswert": "Claim Value",
|
||||
"kuendigungsservice": "Termination Service",
|
||||
"aussergerichtlicheGebuehren13": "Out-of-court Fees 1.3",
|
||||
@@ -14,8 +13,7 @@
|
||||
"freigeschalteteNutzer": "Activated Users (deprecated)",
|
||||
"collaborators": "Collaborators",
|
||||
"vmhVermietersMIK": "Landlord",
|
||||
"cAdvowareAkte": "Advoware File",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
@@ -30,14 +28,12 @@
|
||||
"collaborators": "Collaborators",
|
||||
"vmhVermietersMIK": "Landlord",
|
||||
"pulse": "Pulses",
|
||||
"cAdvowareAkte": "Advoware File",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"labels": {
|
||||
"Create CMietinkasso": "Create Mietinkasso"
|
||||
},
|
||||
"tooltips": {
|
||||
"gerichtsrubrum": "Court proceeding rubrum",
|
||||
"gegenstandswert": "Value of the disputed matter",
|
||||
"kuendigungsservice": "Termination service enabled"
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
"aussergerichtlicheGebuehren13": "Out-of-Court Fees 1.3",
|
||||
"gerichtskosten1Instanz": "Court Costs 1st Instance",
|
||||
"anwaltskosten1Instanz": "Attorney Fees 1st Instance",
|
||||
"cAdvowareAkte": "Advoware File",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"links": {
|
||||
"meetings": "Meetings",
|
||||
"calls": "Calls",
|
||||
"tasks": "Tasks",
|
||||
"vmhMietverhltnises": "Tenancies",
|
||||
"kuendigungen": "Terminations",
|
||||
"freigeschalteteNutzer": "Activated Users",
|
||||
"collaborators": "Collaborators",
|
||||
"vmhVermietersRKL": "Landlord",
|
||||
@@ -29,8 +29,7 @@
|
||||
"klaeger": "Plaintiff",
|
||||
"contactsRumungsklage": "Portal Users",
|
||||
"pulse": "Pulses",
|
||||
"cAdvowareAkte": "Advoware File",
|
||||
"cAICollection": "AI Collection"
|
||||
"advowareAkten": "Advoware Akten"
|
||||
},
|
||||
"labels": {
|
||||
"Create CVmhRumungsklage": "Create Räumungsklage"
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
"CMietinkasso": "Mietinkasso",
|
||||
"CKuendigung": "Kündigung",
|
||||
"CPuls": "Puls",
|
||||
"CAICollection": "AI Collection",
|
||||
"CAdvowareAkten": "Advoware Akte"
|
||||
"CAkten": "Akten"
|
||||
},
|
||||
"scopeNamesPlural": {
|
||||
"CVmhMietverhltnis": "Mietverhältnisse",
|
||||
@@ -34,7 +33,6 @@
|
||||
"CMietinkasso": "Mietinkassa",
|
||||
"CKuendigung": "Kündigungen",
|
||||
"CPuls": "Pulse",
|
||||
"CAICollection": "AI Collections",
|
||||
"CAdvowareAkten": "Advoware Akten"
|
||||
"CAkten": "Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Crear Advoware Akte"
|
||||
"Create CAdvowareAkten": "Crear Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Crear AI Collection"
|
||||
"Create CAkten": "Crear Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Crear Advoware Akte"
|
||||
"Create CAdvowareAkten": "Crear Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Tareas"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Crear AI Collection"
|
||||
"Create CAkten": "Crear Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "وظایف"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "ایجاد Advoware Akte"
|
||||
"Create CAdvowareAkten": "ایجاد Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "وظایف"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "ایجاد AI Collection"
|
||||
"Create CAkten": "ایجاد Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAICollection": "Créer un AI Collection"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Créer un Advoware Akte"
|
||||
"Create CAdvowareAkten": "Créer un Advoware Akten"
|
||||
}
|
||||
}
|
||||
5
custom/Espo/Custom/Resources/i18n/fr_FR/CAkten.json
Normal file
5
custom/Espo/Custom/Resources/i18n/fr_FR/CAkten.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAkten": "Créer un Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Zadaci"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Kreiraj Advoware Akte"
|
||||
"Create CAdvowareAkten": "Kreiraj Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Zadaci"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "Kreiraj AI Collection"
|
||||
"Create CAkten": "Kreiraj Advoware Akten"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@
|
||||
"tasks": "Feladatok"
|
||||
},
|
||||
"labels": {
|
||||
"Create CAICollection": "{EntityTypeTranslated} létrehozása"
|
||||
"Create CAkten": "{EntityTypeTranslated} létrehozása"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAICollection": "Buat AI Collection"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"labels": {
|
||||
"Create CAdvowareAkten": "Buat Advoware Akte"
|
||||
"Create CAdvowareAkten": "Buat Advoware Akten"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user