Compare commits

...

113 Commits
7.1.0 ... 7.1.8

Author SHA1 Message Date
Yuri Kuznetsov
8ec6fa0f52 v 2022-06-29 19:41:06 +03:00
Yuri Kuznetsov
0fb683bbac secure cookie 2022-06-29 19:33:40 +03:00
Yuri Kuznetsov
bc9490a7e4 sanitize csv export 2022-06-29 18:50:08 +03:00
Yuri Kuznetsov
a0642e85b4 sanitize import preview 2022-06-29 17:45:55 +03:00
Yuri Kuznetsov
e61f9eb242 cut long email subject 2022-06-28 09:36:07 +03:00
Yuri Kuznetsov
2c87d47507 fix 2022-06-26 12:11:55 +03:00
Yuri Kuznetsov
2c7249f12d translations 2022-06-24 20:57:10 +03:00
Yuri Kuznetsov
d9806e8ea9 lang ignore language name translations 2022-06-24 20:52:22 +03:00
Yuri Kuznetsov
373de97515 refactoring 2022-06-24 20:36:10 +03:00
Yuri Kuznetsov
e5f0ca77a9 fix request wrapper 2022-06-23 12:55:03 +03:00
Yuri Kuznetsov
973e8cc77a fix case email address order 2022-06-20 10:29:38 +03:00
Yuri Kuznetsov
9e2fbbe494 fix stream fetch-new race condition 2022-06-16 10:48:00 +03:00
Yuri Kuznetsov
322091248e fix 2022-06-16 10:40:38 +03:00
Yuri Kuznetsov
6f241d8803 Arabic lang 2022-06-16 09:22:25 +03:00
Yuri Kuznetsov
e267c88043 fix label manager empty array 2022-06-09 09:39:48 +03:00
Yuri Kuznetsov
fb4730942f datetime time format map 2022-06-08 15:23:18 +03:00
Yuri Kuznetsov
9441825b8f fix not read-only race condition 2022-06-07 14:45:38 +03:00
Yuri Kuznetsov
b26ea22041 fix lang 2022-06-07 10:42:45 +03:00
Yuri Kuznetsov
2bdde353b1 fix acl user frontend 2022-06-07 10:20:52 +03:00
Yuri Kuznetsov
cb18485c3a stream fetch new no rebuild fix 2022-06-06 10:34:48 +03:00
Yuri Kuznetsov
0e267ca2a6 cs fix 2022-06-06 10:01:21 +03:00
Yuri Kuznetsov
085f93ba39 hard bounce statuses 2022-06-05 13:44:32 +03:00
Yuri Kuznetsov
afea99ae6f bounced test 2022-06-04 20:49:53 +03:00
Yuri Kuznetsov
c7e74fe209 request wrapper fix 2022-06-02 10:36:13 +03:00
Yuri Kuznetsov
b3f69c0c70 stream post button fixes 2022-06-02 10:31:28 +03:00
Yuri Kuznetsov
11848b1ded fix post button 2022-06-02 10:07:40 +03:00
Yuri Kuznetsov
4f00a18599 type fixes 2022-05-29 10:34:48 +03:00
Yuri Kuznetsov
767e775f31 fix mass convert currency 2022-05-27 11:50:51 +03:00
Yuri Kuznetsov
bd2204156e v 2022-05-24 16:14:19 +03:00
Yuri Kuznetsov
fe15eeeac7 wysiwyg fix paste upload duplicate 2022-05-24 16:08:48 +03:00
Yuri Kuznetsov
280a1a9313 cs fix 2022-05-24 14:37:47 +03:00
Yuri Kuznetsov
28227ddc2e v 2022-05-23 15:30:21 +03:00
Yuri Kuznetsov
b848261468 category tree fix 2022-05-23 13:49:33 +03:00
Yuri Kuznetsov
f1ff31829c related list modal sync model change 2022-05-23 12:36:24 +03:00
Yuri Kuznetsov
0736285e24 fix range fields 2022-05-23 11:47:32 +03:00
Yuri Kuznetsov
a737711652 move config params 2022-05-19 11:47:59 +03:00
Yuri Kuznetsov
b5e8b89ed5 formula attribute id 2022-05-19 11:14:36 +03:00
Yuri Kuznetsov
a51b45df90 move config params 2022-05-19 10:35:08 +03:00
Yuri Kuznetsov
5612055b85 move config params to default 2022-05-19 10:26:09 +03:00
Yuri Kuznetsov
e3aff78e89 link manager hook assigned users 2022-05-19 10:19:08 +03:00
Yuri Kuznetsov
84a7576772 cs fix 2022-05-18 16:04:44 +03:00
Yuri Kuznetsov
69cd14f471 fix filter bool any 2022-05-18 16:03:34 +03:00
Yuri Kuznetsov
8c1494e17e notify 2022-05-17 15:43:36 +03:00
Yuri Kuznetsov
50a6209f11 php version required 2022-05-13 16:33:52 +03:00
Yuri Kuznetsov
f0d508be6f v 2022-05-13 15:15:33 +03:00
Yuri Kuznetsov
e2b0aa65f8 fix convert lead 2022-05-13 09:40:43 +03:00
Yuri Kuznetsov
930675672b duration fixes 2022-05-12 17:07:04 +03:00
Yuri Kuznetsov
b5ee03b142 fix all-day event duration 2022-05-12 14:33:08 +03:00
Yuri Kuznetsov
a0d4fa5b82 cs fix 2022-05-12 14:08:14 +03:00
Yuri Kuznetsov
317bbba8c9 cs fix 2022-05-12 13:54:57 +03:00
Yuri Kuznetsov
3da95cce76 cs fix 2022-05-12 10:53:05 +03:00
Yuri Kuznetsov
9a7cf5c35e duration 3h 2022-05-12 10:04:28 +03:00
Yuri Kuznetsov
b96ae74c14 cs fix 2022-05-10 17:57:54 +03:00
Yuri Kuznetsov
7a420fb6f9 fix clearAllStoredMainViews 2022-05-10 17:51:45 +03:00
Yuri Kuznetsov
58d161210d image silent exceptions 2022-05-10 17:42:14 +03:00
Yuri Kuznetsov
41c7cf115d clear stored main views on logout 2022-05-10 17:41:02 +03:00
Yuri Kuznetsov
ba3bbfc097 fix autocomplete search no full-text 2022-05-09 16:03:54 +03:00
Yuri Kuznetsov
7758e20224 v 2022-05-09 12:52:28 +03:00
Yuri Kuznetsov
a1cc2ee8c6 fix duplicate link multiple 2022-05-09 12:39:47 +03:00
Yuri Kuznetsov
bdf397ad0f lt lv lang 2022-05-09 10:13:57 +03:00
Yuri Kuznetsov
4dcae92ab7 fix label 2022-05-09 10:11:26 +03:00
Yuri Kuznetsov
1d4fedf7c7 fix mass delete 2022-05-08 16:23:17 +03:00
Yuri Kuznetsov
24e6f2469f record service factory 2022-05-08 15:50:14 +03:00
Arkadiy Asuratov
7b16d3541d fix entity type (#2308) 2022-05-06 22:05:31 +03:00
Yuri Kuznetsov
3c9c3c9c8c fix 2022-05-05 18:04:48 +03:00
Yuri Kuznetsov
f0413b7037 message partList and bounced recognizer 2022-05-05 17:39:36 +03:00
Yuri Kuznetsov
749f1a6a70 fix modal backdrop close on drag 2022-05-05 11:05:53 +03:00
Yuri Kuznetsov
512a23ef64 bg lang fixes 2022-05-05 10:19:47 +03:00
Yuri Kuznetsov
23729c5b89 scan barcode white background 2022-05-05 10:10:17 +03:00
Yuri Kuznetsov
f31ee10cf7 second step login autocomplete off 2022-05-05 10:09:58 +03:00
Yuri Kuznetsov
21d34b091b css label fix 2022-05-04 15:04:36 +03:00
Yuri Kuznetsov
fd19aa8b2e multi-enum max length 2022-05-04 14:36:24 +03:00
Arkadiy Asuratov
5af0b62e8e fix undeclared variable (#2304) 2022-05-04 14:00:51 +03:00
Yuri Kuznetsov
965cb33e34 layout set removal 2022-04-30 18:25:33 +03:00
Yuri Kuznetsov
aca19b3427 send button position 2022-04-30 11:08:02 +03:00
Yuri Kuznetsov
238baf89be spin color 2022-04-29 13:08:35 +03:00
Yuri Kuznetsov
50218a1146 fetch model on followers change 2022-04-29 12:21:35 +03:00
Yuri Kuznetsov
d1280a8797 cs fix 2022-04-29 12:16:57 +03:00
Yuri Kuznetsov
ca9358cf1a cs fix 2022-04-29 11:59:41 +03:00
Yuri Kuznetsov
c3fa8f3131 after relete link event 2022-04-29 11:51:10 +03:00
Yuri Kuznetsov
4af110cd69 followers fix 2022-04-29 11:34:55 +03:00
Yuri Kuznetsov
45d2d4306b cs fix 2022-04-29 11:31:00 +03:00
Yuri Kuznetsov
385f01da8b css text-gray 2022-04-29 10:23:34 +03:00
Yuri Kuznetsov
85da160957 menu button re-render fix 2022-04-28 22:17:36 +03:00
Yuri Kuznetsov
ff15f318c4 cs fix 2022-04-28 21:55:24 +03:00
Yuri Kuznetsov
5769e1b58f email address css fix 2022-04-28 14:43:37 +03:00
Yuri Kuznetsov
028a7c728a fix list extended empty cell 2022-04-28 13:37:16 +03:00
Yuri Kuznetsov
9ec3889f96 date-time none 2022-04-28 13:07:28 +03:00
Yuri Kuznetsov
3aa6502996 phone number css fix 2022-04-28 12:47:49 +03:00
Yuri Kuznetsov
847f8713c9 timeline gray axis color 2022-04-28 12:42:46 +03:00
Yuri Kuznetsov
7405476f61 none value gray 2022-04-28 12:34:23 +03:00
Yuri Kuznetsov
985903e99b loading-value class 2022-04-28 12:34:23 +03:00
Pavel Martínek
347f4e5566 Update Admin.json (#2302) 2022-04-28 11:55:52 +03:00
Yuri Kuznetsov
085964dc58 none-value class 2022-04-28 11:08:12 +03:00
Yuri Kuznetsov
6c0a1265ab global search, notifications panel spinner 2022-04-28 10:31:02 +03:00
Yuri Kuznetsov
655a499caa v 2022-04-27 15:45:28 +03:00
Yuri Kuznetsov
bcf6f33965 no data gray 2022-04-27 13:33:34 +03:00
Yuri Kuznetsov
7c04febb3b fix invitation error 2022-04-27 10:59:45 +03:00
Yuri Kuznetsov
4e7779ee48 fix entity manager edit 2022-04-27 10:14:09 +03:00
Yuri Kuznetsov
4b17896ff1 ref 2022-04-25 16:42:08 +03:00
Yuri Kuznetsov
caf20a5e61 global search fix 2022-04-25 13:14:31 +03:00
Yuri Kuznetsov
896d42df43 v 2022-04-25 11:44:48 +03:00
Yuri Kuznetsov
1905be823d upgrade change 2022-04-25 11:40:05 +03:00
Yuri Kuznetsov
6347992b6e before upgrade fix 2022-04-23 22:53:19 +03:00
Yuri Kuznetsov
b695d7c148 upgrade fix 2022-04-23 22:17:04 +03:00
Yuri Kuznetsov
9b75cdc2ac lang updates 2022-04-22 15:51:30 +03:00
Yuri Kuznetsov
da80ed0130 formula parser only comment fix 2022-04-21 18:42:00 +03:00
Yuri Kuznetsov
e8a23de848 refactoring 2022-04-21 18:02:02 +03:00
Yuri Kuznetsov
cb431a03df fix diff 2022-04-21 12:29:01 +03:00
Yuri Kuznetsov
4979fb7326 fix workflow 2022-04-21 12:27:59 +03:00
Yuri Kuznetsov
aaae51bb37 version tag empty 2022-04-21 12:20:29 +03:00
Yuri Kuznetsov
4d860e3764 v 2022-04-21 12:14:34 +03:00
Yuri Kuznetsov
e73ba5c734 email fetch bc fix 2022-04-21 12:14:07 +03:00
575 changed files with 12331 additions and 4728 deletions

View File

@@ -4,7 +4,7 @@ on:
push:
branches:
- 'master'
- 'hotfix/**'
- 'fix'
paths:
- '**.php'
- '**.json'

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
tag-version-prefix = ""

View File

@@ -71,7 +71,7 @@ class LinkMultiple implements FieldDuplicator
->getRelation($relationDefs->getForeignRelationName())
->getType();
if ($foreignRelationType !== Entity::HAS_MANY) {
if ($foreignRelationType !== Entity::MANY_MANY) {
$valueMap->{$field . 'Ids'} = [];
$valueMap->{$field . 'Names'} = (object) [];
$valueMap->{$field . 'Columns'} = (object) [];

View File

@@ -44,7 +44,6 @@ use Espo\Core\{
};
use ICal\ICal;
use ICal\Event;
use Throwable;
use stdClass;
@@ -85,7 +84,7 @@ class IcsDataLoader implements Loader
$ical->initString($icsContents);
/* @var $event Event */
/* @var \ICal\Event|null $event */
$event = $ical->events()[0] ?? null;
if ($event === null) {

View File

@@ -29,6 +29,9 @@
namespace Espo\Core\Api;
use Espo\Core\Utils\Json;
use Espo\Core\Exceptions\Error;
use Psr\Http\Message\{
ServerRequestInterface as Psr7Request,
UriInterface,
@@ -187,7 +190,9 @@ class RequestWrapper implements ApiRequest
$this->initParsedBody();
}
assert($this->parsedBody !== null);
if ($this->parsedBody === null) {
throw new Error();
}
return Util::cloneObject($this->parsedBody);
}
@@ -197,14 +202,20 @@ class RequestWrapper implements ApiRequest
$contents = $this->getBodyContents();
if ($this->getContentType() === 'application/json' && $contents) {
$this->parsedBody = json_decode($contents);
$parsedBody = Json::decode($contents);
if (is_array($this->parsedBody)) {
$this->parsedBody = (object) [
'list' => $this->parsedBody,
if (is_array($parsedBody)) {
$parsedBody = (object) [
'list' => $parsedBody,
];
}
if (!$parsedBody instanceof stdClass) {
throw new Error("Body is not a JSON object.");
}
$this->parsedBody = $parsedBody;
return;
}

View File

@@ -504,7 +504,7 @@ class Authentication
);
if ($createSecret) {
$this->setSecretInCookie($authToken->getSecret(), $response);
$this->setSecretInCookie($authToken->getSecret(), $response, $request);
}
if (
@@ -612,7 +612,7 @@ class Authentication
$this->entityManager->saveEntity($authLogRecord);
}
private function setSecretInCookie(?string $secret, Response $response): void
private function setSecretInCookie(?string $secret, Response $response, ?Request $request = null): void
{
$time = $secret ? strtotime('+1000 days') : 1;
@@ -625,9 +625,36 @@ class Authentication
'; HttpOnly' .
'; SameSite=Lax';
if ($request && self::isSecureRequest($request)) {
$headerValue .= "; Secure";
}
$response->addHeader('Set-Cookie', $headerValue);
}
private static function isSecureRequest(Request $request): bool
{
$https = $request->getServerParam('HTTPS');
if ($https === 'on') {
return true;
}
$scheme = $request->getServerParam('REQUEST_SCHEME');
if ($scheme === 'https') {
return true;
}
$forwardedProto = $request->getServerParam('HTTP_X_FORWARDED_PROTO');
if ($forwardedProto === 'https') {
return true;
}
return false;
}
private function processFail(Result $result, AuthenticationData $data, Request $request): Result
{
$this->hookManager->processOnFail($result, $data, $request);

View File

@@ -315,6 +315,8 @@ class Upgrade implements Command
if (!$useSingleProcess && $this->isShellEnabled()) {
$this->runSteps($upgradeId, $stepList);
return;
}
$this->runStepsInSingleProcess($upgradeId, $stepList);

View File

@@ -48,7 +48,7 @@ use Espo\Services\Stream as StreamService;
*/
class FollowersLoader implements LoaderInterface
{
private const FOLLOWERS_LIMIT = 5;
private const FOLLOWERS_LIMIT = 6;
private StreamService $streamService;

View File

@@ -48,6 +48,10 @@ class SetAttributeType extends Base
throw new Error("SetAttribute: First argument is not string.");
}
if ($name === 'id') {
throw new Error("Formula set-attribute: Not allowed to set `id` attribute.");
}
$value = $this->evaluate($item->value[1]);
$this->getEntity()->set($name, $value);

View File

@@ -251,7 +251,6 @@ class Parser
$expression = trim($expression);
$braceCounter = 0;
$singleQuoteCounter = 0;
$hasExcessBraces = true;
$modifiedExpression = '';
$splitterIndexList = [];
@@ -346,7 +345,7 @@ class Parser
$firstOperator = null;
$minIndex = null;
if ($expression === '') {
if (trim($expression) === '') {
return (object) [
'type' => 'value',
'value' => null,
@@ -370,6 +369,7 @@ class Parser
$startFrom = $index + 1;
}
if ($index !== false) {
$possibleRightOperator = null;
@@ -413,10 +413,8 @@ class Parser
$this->processStrings($secondPart, $modifiedSecondPart);
if (
substr_count($modifiedFirstPart, '(') === substr_count($modifiedFirstPart, ')')
&&
substr_count($modifiedSecondPart, '(') === substr_count($modifiedSecondPart, ')')
&&
substr_count($modifiedFirstPart, '(') === substr_count($modifiedFirstPart, ')') &&
substr_count($modifiedSecondPart, '(') === substr_count($modifiedSecondPart, ')') &&
!$isString
) {
if ($minIndex === null) {
@@ -449,133 +447,130 @@ class Parser
return $this->applyOperator($firstOperator, $firstPart, $secondPart);
}
else {
$expression = trim($expression);
if ($expression[0] === '!') {
return (object) [
'type' => 'logical\\not',
'value' => $this->split(substr($expression, 1))
];
}
$expression = trim($expression);
if ($expression[0] === '-') {
return (object) [
'type' => 'numeric\\subtraction',
'value' => [
$this->split('0'),
$this->split(substr($expression, 1))
]
];
}
if ($expression[0] === '!') {
return (object) [
'type' => 'logical\\not',
'value' => $this->split(substr($expression, 1))
];
}
if ($expression[0] === '+') {
return (object) [
'type' => 'numeric\\summation',
'value' => [
$this->split('0'),
$this->split(substr($expression, 1))
]
];
}
if ($expression[0] === '-') {
return (object) [
'type' => 'numeric\\subtraction',
'value' => [
$this->split('0'),
$this->split(substr($expression, 1))
]
];
}
if (
$expression[0] === "'" && $expression[strlen($expression) - 1] === "'"
||
$expression[0] === "\"" && $expression[strlen($expression) - 1] === "\""
) {
return (object) [
'type' => 'value',
'value' => substr($expression, 1, strlen($expression) - 2)
];
}
if ($expression[0] === '+') {
return (object) [
'type' => 'numeric\\summation',
'value' => [
$this->split('0'),
$this->split(substr($expression, 1))
]
];
}
if ($expression[0] === "$") {
$value = substr($expression, 1);
if (
$expression[0] === "'" && $expression[strlen($expression) - 1] === "'"
||
$expression[0] === "\"" && $expression[strlen($expression) - 1] === "\""
) {
return (object) [
'type' => 'value',
'value' => substr($expression, 1, strlen($expression) - 2)
];
}
if ($value === '' || !preg_match($this->variableNameRegExp, $value)) {
throw new SyntaxError("Bad varable name `{$value}`.");
}
if ($expression[0] === "$") {
$value = substr($expression, 1);
return (object) [
'type' => 'variable',
'value' => $value,
];
}
if (is_numeric($expression)) {
$value = filter_var($expression, FILTER_VALIDATE_INT) !== false ?
(int) $expression :
(float) $expression;
return (object) [
'type' => 'value',
'value' => $value,
];
}
if ($expression === 'true') {
return (object) [
'type' => 'value',
'value' => true,
];
}
else if ($expression === 'false') {
return (object) [
'type' => 'value',
'value' => false,
];
}
else if ($expression === 'null') {
return (object) [
'type' => 'value',
'value' => null,
];
}
if ($expression[strlen($expression) - 1] === ')') {
$firstOpeningBraceIndex = strpos($expression, '(');
if ($firstOpeningBraceIndex > 0) {
$functionName = trim(substr($expression, 0, $firstOpeningBraceIndex));
$functionContent = substr($expression, $firstOpeningBraceIndex + 1, -1);
$argumentList = $this->parseArgumentListFromFunctionContent($functionContent);
$argumentSplittedList = [];
foreach ($argumentList as $argument) {
$argumentSplittedList[] = $this->split($argument);
}
if ($functionName === '' || !preg_match($this->functionNameRegExp, $functionName)) {
throw new SyntaxError("Bad function name `{$functionName}`.");
}
return (object) [
'type' => $functionName,
'value' => $argumentSplittedList,
];
}
}
if ($expression === '') {
throw SyntaxError::create("Empty attribute.");
}
if (!preg_match($this->attributeNameRegExp, $expression)) {
throw SyntaxError::create("Attribute name `$expression` contains not allowed characters.");
}
if (substr($expression, -1) === '.') {
throw SyntaxError::create("Attribute ends with dot.");
if ($value === '' || !preg_match($this->variableNameRegExp, $value)) {
throw new SyntaxError("Bad varable name `{$value}`.");
}
return (object) [
'type' => 'attribute',
'value' => $expression,
'type' => 'variable',
'value' => $value,
];
}
if (is_numeric($expression)) {
$value = filter_var($expression, FILTER_VALIDATE_INT) !== false ?
(int) $expression :
(float) $expression;
return (object) [
'type' => 'value',
'value' => $value,
];
}
if ($expression === 'true') {
return (object) [
'type' => 'value',
'value' => true,
];
}
if ($expression === 'false') {
return (object) [
'type' => 'value',
'value' => false,
];
}
if ($expression === 'null') {
return (object) [
'type' => 'value',
'value' => null,
];
}
if ($expression[strlen($expression) - 1] === ')') {
$firstOpeningBraceIndex = strpos($expression, '(');
if ($firstOpeningBraceIndex > 0) {
$functionName = trim(substr($expression, 0, $firstOpeningBraceIndex));
$functionContent = substr($expression, $firstOpeningBraceIndex + 1, -1);
$argumentList = $this->parseArgumentListFromFunctionContent($functionContent);
$argumentSplittedList = [];
foreach ($argumentList as $argument) {
$argumentSplittedList[] = $this->split($argument);
}
if ($functionName === '' || !preg_match($this->functionNameRegExp, $functionName)) {
throw new SyntaxError("Bad function name `{$functionName}`.");
}
return (object) [
'type' => $functionName,
'value' => $argumentSplittedList,
];
}
}
if (!preg_match($this->attributeNameRegExp, $expression)) {
throw SyntaxError::create("Attribute name `$expression` contains not allowed characters.");
}
if (substr($expression, -1) === '.') {
throw SyntaxError::create("Attribute ends with dot.");
}
return (object) [
'type' => 'attribute',
'value' => $expression,
];
}
private function stripComments(string &$expression, string &$modifiedExpression): void

View File

@@ -67,6 +67,11 @@ class FetchData
return null;
}
// For backward compatibility.
if ($value === 0) {
return null;
}
if (!is_string($value)) {
throw new RuntimeException("Bad value in fetch-data.");
}

View File

@@ -0,0 +1,149 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Mail\Account\GroupAccount;
use Espo\Core\Mail\Message;
use Espo\Core\Mail\Message\Part;
class BouncedRecognizer
{
/** @var string[] */
private array $hardBounceCodeList = [
'5.0.0',
'5.1.1', // bad destination mailbox address
'5.1.2', // bad destination system address
'5.1.6', // destination mailbox has moved, no forwarding address
'5.4.1', // no answer from host
];
public function isBounced(Message $message): bool
{
$from = $message->getHeader('From');
$contentType = $message->getHeader('Content-Type');
if (preg_match('/MAILER-DAEMON|POSTMASTER/i', $from ?? '')) {
return true;
}
if (strpos($contentType ?? '', 'multipart/report') === 0) {
// @todo Check whether ever works.
$deliveryStatusPart = $this->getDeliveryStatusPart($message);
if ($deliveryStatusPart) {
return true;
}
$content = $message->getRawContent();
if (
strpos($content, 'message/delivery-status') !== false &&
strpos($content, 'Status: ') !== false
) {
return true;
}
}
return false;
}
public function isHard(Message $message): bool
{
$content = $message->getRawContent();
if (preg_match('/permanent[ ]*[error|failure]/', $content)) {
return true;
}
$m = null;
$has5xxStatus = preg_match('/Status: (5\.[0-9]\.[0-9])/', $content, $m);
if ($has5xxStatus) {
$status = $m[1] ?? null;
if (in_array($status, $this->hardBounceCodeList)) {
return true;
}
}
return false;
}
public function extractStatus(Message $message): ?string
{
$content = $message->getRawContent();
$m = null;
$hasStatus = preg_match('/Status: ([0-9]\.[0-9]\.[0-9])/', $content, $m);
if ($hasStatus) {
$status = $m[1] ?? null;
return $status;
}
return null;
}
public function extractQueueItemId(Message $message): ?string
{
$content = $message->getRawContent();
if (preg_match('/X-Queue-Item-Id: [a-z0-9\-]*/', $content, $m)) {
/** @var array{string} */
$arr = preg_split('/X-Queue-Item-Id: /', $m[0], -1, \PREG_SPLIT_NO_EMPTY);
return $arr[0];
}
$to = $message->getHeader('to');
if (preg_match('/\+bounce-qid-[a-z0-9\-]*/', $to ?? '', $m)) {
/** @var array{string} */
$arr = preg_split('/\+bounce-qid-/', $m[0], -1, \PREG_SPLIT_NO_EMPTY);
return $arr[0];
}
return null;
}
private function getDeliveryStatusPart(Message $message): ?Part
{
foreach ($message->getPartList() as $part) {
if ($part->getContentType() === 'message/delivery-status') {
return $part;
}
}
return null;
}
}

View File

@@ -34,6 +34,7 @@ use Espo\Core\Mail\Account\Hook\BeforeFetchResult;
use Espo\Core\Mail\Account\Account;
use Espo\Core\Mail\Message;
use Espo\Core\Mail\Account\GroupAccount\BouncedRecognizer;
use Espo\Core\Utils\Log;
use Espo\Core\InjectableFactory;
@@ -55,21 +56,25 @@ class BeforeFetch implements BeforeFetchInterface
private InjectableFactory $injectableFactory;
private BouncedRecognizer $bouncedRecognizer;
private ?CampaignService $campaignService = null;
public function __construct(Log $log, EntityManager $entityManager, InjectableFactory $injectableFactory)
{
public function __construct(
Log $log,
EntityManager $entityManager,
InjectableFactory $injectableFactory,
BouncedRecognizer $bouncedRecognizer
) {
$this->log = $log;
$this->entityManager = $entityManager;
$this->injectableFactory = $injectableFactory;
$this->bouncedRecognizer = $bouncedRecognizer;
}
public function process(Account $account, Message $message): BeforeFetchResult
{
if (
$message->hasHeader('from') &&
preg_match('/MAILER-DAEMON|POSTMASTER/i', $message->getHeader('from') ?? '')
) {
if ($this->bouncedRecognizer->isBounced($message)) {
try {
$toSkip = $this->processBounced($message);
}
@@ -94,32 +99,8 @@ class BeforeFetch implements BeforeFetchInterface
private function processBounced(Message $message): bool
{
$content = $message->getRawContent();
$isHard = false;
if (preg_match('/permanent[ ]*[error|failure]/', $content)) {
$isHard = true;
}
$queueItemId = null;
if (preg_match('/X-Queue-Item-Id: [a-z0-9\-]*/', $content, $m)) {
/** @var array{string} */
$arr = preg_split('/X-Queue-Item-Id: /', $m[0], -1, \PREG_SPLIT_NO_EMPTY);
$queueItemId = $arr[0];
}
else {
$to = $message->getHeader('to');
if (preg_match('/\+bounce-qid-[a-z0-9\-]*/', $to ?? '', $m)) {
/** @var array{string} */
$arr = preg_split('/\+bounce-qid-/', $m[0], -1, \PREG_SPLIT_NO_EMPTY);
$queueItemId = $arr[0];
}
}
$isHard = $this->bouncedRecognizer->isHard($message);
$queueItemId = $this->bouncedRecognizer->extractQueueItemId($message);
if (!$queueItemId) {
return false;

View File

@@ -29,7 +29,6 @@
namespace Espo\Core\Mail\Event;
use ICal\Event as U01jmg3Event;
use ICal\ICal as U01jmg3ICal;
use RuntimeException;
@@ -38,7 +37,7 @@ class EventFactory
{
public static function createFromU01jmg3Ical(U01jmg3ICal $ical): Event
{
/* @var $event U01jmg3Event */
/* @var \ICal\Event|null $event */
$event = $ical->events()[0] ?? null;
if (!$event) {

View File

@@ -72,6 +72,8 @@ class Importer
private LinkMultipleSaver $linkMultipleSaver;
private const SUBJECT_MAX_LENGTH = 255;
public function __construct(
EntityManager $entityManager,
Config $config,
@@ -122,6 +124,10 @@ class Importer
$subject = '(No Subject)';
}
if (strlen($subject) > self::SUBJECT_MAX_LENGTH) {
$subject = substr($subject, 0, self::SUBJECT_MAX_LENGTH);
}
$email->set('isHtml', false);
$email->set('name', $subject);
$email->set('status', Email::STATUS_ARCHIVED);

View File

@@ -29,6 +29,8 @@
namespace Espo\Core\Mail;
use Espo\Core\Mail\Message\Part;
interface Message
{
/**
@@ -67,4 +69,9 @@ interface Message
* Whether contents is fetched.
*/
public function isFetched(): bool;
/**
* @return Part[]
*/
public function getPartList(): array;
}

View File

@@ -0,0 +1,79 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Mail\Message\MailMimeParser;
use Espo\Core\Mail\Message\Part as PartInterface;
use ZBateson\MailMimeParser\Message\Part\MessagePart;
class Part implements PartInterface
{
private MessagePart $part;
public function __construct(MessagePart $part)
{
$this->part = $part;
}
public function getContentType(): ?string
{
return $this->part->getContentType();
}
public function hasContent(): bool
{
return $this->part->hasContent();
}
public function getContent(): ?string
{
return $this->part->getContent();
}
public function getContentId(): ?string
{
return $this->part->getContentId();
}
public function getCharset(): ?string
{
return $this->part->getCharset();
}
public function getContentDisposition(): ?string
{
return $this->part->getContentDisposition();
}
public function getFilename(): ?string
{
return $this->part->getFilename();
}
}

View File

@@ -0,0 +1,47 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Mail\Message;
interface Part
{
public function getContentType(): ?string;
public function hasContent(): bool;
public function getContent(): ?string;
public function getContentId(): ?string;
public function getCharset(): ?string;
public function getContentDisposition(): ?string;
public function getFilename(): ?string;
}

View File

@@ -30,6 +30,7 @@
namespace Espo\Core\Mail;
use Espo\Core\Mail\Account\Storage;
use Espo\Core\Mail\Message\Part;
use RuntimeException;
@@ -69,6 +70,24 @@ class MessageWrapper implements Message
$this->storage = $storage;
$this->parser = $parser;
$this->fullRawContent = $fullRawContent;
if (
!$storage &&
$this->fullRawContent
) {
$rawHeader = null;
$rawBody = null;
if (strpos($this->fullRawContent, "\r\n\r\n") !== false) {
[$rawHeader, $rawBody] = explode("\r\n\r\n", $this->fullRawContent, 2);
}
else if (strpos($this->fullRawContent, "\n\n") !== false) {
[$rawHeader, $rawBody] = explode("\n\n", $this->fullRawContent, 2);
}
$this->rawHeader = $rawHeader;
$this->rawContent = $rawBody;
}
}
public function getRawHeader(): string
@@ -133,4 +152,16 @@ class MessageWrapper implements Message
{
return (bool) $this->rawHeader;
}
/**
* @return Part[]
*/
public function getPartList(): array
{
if (!$this->parser) {
throw new RuntimeException();
}
return $this->parser->getPartList($this);
}
}

View File

@@ -32,6 +32,7 @@ namespace Espo\Core\Mail;
use Espo\Entities\Email;
use Espo\Entities\Attachment;
use Espo\Core\Mail\Message;
use Espo\Core\Mail\Message\Part;
use stdClass;
@@ -56,4 +57,9 @@ interface Parser
* @return Attachment[] A list of inline attachments.
*/
public function getInlineAttachmentList(Message $message, Email $email): array;
/**
* @return Part[]
*/
public function getPartList(Message $message): array;
}

View File

@@ -36,6 +36,10 @@ use Espo\Entities\Attachment;
use Espo\Core\Mail\Message;
use Espo\Core\Mail\Parser;
use Espo\Core\Mail\Message\Part;
use Espo\Core\Mail\Message\MailMimeParser\Part as WrapperPart;
use Espo\ORM\EntityManager;
use ZBateson\MailMimeParser\MailMimeParser as WrappeeParser;
@@ -211,6 +215,22 @@ class MailMimeParser implements Parser
return $addressList;
}
/**
* @return Part[]
*/
public function getPartList(Message $message): array
{
$wrappeeList = $this->getMessage($message)->getChildParts();
$partList = [];
foreach ($wrappeeList as $wrappee) {
$partList[] = new WrapperPart($wrappee);
}
return $partList;
}
/**
* @return Attachment[]
*/

View File

@@ -31,6 +31,8 @@ namespace Espo\Core\MassAction\Actions;
use Espo\Entities\User;
use Espo\Core\Acl\Table;
use Espo\Core\{
Exceptions\Forbidden,
Exceptions\BadRequest,
@@ -93,11 +95,11 @@ class MassConvertCurrency implements MassAction
{
$entityType = $params->getEntityType();
if (!$this->acl->check($entityType, 'delete')) {
throw new Forbidden("No delete access for '{$entityType}'.");
if (!$this->acl->checkScope($entityType, Table::ACTION_EDIT)) {
throw new Forbidden("No edit access for '{$entityType}'.");
}
if ($this->acl->get('massUpdatePermission') !== 'yes') {
if ($this->acl->get('massUpdatePermission') !== Table::LEVEL_YES) {
throw new Forbidden("No mass-update permission.");
}
@@ -142,7 +144,7 @@ class MassConvertCurrency implements MassAction
$count = 0;
foreach ($collection as $entity) {
if (!$this->acl->checkEntity($entity, 'edit')) {
if (!$this->acl->checkEntity($entity, Table::ACTION_EDIT)) {
continue;
}

View File

@@ -38,7 +38,7 @@ use Espo\Core\{
MassAction\Data,
MassAction\MassAction,
Acl,
Record\ServiceContainer as RecordServiceContainer,
Record\ServiceFactory,
ORM\EntityManager,
Exceptions\Forbidden,
};
@@ -56,9 +56,9 @@ class MassDelete implements MassAction
protected $acl;
/**
* @var RecordServiceContainer
* @var ServiceFactory
*/
protected $recordServiceContainer;
protected $serviceFactory;
/**
* @var EntityManager
@@ -73,13 +73,13 @@ class MassDelete implements MassAction
public function __construct(
QueryBuilder $queryBuilder,
Acl $acl,
RecordServiceContainer $recordServiceContainer,
ServiceFactory $serviceFactory,
EntityManager $entityManager,
User $user
) {
$this->queryBuilder = $queryBuilder;
$this->acl = $acl;
$this->recordServiceContainer = $recordServiceContainer;
$this->serviceFactory = $serviceFactory;
$this->entityManager = $entityManager;
$this->user = $user;
}
@@ -96,7 +96,7 @@ class MassDelete implements MassAction
throw new Forbidden("No mass-update permission.");
}
$service = $this->recordServiceContainer->get($entityType);
$service = $this->serviceFactory->create($entityType);
$repository = $this->entityManager->getRDBRepository($entityType);

View File

@@ -40,7 +40,7 @@ use Espo\Core\{
MassAction\Data,
MassAction\MassAction,
Acl,
Record\ServiceContainer as RecordServiceContainer,
Record\ServiceFactory as RecordServiceFactory,
ORM\EntityManager,
Utils\FieldUtil,
Utils\ObjectUtil,
@@ -63,9 +63,9 @@ class MassUpdate implements MassAction
protected $acl;
/**
* @var RecordServiceContainer
* @var RecordServiceFactory
*/
protected $recordServiceContainer;
protected $recordServiceFactory;
/**
* @var EntityManager
@@ -85,14 +85,14 @@ class MassUpdate implements MassAction
public function __construct(
QueryBuilder $queryBuilder,
Acl $acl,
RecordServiceContainer $recordServiceContainer,
RecordServiceFactory $recordServiceFactory,
EntityManager $entityManager,
FieldUtil $fieldUtil,
User $user
) {
$this->queryBuilder = $queryBuilder;
$this->acl = $acl;
$this->recordServiceContainer = $recordServiceContainer;
$this->recordServiceFactory = $recordServiceFactory;
$this->entityManager = $entityManager;
$this->fieldUtil = $fieldUtil;
$this->user = $user;
@@ -112,7 +112,7 @@ class MassUpdate implements MassAction
$valueMap = $data->getRaw();
$service = $this->recordServiceContainer->get($entityType);
$service = $this->recordServiceFactory->create($entityType);
$repository = $this->entityManager->getRDBRepository($entityType);

View File

@@ -29,14 +29,14 @@
namespace Espo\Core\Record;
use Espo\Core\{
Exceptions\Forbidden,
Exceptions\BadRequest,
Utils\Config,
Api\Request,
Select\SearchParams,
Utils\Json,
};
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Utils\Config;
use Espo\Core\Api\Request;
use Espo\Core\Select\SearchParams;
use Espo\Core\Select\Text\MetadataProvider as TextMetadataProvider;
use Espo\Core\Utils\Json;
use JsonException;
@@ -46,9 +46,12 @@ class SearchParamsFetcher
private Config $config;
public function __construct(Config $config)
private TextMetadataProvider $textMetadataProvider;
public function __construct(Config $config, TextMetadataProvider $textMetadataProvider)
{
$this->config = $config;
$this->textMetadataProvider = $textMetadataProvider;
}
public function fetch(Request $request): SearchParams
@@ -67,7 +70,7 @@ class SearchParamsFetcher
$this->fetchRawJsonSearchParams($request):
$this->fetchRawMultipleParams($request);
$this->handleRawParams($params);
$this->handleRawParams($params, $request);
return $params;
}
@@ -164,7 +167,7 @@ class SearchParamsFetcher
/**
* @param array<string,mixed> $params
*/
private function handleRawParams(array &$params): void
private function handleRawParams(array &$params, Request $request): void
{
if (isset($params['maxSize']) && !is_int($params['maxSize'])) {
throw new BadRequest('maxSize must be integer.');
@@ -178,7 +181,8 @@ class SearchParamsFetcher
strpos($q, '*') === false &&
strpos($q, '"') === false &&
strpos($q, '+') === false &&
strpos($q, '-') === false
strpos($q, '-') === false &&
$this->hasFullTextSearch($request)
) {
$params['q'] = $q . '*';
}
@@ -186,6 +190,21 @@ class SearchParamsFetcher
$this->handleMaxSize($params);
}
private function hasFullTextSearch(Request $request): bool
{
$scope = $request->getRouteParam('controller');
if (!$scope) {
return false;
}
if ($request->getRouteParam('action') !== 'index') {
return false;
}
return $this->textMetadataProvider->hasFullTextSearch($scope);
}
/**
* @param array<string,mixed> $params
*/

View File

@@ -29,32 +29,18 @@
namespace Espo\Core\Record;
use Espo\Core\{
Exceptions\Error,
ServiceFactory,
Utils\Metadata,
};
use RuntimeException;
use Espo\Core\Exceptions\Error;
/**
* Container for record services. Lazy loading is used.
* Usually there's no need to have multiple record service instances of the same entity type.
* Use this container instead of serviceFactory to get record services.
*
* Important. Returns services for the current user.
* Use the service-factory to create services for a specific user.
*/
class ServiceContainer
{
private const RECORD_SERVICE_NAME = 'Record';
private const RECORD_TREE_SERVICE_NAME = 'RecordTree';
/**
* @var array<string,string>
*/
private $defaultTypeMap = [
'CategoryTree' => self::RECORD_TREE_SERVICE_NAME,
];
/**
* @var array<string,Service<\Espo\ORM\Entity>>
*/
@@ -62,16 +48,14 @@ class ServiceContainer
private ServiceFactory $serviceFactory;
private Metadata $metadata;
public function __construct(ServiceFactory $serviceFactory, Metadata $metadata)
public function __construct(ServiceFactory $serviceFactory)
{
$this->serviceFactory = $serviceFactory;
$this->metadata = $metadata;
}
/**
* @return Service<\Espo\ORM\Entity>
* @throws Error
*/
public function get(string $entityType): Service
{
@@ -84,45 +68,6 @@ class ServiceContainer
private function load(string $entityType): void
{
if (!$this->metadata->get(['scopes', $entityType, 'entity'])) {
throw new Error("Can't create record service '{$entityType}', there's no such entity type.");
}
if ($this->serviceFactory->checkExists($entityType)) {
$service = $this->serviceFactory->createWith($entityType, ['entityType' => $entityType]);
if (!$service instanceof Service) {
$this->loadDefault($entityType);
return;
}
$this->data[$entityType] = $service;
return;
}
$this->loadDefault($entityType);
}
private function loadDefault(string $entityType): void
{
$default = self::RECORD_SERVICE_NAME;
$type = $this->metadata->get(['scopes', $entityType, 'type']);
if ($type) {
$default = $this->defaultTypeMap[$type] ?? $default;
}
$obj = $this->serviceFactory->createWith($default, ['entityType' => $entityType]);
if (!$obj instanceof Service) {
throw new RuntimeException("Service class {$default} is not instance of Record.");
}
//$obj->setEntityType($entityType);
$this->data[$entityType] = $obj;
$this->data[$entityType] = $this->serviceFactory->create($entityType);
}
}

View File

@@ -0,0 +1,153 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Record;
use Espo\Core\Exceptions\Error;
use Espo\Core\ServiceFactory as Factory;
use Espo\Core\Utils\Metadata;
use Espo\Entities\User;
use Espo\Core\Acl;
use Espo\Core\AclManager;
use RuntimeException;
/**
* Create a service for a specific user.
*/
class ServiceFactory
{
private const RECORD_SERVICE_NAME = 'Record';
private const RECORD_TREE_SERVICE_NAME = 'RecordTree';
/**
* @var array<string,string>
*/
private $defaultTypeMap = [
'CategoryTree' => self::RECORD_TREE_SERVICE_NAME,
];
private Factory $serviceFactory;
private Metadata $metadata;
private User $user;
private Acl $acl;
private AclManager $aclManager;
public function __construct(
Factory $serviceFactory,
Metadata $metadata,
User $user,
Acl $acl,
AclManager $aclManager
) {
$this->serviceFactory = $serviceFactory;
$this->metadata = $metadata;
$this->user = $user;
$this->acl = $acl;
$this->aclManager = $aclManager;
}
/**
* @return Service<\Espo\ORM\Entity>
*/
public function create(string $entityType): Service
{
$obj = $this->createInternal($entityType);
$obj->setUser($this->user);
$obj->setAcl($this->acl);
return $obj;
}
/**
* @return Service<\Espo\ORM\Entity>
*/
public function createForUser(string $entityType, User $user): Service
{
$obj = $this->createInternal($entityType);
$acl = $this->aclManager->createUserAcl($user);
$obj->setUser($user);
$obj->setAcl($acl);
return $obj;
}
/**
* @return Service<\Espo\ORM\Entity>
*/
public function createInternal(string $entityType): Service
{
if (!$this->metadata->get(['scopes', $entityType, 'entity'])) {
throw new Error("Can't create record service '{$entityType}', there's no such entity type.");
}
if (!$this->serviceFactory->checkExists($entityType)) {
return $this->createDefault($entityType);
}
$service = $this->serviceFactory->createWith($entityType, ['entityType' => $entityType]);
if (!$service instanceof Service) {
return $this->createDefault($entityType);
}
return $service;
}
/**
* @return Service<\Espo\ORM\Entity>
*/
private function createDefault(string $entityType): Service
{
$default = self::RECORD_SERVICE_NAME;
$type = $this->metadata->get(['scopes', $entityType, 'type']);
if ($type) {
$default = $this->defaultTypeMap[$type] ?? $default;
}
$obj = $this->serviceFactory->createWith($default, ['entityType' => $entityType]);
if (!$obj instanceof Service) {
throw new RuntimeException("Service class {$default} is not instance of Record.");
}
return $obj;
}
}

View File

@@ -38,7 +38,7 @@
"type": "duration",
"start": "dateStart",
"end": "dateEnd",
"options": [300, 600, 900, 1800, 2700, 3600, 7200],
"options": [300, 600, 900, 1800, 2700, 3600, 7200, 10800],
"default": 300,
"notStorable": true,
"select": {

View File

@@ -0,0 +1,5 @@
{
"labels": {
"Create {entityType}": "إنشاء {الكيانTypeTranslated}"
}
}

View File

@@ -0,0 +1,10 @@
{
"links": {
"meetings": "الاجتماعات",
"calls": "المكالمات",
"tasks": "مهام"
},
"labels": {
"Create {entityType}": "إنشاء {الكيانTypeTranslated}"
}
}

View File

@@ -0,0 +1,15 @@
{
"fields": {
"billingAddress": "عنوان وصول الفواتير",
"shippingAddress": "عنوان الشحن",
"website": "موقع الكتروني"
},
"links": {
"meetings": "الاجتماعات",
"calls": "المكالمات",
"tasks": "مهام"
},
"labels": {
"Create {entityType}": "إنشاء {الكيانTypeTranslated}"
}
}

View File

@@ -0,0 +1,39 @@
{
"fields": {
"parent": "الأبوين",
"dateStart": "تاريخ البدء",
"dateEnd": "تاريخ الانتهاء",
"duration": "مدة",
"status": "حالة",
"reminders": "تذكير",
"dateStartDate": "تاريخ البدء (طوال اليوم)",
"dateEndDate": "تاريخ الانتهاء (طوال اليوم)",
"isAllDay": "طوال اليوم"
},
"links": {
"parent": "الأبوين"
},
"options": {
"status": {
"Planned": "مخطط",
"Held": "محتجز",
"Not Held": "لم يعقد"
}
},
"labels": {
"Create {entityType}": "إنشاء {الكيانTypeTranslated}",
"Schedule {entityType}": "جدولة {الكيانTypeTranslated}",
"Log {entityType}": "سجل {الكيانTypeTranslated}",
"Set Held": "مجموعة معلقة",
"Set Not Held": "التعيين لم يتم عقده"
},
"massActions": {
"setHeld": "مجموعة معلقة",
"setNotHeld": "التعيين لم يتم عقده"
},
"presetFilters": {
"planned": "مخطط",
"held": "محتجز",
"todays": "اليوم"
}
}

View File

@@ -0,0 +1,13 @@
{
"fields": {
"address": "العنوان"
},
"links": {
"meetings": "الاجتماعات",
"calls": "المكالمات",
"tasks": "مهام"
},
"labels": {
"Create {entityType}": "إنشاء {الكيانTypeTranslated}"
}
}

View File

@@ -1,5 +1,5 @@
{
"labels": {
"Create {entityType}": "Създаване {entityTypeTranslated}"
"Create {entityType}": "Създаване на {entityTypeTranslated}"
}
}

View File

@@ -1,10 +1,10 @@
{
"links": {
"meetings": "срещи",
"calls": "призовава",
"meetings": "Срещи",
"calls": "Разговори",
"tasks": "Задачи"
},
"labels": {
"Create {entityType}": "Създаване {entityTypeTranslated}"
"Create {entityType}": "Създаване на {entityTypeTranslated}"
}
}

View File

@@ -1,15 +1,15 @@
{
"fields": {
"billingAddress": "адрес на плащане",
"billingAddress": "Адрес за плащане",
"shippingAddress": "Адрес за доставка",
"website": "уебсайт"
"website": "Уебсайт"
},
"links": {
"meetings": "срещи",
"calls": "призовава",
"meetings": "Срещи",
"calls": "Обаждане",
"tasks": "Задачи"
},
"labels": {
"Create {entityType}": "Създаване {entityTypeTranslated}"
"Create {entityType}": "Създаване на {entityTypeTranslated}"
}
}

View File

@@ -1,39 +1,39 @@
{
"fields": {
"parent": "родител",
"dateStart": "Дата Старт",
"parent": "Родител",
"dateStart": "Начална дата",
"dateEnd": "Крайна дата",
"duration": "продължителност",
"duration": "Продължителност",
"status": "Статус",
"reminders": "Напомняния",
"dateStartDate": "Дата Start (цял ден)",
"dateStartDate": "Начална дата (цял ден)",
"dateEndDate": "Крайна дата (цял ден)",
"isAllDay": "Дали през целия ден"
"isAllDay": "Цял ден"
},
"links": {
"parent": "родител"
"parent": "Родител"
},
"options": {
"status": {
"Planned": "Планирано",
"Held": "Държани",
"Not Held": "Не държани"
"Held": "Състояло се",
"Not Held": "Несъстояло се"
}
},
"labels": {
"Create {entityType}": "Създаване {entityTypeTranslated}",
"Schedule {entityType}": "График {entityTypeTranslated}",
"Log {entityType}": "Вход {entityTypeTranslated}",
"Set Held": "Задайте държани",
"Set Not Held": "Задайте не се държат"
"Create {entityType}": "Създаване на {entityTypeTranslated}",
"Schedule {entityType}": "Насрочи {entityTypeTranslated}",
"Log {entityType}": "Регистрирай {entityTypeTranslated}",
"Set Held": "Задай като състояло се",
"Set Not Held": "Задай като несъстояло се"
},
"massActions": {
"setHeld": "Задайте държани",
"setNotHeld": "Задайте не се държат"
"setHeld": "Задай като състояло се",
"setNotHeld": "Задай като несъстояло се"
},
"presetFilters": {
"planned": "Планирано",
"held": "Държани",
"held": "Състояли се",
"todays": "Днешните"
}
}

View File

@@ -1,13 +1,13 @@
{
"fields": {
"address": "адрес"
"address": "Адрес"
},
"links": {
"meetings": "срещи",
"calls": "призовава",
"meetings": "Срещи",
"calls": "Разговори",
"tasks": "Задачи"
},
"labels": {
"Create {entityType}": "Създаване {entityTypeTranslated}"
"Create {entityType}": "Създаване на {entityTypeTranslated}"
}
}

View File

@@ -3,7 +3,7 @@
"parent": "Genitore",
"dateStart": "Data inizio",
"dateEnd": "Data termine",
"duration": "Dirata",
"duration": "Durata",
"status": "Stato",
"reminders": "Promemoria",
"dateStartDate": "Data inizio (tutto il giorno)",
@@ -16,24 +16,24 @@
"options": {
"status": {
"Planned": "Pianificato",
"Held": "Trattenuto",
"Not Held": "Non trattenuto"
"Held": "Effettuata",
"Not Held": "Non Effettuata"
}
},
"labels": {
"Create {entityType}": "Crea {entityTypeTranslated}",
"Schedule {entityType}": "Pianificazione {entityTypeTranslated}",
"Log {entityType}": "Registro {entityTypeTranslated}",
"Set Held": "Imposta trattenuto",
"Set Not Held": "Imposta non trattenuto"
"Set Held": "Effettuata",
"Set Not Held": "Non Effettuata"
},
"massActions": {
"setHeld": "Imposta trattenuto",
"setNotHeld": "Imposta non trattenuto"
"setHeld": "Effettuata",
"setNotHeld": "Non Effettuata"
},
"presetFilters": {
"planned": "Pianificato",
"held": "Trattenuto",
"held": "Effettuata",
"todays": "Di oggi"
}
}

View File

@@ -4,7 +4,8 @@
"dateStart": "Startdato",
"dateEnd": "Sluttdato",
"duration": "Varighet",
"reminders": "Påminnelser"
"reminders": "Påminnelser",
"dateEndDate": "Sluttdato (hele dagen)"
},
"links": {
"parent": "Forelder"

View File

@@ -295,17 +295,21 @@ class Util
*/
public static function arrayToObject($array)
{
/** @phpstan-var mixed $array */
/** @var \stdClass */
return self::arrayToObjectInternal($array);
}
if (is_array($array)) {
/** @var callable */
$callable = ['static', 'arrayToObject'];
return (object) array_map($callable, $array);
/**
* @param mixed $value
* @return mixed
*/
private static function arrayToObjectInternal($value)
{
if (is_array($value)) {
return (object) array_map(fn($v) => self::arrayToObjectInternal($v), $value);
}
/** @var \stdClass */
return $array;
return $value;
}
/**
@@ -316,16 +320,25 @@ class Util
*/
public static function objectToArray($object)
{
/** @phpstan-var mixed $object */
/** @var array<string,mixed> */
return self::objectToArrayInternal($object);
}
if (is_object($object)) {
$object = (array) $object;
/**
* @param mixed $value
* @return mixed
*/
private static function objectToArrayInternal($value)
{
if (is_object($value)) {
$value = (array) $value;
}
/** @var callable */
$callable = ['static', 'objectToArray'];
if (is_array($value)) {
return array_map(fn($v) => self::objectToArrayInternal($v), $value);
}
return is_array($object) ? array_map($callable, $object) : $object;
return $value;
}
/**

View File

@@ -34,8 +34,8 @@ use Espo\Repositories\Attachment as AttachmentRepository;
use Espo\Core\{
Exceptions\NotFound,
Exceptions\NotFoundSilent,
Exceptions\Forbidden,
Exceptions\BadRequest,
Exceptions\ForbiddenSilent,
Exceptions\Error,
EntryPoint\EntryPoint,
Acl,
@@ -120,24 +120,24 @@ class Image implements EntryPoint
}
if (!$disableAccessCheck && !$this->acl->checkEntity($attachment)) {
throw new Forbidden();
throw new ForbiddenSilent("No access to attachment.");
}
$fileType = $attachment->get('type');
if (!in_array($fileType, $this->getAllowedFileTypeList())) {
throw new Forbidden("Not allowed file type '{$fileType}'.");
throw new ForbiddenSilent("Not allowed file type '{$fileType}'.");
}
if ($this->allowedRelatedTypeList) {
if (!in_array($attachment->get('relatedType'), $this->allowedRelatedTypeList)) {
throw new NotFound();
throw new NotFoundSilent();
}
}
if ($this->allowedFieldList) {
if (!in_array($attachment->get('field'), $this->allowedFieldList)) {
throw new NotFound();
throw new NotFoundSilent();
}
}

View File

@@ -0,0 +1,85 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Hooks\LayoutSet;
use Espo\ORM\Entity;
use Espo\ORM\EntityManager;
use Espo\Entities\LayoutSet;
use Espo\Entities\Team;
use Espo\Entities\Portal;
class Removal
{
private EntityManager $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* @param LayoutSet $entity
*/
public function afterRemove(Entity $entity): void
{
$updateQuery1 = $this->entityManager
->getQueryBuilder()
->update()
->in(Team::ENTITY_TYPE)
->set([
'layoutSetId' => null,
])
->where([
'layoutSetId' => $entity->getId(),
])
->build();
$this->entityManager
->getQueryExecutor()
->execute($updateQuery1);
$updateQuery2 = $this->entityManager
->getQueryBuilder()
->update()
->in(Portal::ENTITY_TYPE)
->set([
'layoutSetId' => null,
])
->where([
'layoutSetId' => $entity->getId(),
])
->build();
$this->entityManager
->getQueryExecutor()
->execute($updateQuery2);
}
}

View File

@@ -211,8 +211,6 @@ class Invitations
->withMessage($message)
->withAttachments([$attachment])
->send($email);
$this->entityManager->removeEntity($email);
}
protected function getIscContents(Entity $entity): string

View File

@@ -0,0 +1,107 @@
{
"fields": {
"name": "الاسم",
"emailAddress": "البريد الإلكتروني",
"website": "الموقع الالكتروني",
"phoneNumber": "رقم التليفون",
"billingAddress": "عنوان وصول الفواتير",
"shippingAddress": "عنوان الشحن",
"description": "الوصف",
"sicCode": "رقم العقد",
"industry": "الصناعة",
"type": "النوع",
"contactRole": "الوظيفة",
"campaign": "حملة اعلانية",
"targetLists": "قوائم الإستهداف",
"targetList": "قائمة الاستهداف",
"originalLead": "الفرصة الأصلية",
"contactIsInactive": "غير نشط"
},
"links": {
"contacts": "جهات الاتصال",
"opportunities": "الفرص",
"cases": "التذاكر",
"documents": "المستندات",
"meetingsPrimary": "الاجتماعات (موسعة)",
"callsPrimary": "المكالمات (موسعة)",
"tasksPrimary": "المهام (موسعة)",
"emailsPrimary": "رسائل البريد الإلكتروني (موسعة)",
"targetLists": "قوائم الإستهداف",
"campaignLogRecords": "سجل الحملة",
"campaign": "الحملة",
"portalUsers": "مستخدمي البوابة",
"originalLead": "الفرصة الأصلية",
"contactsPrimary": "جهات الاتصال أساسي"
},
"options": {
"type": {
"Customer": "عميل حالي",
"Investor": "مستثمر",
"Partner": "شريك",
"Reseller": "موزع"
},
"industry": {
"Agriculture": "الزراعة",
"Advertising": "دعاية وإعلان",
"Apparel & Accessories": "ملابس واكسسوارات",
"Automotive": "السيارات",
"Banking": "الخدمات المصرفية",
"Biotechnology": "التكنولوجيا الحيوية",
"Building Materials & Equipment": "مواد ومعدات بناء",
"Chemical": "المواد الكيميائية",
"Computer": "الكمبيوتر",
"Education": "التعليم",
"Electronics": "إلكترونيات",
"Energy": "طاقة",
"Entertainment & Leisure": "الترفيه و الترفيه",
"Finance": "المالي",
"Food & Beverage": "الطعام و الشراب",
"Grocery": "البقالة",
"Healthcare": "الرعاية الصحية",
"Insurance": "التأمين",
"Legal": "قانوني",
"Manufacturing": "تصنيع",
"Publishing": "نشر",
"Real Estate": "العقارات",
"Service": "خدمات",
"Sports": "رياضة",
"Software": "البرمجيات",
"Technology": "تقنية",
"Telecommunications": "الاتصالات السلكية و اللاسلكية",
"Television": "التلفاز",
"Transportation": "وسائل النقل",
"Venture Capital": "رأس المال الاستثماري",
"Aerospace": "الفضاء",
"Architecture": "هندسة عامة",
"Construction": "بناء",
"Defense": "دفاع",
"Creative": "مبدع",
"Culture": "ثقافة",
"Consulting": "مستشار",
"Electric Power": "الطاقة الكهربائية",
"Hospitality": "ضيافة",
"Mass Media": "وسائل الإعلام الجماهيرية",
"Mining": "التعدين",
"Music": "موسيقى",
"Marketing": "تسويق",
"Petroleum": "البترول",
"Retail": "بيع بالتجزئة",
"Shipping": "شحن",
"Support": "الدعم",
"Testing, Inspection & Certification": "الاختبار والتفتيش ومنح الشهادات",
"Wholesale": "بالجملة",
"Water": "ماء",
"Travel": "يسافر"
}
},
"labels": {
"Create Account": "إنشئ حساب",
"Copy Billing": "نسخ الفواتير",
"Set Primary": "تعيين الأساسي"
},
"presetFilters": {
"customers": "العملاء",
"partners": "الشركاء",
"recentlyCreated": "تم إنشاؤه مؤخرًا"
}
}

View File

@@ -0,0 +1,11 @@
{
"layouts": {
"detailConvert": "تحويل الفرصة",
"listForAccount": "قائمة (للحساب)",
"listForContact": "قائمة (للاتصال)"
},
"templates": {
"invitation": "رسالة دعوة",
"reminder": "تذكير"
}
}

View File

@@ -0,0 +1,22 @@
{
"modes": {
"month": "شهر",
"week": "إسبوع",
"agendaWeek": "إسبوع",
"day": "يوم",
"agendaDay": "يوم",
"timeline": "الجدول الزمني"
},
"labels": {
"Today": "اليوم",
"Create": "إنشاء",
"Shared": "مشترك",
"Add User": "اضافة مستخدم",
"current": "الحالي",
"time": "الوقت",
"User List": "قائمة المستخدمين",
"Manage Users": "ادارة المستخدمين",
"View Calendar": "مشاهدة التقويم",
"Create Shared View": "إنشاء طريقة عرض مشتركة"
}
}

View File

@@ -0,0 +1,50 @@
{
"fields": {
"name": "الأسم",
"parent": "الأصل",
"status": "الحالة",
"dateStart": "تاريخ البداية",
"dateEnd": "تاريخ النتهاء",
"direction": "اتجاه",
"duration": "المدة الزمنية",
"description": "وصف",
"users": "المستخدمين",
"contacts": "جهات الاتصال",
"leads": "الفرص",
"reminders": "تنبيهات",
"account": "حساب",
"acceptanceStatus": "حالة القبول"
},
"options": {
"status": {
"Planned": "مخططة",
"Held": "تمت",
"Not Held": "لم يعقد"
},
"direction": {
"Outbound": "صادرة",
"Inbound": "واردة"
},
"acceptanceStatus": {
"None": "لاشئ",
"Accepted": "تم القبول",
"Declined": "تم الرفض",
"Tentative": "متردد"
}
},
"massActions": {
"setHeld": "تمت",
"setNotHeld": "لم تتم"
},
"labels": {
"Create Call": "إنشئ مكالمة",
"Set Held": "تمت",
"Set Not Held": "لم تتم",
"Send Invitations": "إرسل دعاوي"
},
"presetFilters": {
"planned": "مخططة",
"held": "تمت",
"todays": "اليوم الحاضر"
}
}

View File

@@ -0,0 +1,88 @@
{
"fields": {
"name": "الاسم",
"description": "الوصف",
"status": "الحالة",
"type": "النوع",
"startDate": "تاريخ البدء",
"endDate": "تاريخ الانتهاء",
"targetLists": "قوائم الاستهداف",
"excludingTargetLists": "إستثناء قوائم الاستهداف",
"sentCount": "تم الارسال",
"openedCount": "تم الفتح",
"clickedCount": "تم النقر",
"optedOutCount": "تم سحبها",
"bouncedCount": "ارتدت",
"hardBouncedCount": "ارتدت بعنف",
"softBouncedCount": "ارتد لينة",
"leadCreatedCount": "تم انشاء فرص",
"revenue": "إيرادات",
"revenueConverted": "الإيرادات (المحولة)",
"budget": "ميزانية",
"budgetConverted": "الميزانية (المحولة)",
"contactsTemplate": "نموذج جهات الاتصال",
"leadsTemplate": "نموذج العملاء المحتملين",
"accountsTemplate": "نموذج الحسابات",
"usersTemplate": "قالب المستخدمين",
"mailMergeOnlyWithAddress": "تخطي السجلات بدون عنوان معبأ",
"optedInCount": "اختارت في",
"budgetCurrency": "عملة الميزانية"
},
"links": {
"targetLists": "القوائم المستهدفة",
"excludingTargetLists": "باستثناء القوائم المستهدفة",
"accounts": "الحسابات",
"contacts": "جهات الاتصال",
"leads": "الفرص",
"opportunities": "الفرص",
"campaignLogRecords": "سجل",
"massEmails": "رسائل بريد الكتروني متعدد",
"trackingUrls": "روابط التتبع",
"contactsTemplate": "نموذج جهات الاتصال",
"leadsTemplate": "نموذج العملاء المحتملين",
"accountsTemplate": "نموذج الحسابات",
"usersTemplate": "قالب المستخدمين"
},
"options": {
"type": {
"Email": "البريد الإلكتروني",
"Web": "موقع الويب",
"Television": "التلفاز",
"Radio": "راديو",
"Newsletter": "النشرة الإخبارية",
"Mail": "بريد"
},
"status": {
"Planning": "تخطيط",
"Active": "نشط",
"Inactive": "غير نشط",
"Complete": "اكتملت"
}
},
"labels": {
"Create Campaign": "انشاء حملة اعلانية",
"Target Lists": "القوائم المستهدفة",
"Statistics": "الاحصائيات",
"hard": "مطبوعة",
"soft": "الكترونية",
"Unsubscribe": "إلغاء الاشتراك",
"Mass Emails": "رسائل البريد الإلكتروني المتعددة",
"Email Templates": "قوالب البريد الإلكتروني",
"Unsubscribe again": "إلغاء الاشتراك مرة أخرى",
"Subscribe again": "اشترك مرة أخرى",
"Create Target List": "إنشاء قائمة الهدف",
"Mail Merge": "دمج المراسلات",
"Generate Mail Merge PDF": "إنشاء دمج المراسلات PDF"
},
"presetFilters": {
"active": "نشط"
},
"messages": {
"unsubscribed": "لقد تم إلغاء اشتراكك من قائمتنا البريدية.",
"subscribedAgain": "أنت مشترك مرة أخرى."
},
"tooltips": {
"targetLists": "الأهداف التي يجب أن تتلقى الرسائل.",
"excludingTargetLists": "الأهداف التي يجب ألا تتلقى رسائل."
}
}

View File

@@ -0,0 +1,44 @@
{
"fields": {
"action": "الإجراء",
"actionDate": "تاريخ",
"data": "تاريخ",
"campaign": "حملة إعلانية",
"parent": "الإستهداف",
"object": "كائن",
"application": "تطبيق",
"queueItem": "قائمة انتظار البند",
"stringData": "سلسلة البيانات",
"stringAdditionalData": "سلسلة بيانات إضافية",
"isTest": "هو اختبار"
},
"links": {
"queueItem": "بند قائمة الانتظار",
"parent": "الأب",
"object": "كائن",
"campaign": "الحملة الانتخابية"
},
"options": {
"action": {
"Sent": "أرسلت",
"Opened": "افتتح",
"Opted Out": "انسحبت",
"Bounced": "اردتدت",
"Clicked": "النقر",
"Lead Created": "تم انشاء فرصة",
"Opted In": "اختارت في"
}
},
"labels": {
"All": "الكل"
},
"presetFilters": {
"sent": "تم الارسال",
"opened": "تم الفتح",
"optedOut": "انسحبت",
"bounced": "ارتدت",
"clicked": "تم النقر",
"leadCreated": "تم انشاء فرصة",
"optedIn": "اختارت في"
}
}

View File

@@ -0,0 +1,25 @@
{
"fields": {
"url": "رابط",
"urlToUse": "رمز لإدراجه بدلاً من عنوان الرابط",
"campaign": "حملة اعلانية",
"action": "عمل",
"message": "رسالة"
},
"links": {
"campaign": "الحملة"
},
"labels": {
"Create CampaignTrackingUrl": "إنشاء رابط للتتبع"
},
"options": {
"action": {
"Redirect": "إعادة توجيه",
"Show Message": "اظهر الرسالة"
}
},
"tooltips": {
"url": "سيتم إعادة توجيه المستلم إلى هذا الموقع بعد اتباع الارتباط.",
"message": "سيتم عرض الرسالة على المستلم بعد اتباع الارتباط. Markdown مدعوم."
}
}

View File

@@ -0,0 +1,61 @@
{
"fields": {
"name": "الاسم",
"number": "الرقم",
"status": "الحالة",
"account": "حساب",
"contact": "جهة إتصال",
"contacts": "جهات إتصال",
"priority": "الأولوية",
"type": "نوع",
"description": "الوصف",
"lead": "فرصة",
"attachments": "مرفقات",
"inboundEmail": "حساب البريد الإلكتروني للمجموعة"
},
"links": {
"account": "حساب",
"contact": "جهة الاتصال (المبدئية)",
"Contacts": "جهات الإتصال",
"meetings": "إجتماعات",
"calls": "المكالمات",
"tasks": "المهام",
"emails": "رسائل البريد الإلكتروني",
"articles": "مقالات قاعدة المعلومات",
"lead": "فرصة",
"attachments": "مرفقات",
"inboundEmail": "حساب البريد الإلكتروني للمجموعة"
},
"options": {
"status": {
"New": "جديد",
"Assigned": "تم التعيين",
"Pending": "معلق",
"Closed": "تم الإنتهاء",
"Rejected": "مرفوض",
"Duplicate": "مكرر"
},
"priority": {
"Low": "ضعيف",
"Normal": "عادي",
"High": "مرتفع",
"Urgent": "ضروري"
},
"type": {
"Question": "سؤال",
"Incident": "حادث عرضي",
"Problem": "مشكلة"
}
},
"labels": {
"Create Case": "إنشاء تذكرة",
"Close": "غلق",
"Reject": "رفض",
"Closed": "تم الإنتهاء",
"Rejected": "مرفوض"
},
"presetFilters": {
"open": "مفتوح",
"closed": "تم الإنتهاء"
}
}

View File

@@ -0,0 +1,56 @@
{
"fields": {
"name": "الاسم",
"emailAddress": "البريد الإلكتروني",
"accountRole": "الوظيفة",
"account": "الحساب ",
"accounts": "حساسبات العملاء",
"phoneNumber": "رقم التليفون",
"accountType": "نوع الحساب",
"doNotCall": "لا تتصل",
"address": "العنوان",
"opportunityRole": "دور الصفقة",
"description": "الوصف",
"campaign": "حملة اعلانية",
"targetLists": "قوائم الاستهداف",
"targetList": "قائمة الاستهداف",
"portalUser": "مستخدم البوابة",
"originalLead": "الفرصة الأصلية",
"acceptanceStatus": "حالة القبول",
"accountIsInactive": "الحساب غير نشط",
"acceptanceStatusMeetings": "حالة القبول (اجتماعات)",
"acceptanceStatusCalls": "حالة القبول (المكالمات)",
"title": "عنوان الحساب",
"hasPortalUser": "مستخدم البوابة"
},
"links": {
"opportunities": "الصفقات",
"cases": "تذاكر",
"targetLists": "قوائم الاستهداف",
"campaignLogRecords": "سجل الحملة",
"campaign": "حملة اعلانية",
"account": "الحساب (المبدئي)",
"accounts": "الحسابات",
"casesPrimary": "التذاكر (المبدئية)",
"portalUser": "مستخدم البوابة",
"originalLead": "الفرصة الأصلية",
"documents": "وثائق",
"tasksPrimary": "المهام (موسعة)",
"opportunitiesPrimary": "الفرص (الأساسية)"
},
"labels": {
"Create Contact": "انشاء جهة اتصال"
},
"options": {
"opportunityRole": {
"Decision Maker": "صانع القرار",
"Evaluator": "مقيم الاداء",
"Influencer": "المؤثر"
}
},
"presetFilters": {
"portalUsers": "مستخدمي البوابة",
"notPortalUsers": "لا يوجد مستخدمين للبوابة",
"accountActive": "نشيط"
}
}

View File

@@ -0,0 +1,7 @@
{
"fields": {
"futureDays": "X أيام القادمة",
"useLastStage": "تجميع حسب آخر مرحلة وصلت",
"team": "فريق"
}
}

View File

@@ -0,0 +1,41 @@
{
"labels": {
"Create Document": "إنشاء وثيقة",
"Details": "تفاصيل"
},
"fields": {
"name": "الاسم",
"status": "الحالة",
"file": "ملف",
"type": "النوع",
"publishDate": "تاريخ النشر",
"expirationDate": "تاريخ إنتهاء الصلاحية",
"description": "الوصف",
"accounts": "الحسابات",
"folder": "المجلد"
},
"links": {
"accounts": "الحسابات",
"opportunities": "الفرص",
"folder": "ملف",
"leads": "الفرص",
"contacts": "جهات الاتصال"
},
"options": {
"status": {
"Active": "نشط",
"Draft": "مسودة",
"Expired": "منتهية الصلاحية",
"Canceled": "ملغية"
},
"type": {
"": "لاشئ",
"Contract": "عقد",
"License Agreement": "اتفاقية الترخيص"
}
},
"presetFilters": {
"active": "نشط",
"draft": "مسودة"
}
}

View File

@@ -0,0 +1,10 @@
{
"labels": {
"Create DocumentFolder": "إنشاء ",
"Manage Categories": "إدارة المجلدات",
"Documents": "مستندات"
},
"links": {
"documents": "مستندات"
}
}

View File

@@ -0,0 +1,13 @@
{
"labels": {
"Create Lead": "إنشاء فرصة",
"Create Contact": "إنشاء جهة اتصال",
"Create Task": "إنشاء مهمة",
"Create Case": "إنشاء تذكرة",
"Add to Contact": "إضافة لقائمة المتصلين",
"Add to Lead": "أضف للفرصة"
},
"fields": {
"tasks": "مهام"
}
}

View File

@@ -0,0 +1,29 @@
{
"fields": {
"name": "الاسم",
"status": "الحالة",
"target": "الهدف",
"sentAt": "تاريخ الارسال",
"attemptCount": "المحاولات",
"emailAddress": "البريد الإلكتروني",
"massEmail": "البريد الإلكتروني المتعدد",
"isTest": "تحت الاختبار"
},
"links": {
"target": "الهدف",
"massEmail": "البريد الإلكتروني المتعدد"
},
"options": {
"status": {
"Pending": "قيد النتظار",
"Sent": "ارسل",
"Failed": "فشل",
"Sending": "إرسال"
}
},
"presetFilters": {
"pending": "قيد النتظار",
"sent": "ارسل",
"failed": "فشل"
}
}

View File

@@ -0,0 +1,119 @@
{
"links": {
"parent": "الأب",
"contacts": "جهات الإتصال",
"opportunities": "فرص",
"leads": "الفرص",
"meetings": "اجتماعات",
"calls": "اتصالات",
"tasks": "مهام",
"emails": "رسائل البريد الإلكتروني",
"accounts": "حسابات",
"cases": "تذاكر",
"documents": "مستندات",
"account": "حساب",
"opportunity": "الصفقة",
"contact": "جهة اتصال"
},
"scopeNames": {
"Account": "حساب",
"Contact": "جهة اتصال",
"Lead": "فرصة",
"Target": "هدف",
"Opportunity": "الصفقة",
"Meeting": "إجتماع",
"Calendar": "جدول المواعيد",
"Call": "مكالمة",
"Task": "مهمة",
"Case": "تذكرة",
"Document": "وثيقة",
"DocumentFolder": "ملف المستندات",
"Campaign": "حملة اعلانية",
"TargetList": "القائمة المستهدفة",
"MassEmail": "البريد الإلكتروني المتعدد",
"EmailQueueItem": "عنصر قائمة انتظار البريد الإلكتروني",
"CampaignTrackingUrl": "رابط التتبع",
"Activities": "الانشطة",
"KnowledgeBaseArticle": "مقالات قاعدة المعلومات",
"KnowledgeBaseCategory": "اقسام قاعدة المعلومات",
"CampaignLogRecord": "سجل سجل الحملة"
},
"scopeNamesPlural": {
"Account": "الحسابات",
"Contact": "جهات الاتصال",
"Lead": "الفرص",
"Target": "الاستهدافات",
"Opportunity": "الفرص",
"Meeting": "الاجتماعات",
"Calendar": "التقويم",
"Call": "المكالمات",
"Task": "المهام",
"Case": "تذاكر",
"Document": "المستندات",
"DocumentFolder": "مجلد المستندات",
"Campaign": "الحملات",
"TargetList": "القوائم المستهدفة",
"MassEmail": "رسائل البريد الإلكتروني المتعددة",
"EmailQueueItem": "عناصر قائمة انتظار البريد الإلكتروني",
"CampaignTrackingUrl": "تتبع عناوين المواقع",
"Activities": "انشطة",
"KnowledgeBaseArticle": "قاعدة المعرفة",
"KnowledgeBaseCategory": "فئات قاعدة المعرفة",
"CampaignLogRecord": "سجلات سجل الحملة"
},
"dashlets": {
"Leads": "فرصي",
"Opportunities": "صفقاتي",
"Tasks": "مهامي",
"Cases": "التذاكر الخاصة بي",
"Calendar": "التقويم",
"Calls": "مكالماتي",
"Meetings": "اجتماعاتي",
"OpportunitiesByStage": "الفرص حسب المرحلة",
"OpportunitiesByLeadSource": "الصفقات بالنسبة لمصدر الليدز",
"SalesByMonth": "المبيعات حسب الشهر",
"SalesPipeline": "مجرى البيع",
"Activities": "نشاطاتي"
},
"labels": {
"Create InboundEmail": "إنشاء بريد الكتروني وارد",
"Activities": "الانشطة",
"History": "سجل",
"Attendees": "الحاضرين",
"Schedule Meeting": "ترتيب موعد للاجتماع",
"Schedule Call": "ترتيب موعد للمكالمة",
"Compose Email": "إنشاء البريد الإلكتروني",
"Log Meeting": "سجل الاجتماع",
"Log Call": "سجل المكالمة",
"Archive Email": "ارشيف البريد الالكتروني",
"Create Task": "أنشاء مهمة",
"Tasks": "المهام",
"Scheduler": "جدولة"
},
"fields": {
"billingAddressCity": "المدينة",
"addressCity": "المدينة",
"billingAddressCountry": "البلد",
"addressCountry": "البلد",
"billingAddressPostalCode": "الرمز البريدي",
"addressPostalCode": "الرمز البريدي",
"billingAddressState": "المدينة",
"addressState": "المدينة",
"billingAddressStreet": "الشارع",
"addressStreet": "الشارع",
"billingAddressMap": "الخريطة",
"addressMap": "الخريطة",
"shippingAddressCity": "المدينة (الشحن)",
"shippingAddressStreet": "الشارع (الشحن)",
"shippingAddressCountry": "البلد (الشحن)",
"shippingAddressState": "المدينة (الشحن)",
"shippingAddressPostalCode": "الرمز البريدي (الشحن)",
"shippingAddressMap": "الخريطة (الشحن)"
},
"options": {
"reminderTypes": {
"Popup": "تذكير على الشاشة",
"Email": "البريد الإلكتروني"
}
}
}

View File

@@ -0,0 +1,47 @@
{
"labels": {
"Create KnowledgeBaseArticle": "أنشئ مقال",
"Any": "أي",
"Send in Email": "إرسال بالبريد الإلكتروني",
"Move Up": "تحرك",
"Move Down": "تحرك لأسفل",
"Move to Top": "الانتقال إلى الأعلى",
"Move to Bottom": "انتقل إلى الأسفل"
},
"fields": {
"name": "الاسم",
"status": "الحالة",
"type": "نوع",
"attachments": "المرفقات",
"publishDate": "تاريخ الإنشاء",
"expirationDate": "تاريخ الانتهاء",
"description": "الوصف",
"body": "الجسم",
"categories": "الاقسام",
"language": "اللغة",
"portals": "البوابات"
},
"links": {
"cases": "تذاكر",
"opportunities": "الفرص",
"categories": "الاقسام",
"portals": "البوابات"
},
"options": {
"status": {
"In Review": "تحت المراجعة",
"Draft": "مسودة",
"Archived": "المؤرشفة",
"Published": "تم النشر"
},
"type": {
"Article": "مقالة"
}
},
"presetFilters": {
"published": "تم الإنشاء"
},
"tooltips": {
"portals": "المادة ستكون متاحة فقط في بوابات محددة."
}
}

View File

@@ -0,0 +1,10 @@
{
"labels": {
"Create KnowledgeBaseCategory": "أنشئ قسم",
"Manage Categories": "إدارة الفئات",
"Articles": "مقالات"
},
"links": {
"articles": "مقالات"
}
}

View File

@@ -0,0 +1,70 @@
{
"labels": {
"Converted To": "تحويل لـ",
"Create Lead": "إنشاء فرصة",
"Convert": "تحويل",
"convert": "يتحول"
},
"fields": {
"name": "الاسم",
"emailAddress": "الإيميل",
"title": "العنوان",
"website": "الموقع الإلكتروني",
"phoneNumber": "رقم الهاتف",
"accountName": "اسم الحساب",
"doNotCall": "لا تتصل",
"address": "العنوان",
"status": "الحالة",
"source": "المصدر",
"opportunityAmount": "قيمة الصفقة",
"opportunityAmountConverted": "مبلغ الفرصة (تم تحويله)",
"description": "الوصف",
"createdAccount": "الحساب",
"createdContact": "اتصل",
"createdOpportunity": "الصفقات",
"campaign": "الحملة",
"targetLists": "القوائم الهدف",
"targetList": "القائمة الهدف",
"industry": "صناعة",
"acceptanceStatus": "حالة القبول",
"opportunityAmountCurrency": "قيمة عملة الصفقة",
"acceptanceStatusMeetings": "حالة القبول (اجتماعات)",
"acceptanceStatusCalls": "حالة القبول (المكالمات)",
"convertedAt": "تم التحويل عند"
},
"links": {
"targetLists": "القوائم الهدف",
"campaignLogRecords": "سجل الحملة",
"campaign": "الحملة",
"createdAccount": "حساب",
"createdContact": "جهة اتصال",
"createdOpportunity": "صفقة",
"cases": "تذاكر",
"documents": "وثاق"
},
"options": {
"status": {
"New": "جديد",
"Assigned": "مخصص",
"In Process": "تحت المعالجة",
"Converted": "تم التحويل",
"Recycled": "المعاد تدويره",
"Dead": "في ذمة الله تعالى"
},
"source": {
"Call": "اتصال",
"Email": "البريد الإلكتروني",
"Existing Customer": "زبون موجود",
"Partner": "شريك",
"Public Relations": "علاقة عامة",
"Web Site": "موقع ويب",
"Campaign": "حملة",
"Other": "غير ذلك"
}
},
"presetFilters": {
"active": "فعال",
"actual": "الفعلي",
"converted": "تم تحويله"
}
}

View File

@@ -0,0 +1,58 @@
{
"fields": {
"name": "الاسم",
"status": "الحالة",
"storeSentEmails": "تخزين رسائل البريد الإلكتروني المرسلة",
"startAt": "تاريخ البداية",
"fromAddress": "من عنوان",
"fromName": "اسم النموذج",
"replyToAddress": "الرد إلى العنوان",
"replyToName": "الرد إلى الاسم",
"campaign": "حملة",
"emailTemplate": "قالب البريد الإلكتروني",
"inboundEmail": "حساب البريد الإلكتروني",
"targetLists": "القوائم الهدف",
"excludingTargetLists": "استثناء قوائم الهدف",
"optOutEntirely": "الانسحاب بالكامل",
"smtpAccount": "حساب SMTP"
},
"links": {
"targetLists": "قوائم الهدف",
"excludingTargetLists": "استثناء قوائم الهدف",
"queueItems": "عناصر قائمة الانتظار",
"campaign": "الحملة الانتخابية",
"emailTemplate": "قالب البريد الإلكتروني",
"inboundEmail": "حساب البريد الإلكتروني"
},
"options": {
"status": {
"Draft": "مسودة",
"Pending": "قيد الإنتظار",
"In Process": "قيد المعالجة",
"Complete": "مكتمل",
"Canceled": "تم الإلغاء",
"Failed": "فشل"
}
},
"labels": {
"Create MassEmail": " إنشاء بريد الكتروني متعدد",
"Send Test": "إرسال إختبار",
"System SMTP": "نظام SMTP",
"system": "النظام",
"group": "مجموعة"
},
"messages": {
"selectAtLeastOneTarget": "إختر على الأقل هدف واحد",
"testSent": "من المفترض إرسال رسائل البريد الإلكتروني التجريبية"
},
"tooltips": {
"optOutEntirely": "سيتم وضع علامة على عناوين البريد الإلكتروني للمستلمين الذين تم إلغاء اشتراكهم على أنهم غير مشتركين ولن يتلقوا أي رسائل بريد إلكتروني جماعية بعد الآن.",
"targetLists": "الأهداف التي يجب أن تتلقى الرسائل.",
"excludingTargetLists": "الأهداف التي لا ينبغي أن تتلقى رسائل.",
"storeSentEmails": "سيتم تخزين رسائل البريد الإلكتروني في CRM."
},
"presetFilters": {
"actual": "فِعلي",
"complete": "مكتمل"
}
}

View File

@@ -0,0 +1,57 @@
{
"fields": {
"name": "الإسم",
"parent": "الأبوين",
"status": "الحاله",
"dateStart": "تاريخ البدايه",
"dateEnd": "تاريخ النهاية",
"duration": "المده",
"description": "الوصف",
"users": "المستخدمين",
"contacts": "جهات الاتصال",
"leads": "الفرص",
"reminders": "التذكيرات",
"account": "الحساب",
"acceptanceStatus": "حالة القبول",
"dateStartDate": "تاريخ البدء (طوال اليوم)",
"dateEndDate": "تاريخ الانتهاء (طوال اليوم)",
"isAllDay": "طوال اليوم",
"Acceptance": "قبول",
"sourceEmail": "البريد الإلكتروني المصدر"
},
"options": {
"status": {
"Planned": "مخطط له",
"Held": "تم حضوره",
"Not Held": "لم يتم حضوره"
},
"acceptanceStatus": {
"None": "لاشئ",
"Accepted": "تم القبول",
"Declined": "تم الرفض",
"Tentative": "مُتَردِّد"
}
},
"massActions": {
"setHeld": "حفظ على أنه تم الحضور",
"setNotHeld": "حفظ على أنه لم يتم الحضور"
},
"labels": {
"Create Meeting": "إنشاء إجتماع",
"Set Held": "حفظ على أنه تم الحضور",
"Set Not Held": "حفظ على أنه لم يتم الحضور",
"Send Invitations": "إرسال الدعوات",
"on time": "في الوقت",
"before": "قبل",
"All-Day": "طوال اليوم"
},
"presetFilters": {
"planned": "مخطط له",
"held": "تم الحضور",
"todays": "في هذا اليوم"
},
"messages": {
"nothingHasBeenSent": "لم يتم إرسال أي شيء",
"selectAcceptanceStatus": "قم بتعيين حالة القبول الخاصة بك."
}
}

View File

@@ -0,0 +1,53 @@
{
"fields": {
"name": "الاسم",
"account": "الحساب",
"stage": "المرحلة",
"amount": "القيمة",
"probability": "الإحتمالية, %",
"leadSource": "مصدر الفرصة",
"doNotCall": "لا تتصل",
"closeDate": "تاريخ الإقفال",
"contacts": "جهات الإتصال",
"description": "الوصف",
"amountConverted": "القيمة (المحولة)",
"amountWeightedConverted": "المبلغ المرجح",
"campaign": "الحملة",
"originalLead": "الفرصة الأصلية",
"amountCurrency": "العملة كمية",
"contactRole": "دور الاتصال",
"lastStage": "اخر مرحلة",
"contact": "جهة اتصال (أساسية)"
},
"links": {
"contacts": "جهات الإتصال",
"documents": "المستندات",
"campaign": "الحملة",
"originalLead": "الفرصة الأصلية",
"contact": "جهة اتصال (أساسية)"
},
"options": {
"stage": {
"Prospecting": "التنقيب",
"Qualification": "المُؤهّل",
"Needs Analysis": "يحتاج إلى تحليل",
"Value Proposition": "موقع ذو قيمة",
"Id. Decision Makers": "في انتظار صناع القرار",
"Perception Analysis": "تحليل التصور",
"Proposal/Price Quote": "عرض سعر",
"Negotiation/Review": "التفاوض/مراجعة",
"Closed Won": "ناجحة",
"Closed Lost": "مغلق فقدت",
"Proposal": "عرض",
"Negotiation": "تفاوض"
}
},
"labels": {
"Create Opportunity": "إنشاء صفقة"
},
"presetFilters": {
"open": "مفتوح",
"won": "ربح",
"lost": "خسارة"
}
}

View File

@@ -0,0 +1,5 @@
{
"links": {
"articles": "مقالات القاعدة المعرفية"
}
}

View File

@@ -0,0 +1,8 @@
{
"options": {
"job": {
"ProcessMassEmail": " إرسال رسائل البريد الإلكتروني المتعددة",
"ControlKnowledgeBaseArticleStatus": "التحكّم في حالة مقالات القاعدة المعرفية"
}
}
}

View File

@@ -0,0 +1,41 @@
{
"fields": {
"name": "الاسم",
"description": "الوصف",
"entryCount": "عدد الدخول",
"campaigns": "الحملات",
"endDate": "تاريخ النهاية",
"targetLists": "القوائم الهدف",
"includingActionList": "مشتمل",
"excludingActionList": "ازالة",
"optedOutCount": "عدد المعوقين",
"targetStatus": "الوضع الهدف",
"isOptedOut": "تم الانسحاب"
},
"links": {
"accounts": "الحسابات",
"contacts": "جهات الاتصال",
"leads": "الفرص",
"campaigns": "الحملات",
"massEmails": " رسائل البريد الإلكتروني المتعددة"
},
"options": {
"type": {
"Email": "البريد الإلكتروني",
"Web": "ويب",
"Television": "التلفاز",
"Radio": "الراديو",
"Newsletter": "النشرة الإخبارية"
},
"targetStatus": {
"Opted Out": "انسحبت",
"Listed": "مدرج"
}
},
"labels": {
"Create TargetList": "إنشاء قائمة الهدف",
"Opted Out": "انسحبت",
"Cancel Opt-Out": "إلغاء الانسحاب",
"Opt-Out": "انسحب"
}
}

View File

@@ -0,0 +1,55 @@
{
"fields": {
"name": "اسم",
"parent": "الأبوين",
"status": "الحاله",
"dateStart": "تاريخ البدايه",
"dateEnd": "تاريخ الاستحقاق",
"dateStartDate": "تاريخ البدايه (لكل الايام)",
"dateEndDate": "تاريخ النهايه (لكل الايام)",
"priority": "الاولويات",
"description": "الوصف",
"isOverdue": "متأخر",
"account": "حساب",
"dateCompleted": "تاريخ الإنهاء",
"attachments": "المرفقات",
"reminders": "تذكير",
"contact": "اتصال"
},
"links": {
"attachments": "المرفقات",
"account": "الحساب",
"contact": "جهة إتصال",
"email": "بريد"
},
"options": {
"status": {
"Not Started": "لم تبدأ",
"Started": "بدأت",
"Completed": "انتهت",
"Canceled": "تم إلغاءها",
"Deferred": "تم تأجيلها"
},
"priority": {
"Low": "مُنخفض",
"Normal": "عادي",
"High": "مُرتفع",
"Urgent": "عاجل"
}
},
"labels": {
"Create Task": "إنشاء مُهمّة",
"Complete": "إنهاء",
"overdue": "متأخر"
},
"presetFilters": {
"actual": "فعلي",
"completed": "تم إنهاءها",
"todays": "اليوم",
"overdue": "مُتأخّر",
"deferred": "مؤجل"
},
"nameOptions": {
"replyToEmail": "الرد ع البريد"
}
}

View File

@@ -0,0 +1,10 @@
{
"links": {
"targetLists": "قوائم الهدف"
},
"fields": {
"acceptanceStatus": "حالة القبول",
"acceptanceStatusMeetings": "حالة القبول (اجتماعات)",
"acceptanceStatusCalls": "حالة القبول (المكالمات)"
}
}

View File

@@ -1,104 +1,107 @@
{
"fields": {
"name": "име",
"emailAddress": "електронна поща",
"website": "уебсайт",
"phoneNumber": "телефон",
"billingAddress": "адрес на плащане",
"name": "Име",
"emailAddress": "Електронна поща",
"website": "Уебсайт",
"phoneNumber": "Телефон",
"billingAddress": "Адрес за плащане",
"shippingAddress": "Адрес за доставка",
"description": "описание",
"sicCode": "Sic Код",
"industry": "промишленост",
"description": "Описание",
"sicCode": "SIC Код",
"industry": "Промишленост",
"type": "Тип",
"contactRole": "Заглавие",
"campaign": "кампания",
"campaign": "Кампания",
"targetLists": "Целеви списъци",
"targetList": "Целева Списък",
"originalLead": "Оригинален Lead",
"contactIsInactive": "неактивен"
"targetList": "Целеви списък",
"originalLead": "Оригинална потенциална продажба",
"contactIsInactive": "Неактивен"
},
"links": {
"contacts": "Контакти",
"opportunities": "възможности",
"cases": "случаи",
"opportunities": "Сделки",
"cases": "Тикети",
"documents": "Документи",
"meetingsPrimary": "Заседания (разширена)",
"callsPrimary": "Призовава (разширена)",
"tasksPrimary": "Задачи (разширена)",
"emailsPrimary": "Имейли (разширен)",
"meetingsPrimary": "Срещи (разширено)",
"callsPrimary": "Разговори (разширено)",
"tasksPrimary": "Задачи (разширено)",
"emailsPrimary": "Имейли (разширено)",
"targetLists": "Целеви списъци",
"campaignLogRecords": "кампания Вход",
"campaign": "кампания",
"portalUsers": "потребители на портала",
"originalLead": "Оригинален Lead"
"campaignLogRecords": "Логове на кампанията",
"campaign": "Кампания",
"portalUsers": "Потребители на портала",
"originalLead": "Оригинална потенциална продажба",
"contactsPrimary": "Контакти (основен)"
},
"options": {
"type": {
"Customer": "клиент",
"Investor": "инвеститор",
"Partner": "партньор"
"Customer": "Клиент",
"Investor": "Инвеститор",
"Partner": "Партньор",
"Reseller": "Реселър"
},
"industry": {
"Agriculture": "селско стопанство",
"Advertising": "реклама",
"Agriculture": "Селско стопанство",
"Advertising": "Реклама",
"Apparel & Accessories": "Облекло & Аксесоари",
"Automotive": "автомобилен",
"Banking": "банково дело",
"Biotechnology": "биотехнологии",
"Automotive": "Автомобилна индустрия",
"Banking": "Банково дело",
"Biotechnology": "Биотехнологии",
"Building Materials & Equipment": "Строителни материали и техника",
"Chemical": "химически",
"Computer": "компютър",
"Education": "образование",
"Electronics": "електроника",
"Chemical": "Химическа индустрия",
"Computer": "Компютърна индустрия",
"Education": "Образование",
"Electronics": "Електроника",
"Energy": "Енергия",
"Entertainment & Leisure": "Забавление и свободно време",
"Finance": "Финанси",
"Food & Beverage": "Храни и напитки",
"Grocery": "хранителни стоки",
"Grocery": "Хранителни стоки",
"Healthcare": "Здравеопазване",
"Insurance": "Застраховка",
"Legal": "правен",
"Manufacturing": "производство",
"Publishing": "издаване",
"Real Estate": "Недвижим имот",
"Legal": "Правна индустрия",
"Manufacturing": "Производство",
"Publishing": "Издателска дейност",
"Real Estate": "Недвижими имоти",
"Service": "Обслужване",
"Sports": "спортен",
"Sports": "Спортни дейности",
"Software": "Софтуер",
"Technology": "технология",
"Telecommunications": "телекомуникации",
"Television": "телевизия",
"Transportation": "транспорт",
"Venture Capital": "рисков капитал",
"Aerospace": "космически",
"Architecture": "архитектура",
"Construction": "строителство",
"Defense": "отбрана",
"Creative": "творчески",
"Culture": "култура",
"Technology": "Технологии",
"Telecommunications": "Телекомуникации",
"Television": "Телевизия",
"Transportation": "Транспорт",
"Venture Capital": "Рисков капитал",
"Aerospace": "Авиокосмически",
"Architecture": "Архитектура",
"Construction": "Строителство",
"Defense": "Отбрана",
"Creative": "Творчески",
"Culture": "Култура",
"Consulting": "Консултации",
"Electric Power": "Електрическа енергия",
"Hospitality": "гостоприемство",
"Mass Media": "Средства за масова информация",
"Mining": "Минен",
"Music": "музика",
"Marketing": "маркетинг",
"Petroleum": "петролен",
"Retail": "На дребно",
"Shipping": "Доставка",
"Support": "поддържа",
"Hospitality": "Болници",
"Mass Media": "Масови медии",
"Mining": "Минно дело",
"Music": "Музика",
"Marketing": "Маркетинг",
"Petroleum": "Петролен бизнес",
"Retail": "Търговия на дребно",
"Shipping": "Спедиция",
"Support": "Поддръжка",
"Testing, Inspection & Certification": "Тестване, контрол и сертификация",
"Wholesale": "на едро",
"Water": "вода",
"Travel": "пътуване"
"Wholesale": "Търговия на едро",
"Water": "Вода",
"Travel": "Пътуване"
}
},
"labels": {
"Create Account": "Създай акаунт",
"Copy Billing": "Копие за фактуриране",
"Set Primary": "Комплект Основно"
"Create Account": "Създаване на клиент",
"Copy Billing": "Пренасяне на данните",
"Set Primary": "Задай като основен"
},
"presetFilters": {
"customers": "Клиенти",
"partners": "Партньори",
"recentlyCreated": "Наскоро Създадени"
"recentlyCreated": "Наскоро създадени"
}
}

View File

@@ -1,11 +1,11 @@
{
"layouts": {
"detailConvert": "Конвертиране",
"listForAccount": "Списък (за сметка)",
"listForAccount": "Списък (за клиент)",
"listForContact": "Списък (за контакти)"
},
"templates": {
"invitation": "покана",
"reminder": "напомняне"
"invitation": "Покана",
"reminder": "Напомняне"
}
}

View File

@@ -1,21 +1,22 @@
{
"modes": {
"month": "месец",
"week": "седмица",
"agendaWeek": "седмица",
"day": "ден",
"agendaDay": "ден"
"month": "Месец",
"week": "Седмица",
"agendaWeek": "Седмица",
"day": "Ден",
"agendaDay": "Ден",
"timeline": "Хронология"
},
"labels": {
"Today": "днес",
"Create": "създавам",
"Shared": "Споделено",
"Today": "Днес",
"Create": "Създаване",
"Shared": "Споделено с други потребители",
"Add User": "Добавяне на потребител",
"current": "текущ",
"time": "път",
"current": "Текущ",
"time": "време",
"User List": "Списък с потребители",
"Manage Users": "Управление на потребителите",
"View Calendar": "Вижте Календар",
"Create Shared View": "Създаване на споделена View"
"View Calendar": "Вижте календара",
"Create Shared View": "Създаване на споделен изглед"
}
}

View File

@@ -1,50 +1,50 @@
{
"fields": {
"name": "име",
"parent": "родител",
"name": "Име",
"parent": "Родител",
"status": "Статус",
"dateStart": "Дата Старт",
"dateStart": "Начална дата",
"dateEnd": "Крайна дата",
"direction": "Посока",
"duration": "продължителност",
"description": "описание",
"duration": "Продължителност",
"description": "Описание",
"users": "Потребители",
"contacts": "Контакти",
"leads": "Потенциална Продажба",
"leads": "Потенциални продажби",
"reminders": "Напомняния",
"account": "Сметка",
"acceptanceStatus": "Приемане Статус"
"account": "Клиент",
"acceptanceStatus": "Статус за приемане"
},
"options": {
"status": {
"Planned": "Планирано",
"Held": "Държани",
"Not Held": "Не държани"
"Planned": "Планирани",
"Held": "Състояли се",
"Not Held": "Несъстояли се"
},
"direction": {
"Outbound": "Изходяща",
"Outbound": "Изходящ",
"Inbound": "Входящ"
},
"acceptanceStatus": {
"None": "Нито един",
"Accepted": "общоприет",
"Declined": "Отхвърлена",
"Tentative": "Експериментален"
"Accepted": "Прието",
"Declined": "Пропуснато",
"Tentative": "Колеблив"
}
},
"massActions": {
"setHeld": "Задайте държани",
"setNotHeld": "Задайте не се държат"
"setHeld": "Задай като състоял се",
"setNotHeld": "Задай като несъстоял се"
},
"labels": {
"Create Call": "Създаване на Call",
"Set Held": "Задайте държани",
"Set Not Held": "Задайте не се държат",
"Create Call": "Създаване на Разговор",
"Set Held": "Задай като състоял се",
"Set Not Held": "Задай като несъстоял се",
"Send Invitations": "Изпращането на покани"
},
"presetFilters": {
"planned": "Планирано",
"held": "Държани",
"planned": "Планирани",
"held": "Състояли се",
"todays": "Днешните"
}
}

View File

@@ -1,61 +1,62 @@
{
"fields": {
"name": "име",
"description": "описание",
"name": "Име",
"description": "Описание",
"status": "Статус",
"type": "Тип",
"startDate": "Начална дата",
"endDate": "Крайна дата",
"targetLists": "Целеви списъци",
"excludingTargetLists": "С изключение на целевите списъци",
"sentCount": "Изпратено",
"openedCount": "Отворен",
"clickedCount": "Кликване",
"optedOutCount": "Отказахте се",
"bouncedCount": "Върната",
"hardBouncedCount": "Hard Върната",
"softBouncedCount": "Мека Върната",
"leadCreatedCount": "Създадена Потенциална Продажба",
"revenue": "приход",
"revenueConverted": "Приходите (изчислена)",
"budget": "бюджет",
"budgetConverted": "Бюджет (изчислена)",
"contactsTemplate": "Контакти с шаблони",
"leadsTemplate": "Leads Шаблон",
"accountsTemplate": "сметки за шаблони",
"usersTemplate": "Потребителите на шаблона",
"mailMergeOnlyWithAddress": "Напред записи / М попълнено адрес",
"sentCount": "Изпратени",
"openedCount": "Отваряния",
"clickedCount": "Кликвания",
"optedOutCount": "Отписали се",
"bouncedCount": "Неуспешно получени",
"hardBouncedCount": "Неуспешно получени",
"softBouncedCount": "Неуспешно получени",
"leadCreatedCount": "Генерирани потенциални продажби",
"revenue": "Приход",
"revenueConverted": "Приходи (изчислени)",
"budget": "Бюджет",
"budgetConverted": "Бюджет (изчислен)",
"contactsTemplate": "Шаблон за контакти",
"leadsTemplate": "Шаблон за потенциална продажба",
"accountsTemplate": "Шаблон за Клиенти",
"usersTemplate": "Шаблон за потребители",
"mailMergeOnlyWithAddress": "Пропускане на записи без попълнен адрес",
"optedInCount": "Избрал участие",
"budgetCurrency": "Бюджет на валута"
"budgetCurrency": "Валута на бюджета"
},
"links": {
"targetLists": "Целеви списъци",
"excludingTargetLists": "С изключение на целевите списъци",
"accounts": "сметки",
"accounts": "Клиенти",
"contacts": "Контакти",
"leads": "Потенциална Продажба",
"opportunities": "възможности",
"leads": "Потенциални продажби",
"opportunities": "Сделки",
"campaignLogRecords": "Вход",
"massEmails": "Масови имейли",
"trackingUrls": "Проследяване на URL адреси",
"contactsTemplate": "Контакти с шаблони",
"leadsTemplate": "Leads Шаблон",
"accountsTemplate": "сметки за шаблони",
"contactsTemplate": "Шаблон за контакти",
"leadsTemplate": "Шаблон за потенциални продажби",
"accountsTemplate": "Шаблон за Клиенти",
"usersTemplate": "Потребителите на шаблона"
},
"options": {
"type": {
"Email": "електронна поща",
"Web": "мрежа",
"Television": "телевизия",
"Radio": "радио",
"Mail": "поща"
"Email": "Електронна поща",
"Web": "Интернет",
"Television": "Телевизия",
"Radio": "Радио",
"Newsletter": "Имейл бюлетин",
"Mail": "Електронна поща"
},
"status": {
"Planning": "планиране",
"Active": "Активен",
"Inactive": "неактивен",
"Complete": "пълен"
"Planning": "Планиране",
"Active": "Активна",
"Inactive": "Неактивна",
"Complete": "Завършена"
}
},
"labels": {
@@ -66,18 +67,19 @@
"soft": "мек",
"Unsubscribe": "Отписване",
"Mass Emails": "Масови имейли",
"Email Templates": "Шаблони за имейл",
"Email Templates": "Шаблони за имейли",
"Unsubscribe again": "Отписване отново",
"Subscribe again": "Абонирайте се отново",
"Create Target List": "Създаване на Target Списък",
"Generate Mail Merge PDF": "Генериране на циркулярни PDF"
"Create Target List": "Създаване на целеви списък",
"Mail Merge": "Сливане на имейли",
"Generate Mail Merge PDF": "Генериране на Mail Merge PDF"
},
"presetFilters": {
"active": "Активен"
},
"messages": {
"unsubscribed": "Отписахте се от нашия пощенски списък.",
"subscribedAgain": "Абонирани сте отново."
"unsubscribed": "Отписахте се от нашия имейл бюлетин",
"subscribedAgain": "Абонирахте се отново."
},
"tooltips": {
"targetLists": "Цели, които трябва да получават съобщения.",

View File

@@ -1,42 +1,44 @@
{
"fields": {
"action": "действие",
"action": "Действия",
"actionDate": "Дата",
"data": "Данни",
"campaign": "кампания",
"campaign": "Кампания",
"parent": "Цел",
"object": "обект",
"object": "Обект",
"application": "Приложение",
"queueItem": "опашка Точка",
"stringAdditionalData": "String Допълнителна данни"
"queueItem": "Елементи в опашката",
"stringData": "Низови данни",
"stringAdditionalData": "Допълнителни низови данни",
"isTest": "Е тестов"
},
"links": {
"queueItem": "опашка Точка",
"parent": "родител",
"object": "обект",
"campaign": "кампания"
"queueItem": "Елементи в опашката",
"parent": "Родител",
"object": "Обект",
"campaign": "Кампания"
},
"options": {
"action": {
"Sent": "Изпратено",
"Opened": "Отворен",
"Opted Out": "Отказахте се",
"Bounced": "Върната",
"Clicked": "Кликване",
"Lead Created": "Създадена Потенциална Продажба",
"Sent": "Изпратени",
"Opened": "Отворени",
"Opted Out": "Отписали се",
"Bounced": "Неуспешно получени",
"Clicked": "Кликнали",
"Lead Created": "Създадени потенциални продажби",
"Opted In": "Избрал участие"
}
},
"labels": {
"All": "всичко"
"All": "Всички"
},
"presetFilters": {
"sent": "Изпратено",
"opened": "Отворен",
"optedOut": "Отказахте се",
"bounced": "Върната",
"clicked": "Кликване",
"leadCreated": "Създадена Потенциална Продажба",
"sent": "Изпратени",
"opened": "Отворени",
"optedOut": "Отказали се",
"bounced": "Неуспешно получени",
"clicked": "Кликвани",
"leadCreated": "Създадени потенциални продажби",
"optedIn": "Избрал участие"
}
}

View File

@@ -1,12 +1,12 @@
{
"fields": {
"urlToUse": "Код за вмъкване вместо URL",
"campaign": "кампания",
"action": "действие",
"message": "съобщение"
"campaign": "Кампания",
"action": "Действие",
"message": "Съобщение"
},
"links": {
"campaign": "кампания"
"campaign": "Кампания"
},
"labels": {
"Create CampaignTrackingUrl": "Създаване на URL адрес за проследяване"
@@ -18,7 +18,7 @@
}
},
"tooltips": {
"url": "Получателят ще бъдат пренасочени към това място, след като следвайте връзката.",
"message": "Съобщението ще бъде показан на получателя, след като следвайте връзката. Markdown се поддържа."
"url": "Получателят ще бъде пренасочен към този URL, след като кликне на връзката.",
"message": "Съобщението ще бъде показано на получателя, след като кликне на връзката. Markdown се поддържа."
}
}

View File

@@ -1,60 +1,61 @@
{
"fields": {
"name": "име",
"number": "номер",
"name": "Име",
"number": "Номер",
"status": "Статус",
"account": "Сметка",
"contact": "контакт",
"contact": "Контакт",
"contacts": "Контакти",
"priority": "приоритет",
"priority": "Приоритет",
"type": "Тип",
"description": "описание",
"lead": "Потенциална Продажба",
"attachments": "Прикачени",
"inboundEmail": "Група имейл акаунт"
"description": "Описание",
"lead": "Потенциална продажба",
"attachments": "Прикачени файлове",
"inboundEmail": "Групов имейл акаунт"
},
"links": {
"account": "Сметка",
"contact": "Свържи (Основно)",
"account": "Клиент",
"contact": "Контакт (Основен)",
"Contacts": "Контакти",
"meetings": "срещи",
"calls": "призовава",
"meetings": "Срещи",
"calls": "Обаждания",
"tasks": "Задачи",
"emails": "имейли",
"emails": "Имейли",
"articles": "Статии от базата знания",
"lead": "Потенциална Продажба",
"attachments": "Прикачени",
"inboundEmail": "Група имейл акаунт"
"lead": "Потенциална продажба",
"attachments": "Прикачени файлове",
"inboundEmail": "Групов имейл акаунт"
},
"options": {
"status": {
"New": "нов",
"Assigned": "целеви",
"Pending": "Предстоящо",
"Closed": "Затворена",
"Rejected": "Отхвърлени"
"New": "Нов",
"Assigned": "Назначен",
"Pending": "Отворен",
"Closed": "Затворен",
"Rejected": "Отхвърлен",
"Duplicate": "Дублиран"
},
"priority": {
"Low": "ниско",
"Normal": "нормален",
"High": "Високо",
"Urgent": "спешно"
"Low": "Нисък",
"Normal": "Нормален",
"High": "Висок",
"Urgent": "Спешен"
},
"type": {
"Question": "въпрос",
"Question": "Въпрос",
"Incident": "Инцидент",
"Problem": "проблем"
"Problem": "Проблем"
}
},
"labels": {
"Create Case": "Създаване на дело",
"Close": "Близо",
"Create Case": "Създаване на тикет",
"Close": "Затваряне",
"Reject": "Отхвърляне",
"Closed": "Затворена",
"Rejected": "Отхвърлени"
"Closed": "Затворен",
"Rejected": "Отхвърлен"
},
"presetFilters": {
"open": "отворено",
"closed": "Затворена"
"open": "Отворени",
"closed": "Затворени"
}
}

View File

@@ -1,38 +1,39 @@
{
"fields": {
"name": "име",
"emailAddress": "електронна поща",
"name": "Име",
"emailAddress": "Електронна поща",
"accountRole": "Заглавие",
"account": "Сметка",
"accounts": "сметки",
"phoneNumber": "телефон",
"account": "Клиент",
"accounts": "Клиенти",
"phoneNumber": "Телефон",
"accountType": "Тип на профила",
"doNotCall": "Не звъни",
"address": "адрес",
"opportunityRole": "възможност Роля",
"description": "описание",
"campaign": "кампания",
"address": "Адрес",
"opportunityRole": "Роля в сделка",
"description": "Описание",
"campaign": "Кампания",
"targetLists": "Целеви списъци",
"targetList": "Целева Списък",
"portalUser": "портал за потребителя",
"originalLead": "Оригинален Lead",
"acceptanceStatus": "Приемане Статус",
"accountIsInactive": "неактивен акаунт",
"acceptanceStatusMeetings": "Приемане Статус (срещи)",
"acceptanceStatusCalls": "Приемане Статус (призовава)",
"title": "Основно заглавие на профила"
"portalUser": "Потребител на портал",
"originalLead": "Оригинална потенциална продажба",
"acceptanceStatus": "Статус за приемане",
"accountIsInactive": "Неактивен клиент",
"acceptanceStatusMeetings": "Статус на приемане (Срещи)",
"acceptanceStatusCalls": "Статус на приемане (Разговори)",
"title": "Роля при клиент",
"hasPortalUser": "Притежава акаунт в портала"
},
"links": {
"opportunities": "възможности",
"cases": "случаи",
"opportunities": "Сделки",
"cases": "Тикети",
"targetLists": "Целеви списъци",
"campaignLogRecords": "кампания Вход",
"campaign": "кампания",
"account": "Сметката (Основно)",
"accounts": "сметки",
"casesPrimary": "Случаи (Основно)",
"portalUser": "портал за потребителя",
"originalLead": "Оригинален Lead",
"campaignLogRecords": "Логове от кампания",
"campaign": "Кампания",
"account": "Клиент (Основен)",
"accounts": "Клиенти",
"casesPrimary": "Тикети (Основни)",
"portalUser": "Потребител в портал",
"originalLead": "Оригинална потенциална продажба",
"documents": "Документи",
"tasksPrimary": "Задачи (разширена)",
"opportunitiesPrimary": "Възможности (Основно)"
@@ -42,12 +43,13 @@
},
"options": {
"opportunityRole": {
"Decision Maker": "Решение Maker",
"Evaluator": "оценител"
"Decision Maker": "Вземащ решения",
"Evaluator": "Оценител",
"Influencer": "Инфлуенсър"
}
},
"presetFilters": {
"portalUsers": "потребители на портала",
"portalUsers": "Потребители на портала",
"notPortalUsers": "Не потребители на портала",
"accountActive": "Активен"
}

View File

@@ -1,6 +1,7 @@
{
"fields": {
"futureDays": "Следваща X Дни",
"useLastStage": "Група от миналата достигна етап"
"futureDays": "Следващите X Дни",
"useLastStage": "Групиране по последната фаза",
"team": "Отдел"
}
}

View File

@@ -1,41 +1,42 @@
{
"labels": {
"Create Document": "Създаване на документ",
"Details": "детайли"
"Details": "Детайли"
},
"fields": {
"name": "име",
"name": "Име",
"status": "Статус",
"file": "досие",
"file": "Файл",
"type": "Тип",
"publishDate": "Дата на публикуване",
"expirationDate": "Срок на годност",
"description": "описание",
"accounts": "сметки",
"folder": "папка"
"expirationDate": "Срок на валидност",
"description": "Описание",
"accounts": "Клиенти",
"folder": "Папка"
},
"links": {
"accounts": "сметки",
"opportunities": "възможности",
"folder": "папка",
"accounts": "Клиенти",
"opportunities": "Сделки",
"folder": "Папка",
"leads": "Потенциални продажби",
"contacts": "Контакти"
},
"options": {
"status": {
"Active": "Активен",
"Draft": "проект",
"Expired": "Просрочен",
"Draft": "Чернова",
"Expired": "Изтекъл",
"Canceled": "Отменен"
},
"type": {
"": "Нито един",
"Contract": "Договор",
"NDA": "ЕБК",
"NDA": "Споразумение за неразкриване на информация",
"License Agreement": "Лицензионно споразумение"
}
},
"presetFilters": {
"active": "Активен",
"draft": "проект"
"active": "Активни",
"draft": "Чернови"
}
}

View File

@@ -1,10 +1,13 @@
{
"labels": {
"Create Lead": "Създаване на олово",
"Create Lead": "Създаване на потенциална продажба",
"Create Contact": "Създаване на контакт",
"Create Task": "Създаване на Task",
"Create Case": "Създаване на дело",
"Add to Contact": "Добави към контакти",
"Add to Lead": "Добави в Lead"
"Create Task": "Създаване на задача",
"Create Case": "Създаване на тикет",
"Add to Contact": "Добави към контакт",
"Add to Lead": "Добави към потенциална продажба"
},
"fields": {
"tasks": "Задачи"
}
}

View File

@@ -1,28 +1,29 @@
{
"fields": {
"name": "име",
"name": "Име",
"status": "Статус",
"target": "Цел",
"sentAt": "Дата на изпращане",
"attemptCount": "Опити",
"emailAddress": "Имейл адрес",
"massEmail": "Маса Email"
"massEmail": "Масов имейл",
"isTest": "Е тестов"
},
"links": {
"target": "Цел",
"massEmail": "Маса Email"
"massEmail": "Масов имейл"
},
"options": {
"status": {
"Pending": "Предстоящо",
"Sent": "Изпратено",
"Failed": "Се провали",
"Pending": "Предстоящ",
"Sent": "Изпратен",
"Failed": "Провален",
"Sending": "Изпращане"
}
},
"presetFilters": {
"pending": "Предстоящо",
"sent": "Изпратено",
"failed": "Се провали"
"pending": "Предстоящ",
"sent": "Изпратен",
"failed": "Провален"
}
}

View File

@@ -1,103 +1,108 @@
{
"links": {
"parent": "родител",
"parent": "Родител",
"contacts": "Контакти",
"opportunities": "възможности",
"meetings": "срещи",
"calls": "призовава",
"opportunities": "Сделки",
"leads": "Потенциална продажба",
"meetings": "Срещи",
"calls": "Обаждане",
"tasks": "Задачи",
"emails": "имейли",
"accounts": "сметки",
"cases": "случаи",
"emails": "Имейли",
"accounts": "Клиенти",
"cases": "Тикети",
"documents": "Документи",
"account": "Сметка",
"contact": "контакт"
"account": "Клиент",
"opportunity": "Сделка",
"contact": "Контакт"
},
"scopeNames": {
"Account": "Сметка",
"Contact": "контакт",
"Lead": "Водя",
"Account": "Клиент",
"Contact": "Контакт",
"Lead": "Потенциална продажба",
"Target": "Цел",
"Opportunity": "Възможност",
"Meeting": "Среща",
"Calendar": "календар",
"Calendar": "Календар",
"Call": "Обадете се",
"Task": "задача",
"Case": "случай",
"Document": "документ",
"DocumentFolder": "Документ Папка",
"Campaign": "кампания",
"TargetList": "Целева Списък",
"MassEmail": "Маса Email",
"EmailQueueItem": "Email Queue Точка",
"CampaignTrackingUrl": "проследяване на URL",
"Activities": "дейности",
"KnowledgeBaseArticle": "Статия от Базата знания",
"KnowledgeBaseCategory": "Базата знания Категория",
"CampaignLogRecord": "Вход Запис на кампанията"
"Task": "Задача",
"Case": "Тикет",
"Document": "Документ",
"DocumentFolder": "Папка с документи",
"Campaign": "Кампания",
"TargetList": "Целеви списък",
"MassEmail": "Масов имейл",
"EmailQueueItem": "Имейл - елементи от опашката",
"CampaignTrackingUrl": "Проследяване на URL",
"Activities": "Активности",
"KnowledgeBaseArticle": "Статия от документацията",
"KnowledgeBaseCategory": "Категория от документацията",
"CampaignLogRecord": "Запис в дневника на кампанията"
},
"scopeNamesPlural": {
"Account": "сметки",
"Account": "Клиенти",
"Contact": "Контакти",
"Lead": "Потенциални продажби",
"Target": "Цели",
"Opportunity": "възможности",
"Meeting": "срещи",
"Calendar": "календар",
"Call": "призовава",
"Opportunity": "Сделки",
"Meeting": "Срещи",
"Calendar": "Календар",
"Call": "Обаждания",
"Task": "Задачи",
"Case": "случаи",
"Case": "Тикети",
"Document": "Документи",
"DocumentFolder": "Документ папки",
"DocumentFolder": "Папки за документи",
"Campaign": "Кампании",
"TargetList": "Целеви списъци",
"MassEmail": "Масови имейли",
"EmailQueueItem": "Изпратете елемента от опашка",
"CampaignTrackingUrl": "Проследяване на URL адреси",
"Activities": "дейности",
"KnowledgeBaseArticle": "Знание",
"KnowledgeBaseCategory": "Базата знания Категории",
"CampaignLogRecord": "Кампания Вход Records"
"Activities": "Активности",
"KnowledgeBaseArticle": "Документация",
"KnowledgeBaseCategory": "Категории за документация",
"CampaignLogRecord": "Записи в дневника на кампанията"
},
"dashlets": {
"Leads": "Моите Leads",
"Opportunities": "Моите възможности",
"Leads": "Моите потенциални продажби",
"Opportunities": "Моите сделки",
"Tasks": "Моите задачи",
"Cases": "Мои случаи",
"Calendar": "календар",
"Calls": "Моите призовава",
"Cases": "Моите тикети",
"Calendar": "Календар",
"Calls": "Моите oбаждания",
"Meetings": "Моите срещи",
"OpportunitiesByStage": "Възможности от Етап",
"OpportunitiesByLeadSource": "Възможности от преднината Източник",
"SalesByMonth": "Продажбите на месец",
"SalesPipeline": "процеса на продажбите",
"OpportunitiesByStage": "Сделки по статуси",
"OpportunitiesByLeadSource": "Сделки по източник",
"SalesByMonth": "Продажбите по месец",
"SalesPipeline": "Процеса на продажбите",
"Activities": "Моите дейности"
},
"labels": {
"Create InboundEmail": "Създаване Входящ Email",
"Activities": "дейности",
"History": "история",
"Attendees": "Присъстващите",
"Schedule Meeting": "График Среща",
"Schedule Call": "График Call",
"Compose Email": "Състави имейл",
"Log Meeting": "Вход Среща",
"Log Call": "Вход Call",
"Archive Email": "Архив Email",
"Create Task": "Създаване на Task",
"Tasks": "Задачи"
"Create InboundEmail": "Създаване на входящ имейл",
"Activities": "Активности",
"History": "История",
"Attendees": "Присъстващи",
"Schedule Meeting": "Насрочване на среща",
"Schedule Call": "Насрочване на разговор",
"Compose Email": "Създаване на имейл",
"Log Meeting": "Регистриране на среща",
"Log Call": "Регистриране на разговор",
"Archive Email": "Архивиране на имейл",
"Create Task": "Създаване на задача",
"Tasks": "Задачи",
"Scheduler": "График"
},
"fields": {
"billingAddressCity": "град",
"addressCity": "град",
"billingAddressCountry": "Страна",
"addressCountry": "Страна",
"billingAddressPostalCode": "пощенски код",
"addressPostalCode": "пощенски код",
"billingAddressState": "състояние",
"addressState": "състояние",
"billingAddressStreet": "улица",
"addressStreet": "улица",
"billingAddressMap": "карта",
"addressMap": "карта",
"billingAddressCity": "Град",
"addressCity": "Град",
"billingAddressCountry": "Държава",
"addressCountry": "Държава",
"billingAddressPostalCode": "Пощенски код",
"addressPostalCode": "Пощенски код",
"billingAddressState": "Състояние",
"addressState": "Състояние",
"billingAddressStreet": "Улица",
"addressStreet": "Улица",
"billingAddressMap": "Карта",
"addressMap": "Карта",
"shippingAddressCity": "Град (доставка)",
"shippingAddressStreet": "Улица (доставка)",
"shippingAddressCountry": "Държава (доставка)",
@@ -107,7 +112,8 @@
},
"options": {
"reminderTypes": {
"Email": "електронна поща"
"Popup": "Попъп",
"Email": "Електронна поща"
}
}
}

View File

@@ -1,47 +1,47 @@
{
"labels": {
"Create KnowledgeBaseArticle": "Създаване на член",
"Any": "който и да е",
"Send in Email": "Изпрати на Email",
"Create KnowledgeBaseArticle": "Създаване на статия",
"Any": "Всички",
"Send in Email": "Изпрати по имейл",
"Move Up": "Премести нагоре",
"Move Down": "Премести надолу",
"Move to Top": "Преминаване към Top",
"Move to Top": "Преместване най-отгоре",
"Move to Bottom": "Преместване най-долу"
},
"fields": {
"name": "име",
"name": "Име",
"status": "Статус",
"type": "Тип",
"attachments": "Прикачени",
"publishDate": "Дата на публикуване",
"expirationDate": "Срок на годност",
"description": "описание",
"body": "тяло",
"description": "Описание",
"body": "Съдържание",
"categories": "Категории",
"language": "език",
"language": "Език",
"portals": "Портали"
},
"links": {
"cases": "случаи",
"opportunities": "възможности",
"cases": "Тикети",
"opportunities": "Сделки",
"categories": "Категории",
"portals": "Портали"
},
"options": {
"status": {
"In Review": "В Преглед",
"Draft": "проект",
"In Review": "Чернова",
"Draft": "Чернова",
"Archived": "Архив",
"Published": "Публикуван"
"Published": "Публикувана"
},
"type": {
"Article": "статия"
"Article": "Статия"
}
},
"presetFilters": {
"published": "Публикуван"
},
"tooltips": {
"portals": "Член ще бъде достъпен само в определени портали."
"portals": "Статията ще бъде достъпна само в избраните портали."
}
}

View File

@@ -2,9 +2,9 @@
"labels": {
"Create KnowledgeBaseCategory": "Създаване на Категория",
"Manage Categories": "Управление на категории",
"Articles": "статии"
"Articles": "Статии"
},
"links": {
"articles": "статии"
"articles": "Статии"
}
}

View File

@@ -1,68 +1,70 @@
{
"labels": {
"Converted To": "превръща в",
"Create Lead": "Създаване на олово",
"Converted To": "Конвертирана в",
"Create Lead": "Създаване на Потенциална продажба",
"Convert": "Конвертиране",
"convert": "конвертиране"
},
"fields": {
"name": "име",
"emailAddress": "електронна поща",
"name": "Име",
"emailAddress": "Електронна поща",
"title": "Заглавие",
"website": "уебсайт",
"phoneNumber": "телефон",
"accountName": "Име на акаунта",
"website": "Уебсайт",
"phoneNumber": "Телефон",
"accountName": "Име на клиента",
"doNotCall": "Не звъни",
"address": "адрес",
"address": "Адрес",
"status": "Статус",
"source": "източник",
"opportunityAmount": "възможност сума",
"opportunityAmountConverted": "Възможност сума (изчислена)",
"description": "описание",
"createdAccount": "Сметка",
"createdContact": "контакт",
"campaign": "кампания",
"source": "Източник",
"opportunityAmount": "Сума на сделката",
"opportunityAmountConverted": "Сума на сделката (изчислена)",
"description": "Описание",
"createdAccount": "Клиент",
"createdContact": "Контакт",
"createdOpportunity": "Сделка",
"campaign": "Кампания",
"targetLists": "Целеви списъци",
"targetList": "Целева Списък",
"industry": "промишленост",
"acceptanceStatus": "Приемане Статус",
"opportunityAmountCurrency": "Възможност сума във валута",
"acceptanceStatusMeetings": "Приемане Статус (срещи)",
"acceptanceStatusCalls": "Приемане Статус (призовава)",
"convertedAt": "конвертирани по"
"targetList": "Целева списък",
"industry": "Промишленост",
"acceptanceStatus": "Статус за приемане",
"opportunityAmountCurrency": "Валута на сумата в сделката",
"acceptanceStatusMeetings": "Статус на приемане (Срещи)",
"acceptanceStatusCalls": "Статус на приемане (Разговори)",
"convertedAt": "Конвертирана на"
},
"links": {
"targetLists": "Целеви списъци",
"campaignLogRecords": "кампания Вход",
"campaign": "кампания",
"createdAccount": "Сметка",
"createdContact": "контакт",
"cases": "случаи",
"campaignLogRecords": "Логове на кампанията",
"campaign": "Кампания",
"createdAccount": "Клиент",
"createdContact": "Контакт",
"createdOpportunity": "Сделка",
"cases": "Тикети",
"documents": "Документи"
},
"options": {
"status": {
"New": "нов",
"Assigned": "целеви",
"New": "Нова",
"Assigned": "Назначена",
"In Process": "В процес",
"Converted": "покръстен",
"Converted": "Конвертирана",
"Recycled": "Рециклирана",
"Dead": "мъртъв"
"Dead": "Изоставена"
},
"source": {
"": "Нито един",
"Call": "Обадете се",
"Email": "електронна поща",
"Email": "Електронна поща",
"Existing Customer": "Съществуващ клиент",
"Partner": "партньор",
"Partner": "Партньор",
"Public Relations": "Връзки с обществеността",
"Web Site": "уеб сайт",
"Campaign": "кампания",
"Other": "друг"
"Web Site": "Уеб сайт",
"Campaign": "Кампания",
"Other": "Друг"
}
},
"presetFilters": {
"active": "Активен",
"actual": "действителен",
"converted": "покръстен"
"actual": "Актуален",
"converted": "Конвертиран"
}
}

View File

@@ -1,14 +1,14 @@
{
"fields": {
"name": "име",
"name": "Име",
"status": "Статус",
"storeSentEmails": "Магазин изпращат съобщения",
"startAt": "Дата Старт",
"fromAddress": "От Адрес",
"storeSentEmails": "Съхраняване на изпратените имейли",
"startAt": "Дата на стартиране",
"fromAddress": "От адрес",
"fromName": "От име",
"replyToAddress": "Адрес за отговор",
"replyToName": "Отговор до Наименование",
"campaign": "кампания",
"campaign": "Кампания",
"emailTemplate": "Шаблон за имейл",
"inboundEmail": "Имейл акаунт",
"targetLists": "Целеви списъци",
@@ -19,40 +19,40 @@
"links": {
"targetLists": "Целеви списъци",
"excludingTargetLists": "С изключение на целевите списъци",
"queueItems": "елемента от опашка",
"campaign": "кампания",
"queueItems": "Елементи от опашката",
"campaign": "Кампания",
"emailTemplate": "Шаблон за имейл",
"inboundEmail": "Имейл акаунт"
},
"options": {
"status": {
"Draft": "проект",
"Draft": "Чернова",
"Pending": "Предстоящо",
"In Process": "В процес",
"Complete": "пълен",
"Complete": "Завършен",
"Canceled": "Отменен",
"Failed": "Се провали"
"Failed": "Провален"
}
},
"labels": {
"Create MassEmail": "Създаване на Маса Email",
"Send Test": "Изпрати Test",
"System SMTP": "система за SMTP",
"Create MassEmail": "Създаване на масов имейл",
"Send Test": "Изпрати тестов имейл",
"System SMTP": "Системен SMTP",
"system": "система",
"group": "група"
},
"messages": {
"selectAtLeastOneTarget": "Изберете поне една мишена.",
"testSent": "Тест имейл (и) трябва да бъде изпратен"
"selectAtLeastOneTarget": "Изберете поне една цел.",
"testSent": "Тестовият имейл би трябвало да е изпратен"
},
"tooltips": {
"optOutEntirely": "Имейл адресите на получателите, които се отписали, ще бъдат маркирани като се отказали и те няма да получават никакви масови имейли вече.",
"optOutEntirely": "Имейл адресите на получателите, които са се отказали, ще бъдат маркирани като отписали се и те няма да получават повече имейли.",
"targetLists": "Цели, които трябва да получават съобщения.",
"excludingTargetLists": "Цели, които не трябва да получават съобщения.",
"storeSentEmails": "Имейлите ще бъдат съхранявани в CRM."
},
"presetFilters": {
"actual": "действителен",
"complete": "пълен"
"actual": "Актуални",
"complete": "Завършени"
}
}

View File

@@ -1,55 +1,57 @@
{
"fields": {
"name": "име",
"parent": "родител",
"name": "Име",
"parent": "Родител",
"status": "Статус",
"dateStart": "Дата Старт",
"dateStart": "Начална дата",
"dateEnd": "Крайна дата",
"duration": "продължителност",
"description": "описание",
"duration": "Продължителност",
"description": "Описание",
"users": "Потребители",
"contacts": "Контакти",
"leads": "Потенциални продажби",
"reminders": "Напомняния",
"account": "Сметка",
"acceptanceStatus": "Приемане Статус",
"dateStartDate": "Дата Start (цял ден)",
"account": "Клиент",
"acceptanceStatus": "Статус за приемане",
"dateStartDate": "Начална дата (цял ден)",
"dateEndDate": "Крайна дата (цял ден)",
"isAllDay": "Дали през целия ден",
"Acceptance": "приемане"
"isAllDay": "Цял ден",
"Acceptance": "Приемане",
"sourceEmail": "Източник на имейла"
},
"options": {
"status": {
"Planned": "Планирано",
"Held": "Държани",
"Not Held": "Не държани"
"Planned": "Планирана",
"Held": "Състояла се",
"Not Held": "Несъстояла се"
},
"acceptanceStatus": {
"None": "Нито един",
"Accepted": "общоприет",
"Accepted": "Приета",
"Declined": "Отхвърлена",
"Tentative": "Експериментален"
"Tentative": "Несигурна"
}
},
"massActions": {
"setHeld": "Задайте държани",
"setNotHeld": "Задайте не се държат"
"setHeld": "Задай като състояла се",
"setNotHeld": "Задай като несъстояла се"
},
"labels": {
"Create Meeting": "Създаване на среща",
"Set Held": "Задайте държани",
"Set Not Held": "Задайте не се държат",
"Set Held": "Задай като състояла се",
"Set Not Held": "Задай като състояла се",
"Send Invitations": "Изпращането на покани",
"on time": "на време",
"before": "преди",
"All-Day": "Цял ден"
},
"presetFilters": {
"planned": "Планирано",
"held": "Държани",
"planned": "Планирани",
"held": "Състояли се",
"todays": "Днешните"
},
"messages": {
"nothingHasBeenSent": "Нищо не бяха изпратени",
"selectAcceptanceStatus": "Задайте състоянието си приемане."
"nothingHasBeenSent": "Нищо не беше изпратено",
"selectAcceptanceStatus": "Задайте състоянието на приемане."
}
}

View File

@@ -1,52 +1,53 @@
{
"fields": {
"name": "име",
"account": "Сметка",
"stage": "сцена",
"amount": "Количество",
"probability": "Вероятност,%",
"leadSource": "Водещ Източник",
"name": "Име",
"account": "Клиент",
"stage": "Фаза",
"amount": "Сума",
"probability": "Вероятност (%)",
"leadSource": "Източник на потенциалната продажба",
"doNotCall": "Не звъни",
"closeDate": "Близо Дата",
"closeDate": "Дата на затваряне",
"contacts": "Контакти",
"description": "описание",
"amountConverted": "Количество (изчислена)",
"amountWeightedConverted": "сума Weighted",
"campaign": "кампания",
"originalLead": "Оригинален Lead",
"amountCurrency": "сума на валута",
"contactRole": "Свържи Роля",
"lastStage": "Последният етап",
"contact": "Свържи (Основно)"
"description": "Описание",
"amountConverted": "Сума (изчислена)",
"amountWeightedConverted": "Сума (изчислена)",
"campaign": "Кампания",
"originalLead": "Оригинална потенциална продажба",
"amountCurrency": "Валута на сумата",
"contactRole": "Роля на контакта",
"lastStage": "Последна фаза",
"contact": "Контакт (Основен)"
},
"links": {
"contacts": "Контакти",
"documents": "Документи",
"campaign": "кампания",
"originalLead": "Оригинален Lead",
"contact": "Свържи (Основно)"
"campaign": "Кампания",
"originalLead": "Оригинална потенциална продажба",
"contact": "Контакт (Основен)"
},
"options": {
"stage": {
"Qualification": "Квалификация",
"Needs Analysis": "Анализ на нуждите",
"Value Proposition": "Стойностно предложение",
"Id. Decision Makers": "Документ за самоличност. Хора, взимащи решения",
"Perception Analysis": "Схващането Анализ",
"Proposal/Price Quote": "Предложение / Цена цитат",
"Prospecting": "Проучване",
"Qualification": "Квалифициране",
"Needs Analysis": "Нужда от анализ",
"Value Proposition": "Предложение",
"Id. Decision Makers": "Вземане на решение",
"Perception Analysis": "Анализ",
"Proposal/Price Quote": "Изготвяне на оферта",
"Negotiation/Review": "Преговори / Преглед",
"Closed Won": "Приключена спечелена",
"Closed Lost": "затворен Изгубени",
"Proposal": "предложение",
"Negotiation": "договаряне"
"Closed Won": "Приключена - спечелена",
"Closed Lost": "Приключена - загубена",
"Proposal": "Предложение",
"Negotiation": "Договаряне"
}
},
"labels": {
"Create Opportunity": "Създаване на възможности"
"Create Opportunity": "Създаване на Сделка"
},
"presetFilters": {
"open": "отворено",
"open": "Отворени",
"won": "Спечелени",
"lost": "загубен"
"lost": "Загубени"
}
}

View File

@@ -1,5 +1,5 @@
{
"links": {
"articles": "Статии от базата знания"
"articles": "Статии от документацията"
}
}

View File

@@ -1,8 +1,8 @@
{
"options": {
"job": {
"ProcessMassEmail": "Изпрати Масови имейли",
"ControlKnowledgeBaseArticleStatus": "Контрол Статия от Базата знания Статус"
"ProcessMassEmail": "Изпращане на масови имейли",
"ControlKnowledgeBaseArticleStatus": "Управление на статуса на статиите от документацията"
}
}
}

View File

@@ -1,39 +1,41 @@
{
"fields": {
"name": "име",
"description": "описание",
"entryCount": "Влизане граф",
"name": "Име",
"description": "Описание",
"entryCount": "Брой записи",
"campaigns": "Кампании",
"endDate": "Крайна дата",
"targetLists": "Целеви списъци",
"includingActionList": "Включително",
"excludingActionList": "с изключение на",
"optedOutCount": "Отказахте се граф",
"targetStatus": "Целева Статус",
"isOptedOut": "Е изключена"
"excludingActionList": "С изключение на",
"optedOutCount": "Отписали се",
"targetStatus": "Целеви статус",
"isOptedOut": "Отписал се"
},
"links": {
"accounts": "сметки",
"accounts": "Клиенти",
"contacts": "Контакти",
"leads": "Потенциални продажба",
"campaigns": "Кампании",
"massEmails": "Масови имейли"
},
"options": {
"type": {
"Email": "електронна поща",
"Web": "мрежа",
"Television": "телевизия",
"Radio": "радио"
"Email": "Електронна поща",
"Web": "Интернет",
"Television": "Телевизия",
"Radio": "Радио",
"Newsletter": "Имейл бюлетин"
},
"targetStatus": {
"Opted Out": "Отказахте се",
"Opted Out": "Отписал се",
"Listed": "изброени"
}
},
"labels": {
"Create TargetList": "Създаване на Target Списък",
"Opted Out": "Отказахте се",
"Cancel Opt-Out": "Отказ за отказване",
"Opt-Out": "Отказване"
"Create TargetList": "Създаване на целеви списък",
"Opted Out": "Отказали се",
"Cancel Opt-Out": "Отмяна на отказване",
"Opt-Out": "Отписване"
}
}

View File

@@ -1,50 +1,55 @@
{
"fields": {
"name": "име",
"parent": "родител",
"name": "Име",
"parent": "Родител",
"status": "Статус",
"dateStart": "Дата Старт",
"dateStart": "Начална дата",
"dateEnd": "Дата до",
"dateStartDate": "Дата Start (цял ден)",
"dateStartDate": "Начална дата (цял ден)",
"dateEndDate": "Крайна дата (цял ден)",
"priority": "приоритет",
"description": "описание",
"isOverdue": "е просрочено",
"account": "Сметка",
"dateCompleted": "Дата Завършен",
"attachments": "Прикачени",
"priority": "Приоритет",
"description": "Описание",
"isOverdue": "Е просрочена",
"account": "Клиент",
"dateCompleted": "Дата на завършване",
"attachments": "Прикачени файлове",
"reminders": "Напомняния",
"contact": "контакт"
"contact": "Контакт"
},
"links": {
"attachments": "Прикачени",
"account": "Сметка",
"contact": "контакт"
"attachments": "Прикачени файлове",
"account": "Клиент",
"contact": "Контакт",
"email": "Имейл"
},
"options": {
"status": {
"Not Started": "Не е започнало",
"Not Started": "Не е стартирана",
"Started": "Започната",
"Completed": "завършен",
"Canceled": "Отменен",
"Deferred": "Разсрочено"
"Completed": "Завършен",
"Canceled": "Отменена",
"Deferred": "Отложена"
},
"priority": {
"Low": "ниско",
"Normal": "нормален",
"High": "Високо",
"Urgent": "спешно"
"Low": "Нисък",
"Normal": "Нормален",
"High": "Висок",
"Urgent": "Спешен"
}
},
"labels": {
"Create Task": "Създаване на Task",
"Complete": "пълен"
"Create Task": "Създаване на задача",
"Complete": "Завършване",
"overdue": "просрочена"
},
"presetFilters": {
"actual": "действителен",
"completed": "завършен",
"actual": "Актуални",
"completed": "Завършени",
"todays": "Днешните",
"overdue": "просрочен",
"overdue": "Просрочени",
"deferred": "Разсрочено"
},
"nameOptions": {
"replyToEmail": "Отговор до имейл"
}
}

View File

@@ -3,8 +3,8 @@
"targetLists": "Целеви списъци"
},
"fields": {
"acceptanceStatus": "Приемане Статус",
"acceptanceStatusMeetings": "Приемане Статус (срещи)",
"acceptanceStatusCalls": "Приемане Статус (призовава)"
"acceptanceStatus": "Статус за приемане",
"acceptanceStatusMeetings": "Статус на приемане (Срещи)",
"acceptanceStatusCalls": "Статус на приемане (Разговори)"
}
}

View File

@@ -41,7 +41,6 @@
"Dead": "Mrtvý"
},
"source": {
"": "-",
"Call": "Volání",
"Email": "Email",
"Existing Customer": "Existující zákazník",

View File

@@ -45,7 +45,6 @@
"Dead": "Død"
},
"source": {
"": "Ingen",
"Call": "Samtale",
"Existing Customer": "Eksisterende Kunde",
"Public Relations": "PR",

View File

@@ -50,7 +50,6 @@
"Dead": "'Gestorben'"
},
"source": {
"": "Kein(e)",
"Call": "Anruf",
"Email": "E-Mail",
"Existing Customer": "Bestandskunde",

View File

@@ -52,7 +52,6 @@
"Dead": "Dead"
},
"source": {
"": "None",
"Call": "Call",
"Email": "Email",
"Existing Customer": "Existing Customer",

View File

@@ -52,7 +52,6 @@
"Dead": "Muerto"
},
"source": {
"": "Ninguno",
"Call": "Llamada",
"Email": "Correo electrónico",
"Existing Customer": "Cliente Existente",

Some files were not shown because too many files have changed in this diff Show More