Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a0f8da2f4 | |||
| bb5d5a0ccf | |||
| 1bd5eac103 | |||
| 61957e628b | |||
| c5296bf906 | |||
| a16919f10b | |||
| 7050757e4e | |||
| d27e9c91e7 | |||
| 5e1c7bce33 | |||
| a23ac54da0 | |||
| 260c050f36 | |||
| fc5c07927f | |||
| d321f0d701 | |||
| 95cbc138f7 | |||
| 395063ea35 | |||
| 835f95eb52 | |||
| c0f6c91a0e | |||
| b410d0e66f | |||
| d04f72cfd8 | |||
| a9203b8e22 | |||
| e89c7c9328 | |||
| 7808865080 | |||
| 404e2de3b6 | |||
| f02dabc540 | |||
| c29da46a97 | |||
| b7702d2418 | |||
| 2bc56db4c6 | |||
| dd0ef5455e | |||
| 901bee6d3f | |||
| 72a0415207 | |||
| de69652137 | |||
| 1cd2d6b35e | |||
| 9888ec8a6f | |||
| ea5321577a | |||
| 23c772e029 | |||
| e67387d9ea | |||
| 2156094407 | |||
| 03d5bf1ef2 | |||
| 42f57409c8 | |||
| 69d7ce408d | |||
| 15b3c0440c | |||
| e1f0715c4d | |||
| 15aec72e97 | |||
| 66eade5db7 | |||
| 3d89e25349 | |||
| 7c890aa83a | |||
| 62a29c86ab | |||
| bd57b6bb8e | |||
| 9ab1d16ea0 | |||
| 435aa28ca2 | |||
| 4bd375f154 |
@@ -29,7 +29,7 @@ class GlobalSearch extends \Espo\Core\Controllers\Base
|
||||
{
|
||||
public function actionSearch($params, $data, $request)
|
||||
{
|
||||
$query = $params['query'];
|
||||
$query = $request->get('q');
|
||||
|
||||
$offset = intval($request->get('offset'));
|
||||
$maxSize = intval($request->get('maxSize'));
|
||||
|
||||
@@ -170,6 +170,7 @@ class Record extends Base
|
||||
$asc = $request->get('asc') === 'true';
|
||||
$sortBy = $request->get('sortBy');
|
||||
$q = $request->get('q');
|
||||
$textFilter = $request->get('textFilter');
|
||||
|
||||
if (empty($maxSize)) {
|
||||
$maxSize = self::MAX_SIZE_LIMIT;
|
||||
|
||||
@@ -36,7 +36,7 @@ class FiltersMatcher
|
||||
{
|
||||
foreach ($filterList as $filter) {
|
||||
if ($filter->get('from')) {
|
||||
if (strtolower($filter->get('from')) === strtolower($email->get('from'))) {
|
||||
if ($this->matchString(strtolower($filter->get('from')), strtolower($email->get('from')))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class FiltersMatcher
|
||||
if ($email->get('to')) {
|
||||
$toArr = explode(';', $email->get('to'));
|
||||
foreach ($toArr as $to) {
|
||||
if (strtolower($to) === strtolower($filter->get('to'))) {
|
||||
if ($this->matchString(strtolower($filter->get('to')), strtolower($to))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,6 +194,28 @@ class Importer
|
||||
$n = sscanf($reference, '%s %s %d %d espo', $parentType, $parentId, $emailSent, $number);
|
||||
if ($n == 4 && $emailSent < time()) {
|
||||
if (!empty($parentType) && !empty($parentId)) {
|
||||
if ($parentType == 'Lead') {
|
||||
$parent = $this->getEntityManager()->getEntity('Lead', $parentId);
|
||||
if ($parent && $parent->get('status') == 'Converted') {
|
||||
if ($parent->get('createdAccountId')) {
|
||||
$account = $this->getEntityManager()->getEntity('Account', $parent->get('createdAccountId'));
|
||||
if ($account) {
|
||||
$parentType = 'Account';
|
||||
$parentId = $account->id;
|
||||
}
|
||||
} else {
|
||||
if ($this->getConfig()->get('b2cMode')) {
|
||||
if ($parent->get('createdContactId')) {
|
||||
$contact = $this->getEntityManager()->getEntity('Contact', $parent->get('createdContactId'));
|
||||
if ($contact) {
|
||||
$parentType = 'Contact';
|
||||
$parentId = $contact->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$email->set('parentType', $parentType);
|
||||
$email->set('parentId', $parentId);
|
||||
$parentFound = true;
|
||||
|
||||
@@ -795,7 +795,7 @@ class Base
|
||||
|
||||
foreach ($fieldList as $field) {
|
||||
if (
|
||||
strlen($item['value']) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH
|
||||
strlen($textFilter) >= self::MIN_LENGTH_FOR_CONTENT_SEARCH
|
||||
&&
|
||||
!empty($fieldDefs[$field]['type']) && $fieldDefs[$field]['type'] == 'text'
|
||||
) {
|
||||
|
||||
@@ -55,7 +55,10 @@ class Auth extends \Slim\Middleware
|
||||
}
|
||||
|
||||
$espoCgiAuth = $req->headers('HTTP_ESPO_CGI_AUTH');
|
||||
if ( !isset($authUsername) && !isset($authPassword) && !empty($espoCgiAuth) ) {
|
||||
if (empty($espoCgiAuth)) {
|
||||
$espoCgiAuth = $req->headers('REDIRECT_HTTP_ESPO_CGI_AUTH');
|
||||
}
|
||||
if (!isset($authUsername) && !isset($authPassword) && !empty($espoCgiAuth)) {
|
||||
list($authUsername, $authPassword) = explode(':' , base64_decode(substr($espoCgiAuth, 6)));
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,17 @@ class Config
|
||||
|
||||
$removeData = empty($this->removeData) ? null : $this->removeData;
|
||||
|
||||
$result = $this->getFileManager()->mergePhpContents($this->configPath, $values, $removeData);
|
||||
$data = include($this->configPath);
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
|
||||
foreach ($removeData as $key) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
|
||||
$result = $this->getFileManager()->putPhpContents($this->configPath, $data);
|
||||
|
||||
if ($result) {
|
||||
$this->changedData = array();
|
||||
@@ -220,7 +230,7 @@ class Config
|
||||
$restrictItems = $this->getRestrictItems($isAdmin);
|
||||
|
||||
$values = array();
|
||||
foreach($data as $key => $item) {
|
||||
foreach ($data as $key => $item) {
|
||||
if (!in_array($key, $restrictItems)) {
|
||||
$values[$key]= $item;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
@@ -33,7 +33,6 @@ class EmailAddress extends \Espo\Core\ORM\Entity
|
||||
throw new Error("Not valid email address '{$value}'");
|
||||
}
|
||||
$this->valuesContainer['name'] = $value;
|
||||
$this->set('lower', strtolower($value));
|
||||
}
|
||||
|
||||
$this->set('lower', strtolower($value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,11 +75,8 @@ class Unsubscribe extends \Espo\Core\EntryPoints\Base
|
||||
$link = $m[$target->getEntityType()];
|
||||
}
|
||||
if ($link) {
|
||||
if ($campaign) {
|
||||
$targetListList = $campaign->get('targetLists');
|
||||
} else {
|
||||
$targetListList = $massEmail->get('targetLists');
|
||||
}
|
||||
$targetListList = $massEmail->get('targetLists');
|
||||
|
||||
foreach ($targetListList as $targetList) {
|
||||
$this->getEntityManager()->getRepository('TargetList')->updateRelation($targetList, $link, $target->id, array(
|
||||
'optedOut' => true
|
||||
|
||||
@@ -45,7 +45,7 @@ class Contact extends \Espo\Core\ORM\Repositories\RDB
|
||||
$result = parent::afterSave($entity, $options);
|
||||
$this->handleAfterSaveAccounts($entity, $options);
|
||||
|
||||
if ($entity->has('targetListId') && $entity->isNew()) {
|
||||
if ($entity->has('targetListId')) {
|
||||
$this->relate($entity, 'targetLists', $entity->get('targetListId'));
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,17 @@ class Meeting extends \Espo\Core\ORM\Repositories\RDB
|
||||
if (!empty($parentId) || !empty($parentType)) {
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
if (!empty($parent)) {
|
||||
$accountId = null;
|
||||
if ($parent->getEntityType() == 'Account') {
|
||||
$accountId = $parent->id;
|
||||
} else if ($parent->has('accountId')) {
|
||||
} else if ($parent->get('accountId')) {
|
||||
$accountId = $parent->get('accountId');
|
||||
} else if ($parent->getEntityType() == 'Lead') {
|
||||
if ($parent->get('status') == 'Converted') {
|
||||
if ($parent->get('createdAccountId')) {
|
||||
$accountId = $parent->get('createdAccountId');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($accountId)) {
|
||||
$entity->set('accountId', $accountId);
|
||||
|
||||
@@ -98,10 +98,17 @@ class Task extends \Espo\Core\ORM\Repositories\RDB
|
||||
if (!empty($parentId) || !empty($parentType)) {
|
||||
$parent = $this->getEntityManager()->getEntity($parentType, $parentId);
|
||||
if (!empty($parent)) {
|
||||
$accountId = null;
|
||||
if ($parent->getEntityType() == 'Account') {
|
||||
$accountId = $parent->id;
|
||||
} else if ($parent->has('accountId')) {
|
||||
} else if ($parent->get('accountId')) {
|
||||
$accountId = $parent->get('accountId');
|
||||
} else if ($parent->getEntityType() == 'Lead') {
|
||||
if ($parent->get('status') == 'Converted') {
|
||||
if ($parent->get('createdAccountId')) {
|
||||
$accountId = $parent->get('createdAccountId');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($accountId)) {
|
||||
$entity->set('accountId', $accountId);
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Aktiv",
|
||||
"actual": "Tatsächlich",
|
||||
"converted": "Umgewandelt"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
"Automotive": "Automotive",
|
||||
"Banking": "Banking",
|
||||
"Biotechnology": "Biotechnology",
|
||||
"Building Materials & Equipment": "Building Materials & Equipment",
|
||||
"Chemical": "Chemical",
|
||||
"Computer": "Computer",
|
||||
"Education": "Education",
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Active",
|
||||
"actual": "Actual",
|
||||
"converted": "Converted"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Actif"
|
||||
"active": "Actif",
|
||||
"actual": "En cours"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"actual": "Werkelijke",
|
||||
"active": "Actief"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"actual": "Atual",
|
||||
"active": "Ativo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
}
|
||||
},
|
||||
"presetFilters": {
|
||||
"active": "Активный"
|
||||
"actual": "Актуальные",
|
||||
"active": "Активные"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
"Complete": "Завершить"
|
||||
},
|
||||
"presetFilters": {
|
||||
"actual": "Actual",
|
||||
"completed": "Завершена",
|
||||
"actual": "Актуальные",
|
||||
"completed": "Завершенные",
|
||||
"todays": "На сегодня",
|
||||
"overdue": "Просроченные"
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
{
|
||||
"name":"statistics",
|
||||
"label":"Statistics",
|
||||
"view":"Crm:Campaign.Record.Panels.Statistics"
|
||||
"view":"Crm:Campaign.Record.Panels.Statistics",
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -29,12 +29,9 @@
|
||||
{
|
||||
"name":"convertedTo",
|
||||
"label":"Converted To",
|
||||
"view": "Record.Panels.Side",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true,
|
||||
"options": {
|
||||
"fieldList": ["createdAccount", "createdContact", "createdOpportunity"]
|
||||
}
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name":"activities",
|
||||
@@ -51,6 +48,33 @@
|
||||
"label":"Tasks",
|
||||
"view":"Crm:Record.Panels.Tasks"
|
||||
}
|
||||
],
|
||||
"edit": [
|
||||
{
|
||||
"name":"convertedTo",
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
}
|
||||
],
|
||||
"detailSmall": [
|
||||
{
|
||||
"name":"convertedTo",
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
}
|
||||
],
|
||||
"editSmall": [
|
||||
{
|
||||
"name":"convertedTo",
|
||||
"label":"Converted To",
|
||||
"view": "crm:views/lead/record/panels/converted-to",
|
||||
"notRefreshable": true,
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"relationshipPanels": {
|
||||
@@ -66,7 +90,7 @@
|
||||
},
|
||||
"filterList": [
|
||||
{
|
||||
"name":"active"
|
||||
"name":"actual"
|
||||
},
|
||||
{
|
||||
"name":"converted",
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"Automotive",
|
||||
"Banking",
|
||||
"Biotechnology",
|
||||
"Building Materials & Equipment",
|
||||
"Chemical",
|
||||
"Computer",
|
||||
"Education",
|
||||
@@ -47,7 +48,7 @@
|
||||
"Real Estate",
|
||||
"Service",
|
||||
"Sports",
|
||||
"Sofware",
|
||||
"Software",
|
||||
"Technology",
|
||||
"Telecommunications",
|
||||
"Television",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
},
|
||||
"type": {
|
||||
"type": "enum",
|
||||
"options": ["Email", "Newsletter", "Web", "Television", "Radio", "Mail"]
|
||||
"options": ["Email", "Newsletter", "Web", "Television", "Radio", "Mail"],
|
||||
"default": "Email"
|
||||
},
|
||||
"startDate": {
|
||||
"type": "date"
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
"layoutDetailDisabled": true,
|
||||
"layoutListDisabled": true,
|
||||
"layoutMassUpdateDisabled": true,
|
||||
"importDisabled": true,
|
||||
"noLoad": true
|
||||
},
|
||||
"targetList": {
|
||||
@@ -237,7 +238,8 @@
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
"asc": true,
|
||||
"textFilterFields": ["name", "emailAddress"]
|
||||
},
|
||||
"indexes": {
|
||||
"firstName": {
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false,
|
||||
"textFilterFields": ["name", "accountName"]
|
||||
"textFilterFields": ["name", "accountName", "emailAddress"]
|
||||
},
|
||||
"indexes": {
|
||||
"firstName": {
|
||||
|
||||
@@ -31,6 +31,13 @@ class Lead extends \Espo\Core\SelectManagers\Base
|
||||
);
|
||||
}
|
||||
|
||||
protected function filterActual(&$result)
|
||||
{
|
||||
$result['whereClause'][] = array(
|
||||
'status!=' => ['Converted', 'Recycled', 'Dead']
|
||||
);
|
||||
}
|
||||
|
||||
protected function filterConverted(&$result)
|
||||
{
|
||||
$result['whereClause'][] = array(
|
||||
|
||||
@@ -71,6 +71,15 @@ class Task extends \Espo\Core\SelectManagers\Base
|
||||
];
|
||||
}
|
||||
|
||||
protected function filterTodays(&$result)
|
||||
{
|
||||
$result['whereClause'][] = $this->convertDateTimeWhere(array(
|
||||
'type' => 'today',
|
||||
'field' => 'dateEnd',
|
||||
'timeZone' => $this->getUserTimeZone()
|
||||
));
|
||||
}
|
||||
|
||||
protected function convertDateTimeWhere($item)
|
||||
{
|
||||
$result = parent::convertDateTimeWhere($item);
|
||||
|
||||
@@ -243,10 +243,10 @@ class MassEmail extends \Espo\Services\Record
|
||||
$this->setFailed($massEmail);
|
||||
return;
|
||||
}
|
||||
$attachmetList = $emailTemplate->get('attachmets');
|
||||
$attachmentList = $emailTemplate->get('attachments');
|
||||
|
||||
foreach ($queueItemList as $queueItem) {
|
||||
$this->sendQueueItem($queueItem, $massEmail, $emailTemplate, $attachmetList, $campaign, $isTest);
|
||||
$this->sendQueueItem($queueItem, $massEmail, $emailTemplate, $attachmentList, $campaign, $isTest);
|
||||
}
|
||||
|
||||
if (!$isTest) {
|
||||
@@ -328,7 +328,7 @@ class MassEmail extends \Espo\Services\Record
|
||||
return $email;
|
||||
}
|
||||
|
||||
protected function sendQueueItem(Entity $queueItem, Entity $massEmail, Entity $emailTemplate, $attachmetList = [], $campaign = null, $isTest = false)
|
||||
protected function sendQueueItem(Entity $queueItem, Entity $massEmail, Entity $emailTemplate, $attachmentList = [], $campaign = null, $isTest = false)
|
||||
{
|
||||
$target = $this->getEntityManager()->getEntity($queueItem->get('targetType'), $queueItem->get('targetId'));
|
||||
if (!$target || !$target->id || !$target->get('emailAddress')) {
|
||||
@@ -379,7 +379,7 @@ class MassEmail extends \Espo\Services\Record
|
||||
$header->setId($queueItem->id);
|
||||
$message->getHeaders()->addHeader($header);
|
||||
|
||||
$this->getMailSender()->useGlobal()->send($email, $params, $message, $attachmetList);
|
||||
$this->getMailSender()->useGlobal()->send($email, $params, $message, $attachmentList);
|
||||
|
||||
$emailObject = $emailTemplate;
|
||||
if ($massEmail->get('storeSentEmails')) {
|
||||
@@ -399,7 +399,6 @@ class MassEmail extends \Espo\Services\Record
|
||||
|
||||
} catch (\Exception $e) {
|
||||
if ($queueItem->get('attemptCount') >= self::MAX_ATTEMPT_COUNT) {
|
||||
$this->setQueueItemFailed($queueItem);
|
||||
$queueItem->set('status', 'Failed');
|
||||
}
|
||||
$this->getEntityManager()->saveEntity($queueItem);
|
||||
|
||||
@@ -81,19 +81,30 @@ class Meeting extends \Espo\Services\Record
|
||||
{
|
||||
$invitationManager = $this->getInvitationManager();
|
||||
|
||||
$emailHash = array();
|
||||
|
||||
$users = $entity->get('users');
|
||||
foreach ($users as $user) {
|
||||
$invitationManager->sendInvitation($entity, $user, 'users');
|
||||
if ($user->get('emailAddress') && !array_key_exists($user->get('emailAddress'), $emailHash)) {
|
||||
$invitationManager->sendInvitation($entity, $user, 'users');
|
||||
$emailHash[$user->get('emailAddress')] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$contacts = $entity->get('contacts');
|
||||
foreach ($contacts as $contact) {
|
||||
$invitationManager->sendInvitation($entity, $contact, 'contacts');
|
||||
if ($contact->get('emailAddress') && !array_key_exists($contact->get('emailAddress'), $emailHash)) {
|
||||
$invitationManager->sendInvitation($entity, $contact, 'contacts');
|
||||
$emailHash[$user->get('emailAddress')] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$leads = $entity->get('leads');
|
||||
foreach ($leads as $lead) {
|
||||
$invitationManager->sendInvitation($entity, $lead, 'leads');
|
||||
if ($lead->get('emailAddress') && !array_key_exists($lead->get('emailAddress'), $emailHash)) {
|
||||
$invitationManager->sendInvitation($entity, $lead, 'leads');
|
||||
$emailHash[$user->get('emailAddress')] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -113,6 +113,12 @@ abstract class Base
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($params['additionalSelectColumns']) && is_array($params['additionalSelectColumns'])) {
|
||||
foreach ($params['additionalSelectColumns'] as $column => $field) {
|
||||
$selectPart .= ", " . $column . " AS `{$field}`";
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$aggDist = false;
|
||||
if ($params['distinct'] && $params['aggregation'] == 'COUNT') {
|
||||
@@ -427,7 +433,7 @@ abstract class Base
|
||||
{
|
||||
if (strpos($orderBy, '.') !== false) {
|
||||
list($alias, $field) = explode('.', $orderBy);
|
||||
$fieldPath = $this->toDb($alias) . '.' . $this->toDb($this->sanitize($field));
|
||||
$fieldPath = $this->sanitize($alias) . '.' . $this->toDb($this->sanitize($field));
|
||||
} else {
|
||||
$fieldPath = $this->getFieldPath($entity, $orderBy);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sql = "
|
||||
SELECT email_address.name, email_address.invalid, email_address.opt_out AS optOut, entity_email_address.primary
|
||||
SELECT email_address.name, email_address.lower, email_address.invalid, email_address.opt_out AS optOut, entity_email_address.primary
|
||||
FROM entity_email_address
|
||||
JOIN email_address ON email_address.id = entity_email_address.email_address_id AND email_address.deleted = 0
|
||||
WHERE
|
||||
@@ -80,6 +80,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
foreach ($rows as $row) {
|
||||
$obj = new \StdClass();
|
||||
$obj->emailAddress = $row['name'];
|
||||
$obj->lower = $row['lower'];
|
||||
$obj->primary = ($row['primary'] == '1') ? true : false;
|
||||
$obj->optOut = ($row['optOut'] == '1') ? true : false;
|
||||
$obj->invalid = ($row['invalid'] == '1') ? true : false;
|
||||
@@ -180,22 +181,25 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
foreach ($emailAddressData as $row) {
|
||||
$key = $row->emailAddress;
|
||||
if (!empty($key)) {
|
||||
$key = strtolower($key);
|
||||
$hash[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'optOut' => $row->optOut ? true : false,
|
||||
'invalid' => $row->invalid ? true : false,
|
||||
'emailAddress' => $row->emailAddress
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$hashPrev = array();
|
||||
foreach ($previousEmailAddressData as $row) {
|
||||
$key = $row->emailAddress;
|
||||
$key = $row->lower;
|
||||
if (!empty($key)) {
|
||||
$hashPrev[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'optOut' => $row->optOut ? true : false,
|
||||
'invalid' => $row->invalid ? true : false,
|
||||
'emailAddress' => $row->emailAddress
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -216,7 +220,10 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
|
||||
if (array_key_exists($key, $hashPrev)) {
|
||||
$new = false;
|
||||
$changed = $hash[$key]['optOut'] != $hashPrev[$key]['optOut'] || $hash[$key]['invalid'] != $hashPrev[$key]['invalid'];
|
||||
$changed =
|
||||
$hash[$key]['optOut'] != $hashPrev[$key]['optOut'] ||
|
||||
$hash[$key]['invalid'] != $hashPrev[$key]['invalid'] ||
|
||||
$hash[$key]['emailAddress'] !== $hashPrev[$key]['emailAddress'];
|
||||
if ($hash[$key]['primary']) {
|
||||
if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) {
|
||||
$primary = false;
|
||||
@@ -259,6 +266,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
$emailAddress->set(array(
|
||||
'optOut' => $hash[$address]['optOut'],
|
||||
'invalid' => $hash[$address]['invalid'],
|
||||
'name' => $hash[$address]['emailAddress']
|
||||
));
|
||||
$this->save($emailAddress);
|
||||
}
|
||||
@@ -270,16 +278,21 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
$emailAddress = $this->get();
|
||||
|
||||
$emailAddress->set(array(
|
||||
'name' => $address,
|
||||
'name' => $hash[$address]['emailAddress'],
|
||||
'optOut' => $hash[$address]['optOut'],
|
||||
'invalid' => $hash[$address]['invalid'],
|
||||
));
|
||||
$this->save($emailAddress);
|
||||
} else {
|
||||
if ($emailAddress->get('optOut') != $hash[$address]['optOut'] || $emailAddress->get('invalid') != $hash[$address]['invalid']) {
|
||||
if (
|
||||
$emailAddress->get('optOut') != $hash[$address]['optOut'] ||
|
||||
$emailAddress->get('invalid') != $hash[$address]['invalid'] ||
|
||||
$emailAddress->get('emailAddress') != $hash[$address]['emailAddress']
|
||||
) {
|
||||
$emailAddress->set(array(
|
||||
'optOut' => $hash[$address]['optOut'],
|
||||
'invalid' => $hash[$address]['invalid'],
|
||||
'name' => $hash[$address]['emailAddress']
|
||||
));
|
||||
$this->save($emailAddress);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"Create Only": "Nur erstellen",
|
||||
"Create and Update": "Erstellen und aktualisieren",
|
||||
"Update Only": "Nur aktualisieren",
|
||||
"Update by": "Aktualisieren durch"
|
||||
"Update by": "Aktualisieren durch",
|
||||
"File (CSV)": "Datei (CSV)"
|
||||
},
|
||||
"messages": {
|
||||
"utf8": "Sollte UTF-8 kodiert sein",
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
"name": "Just a name of the filter.",
|
||||
"subject": "Use wildcard *:\n\ntext* - starts with text,\n*text* - contains text,\n*text - ends with text.",
|
||||
"bodyContains": "Body of email contains any of specified words or phrases.",
|
||||
"from": "Emails being sent from the specified address. Leave empty if not needed.",
|
||||
"to": "Emails being sent to the specified address. Leave empty if not needed.",
|
||||
"from": "Emails being sent from the specified address. Leave empty if not needed. You can use wildcard *.",
|
||||
"to": "Emails being sent to the specified address. Leave empty if not needed. You can use wildcard *.",
|
||||
"parent": "Leave it empty to apply this filter globally (to all incoming emails)."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
},
|
||||
"messages": {
|
||||
"entityCreated": "Entity has been created",
|
||||
"linkAlreadyExists": "Link name conflict."
|
||||
"linkAlreadyExists": "Link name conflict.",
|
||||
"linkConflict": "Link with the same name already exists."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"Create Only": "Create Only",
|
||||
"Create and Update": "Create & Update",
|
||||
"Update Only": "Update Only",
|
||||
"Update by": "Update by"
|
||||
"Update by": "Update by",
|
||||
"File (CSV)": "File (CSV)"
|
||||
},
|
||||
"messages": {
|
||||
"utf8": "Should be UTF-8 encoded",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
[
|
||||
{"name": "name", "width": 90, "link": true}
|
||||
{"name": "name", "link": true},
|
||||
{"name": "assignedUser", "width": 20}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[
|
||||
{"name": "name", "link": true},
|
||||
{"name": "assignedUser", "width": 30}
|
||||
]
|
||||
@@ -43,10 +43,6 @@
|
||||
{
|
||||
"name": "defaultReminders"
|
||||
}
|
||||
],
|
||||
[
|
||||
{"name":"theme"},
|
||||
false
|
||||
]
|
||||
]
|
||||
},
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
"from": {
|
||||
"type": "varchar",
|
||||
"maxLength": 255,
|
||||
"tooltip": true
|
||||
"tooltip": true,
|
||||
"trim": true
|
||||
},
|
||||
"to": {
|
||||
"type": "varchar",
|
||||
"maxLength": 255,
|
||||
"tooltip": true
|
||||
"tooltip": true,
|
||||
"trim": true
|
||||
},
|
||||
"subject": {
|
||||
"type": "varchar",
|
||||
|
||||
@@ -87,12 +87,11 @@
|
||||
},
|
||||
|
||||
{
|
||||
"route":"/GlobalSearch/:query",
|
||||
"route":"/GlobalSearch",
|
||||
"method":"get",
|
||||
"params":{
|
||||
"controller":"GlobalSearch",
|
||||
"action":"search",
|
||||
"query": ":query"
|
||||
"action":"search"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ class EmailTemplate extends Record
|
||||
{
|
||||
$this->dependencies[] = 'fileManager';
|
||||
$this->dependencies[] = 'dateTime';
|
||||
$this->dependencies[] = 'language';
|
||||
}
|
||||
|
||||
protected function getFileManager()
|
||||
@@ -48,6 +49,11 @@ class EmailTemplate extends Record
|
||||
return $this->injections['dateTime'];
|
||||
}
|
||||
|
||||
protected function getLanguage()
|
||||
{
|
||||
return $this->getInjection('language');
|
||||
}
|
||||
|
||||
public function parseTemplate(Entity $emailTemplate, array $params = array(), $copyAttachments = false)
|
||||
{
|
||||
$entityHash = array();
|
||||
@@ -154,17 +160,22 @@ class EmailTemplate extends Record
|
||||
protected function parseText($type, Entity $entity, $text)
|
||||
{
|
||||
$fieldList = array_keys($entity->getFields());
|
||||
$fieldList[] = $id;
|
||||
foreach ($fieldList as $field) {
|
||||
$value = $entity->get($field);
|
||||
if (is_object($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($entity->fields[$field]['type'] == 'date') {
|
||||
$value = $this->getDateTime()->convertSystemDateToGlobal($value);
|
||||
} else if ($entity->fields[$field]['type'] == 'datetime') {
|
||||
$value = $this->getDateTime()->convertSystemDateTimeToGlobal($value);
|
||||
$fieldType = $this->getMetadata()->get('entityDefs.' . $entity->getEntityType() .'.fields.' . $field . '.type');
|
||||
|
||||
if ($fieldType === 'enum') {
|
||||
$value = $this->getLanguage()->translateOption($value, $field, $entity->getEntityType());
|
||||
} else {
|
||||
if ($entity->fields[$field]['type'] == 'date') {
|
||||
$value = $this->getDateTime()->convertSystemDateToGlobal($value);
|
||||
} else if ($entity->fields[$field]['type'] == 'datetime') {
|
||||
$value = $this->getDateTime()->convertSystemDateTimeToGlobal($value);
|
||||
}
|
||||
}
|
||||
$text = str_replace('{' . $type . '.' . $field . '}', $value, $text);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,15 @@ class GlobalSearch extends \Espo\Core\Services\Base
|
||||
$row = $sth->fetch(\PDO::FETCH_ASSOC);
|
||||
$totalCount = $row['COUNT'];
|
||||
|
||||
$unionSql .= " ORDER BY name";
|
||||
if (count($entityTypeList)) {
|
||||
$entityListQuoted = [];
|
||||
foreach ($entityTypeList as $entityType) {
|
||||
$entityListQuoted[] = $pdo->quote($entityType);
|
||||
}
|
||||
$unionSql .= " ORDER BY FIELD(entityType, ".implode(', ', $entityListQuoted)."), name";
|
||||
} else {
|
||||
$unionSql .= " ORDER BY name";
|
||||
}
|
||||
$unionSql .= " LIMIT :offset, :maxSize";
|
||||
|
||||
$sth = $pdo->prepare($unionSql);
|
||||
|
||||
@@ -257,7 +257,7 @@ class Import extends \Espo\Services\Record
|
||||
return true;
|
||||
}
|
||||
|
||||
public function import($scope, array $fields, $attachmentId, array $params = array())
|
||||
public function import($scope, array $importFieldList, $attachmentId, array $params = array())
|
||||
{
|
||||
$delimiter = ',';
|
||||
if (!empty($params['fieldDelimiter'])) {
|
||||
@@ -297,7 +297,7 @@ class Import extends \Espo\Services\Record
|
||||
if (count($arr) == 1 && empty($arr[0])) {
|
||||
continue;
|
||||
}
|
||||
$r = $this->importRow($scope, $fields, $arr, $params);
|
||||
$r = $this->importRow($scope, $importFieldList, $arr, $params);
|
||||
if (empty($r)) {
|
||||
continue;
|
||||
}
|
||||
@@ -334,7 +334,7 @@ class Import extends \Espo\Services\Record
|
||||
);
|
||||
}
|
||||
|
||||
public function importRow($scope, array $fields, array $row, array $params = array())
|
||||
public function importRow($scope, array $importFieldList, array $row, array $params = array())
|
||||
{
|
||||
$id = null;
|
||||
$action = 'create';
|
||||
@@ -342,15 +342,19 @@ class Import extends \Espo\Services\Record
|
||||
$action = $params['action'];
|
||||
}
|
||||
|
||||
if (empty($importFieldList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (in_array($action, ['createAndUpdate', 'update'])) {
|
||||
if (!empty($params['updateBy']) && is_array($params['updateBy'])) {
|
||||
$updateByFieldList = [];
|
||||
$whereClause = array();
|
||||
foreach ($params['updateBy'] as $i) {
|
||||
if (array_key_exists($i, $fields)) {
|
||||
$updateByFieldList[] = $fields[$i];
|
||||
$whereClause[$fields[$i]] = $row[$i];
|
||||
if (array_key_exists($i, $importFieldList)) {
|
||||
$updateByFieldList[] = $importFieldList[$i];
|
||||
$whereClause[$importFieldList[$i]] = $row[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +403,7 @@ class Import extends \Espo\Services\Record
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $i => $field) {
|
||||
foreach ($importFieldList as $i => $field) {
|
||||
if (!empty($field)) {
|
||||
$value = $row[$i];
|
||||
if ($field == 'id') {
|
||||
@@ -457,7 +461,7 @@ class Import extends \Espo\Services\Record
|
||||
$isPrimary = false;
|
||||
if (empty($phoneNumberData)) {
|
||||
$phoneNumberData = [];
|
||||
if (!in_array('phoneNumber', $fields)) {
|
||||
if (!in_array('phoneNumber', $importFieldList)) {
|
||||
$isPrimary = true;
|
||||
}
|
||||
}
|
||||
@@ -475,7 +479,7 @@ class Import extends \Espo\Services\Record
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $i => $field) {
|
||||
foreach ($importFieldList as $i => $field) {
|
||||
if (array_key_exists($field, $fieldsDefs) && $fieldsDefs[$field]['type'] == Entity::FOREIGN) {
|
||||
if ($entity->has($field)) {
|
||||
$relation = $fieldsDefs[$field]['relation'];
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
this.menu.buttons.push({
|
||||
'label': 'Send Invitations',
|
||||
'action': 'sendInvitations',
|
||||
icon: 'glyphicon glyphicon-send',
|
||||
'acl': 'edit',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ Espo.define('Crm:Views.Dashlets.Leads', 'Views.Dashlets.Abstract.RecordList', fu
|
||||
bool: {
|
||||
onlyMy: true,
|
||||
},
|
||||
primary: 'active'
|
||||
primary: 'actual'
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -25,31 +25,6 @@ Espo.define('Crm:Views.Lead.Record.DetailSide', 'Views.Record.DetailSide', funct
|
||||
|
||||
setupPanels: function () {
|
||||
|
||||
/*var panel = {
|
||||
name: 'convertedTo',
|
||||
label: 'Converted To',
|
||||
view: 'Record.Panels.Side',
|
||||
notRefreshable: true,
|
||||
options: {
|
||||
fieldList: [],
|
||||
mode: 'detail',
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
panel.options.fieldList.push('createdAccount');
|
||||
|
||||
|
||||
panel.options.fieldList.push('createdContact');
|
||||
|
||||
|
||||
panel.options.fieldList.push('createdOpportunity');
|
||||
|
||||
|
||||
this.panels = Espo.Utils.clone(this.panels);
|
||||
this.panels.splice(1, 0, panel);*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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/.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('crm:views/lead/record/panels/converted-to', 'views/record/panels/side', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setup: function () {
|
||||
this.fieldList = [];
|
||||
|
||||
if (this.getAcl().check('Account')) {
|
||||
this.fieldList.push('createdAccount');
|
||||
}
|
||||
|
||||
if (this.getAcl().check('Contact')) {
|
||||
this.fieldList.push('createdContact');
|
||||
}
|
||||
if (this.getAcl().check('Opportunity')) {
|
||||
this.fieldList.push('createdOpportunity');
|
||||
}
|
||||
|
||||
Dep.prototype.setup.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -29,7 +29,7 @@ Espo.define('crm:views/mass-email/record/row-actions/for-campaign', 'views/recor
|
||||
if (this.options.acl.edit && !~['Complete'].indexOf(this.model.get('status'))) {
|
||||
actionList.unshift({
|
||||
action: 'sendTest',
|
||||
label: 'Sent Test',
|
||||
label: 'Send Test',
|
||||
data: {
|
||||
id: this.model.id
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ Espo.define('Crm:Views.Meeting.Detail', 'Views.Detail', function (Dep) {
|
||||
this.menu.buttons.push({
|
||||
'label': 'Send Invitations',
|
||||
'action': 'sendInvitations',
|
||||
icon: 'glyphicon glyphicon-send',
|
||||
'acl': 'edit',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ Espo.define('Crm:Views.Task.Detail', 'Views.Detail', function (Dep) {
|
||||
this.menu.buttons.push({
|
||||
'label': 'Complete',
|
||||
'action': 'setCompleted',
|
||||
icon: 'glyphicon glyphicon-ok',
|
||||
'iconHtml': '<span class="glyphicon glyphicon-ok"></span>',
|
||||
'acl': 'edit',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<div class="header-buttons btn-group pull-right">
|
||||
{{#each items.buttons}}
|
||||
<a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="btn btn-{{#if style}}{{style}}{{else}}default{{/if}} action{{#if hidden}} hidden{{/if}}" data-action="{{name}}"{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>
|
||||
{{#if iconHtml}}{{{iconHtml}}}{{/if}}
|
||||
{{#if html}}{{{html}}}{{else}}{{translate label scope=../../scope}}{{/if}}
|
||||
</a>
|
||||
{{/each}}
|
||||
@@ -30,7 +31,7 @@
|
||||
</button>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
{{#each items.dropdown}}
|
||||
<li class="{{#if hidden}}hidden{{/if}}"><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" data-action="{{name}}"{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../scope}}{{/if}}</a></li>
|
||||
<li class="{{#if hidden}}hidden{{/if}}"><a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="action" data-action="{{name}}"{{#each data}} data-{{@key}}="{{./this}}"{{/each}}>{{#if iconHtml}}{{{iconHtml}}} {{/if}}{{#if html}}{{{html}}}{{else}}{{translate label scope=../../../scope}}{{/if}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-4 form-group">
|
||||
<label class="control-label">{{translate 'File' scope='Import'}}</label>
|
||||
<label class="control-label">{{translate 'File (CSV)' scope='Import'}}</label>
|
||||
<div>
|
||||
<input type="file" id="import-file">
|
||||
</div>
|
||||
|
||||
@@ -152,7 +152,7 @@ Espo.define('controller', [], function () {
|
||||
|
||||
handleAccessGlobal: function () {
|
||||
if (!this.checkAccessGlobal()) {
|
||||
throw new Espo.Exceptions.AccessDenied("Denied access to action '" + this.name + "#" + action + "'");
|
||||
throw new Espo.Exceptions.AccessDenied("Denied access to '" + this.name + "'");
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -42,6 +42,18 @@ Espo.define('model', [], function () {
|
||||
Dep.prototype.initialize.call(this);
|
||||
},
|
||||
|
||||
set: function (key, val, options) {
|
||||
if (typeof key === 'object') {
|
||||
var o = key;
|
||||
if (this.idAttribute in o) {
|
||||
this.id = o[this.idAttribute];
|
||||
}
|
||||
} else if (key === 'id') {
|
||||
this.id = val;
|
||||
}
|
||||
return Dep.prototype.set.call(this, key, val, options);
|
||||
},
|
||||
|
||||
get: function (key) {
|
||||
if (key === 'id' && this.id) {
|
||||
return this.id;
|
||||
|
||||
@@ -142,7 +142,9 @@ Espo.define('views/admin/entity-manager/modals/edit-entity', ['views/modal', 'mo
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, this);
|
||||
}, this).sort(function (v1, v2) {
|
||||
return this.translate(v1, 'fields', scope).localeCompare(this.translate(v2, 'fields', scope));
|
||||
}.bind(this));
|
||||
|
||||
var translatedOptions = {};
|
||||
orderableFieldList.forEach(function (item) {
|
||||
|
||||
@@ -67,7 +67,7 @@ Espo.define('views/edit', 'views/main', function (Dep) {
|
||||
if (this.options.noHeaderLinks) {
|
||||
arr.push(name);
|
||||
} else {
|
||||
arr.push('<a href="#' + this.model.name + '/view/' + this.model.id + '" class="action" data-action="navigateToRoot">' + name + '</a>');
|
||||
arr.push('<a href="#' + this.model.name + '/view/' + this.model.id + '" class="action">' + name + '</a>');
|
||||
}
|
||||
}
|
||||
return this.buildHeaderHtml(arr);
|
||||
|
||||
@@ -255,6 +255,19 @@ Espo.define('views/email/detail', ['views/detail', 'email-helper'], function (De
|
||||
this.model.set('status', 'Sent');
|
||||
$send.remove();
|
||||
this.menu = this.backedMenu;
|
||||
|
||||
if (record.mode !== 'detail') {
|
||||
record.setDetailMode();
|
||||
record.setFieldReadOnly('dateSent');
|
||||
record.setFieldReadOnly('name');
|
||||
record.setFieldReadOnly('attachments');
|
||||
record.setFieldReadOnly('isHtml');
|
||||
record.setFieldReadOnly('from');
|
||||
record.setFieldReadOnly('to');
|
||||
record.setFieldReadOnly('cc');
|
||||
record.setFieldReadOnly('bcc');
|
||||
}
|
||||
|
||||
}, this);
|
||||
|
||||
this.listenToOnce(record, 'cancel:save', function () {
|
||||
|
||||
@@ -58,7 +58,7 @@ Espo.define('views/email/record/detail', 'views/record/detail', function (Dep) {
|
||||
if (!this.model.get('isRead')) {
|
||||
this.model.set({
|
||||
isRead: true
|
||||
}, {silent: true});
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
@@ -161,6 +161,10 @@ Espo.define('views/email/record/detail', 'views/record/detail', function (Dep) {
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
|
||||
if (this.model.get('status') === 'Draft') {
|
||||
this.setFieldReadOnly('dateSent');
|
||||
}
|
||||
|
||||
if (this.isRestricted) {
|
||||
this.handleAttachmentField();
|
||||
this.listenTo(this.model, 'change:attachmentsIds', function () {
|
||||
|
||||
@@ -55,6 +55,10 @@ Espo.define('views/email/record/edit', ['views/record/edit', 'views/email/record
|
||||
afterRender: function () {
|
||||
Dep.prototype.afterRender.call(this);
|
||||
|
||||
if (this.model.get('status') === 'Draft') {
|
||||
this.setFieldReadOnly('dateSent');
|
||||
}
|
||||
|
||||
this.handleAttachmentField();
|
||||
this.listenTo(this.model, 'change:attachmentsIds', function () {
|
||||
this.handleAttachmentField();
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.GlobalSearch.GlobalSearch', 'View', function (Dep) {
|
||||
Espo.define('views/global-search/global-search', 'view', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'global-search.global-search',
|
||||
template: 'global-search/global-search',
|
||||
|
||||
events: {
|
||||
'keypress #global-search-input': function (e) {
|
||||
@@ -57,13 +57,13 @@ Espo.define('Views.GlobalSearch.GlobalSearch', 'View', function (Dep) {
|
||||
runSearch: function (text) {
|
||||
var text = this.$input.val();
|
||||
if (text != '' && text.length > 2) {
|
||||
text = encodeURI(text);
|
||||
text = text;
|
||||
this.search(text);
|
||||
}
|
||||
},
|
||||
|
||||
search: function (text) {
|
||||
this.collection.url = this.collection.urlRoot = 'GlobalSearch/' + text;
|
||||
this.collection.url = this.collection.urlRoot = 'GlobalSearch?q=' + encodeURIComponent(text);
|
||||
|
||||
this.showPanel();
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.Import.Detail', 'Views.Detail', function (Dep) {
|
||||
Espo.define('views/import/detail', 'views/detail', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
Espo.define('Views.Import.Index', 'View', function (Dep) {
|
||||
Espo.define('views/import/index', 'view', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'import.index',
|
||||
template: 'import/index',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.Import.List', 'Views.List', function (Dep) {
|
||||
Espo.define('views/import/list', 'views/list', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
Espo.define('Views.Import.Step1', 'View', function (Dep) {
|
||||
|
||||
Espo.define('views/import/step1', 'view', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'import.step-1',
|
||||
template: 'import/step-1',
|
||||
|
||||
events: {
|
||||
'change #import-file': function (e) {
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
Espo.define('Views.Import.Step2', 'View', function (Dep) {
|
||||
|
||||
Espo.define('views/import/step2', 'view', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'import.step-2',
|
||||
template: 'import/step-2',
|
||||
|
||||
events: {
|
||||
'click button[data-action="back"]': function () {
|
||||
|
||||
@@ -34,6 +34,8 @@ Espo.define('views/record/detail', 'views/record/base', function (Dep) {
|
||||
|
||||
gridLayout: null,
|
||||
|
||||
detailLayout: null,
|
||||
|
||||
/**
|
||||
* @property {string} or {bool} ['both', 'top', 'bottom', false, true] Where to display buttons.
|
||||
*/
|
||||
@@ -338,6 +340,8 @@ Espo.define('views/record/detail', 'views/record/base', function (Dep) {
|
||||
|
||||
this.layoutName = this.options.layoutName || this.layoutName;
|
||||
|
||||
this.detailLayout = this.options.detailLayout || this.detailLayout;
|
||||
|
||||
this.type = this.options.type || this.type;
|
||||
|
||||
this.buttons = this.options.buttons || this.buttons;
|
||||
@@ -627,10 +631,19 @@ Espo.define('views/record/detail', 'views/record/base', function (Dep) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.detailLayout) {
|
||||
this.gridLayout = {
|
||||
type: 'record',
|
||||
layout: this.convertDetailLayout(this.detailLayout)
|
||||
};
|
||||
callback(this.gridLayout);
|
||||
return;
|
||||
}
|
||||
|
||||
this._helper.layoutManager.get(this.model.name, this.layoutName, function (simpleLayout) {
|
||||
this.gridLayout = {
|
||||
type: 'record',
|
||||
layout: this.convertDetailLayout(simpleLayout),
|
||||
layout: this.convertDetailLayout(simpleLayout)
|
||||
};
|
||||
callback(this.gridLayout);
|
||||
}.bind(this));
|
||||
|
||||
@@ -19,16 +19,18 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.Record.ListTreeItem', 'View', function (Dep) {
|
||||
Espo.define('views/record/list-tree-item', 'view', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'record.list-tree-item',
|
||||
template: 'record/list-tree-item',
|
||||
|
||||
isEnd: false,
|
||||
|
||||
level: 0,
|
||||
|
||||
listViewName: 'views/record/list-tree',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
name: this.model.get('name'),
|
||||
@@ -120,7 +122,7 @@ Espo.define('Views.Record.ListTreeItem', 'View', function (Dep) {
|
||||
view.render();
|
||||
};
|
||||
}
|
||||
this.createView('children', 'Record.ListTree', {
|
||||
this.createView('children', this.listViewName, {
|
||||
collection: childCollection,
|
||||
el: this.options.el + ' > .children',
|
||||
createDisabled: this.options.createDisabled,
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('Views.Record.ListTree', 'Views.Record.List', function (Dep) {
|
||||
Espo.define('views/record/list-tree', 'views/record/list', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
template: 'record.list-tree',
|
||||
template: 'record/list-tree',
|
||||
|
||||
showMore: false,
|
||||
|
||||
@@ -53,6 +53,8 @@ Espo.define('Views.Record.ListTree', 'Views.Record.List', function (Dep) {
|
||||
|
||||
level: 0,
|
||||
|
||||
itemViewName: 'views/record/list-tree-item',
|
||||
|
||||
data: function () {
|
||||
var data = Dep.prototype.data.call(this);
|
||||
data.createDisabled = this.createDisabled;
|
||||
@@ -151,7 +153,7 @@ Espo.define('Views.Record.ListTree', 'Views.Record.List', function (Dep) {
|
||||
var built = 0;
|
||||
modelList.forEach(function (model, i) {
|
||||
this.rows.push('row-' + i);
|
||||
this.createView('row-' + i, 'Record.ListTreeItem', {
|
||||
this.createView('row-' + i, this.itemViewName, {
|
||||
model: model,
|
||||
collection: this.collection,
|
||||
el: this.options.el + ' ' + this.getRowSelector(model.id),
|
||||
@@ -186,14 +188,22 @@ Espo.define('Views.Record.ListTree', 'Views.Record.List', function (Dep) {
|
||||
return this.options.el + ' li[data-id="' + model.id + '"] span.cell-' + item.name;
|
||||
},
|
||||
|
||||
getCreateAttributes: function () {
|
||||
return {};
|
||||
},
|
||||
|
||||
actionCreate: function (data, e) {
|
||||
e.stopPropagation();
|
||||
|
||||
var parentId = null;
|
||||
var parentName = null;
|
||||
var attributes = this.getCreateAttributes();
|
||||
|
||||
attributes.order = this.collection.length + 1;
|
||||
attributes.parentId = null;
|
||||
attributes.parentName = null;
|
||||
|
||||
if (this.model) {
|
||||
parentId = this.model.id;
|
||||
parentName = this.model.get('name');
|
||||
attributes.parentId = this.model.id;
|
||||
attributes.parentName = this.model.get('name');
|
||||
}
|
||||
|
||||
var scope = this.collection.name;
|
||||
@@ -201,11 +211,7 @@ Espo.define('Views.Record.ListTree', 'Views.Record.List', function (Dep) {
|
||||
var viewName = this.getMetadata().get('clientDefs.' + scope + '.modalViews.edit') || 'Modals.Edit';
|
||||
this.createView('quickCreate', viewName, {
|
||||
scope: scope,
|
||||
attributes: {
|
||||
parentId: parentId,
|
||||
parentName: parentName,
|
||||
order: this.collection.length + 1
|
||||
}
|
||||
attributes: attributes
|
||||
}, function (view) {
|
||||
view.render();
|
||||
this.listenToOnce(view, 'after:save', function (model) {
|
||||
|
||||
@@ -17,49 +17,58 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||
************************************************************************/
|
||||
Espo.define('Views.Settings.Fields.CurrencyRates', 'Views.Fields.Base', function (Dep) {
|
||||
************************************************************************/
|
||||
Espo.define('views/settings/fields/currency-rates', 'views/fields/base', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
editTemplate: 'settings.fields.currency-rates.edit',
|
||||
|
||||
|
||||
editTemplate: 'settings/fields/currency-rates/edit',
|
||||
|
||||
data: function () {
|
||||
var baseCurrency = this.model.get('baseCurrency');
|
||||
var currencyRates = this.model.get('currencyRates') || {};
|
||||
|
||||
|
||||
var rateValues = {};
|
||||
this.model.get('currencyList').forEach(function (currency) {
|
||||
if (currency != baseCurrency) {
|
||||
rateValues[currency] = currencyRates[currency] || 1.00;
|
||||
}
|
||||
}, this);
|
||||
|
||||
|
||||
return {
|
||||
rateValues: rateValues
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
setup: function () {
|
||||
},
|
||||
|
||||
|
||||
fetch: function () {
|
||||
var data = {};
|
||||
var currencyRates = {};
|
||||
|
||||
|
||||
var baseCurrency = this.model.get('baseCurrency');
|
||||
|
||||
this.model.get('currencyList').forEach(function (currency) {
|
||||
|
||||
var currencyList = this.model.get('currencyList') || [];
|
||||
|
||||
currencyList.forEach(function (currency) {
|
||||
if (currency != baseCurrency) {
|
||||
currencyRates[currency] = parseFloat(this.$el.find('input[data-currency="'+currency+'"]').val() || 1);
|
||||
}
|
||||
}, this);
|
||||
|
||||
|
||||
delete currencyRates[baseCurrency];
|
||||
for (var c in currencyRates) {
|
||||
if (!~currencyList.indexOf(c)) {
|
||||
delete currencyRates[c];
|
||||
}
|
||||
}
|
||||
|
||||
data[this.name] = currencyRates;
|
||||
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -93,6 +93,8 @@ Espo.define('Views.Site.Navbar', 'View', function (Dep) {
|
||||
|
||||
var tabList = this.getPreferences().get('useCustomTabList') ? this.getPreferences().get('tabList') : this.getConfig().get('tabList');
|
||||
|
||||
tabList = tabList || [];
|
||||
|
||||
this.tabList = tabList.filter(function (scope) {
|
||||
if (this.getMetadata().get('scopes.' + scope + '.acl')) {
|
||||
return this.getAcl().check(scope);
|
||||
|
||||
@@ -111,7 +111,9 @@ Espo.define('views/stream/list', 'views/record/list-expanded', function (Dep) {
|
||||
});
|
||||
},
|
||||
|
||||
actionViewRecord: function (data) {
|
||||
actionViewRecord: function (data, e) {
|
||||
e.stopPropagation();
|
||||
|
||||
var id = data.id;
|
||||
var scope = data.scope;
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "espocrm",
|
||||
"version": "3.7.1",
|
||||
"version": "3.7.4",
|
||||
"description": "",
|
||||
"main": "index.php",
|
||||
"repository": {
|
||||
|
||||
@@ -89,6 +89,15 @@ class FiltersMatcherTest extends \PHPUnit_Framework_TestCase
|
||||
$filterList = [$filter];
|
||||
$this->assertTrue($this->object->match($email, $filterList));
|
||||
|
||||
$email = new \Espo\Entities\Email($this->emailDefs);
|
||||
$email->set('from', 'test@tester');
|
||||
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
|
||||
$filter->set(array(
|
||||
'from' => '*@tester'
|
||||
));
|
||||
$filterList = [$filter];
|
||||
$this->assertTrue($this->object->match($email, $filterList));
|
||||
|
||||
$email->set('from', 'test@tester');
|
||||
$email->set('to', 'test@tester;baraka@tester');
|
||||
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
|
||||
@@ -98,6 +107,15 @@ class FiltersMatcherTest extends \PHPUnit_Framework_TestCase
|
||||
$filterList = [$filter];
|
||||
$this->assertTrue($this->object->match($email, $filterList));
|
||||
|
||||
$email->set('from', 'test@tester');
|
||||
$email->set('to', 'test@tester;baraka@man');
|
||||
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
|
||||
$filter->set(array(
|
||||
'to' => '*@tester'
|
||||
));
|
||||
$filterList = [$filter];
|
||||
$this->assertTrue($this->object->match($email, $filterList));
|
||||
|
||||
$email->set('subject', 'test hello man');
|
||||
$filter = new \Espo\Entities\EmailFilter($this->filterDefs);
|
||||
$filter->set(array(
|
||||
|
||||
Reference in New Issue
Block a user