Compare commits

..

42 Commits
4.8.2 ... 4.8.3

Author SHA1 Message Date
yuri
9b170483da version 2017-10-27 13:33:02 +03:00
yuri
71ecc3c59e fix search preset filter 2017-10-27 10:26:26 +03:00
yuri
04039f5bc3 fix typo 2017-10-24 17:17:21 +03:00
yuri
94d0bccd96 dummy 2017-10-24 16:09:46 +03:00
yuri
72a12636b3 fix 2017-10-24 16:05:57 +03:00
yuri
bfbc69fb25 fix search preset menu 2017-10-24 15:29:24 +03:00
yuri
206dc36a78 person name required 2017-10-24 12:23:11 +03:00
yuri
65f285e93f entity set object support 2017-10-24 11:45:45 +03:00
yuri
41f842e581 fix orm entity 2017-10-24 11:45:29 +03:00
yuri
9879f749e4 order link multiple records 2017-10-24 11:40:43 +03:00
yuri
b88686816b link parent changes 2017-10-24 10:55:41 +03:00
yuri
08da60b1b0 foreign field: support date and datetime 2017-10-23 11:40:01 +03:00
yuri
987b838856 fix layout manager 2017-10-23 11:08:50 +03:00
yuri
8ba79cce2a notificator fix 2017-10-20 14:21:19 +03:00
yuri
3a48b155e2 formula: undefined variable treated as null 2017-10-18 12:18:58 +03:00
yuri
c5af04ec2b formula nl support 2017-10-18 12:17:38 +03:00
yuri
62f0b6ad04 es_ES template 2017-10-10 13:20:27 +03:00
yuri
e7787b18a3 fix actions propagation 2017-10-10 13:13:07 +03:00
yuri
e77127e2d5 fix orm 2017-10-10 13:03:41 +03:00
yuri
a44a25f2e7 fix setup detail view 2017-10-04 13:00:27 +03:00
yuri
2ec595f8b0 admin quick create list fix 2017-10-03 18:23:17 +03:00
yuri
9d61f22296 first name last name max liength 2017-10-03 18:21:36 +03:00
yuri
69a99667a3 fix duplicate check person names 2017-10-03 18:17:19 +03:00
Sebastien DOIDO
f7c5e8773d Array field: fix fetch search replace regexp if multi slash are present (#653)
Thanx
2017-10-02 11:51:52 +03:00
yuri
1e7bdaa991 fix css 2017-09-28 11:01:19 +03:00
yuri
fcd40af7c9 multi enum support empty strings 2017-09-27 13:40:53 +03:00
yuri
8d949fa1fc formula fetch related link mulitple ids 2017-09-26 17:50:37 +03:00
yuri
d9504360d9 cleanup 2017-09-26 17:27:02 +03:00
yuri
09c34ff006 formula entity addLinkMultipleId support array 2017-09-26 17:15:41 +03:00
yuri
dfc3f0a5d3 formula array create 2017-09-26 17:12:07 +03:00
yuri
0a3f1dad50 fix typo 2017-09-25 12:06:53 +03:00
yuri
3772e1e839 fix enum 2017-09-22 14:06:49 +03:00
yuri
c4f5416adf rename campaign statistics 2017-09-21 12:25:53 +03:00
yuri
fcdb9aca5d lang fix 2017-09-15 14:40:23 +03:00
yuri
eaadcca1a9 remove loadAdditionalFields request param 2017-09-15 11:16:24 +03:00
yuri
f0bff56146 Merge branch 'hotfix/4.8.3' of ssh://172.20.0.1/var/git/espo/backend into hotfix/4.8.3 2017-09-14 14:47:00 +03:00
yuri
92e2177ed3 List action: loadAdditionalFields param 2017-09-14 13:48:28 +03:00
yuri
de72e6d6af htmplizer: ifEqual 2017-09-14 12:57:41 +03:00
Taras Machyshyn
32a8efad0e Installer: changed default value of smtpAuth 2017-09-13 14:23:59 +03:00
yuri
f8523cf2b6 htmlizer numberFormat 2017-09-13 12:10:55 +03:00
yuri
4e1df42f36 event stop propagation 2017-09-13 11:03:45 +03:00
yuri
9a60ee9fe6 cleanup 2017-09-13 11:02:17 +03:00
56 changed files with 540 additions and 219 deletions

View File

@@ -70,6 +70,11 @@ class AttributeFetcher
if ($parent = $entity->get($relationName)) {
return $parent->get('name');
}
} else if ($entity->getAttributeParam($attribute, 'isLinkMultipleIdList') && $methodName == 'get') {
$relationName = $entity->getAttributeParam($attribute, 'relation');
if (!$entity->has($attribute)) {
$entity->loadLinkMultipleField($relationName);
}
}
return $entity->$methodName($attribute);

View File

@@ -1,4 +1,4 @@
<?php
<?php
/************************************************************************
* This file is part of EspoCRM.
*
@@ -54,10 +54,20 @@ class AddLinkMultipleIdType extends \Espo\Core\Formula\Functions\Base
if (!is_string($link)) {
throw new Error();
}
if (!is_string($id)) {
throw new Error();
}
$this->getEntity()->addLinkMultipleId($link, $id);
if (is_array($id)) {
$idList = $id;
foreach ($idList as $id) {
if (!is_string($id)) {
throw new Error();
}
$this->getEntity()->addLinkMultipleId($link, $id);
}
} else {
if (!is_string($id)) {
throw new Error();
}
$this->getEntity()->addLinkMultipleId($link, $id);
}
}
}

View File

@@ -1,4 +1,4 @@
<?php
<?php
/************************************************************************
* This file is part of EspoCRM.
*
@@ -40,6 +40,12 @@ class ValueType extends Base
throw new Error();
}
return $item->value;
$value = $item->value;
if (is_string($value)) {
$value = str_replace("\\n", "\n", $value);
}
return $value;
}
}

View File

@@ -1,4 +1,4 @@
<?php
<?php
/************************************************************************
* This file is part of EspoCRM.
*
@@ -47,7 +47,7 @@ class VariableType extends Base
}
if (!property_exists($this->getVariables(), $name)) {
throw new Error();
return null;
}
return $this->getVariables()->$name;

View File

@@ -121,6 +121,8 @@ class Htmlizer
$v = [];
}
foreach ($v as $k => $w) {
$keyRaw = $k . '_RAW';
$v[$keyRaw] = $v[$k];
$v[$k] = $this->format($v[$k]);
}
$newList[] = $v;
@@ -134,6 +136,8 @@ class Htmlizer
$data[$field] = get_object_vars($value);
}
foreach ($data[$field] as $k => $w) {
$keyRaw = $k . '_RAW';
$data[$field][$keyRaw] = $data[$field][$k];
$data[$field][$k] = $this->format($data[$field][$k]);
}
}
@@ -142,7 +146,9 @@ class Htmlizer
}
if (array_key_exists($field, $data)) {
$data[$field] = $this->format($data[$field]);
$keyRaw = $field . '_RAW';
$data[$keyRaw] = $data[$field];
$data[$field] = $this->format($data[$field]);
}
}
@@ -171,12 +177,54 @@ class Htmlizer
public function render(Entity $entity, $template, $id = null, $additionalData = array(), $skipLinks = false)
{
$code = \LightnCandy::compile($template, [
'flags' => \LightnCandy::FLAG_HANDLEBARSJS,
'helpers' => [
'file' => function ($context, $options) {
if (count($context) && $context[0]) {
$id = $context[0];
return "?entryPoint=attachment&id=" . $id;
}
},
'numberFormat' => function ($context, $options) {
if ($context && isset($context[0])) {
$number = $context[0];
$decimals = 0;
$decimalPoint = '.';
$thousandsSeparator = ',';
if (isset($options['decimals'])) {
$decimals = $options['decimals'];
}
if (isset($options['decimalPoint'])) {
$decimalPoint = $options['decimalPoint'];
}
if (isset($options['thousandsSeparator'])) {
$thousandsSeparator = $options['thousandsSeparator'];
}
return number_format($number, $decimals, $decimalPoint, $thousandsSeparator);
}
return '';
}
],
'hbhelpers' => [
'ifEqual' => function () {
$args = func_get_args();
$context = $args[count($args) - 1];
if ($args[0] === $args[1]) {
return $context['fn']();
} else {
return $context['inverse'] ? $context['inverse']() : '';
}
},
'ifNotEqual' => function () {
$args = func_get_args();
$context = $args[count($args) - 1];
if ($args[0] !== $args[1]) {
return $context['fn']();
} else {
return $context['inverse'] ? $context['inverse']() : '';
}
}
]
]);

View File

@@ -92,26 +92,35 @@ class Base implements Injectable
public function process(Entity $entity)
{
if ($entity->has('assignedUserId') && $entity->get('assignedUserId')) {
$assignedUserId = $entity->get('assignedUserId');
if ($assignedUserId != $this->getUser()->id && $entity->isFieldChanged('assignedUserId')) {
$notification = $this->getEntityManager()->getEntity('Notification');
$notification->set(array(
'type' => 'Assign',
'userId' => $assignedUserId,
'data' => array(
'entityType' => $entity->getEntityType(),
'entityId' => $entity->id,
'entityName' => $entity->get('name'),
'isNew' => $entity->isNew(),
'userId' => $this->getUser()->id,
'userName' => $this->getUser()->get('name')
)
));
$this->getEntityManager()->saveEntity($notification);
if (!$entity->get('assignedUserId')) return;
if (!$entity->isFieldChanged('assignedUserId')) return;
$assignedUserId = $entity->get('assignedUserId');
if ($entity->hasAttribute('createdById') && $entity->hasAttribute('modifiedById')) {
if ($entity->isNew()) {
$isNotSelfAssignment = $assignedUserId !== $entity->get('createdById');
} else {
$isNotSelfAssignment = $assignedUserId !== $entity->get('modifiedById');
}
} else {
$isNotSelfAssignment = $assignedUserId !== $this->getUser()->id;
}
if (!$isNotSelfAssignment) return;
$notification = $this->getEntityManager()->getEntity('Notification');
$notification->set(array(
'type' => 'Assign',
'userId' => $assignedUserId,
'data' => array(
'entityType' => $entity->getEntityType(),
'entityId' => $entity->id,
'entityName' => $entity->get('name'),
'isNew' => $entity->isNew(),
'userId' => $this->getUser()->id,
'userName' => $this->getUser()->get('name')
)
));
$this->getEntityManager()->saveEntity($notification);
}
}

View File

@@ -50,6 +50,23 @@ class Entity extends \Espo\ORM\Entity
$defs['additionalColumns'] = $columns;
}
$foreignEntityType = $this->getRelationParam($field, 'entity');
if ($foreignEntityType && $this->entityManager) {
$foreignEntityDefs = $this->entityManager->getMetadata()->get($foreignEntityType);
if ($foreignEntityDefs && !empty($foreignEntityDefs['collection'])) {
$collectionDefs = $foreignEntityDefs['collection'];
if (!empty($foreignEntityDefs['collection']['orderBy'])) {
$orderBy = $foreignEntityDefs['collection']['orderBy'];
$order = 'ASC';
if (array_key_exists('order', $foreignEntityDefs['collection'])) {
$order = $foreignEntityDefs['collection']['order'];
}
$defs['orderBy'] = $orderBy;
$defs['order'] = $order;
}
}
}
$collection = $this->get($field, $defs);
$ids = array();
$names = new \stdClass();

View File

@@ -36,13 +36,16 @@ class Person extends \Espo\Services\Record
protected function getDuplicateWhereClause(Entity $entity, $data = array())
{
$data = array(
'OR' => array(
array(
'firstName' => $entity->get('firstName'),
'lastName' => $entity->get('lastName'),
)
)
'OR' => []
);
$toCheck = false;
if ($entity->get('firstName') || $entity->get('lastName')) {
$part = [];
$part['firstName'] = $entity->get('firstName');
$part['lastName'] = $entity->get('lastName');
$data['OR'][] = $part;
$toCheck = true;
}
if (
($entity->get('emailAddress') || $entity->get('emailAddressData'))
&&
@@ -62,8 +65,12 @@ class Person extends \Espo\Services\Record
$data['OR'][] = array(
'emailAddress' => $emailAddress
);
$toCheck = true;
}
}
if (!$toCheck) {
return false;
}
return $data;
}

View File

@@ -146,51 +146,64 @@ class Converter
{
$entityDefs = $this->getEntityDefs(true);
$ormMeta = array();
foreach($entityDefs as $entityName => $entityMeta) {
$ormMetadata = array();
foreach($entityDefs as $entityName => $entityMetadata) {
if (empty($entityMeta)) {
if (empty($entityMetadata)) {
$GLOBALS['log']->critical('Orm\Converter:process(), Entity:'.$entityName.' - metadata cannot be converted into ORM format');
continue;
}
$ormMeta = Util::merge($ormMeta, $this->convertEntity($entityName, $entityMeta));
$ormMetadata = Util::merge($ormMetadata, $this->convertEntity($entityName, $entityMetadata));
}
$ormMeta = $this->afterProcess($ormMeta);
$ormMetadata = $this->afterProcess($ormMetadata);
return $ormMeta;
return $ormMetadata;
}
protected function convertEntity($entityName, $entityMeta)
protected function convertEntity($entityName, $entityMetadata)
{
$ormMeta = array();
$ormMeta[$entityName] = array(
$ormMetadata = array();
$ormMetadata[$entityName] = array(
'fields' => array(
),
'relations' => array(
),
)
);
foreach ($this->permittedEntityOptions as $optionName) {
if (isset($entityMeta[$optionName])) {
$ormMeta[$entityName][$optionName] = $entityMeta[$optionName];
if (isset($entityMetadata[$optionName])) {
$ormMetadata[$entityName][$optionName] = $entityMetadata[$optionName];
}
}
$ormMeta[$entityName]['fields'] = $this->convertFields($entityName, $entityMeta);
$ormMeta = $this->correctFields($entityName, $ormMeta);
$ormMetadata[$entityName]['fields'] = $this->convertFields($entityName, $entityMetadata);
$ormMetadata = $this->correctFields($entityName, $ormMetadata);
$convertedLinks = $this->convertLinks($entityName, $entityMeta, $ormMeta);
$convertedLinks = $this->convertLinks($entityName, $entityMetadata, $ormMetadata);
$ormMeta = Util::merge($ormMeta, $convertedLinks);
$ormMetadata = Util::merge($ormMetadata, $convertedLinks);
return $ormMeta;
if (!empty($entityMetadata['collection']) && is_array($entityMetadata['collection'])) {
$collectionDefs = $entityMetadata['collection'];
$ormMetadata[$entityName]['collection'] = array();
if (array_key_exists('sortBy', $collectionDefs)) {
$ormMetadata[$entityName]['collection']['orderBy'] = $collectionDefs['sortBy'];
}
$ormMetadata[$entityName]['collection']['order'] = 'ASC';
if (array_key_exists('asc', $collectionDefs)) {
$ormMetadata[$entityName]['collection']['order'] = $collectionDefs['asc'] ? 'ASC' : 'DESC';
}
}
return $ormMetadata;
}
public function afterProcess(array $ormMeta)
public function afterProcess(array $ormMetadata)
{
foreach ($ormMeta as $entityName => &$entityParams) {
foreach ($ormMetadata as $entityName => &$entityParams) {
foreach ($entityParams['fields'] as $fieldName => &$fieldParams) {
/* remove fields without type */
@@ -225,18 +238,18 @@ class Converter
}
}
return $ormMeta;
return $ormMetadata;
}
/**
* Metadata conversion from Espo format into Doctrine
*
* @param string $entityName
* @param array $entityMeta
* @param array $entityMetadata
*
* @return array
*/
protected function convertFields($entityName, &$entityMeta)
protected function convertFields($entityName, &$entityMetadata)
{
//List of unmerged fields with default field defenitions in $outputMeta
$unmergedFields = array(
@@ -249,7 +262,7 @@ class Converter
'dbType' => 'varchar'
),
'name' => array(
'type' => isset($entityMeta['fields']['name']['type']) ? $entityMeta['fields']['name']['type'] : Entity::VARCHAR,
'type' => isset($entityMetadata['fields']['name']['type']) ? $entityMetadata['fields']['name']['type'] : Entity::VARCHAR,
'notStorable' => true
),
'deleted' => array(
@@ -258,7 +271,7 @@ class Converter
)
);
foreach($entityMeta['fields'] as $fieldName => $fieldParams) {
foreach($entityMetadata['fields'] as $fieldName => $fieldParams) {
/** check if "fields" option exists in $fieldMeta */
$fieldTypeMeta = $this->getMetadataHelper()->getFieldDefsByType($fieldParams);
@@ -278,10 +291,10 @@ class Converter
if (isset($fieldTypeMeta['linkDefs'])) {
$linkDefs = $this->getMetadataHelper()->getLinkDefsInFieldMeta($entityName, $fieldParams, $fieldTypeMeta['linkDefs']);
if (isset($linkDefs)) {
if (!isset($entityMeta['links'])) {
$entityMeta['links'] = array();
if (!isset($entityMetadata['links'])) {
$entityMetadata['links'] = array();
}
$entityMeta['links'] = Util::merge( array($fieldName => $linkDefs), $entityMeta['links'] );
$entityMetadata['links'] = Util::merge( array($fieldName => $linkDefs), $entityMetadata['links'] );
}
}
}
@@ -292,17 +305,17 @@ class Converter
/**
* Correct fields defenitions based on \Espo\Custom\Core\Utils\Database\Orm\Fields
*
* @param array $ormMeta
* @param array $ormMetadata
*
* @return array
*/
protected function correctFields($entityName, array $ormMeta)
protected function correctFields($entityName, array $ormMetadata)
{
$entityDefs = $this->getEntityDefs();
$entityMeta = $ormMeta[$entityName];
$entityMetadata = $ormMetadata[$entityName];
//load custom field definitions and customCodes
foreach ($entityMeta['fields'] as $fieldName => $fieldParams) {
foreach ($entityMetadata['fields'] as $fieldName => $fieldParams) {
if (empty($fieldParams['type'])) continue;
$fieldType = ucfirst($fieldParams['type']);
@@ -312,14 +325,14 @@ class Converter
}
if (class_exists($className) && method_exists($className, 'load')) {
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
$helperClass = new $className($this->metadata, $ormMetadata, $entityDefs);
$fieldResult = $helperClass->process($fieldName, $entityName);
if (isset($fieldResult['unset'])) {
$ormMeta = Util::unsetInArray($ormMeta, $fieldResult['unset']);
$ormMetadata = Util::unsetInArray($ormMetadata, $fieldResult['unset']);
unset($fieldResult['unset']);
}
$ormMeta = Util::merge($ormMeta, $fieldResult);
$ormMetadata = Util::merge($ormMetadata, $fieldResult);
}
$defaultAttributes = $this->metadata->get(['entityDefs', $entityName, 'fields', $fieldName, 'defaultAttributes']);
@@ -333,7 +346,7 @@ class Converter
)
)
);
$ormMeta = Util::merge($ormMeta, $defaultMetadataPart);
$ormMetadata = Util::merge($ormMetadata, $defaultMetadataPart);
}
}
@@ -341,24 +354,24 @@ class Converter
//add a field 'isFollowed' for scopes with 'stream => true'
$scopeDefs = $this->getMetadata()->get('scopes.'.$entityName);
if (isset($scopeDefs['stream']) && $scopeDefs['stream']) {
if (!isset($entityMeta['fields']['isFollowed'])) {
$ormMeta[$entityName]['fields']['isFollowed'] = array(
if (!isset($entityMetadata['fields']['isFollowed'])) {
$ormMetadata[$entityName]['fields']['isFollowed'] = array(
'type' => 'varchar',
'notStorable' => true,
);
$ormMeta[$entityName]['fields']['followersIds'] = array(
$ormMetadata[$entityName]['fields']['followersIds'] = array(
'type' => 'jsonArray',
'notStorable' => true,
);
$ormMeta[$entityName]['fields']['followersNames'] = array(
$ormMetadata[$entityName]['fields']['followersNames'] = array(
'type' => 'jsonObject',
'notStorable' => true,
);
}
} //END: add a field 'isFollowed' for stream => true
return $ormMeta;
return $ormMetadata;
}
protected function convertField($entityName, $fieldName, array $fieldParams, $fieldTypeMeta = null)
@@ -397,20 +410,20 @@ class Converter
return $fieldDefs;
}
protected function convertLinks($entityName, $entityMeta, $ormMeta)
protected function convertLinks($entityName, $entityMetadata, $ormMetadata)
{
if (!isset($entityMeta['links'])) {
if (!isset($entityMetadata['links'])) {
return array();
}
$relationships = array();
foreach ($entityMeta['links'] as $linkName => $linkParams) {
foreach ($entityMetadata['links'] as $linkName => $linkParams) {
if (isset($linkParams['skipOrmDefs']) && $linkParams['skipOrmDefs'] === true) {
continue;
}
$convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMeta);
$convertedLink = $this->getRelationManager()->convert($linkName, $linkParams, $entityName, $ormMetadata);
if (isset($convertedLink)) {
$relationships = Util::merge($convertedLink, $relationships);

View File

@@ -39,6 +39,8 @@ class LinkMultiple extends Base
$fieldName.'Ids' => array(
'type' => 'varchar',
'notStorable' => true,
'isLinkMultipleIdList' => true,
'relation' => $fieldName
),
$fieldName.'Names' => array(
'type' => 'varchar',

View File

@@ -103,7 +103,7 @@ class RelationManager
return false;
}
public function convert($linkName, $linkParams, $entityName, $ormMeta)
public function convert($linkName, $linkParams, $entityName, $ormMetadata)
{
$entityDefs = $this->getMetadata()->get('entityDefs');
@@ -132,7 +132,7 @@ class RelationManager
}
if (isset($className) && $className !== false) {
$helperClass = new $className($this->metadata, $ormMeta, $entityDefs);
$helperClass = new $className($this->metadata, $ormMetadata, $entityDefs);
return $helperClass->process($linkName, $entityName, $foreignLink['name'], $foreignEntityName);
}
//END: relationDefs defined in separate file

View File

@@ -93,4 +93,9 @@ class OrmMetadata
return $this->data;
}
public function get($key = null, $default = null)
{
$result = Util::getValueByKey($this->getData(), $key, $default);
return $result;
}
}

View File

@@ -9,12 +9,14 @@
"application": "Application",
"queueItem": "Queue Item",
"stringData": "String Data",
"stringAdditionalData": "String Additional Data"
"stringAdditionalData": "String Additional Data",
"isTest": "Is Test"
},
"links": {
"queueItem": "Queue Item",
"parent": "Parent",
"object": "Object"
"object": "Object",
"campaign": "Campaign"
},
"options": {
"action": {

View File

@@ -38,7 +38,7 @@
{
"name":"statistics",
"label":"Statistics",
"view":"crm:views/campaign/record/panels/statistics",
"view":"crm:views/campaign/record/panels/campaign-stats",
"hidden": false
}
]

View File

@@ -0,0 +1,7 @@
<p>{{assignerUserName}} te ha asignado {{entityTypeLowerFirst}} a ti.</p>
<p><strong>{{name}}</strong></p>
<p>Comienzo: {{dateStart}}</p>
{{#if description}}
<p>{{{description}}}</p>
{{/if}}
<p><a href="{{recordUrl}}">Ver registro</a></p>

View File

@@ -0,0 +1,13 @@
<p>Asunto: {{name}}</p>
<p>Comienzo: {{dateStart}}</p>
{{#if isUser}}
{{#if description}}
<p>{{{description}}}</p>
{{/if}}
{{/if}}
<p>
<a href="{{acceptLink}}">Aceptar</a>, <a href="{{declineLink}}">Declinar</a>, <a href="{{tentativeLink}}">Provisional</a>
</p>
{{#if isUser}}
<p><a href="{{recordUrl}}">Ver registro</a></p>
{{/if}}

View File

@@ -0,0 +1 @@
Invitacion a {{{entityTypeLowerFirst}}} '{{{name}}}'

View File

@@ -0,0 +1,4 @@
<p>Asunto: {{name}}</p>
<p>Fecha Final: {{dateEnd}}</p>
<p><a href="{{recordUrl}}">Ver registro</a></p>

View File

@@ -0,0 +1,4 @@
<p>Asunto: {{name}}</p>
<p>Comienzo: {{dateStart}}</p>
<p><a href="{{recordUrl}}">Ver registro</a></p>

View File

@@ -0,0 +1 @@
Recordatorio sobre {{{entityTypeLowerFirst}}} '{{{name}}}'

View File

@@ -44,6 +44,9 @@ class Account extends \Espo\Services\Record
protected function getDuplicateWhereClause(Entity $entity, $data = array())
{
if (!$entity->get('name')) {
return false;
}
return array(
'name' => $entity->get('name')
);

View File

@@ -31,7 +31,7 @@ namespace Espo\Modules\Crm\Services;
use \Espo\ORM\Entity;
class Contact extends \Espo\Services\Record
class Contact extends \Espo\Core\Templates\Services\Person
{
protected $readOnlyAttributeList = [
@@ -43,41 +43,6 @@ class Contact extends \Espo\Services\Record
'title'
];
protected function getDuplicateWhereClause(Entity $entity, $data = array())
{
$data = array(
'OR' => array(
array(
'firstName' => $entity->get('firstName'),
'lastName' => $entity->get('lastName'),
)
)
);
if (
($entity->get('emailAddress') || $entity->get('emailAddressData'))
&&
($entity->isNew() || $entity->isFieldChanged('emailAddress') || $entity->isFieldChanged('emailAddressData'))
) {
if ($entity->get('emailAddress')) {
$list = [$entity->get('emailAddress')];
}
if ($entity->get('emailAddressData')) {
foreach ($entity->get('emailAddressData') as $row) {
if (!in_array($row->emailAddress, $list)) {
$list[] = $row->emailAddress;
}
}
}
foreach ($list as $emailAddress) {
$data['OR'][] = array(
'emailAddress' => $emailAddress
);
}
}
return $data;
}
public function afterCreate(Entity $entity, array $data = array())
{
parent::afterCreate($entity, $data);
@@ -102,4 +67,3 @@ class Contact extends \Espo\Services\Record
}
}
}

View File

@@ -34,7 +34,7 @@ use \Espo\Core\Exceptions\Forbidden;
use \Espo\ORM\Entity;
class Lead extends \Espo\Services\Record
class Lead extends \Espo\Core\Templates\Services\Person
{
protected function init()
@@ -48,41 +48,6 @@ class Lead extends \Espo\Services\Record
return $this->getInjection('container')->get('fieldManager');
}
protected function getDuplicateWhereClause(Entity $entity, $data = array())
{
$data = array(
'OR' => array(
array(
'firstName' => $entity->get('firstName'),
'lastName' => $entity->get('lastName'),
)
)
);
if (
($entity->get('emailAddress') || $entity->get('emailAddressData'))
&&
($entity->isNew() || $entity->isFieldChanged('emailAddress') || $entity->isFieldChanged('emailAddressData'))
) {
if ($entity->get('emailAddress')) {
$list = [$entity->get('emailAddress')];
}
if ($entity->get('emailAddressData')) {
foreach ($entity->get('emailAddressData') as $row) {
if (!in_array($row->emailAddress, $list)) {
$list[] = $row->emailAddress;
}
}
}
foreach ($list as $emailAddress) {
$data['OR'][] = array(
'emailAddress' => $emailAddress
);
}
}
return $data;
}
public function afterCreate(Entity $entity, array $data = array())
{
parent::afterCreate($entity, $data);

View File

@@ -563,7 +563,7 @@ abstract class Mapper implements IMapper
if (!empty($data) && is_array($data)) {
$setArr = array();
foreach ($data as $column => $value) {
$setArr[] = $this->toDb($column) . " = " . $this->pdo->quote($value);
$setArr[] = $this->toDb($column) . " = " . $this->quote($value);
}
$setPart .= ', ' . implode(', ', $setArr);
}

View File

@@ -110,12 +110,15 @@ abstract class Entity implements IEntity
public function set($p1, $p2 = null)
{
if (is_array($p1)) {
if (is_array($p1) || is_object($p1)) {
if (is_object($p1)) {
$p1 = get_object_vars($p1);
}
if ($p2 === null) {
$p2 = false;
}
$this->populateFromArray($p1, $p2);
} else {
} else if (is_string($p1)) {
$name = $p1;
$value = $p2;
if ($name == 'id') {

View File

@@ -1,25 +1,32 @@
{
"actualFields":[
"salutation",
"first",
"last"
],
"fields":{
"salutation":{
"type":"enum"
},
"first":{
"type":"varchar"
},
"last":{
"type":"varchar"
}
},
"naming":"prefix",
"notMergeable":true,
"notCreatable": true,
"filter": true,
"fieldDefs":{
"skipOrmDefs": true
}
}
"actualFields":[
"salutation",
"first",
"last"
],
"params":[
{
"name":"required",
"type":"bool",
"default":false
}
],
"fields":{
"salutation":{
"type":"enum"
},
"first":{
"type":"varchar"
},
"last":{
"type":"varchar"
}
},
"naming":"prefix",
"notMergeable":true,
"notCreatable":true,
"filter":true,
"fieldDefs":{
"skipOrmDefs":true
}
}

View File

@@ -33,7 +33,7 @@ class EmailFilter extends \Espo\Core\SelectManagers\Base
{
protected function access(&$result)
{
if (!$this->hetUser()->isAdmin()) {
if (!$this->getUser()->isAdmin()) {
$this->accessOnlyOwn($result);
}
}

View File

@@ -757,6 +757,9 @@ class Record extends \Espo\Core\Services\Base
foreach ($collection as $e) {
$this->loadAdditionalFieldsForList($e);
if (!empty($params['loadAdditionalFields'])) {
$this->loadAdditionalFields($e);
}
$this->prepareEntityForOutput($e);
}
@@ -827,6 +830,9 @@ class Record extends \Espo\Core\Services\Base
foreach ($collection as $e) {
$recordService->loadAdditionalFieldsForList($e);
if (!empty($params['loadAdditionalFields'])) {
$recordService->loadAdditionalFields($e);
}
$recordService->prepareEntityForOutput($e);
}

View File

@@ -268,6 +268,7 @@ var Bull = Bull || {};
this.init();
this.setup();
this.setupFinal();
this.template = this.options.template || this.template;
this.layout = this.options.layout || this.layout;
@@ -322,6 +323,8 @@ var Bull = Bull || {};
*/
setup: function () {},
setupFinal: function () {},
/**
* Set view container element if doesn't exist yet. It will call setElement after render.
*/

View File

@@ -27,7 +27,7 @@
************************************************************************/
Espo.define('Crm:Views.Campaign.Record.Panels.Statistics', 'Views.Record.Panels.Side', function (Dep) {
Espo.define('crm:views/campaign/record/panels/campaign-stats', 'views/record/panels/side', function (Dep) {
return Dep.extend({

View File

@@ -36,7 +36,7 @@ Espo.define('crm:views/task/detail', 'views/detail', function (Dep) {
if (this.getAcl().checkModel(this.model, 'edit')) {
this.menu.buttons.push({
'label': 'Complete',
'action': 'setCompleted',
'action': 'setCompletedMain',
'iconHtml': '<span class="glyphicon glyphicon-ok"></span>',
'acl': 'edit',
});
@@ -49,7 +49,7 @@ Espo.define('crm:views/task/detail', 'views/detail', function (Dep) {
}
},
actionSetCompleted: function (data) {
actionSetCompletedMain: function (data) {
var id = data.id;
this.model.save({

View File

@@ -33,7 +33,6 @@ Espo.define('crm:views/task/record/list-expanded', ['views/record/list-expanded'
rowActionsView: 'crm:views/task/record/row-actions/default',
actionSetCompleted: function (data) {
console.log(1);
List.prototype.actionSetCompleted.call(this, data);
},

View File

@@ -1 +1 @@
<a href="#{{model.name}}/view/{{model.id}}" class="link" data-id="{{model.id}}" title="{{value}}">{{value}}</a>
<a href="#{{model.name}}/view/{{model.id}}" class="link" data-id="{{model.id}}" title="{{value}}">{{#if value}}{{value}}{{else}}{{translate 'None'}}{{/if}}</a>

View File

@@ -0,0 +1,5 @@
{{#if idValue}}
<a href="#{{foreignScope}}/view/{{idValue}}" title="{{translate foreignScope category='scopeNames'}}">{{nameValue}}</a>
{{else}}
{{translate 'None'}}
{{/if}}

View File

@@ -1 +1,3 @@
{{translateOption salutationValue field='salutationName' scope=scope}} {{firstValue}} {{lastValue}}
{{#if isNotEmpty}}{{translateOption salutationValue field='salutationName' scope=scope}} {{firstValue}} {{lastValue}}{{else}}
{{translate 'None'}}
{{/if}}

View File

@@ -5,9 +5,9 @@
</select>
</div>
<div class="col-sm-4 col-xs-4">
<input type="text" class="form-control" name="first{{ucName}}" value="{{firstValue}}" placeholder="{{translate 'First Name'}}">
<input type="text" class="form-control" name="first{{ucName}}" value="{{firstValue}}" placeholder="{{translate 'First Name'}}"{{#if firstMaxLength}} maxlength="{{firstMaxLength}}"{{/if}}>
</div>
<div class="col-sm-5 col-xs-5">
<input type="text" class="form-control" name="last{{ucName}}" value="{{lastValue}}" placeholder="{{translate 'Last Name'}}">
<input type="text" class="form-control" name="last{{ucName}}" value="{{lastValue}}" placeholder="{{translate 'Last Name'}}"{{#if lastMaxLength}} maxlength="{{lastMaxLength}}"{{/if}}>
</div>
</div>

View File

@@ -30,7 +30,7 @@ Espo.define('views/admin/field-manager/fields/foreign/field', 'views/fields/enum
return Dep.extend({
typeList: ['varchar', 'enum', 'enumInt', 'enumFloat', 'int', 'float', 'website'],
typeList: ['varchar', 'enum', 'enumInt', 'enumFloat', 'int', 'float', 'website', 'date', 'datetime'],
setup: function () {
Dep.prototype.setup.call(this);
@@ -112,6 +112,10 @@ Espo.define('views/admin/field-manager/fields/foreign/field', 'views/fields/enum
this.viewValue = 'views/fields/foreign-int';
} else if (type == 'float') {
this.viewValue = 'views/fields/foreign-float';
} else if (type == 'date') {
this.viewValue = 'views/fields/foreign-date';
} else if (type == 'datetime') {
this.viewValue = 'views/fields/foreign-datetime';
} else {
this.viewValue = null;
}

View File

@@ -62,6 +62,7 @@ Espo.define('views/admin/layouts/grid', 'views/admin/layouts/base', function (De
}
});
$(e.target).closest('ul.panels > li').remove();
this.normilizaDisabledItemList();
},
'click #layout a[data-action="addRow"]': function (e) {
var tpl = this.unescape($("#layout-row-tpl").html());
@@ -76,6 +77,7 @@ Espo.define('views/admin/layouts/grid', 'views/admin/layouts/base', function (De
}
});
$(e.target).closest('ul.rows > li').remove();
this.normilizaDisabledItemList();
},
'click #layout a[data-action="removeField"]': function (e) {
var el = $(e.target).closest('li');
@@ -166,6 +168,12 @@ Espo.define('views/admin/layouts/grid', 'views/admin/layouts/base', function (De
}
}, Dep.prototype.events),
normilizaDisabledItemList: function () {
$('#layout ul.cells.disabled > li').each(function (i, el) {
$(el).removeAttr('data-full-width');
}.bind(this));
},
addPanel: function (data) {
var tpl = this.unescape($("#layout-panel-tpl").html());

View File

@@ -261,12 +261,19 @@ Espo.define('views/fields/array', ['views/fields/base', 'lib!Selectize'], functi
getValueForDisplay: function () {
return this.selected.map(function (item) {
var label = null;
if (this.translatedOptions != null) {
if (item in this.translatedOptions) {
return this.getHelper().stripTags(this.translatedOptions[item]);
label = this.getHelper().stripTags(this.translatedOptions[item]);
}
}
return this.getHelper().stripTags(item);
if (label === null) {
label = this.getHelper().stripTags(item);
}
if (label === '') {
label = this.translate('None');
}
return label;
}, this).join(', ');
},
@@ -338,7 +345,7 @@ Espo.define('views/fields/array', ['views/fields/base', 'lib!Selectize'], functi
arr.push({
type: 'like',
field: field,
value: "%" + value.replace(/\//, '\\\\/' ) + "%"
value: "%" + value.replace(/\//g, '\\\\/' ) + "%"
});
arrFront.push(value);
});

View File

@@ -184,6 +184,7 @@ Espo.define('views/fields/base', 'view', function (Dep) {
data.searchType = this.getSearchType();
data.searchTypeList = this.getSearchTypeList();
}
return data;
},

View File

@@ -79,26 +79,33 @@ Espo.define('views/fields/enum', ['views/fields/base', 'lib!Selectize'], functio
}
if (this.params.translation) {
var translationObj;
var data = this.getLanguage().data;
var arr = this.params.translation.split('.');
var pointer = this.getLanguage().data;
arr.forEach(function (key) {
if (key in pointer) {
pointer = pointer[key];
t = pointer;
translationObj = pointer;
}
}, this);
this.translatedOptions = null;
var translatedOptions = {};
if (this.params.options) {
this.params.options.forEach(function (o) {
if (typeof t === 'object' && o in t) {
translatedOptions[o] = t[o];
this.params.options.forEach(function (item) {
if (typeof translationObj === 'object' && item in translationObj) {
translatedOptions[item] = translationObj[item];
} else {
translatedOptions[o] = o;
translatedOptions[item] = item;
}
}, this);
var value = this.model.get(this.name);
if ((value || value === '') && !(value in translatedOptions)) {
if (typeof translationObj === 'object' && value in translationObj) {
translatedOptions[value] = translationObj[value];
}
}
this.translatedOptions = translatedOptions;
}
}

View File

@@ -0,0 +1,37 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2017 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/.
*
* 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.
************************************************************************/
Espo.define('views/fields/foreign-date', 'views/fields/date', function (Dep) {
return Dep.extend({
type: 'foreign'
});
});

View File

@@ -0,0 +1,37 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2017 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/.
*
* 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.
************************************************************************/
Espo.define('views/fields/foreign-datetime', 'views/fields/datetime', function (Dep) {
return Dep.extend({
type: 'foreign'
});
});

View File

@@ -34,7 +34,7 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
listTemplate: 'fields/link/list',
detailTemplate: 'fields/link/detail',
detailTemplate: 'fields/link-parent/detail',
editTemplate: 'fields/link-parent/edit',
@@ -86,7 +86,8 @@ Espo.define('views/fields/link-parent', 'views/fields/base', function (Dep) {
this.typeName = this.name + 'Type';
this.idName = this.name + 'Id';
this.foreignScopeList = this.params.entityList || this.model.getLinkParam(this.name, 'entityList') || [];
this.foreignScopeList = this.options.foreignScopeList || this.foreignScopeList;
this.foreignScopeList = this.foreignScopeList || this.params.entityList || this.model.getLinkParam(this.name, 'entityList') || [];
this.foreignScopeList = Espo.Utils.clone(this.foreignScopeList).filter(function (item) {
if (!this.getMetadata().get(['scopes', item, 'disabled'])) return true;
}, this);

View File

@@ -65,8 +65,15 @@ Espo.define('views/fields/multi-enum', ['views/fields/array', 'lib!Selectize'],
afterRender: function () {
if (this.mode == 'edit') {
var $element = this.$element = this.$el.find('[name="' + this.name + '"]');
this.$element.val(this.selected.join(':,:'));
var valueList = Espo.Utils.clone(this.selected);
for (var i in valueList) {
if (valueList[i] === '') {
valueList[i] = '__emptystring__';
}
}
this.$element.val(valueList.join(':,:'));
var data = [];
(this.params.options || []).forEach(function (value) {
@@ -76,6 +83,12 @@ Espo.define('views/fields/multi-enum', ['views/fields/array', 'lib!Selectize'],
label = this.translatedOptions[value];
}
}
if (value === '') {
value = '__emptystring__';
}
if (label === '') {
label = this.translate('None');
}
data.push({
value: value,
label: label
@@ -117,6 +130,11 @@ Espo.define('views/fields/multi-enum', ['views/fields/array', 'lib!Selectize'],
if (list.length == 1 && list[0] == '') {
list = [];
}
for (var i in list) {
if (list[i] === '__emptystring__') {
list[i] = '';
}
}
var data = {};
data[this.name] = list;
return data;

View File

@@ -43,6 +43,14 @@ Espo.define('views/fields/person-name', 'views/fields/varchar', function (Dep) {
data.firstValue = this.model.get(this.firstField);
data.lastValue = this.model.get(this.lastField);
data.salutationOptions = this.model.getFieldParam(this.salutationField, 'options');
data.firstMaxLength = this.model.getFieldParam(this.firstField, 'maxLength');
data.lastMaxLength = this.model.getFieldParam(this.lastField, 'maxLength');
if (this.mode === 'detail') {
data.isNotEmpty = !!data.firstValue || !!data.lastValue || !!data.salutationValue;
} else if (this.mode === 'list' || this.mode === 'listLink') {
data.isNotEmpty = !!data.firstValue || !!data.lastValue;
}
return data;
},
@@ -74,16 +82,26 @@ Espo.define('views/fields/person-name', 'views/fields/varchar', function (Dep) {
},
validateRequired: function () {
var isRequired = this.model.getFieldParam(this.name, 'required');
var validate = function (name) {
if (this.model.isRequired(name)) {
if (this.model.get(name) === '') {
var msg = this.translate('fieldIsRequired', 'messages').replace('{field}', this.translate(this.name, 'fields', this.model.name));
var msg = this.translate('fieldIsRequired', 'messages').replace('{field}', this.translate(name, 'fields', this.model.name));
this.showValidationMessage(msg, '[name="'+name+'"]');
return true;
}
}
}.bind(this);
if (isRequired) {
if (!this.model.get(this.firstField) && !this.model.get(this.lastField)) {
var msg = this.translate('fieldIsRequired', 'messages').replace('{field}', this.translate(this.name, 'fields', this.model.name));
this.showValidationMessage(msg, '[name="'+this.lastField+'"]');
return true;
}
}
var result = false;
result = validate(this.salutationField) || result;
result = validate(this.firstField) || result;
@@ -94,7 +112,8 @@ Espo.define('views/fields/person-name', 'views/fields/varchar', function (Dep) {
isRequired: function () {
return this.model.getFieldParam(this.salutationField, 'required') ||
this.model.getFieldParam(this.firstField, 'required') ||
this.model.getFieldParam(this.lastField, 'required');
this.model.getFieldParam(this.lastField, 'required') ||
this.model.getFieldParam(this.name, 'required');
},
fetch: function (form) {

View File

@@ -274,10 +274,10 @@ Espo.define('views/record/base', ['view', 'view-record-helper', 'dynamic-logic']
this.isNew = true;
}
this.setupFinal();
this.setupBeforeFinal();
},
setupFinal: function () {
setupBeforeFinal: function () {
this.attributes = this.model.getClonedAttributes();
this.listenTo(this.model, 'change', function () {

View File

@@ -681,8 +681,7 @@ Espo.define('views/record/detail', ['views/record/base', 'view-record-helper'],
this.navigateButtonsDisabled = this.options.navigateButtonsDisabled || this.navigateButtonsDisabled;
this.setupActionItems();
this.setupFinal();
this.setupBeforeFinal();
this.on('after:render', function () {
this.$detailButtonContainer = this.$el.find('.detail-button-container');
@@ -690,7 +689,7 @@ Espo.define('views/record/detail', ['views/record/base', 'view-record-helper'],
}, this);
},
setupFinal: function () {
setupBeforeFinal: function () {
this.manageAccess();
this.attributes = this.model.getClonedAttributes();
@@ -716,6 +715,9 @@ Espo.define('views/record/detail', ['views/record/base', 'view-record-helper'],
this.initDynamicLogic();
this.setupFieldLevelSecurity();
},
setupFinal: function () {
this.build();
},

View File

@@ -76,11 +76,11 @@ Espo.define('views/record/edit', 'views/record/detail', function (Dep) {
this.exit('cancel');
},
setupFinal: function () {
setupBeforeFinal: function () {
if (this.model.isNew()) {
this.populateDefaults();
}
Dep.prototype.setupFinal.call(this);
Dep.prototype.setupBeforeFinal.call(this);
}
});

View File

@@ -108,6 +108,18 @@ Espo.define('views/record/search', 'view', function (Dep) {
this.loadSearchData();
if (this.presetName) {
var hasPresetListed = this.presetFilterList.find(function (item) {
var name = (typeof item === 'string') ? item : item.name;
if (name === this.presetName) {
return true;
}
}, this);
if (!hasPresetListed) {
this.presetFilterList.push(this.presetName);
}
}
this.model = new this.collection.model();
this.model.clear();
@@ -577,17 +589,20 @@ Espo.define('views/record/search', 'view', function (Dep) {
this.presetName = searchData.presetName;
}
var primaryIsSet = false;
if ('primary' in searchData) {
this.primary = searchData.primary;
if (!this.presetName) {
this.presetName = this.primary;
}
primaryIsSet = true;
}
if (this.presetName) {
this.advanced = _.extend(Espo.Utils.clone(this.getPresetData()), searchData.advanced);
this.primary = this.getPrimaryFilterName();
if (!primaryIsSet) {
this.primary = this.getPrimaryFilterName();
}
} else {
this.advanced = Espo.Utils.clone(searchData.advanced);
}

View File

@@ -33,7 +33,7 @@ Espo.define('views/settings/fields/quick-create-list', 'views/fields/array', fun
this.params.options = Object.keys(this.getMetadata().get('scopes')).filter(function (scope) {
if (this.getMetadata().get('scopes.' + scope + '.disabled')) return;
return this.getMetadata().get('scopes.' + scope + '.entity') && this.getMetadata().get('scopes.' + scope + '.tab');
return this.getMetadata().get('scopes.' + scope + '.entity') && this.getMetadata().get('scopes.' + scope + '.object');
}, this).sort(function (v1, v2) {
return this.translate(v1, 'scopeNamesPlural').localeCompare(this.translate(v2, 'scopeNamesPlural'));
}.bind(this));

View File

@@ -1316,6 +1316,7 @@ table.table td.cell .complex-text {
margin: 0;
margin-bottom: 0;
border: 0;
line-height: 1.4;
}
#main > .calendar-container {

View File

@@ -37,7 +37,7 @@ $fields = array(
'default' => $config->get('smtpPort', 25),
),
'smtpAuth' => array(
'default' => $config->get('smtpAuth', ''),
'default' => false,
),
'smtpSecurity' => array(
'default' => $config->get('smtpSecurity', ''),

View File

@@ -1,6 +1,6 @@
{
"name": "espocrm",
"version": "4.8.2",
"version": "4.8.3",
"description": "",
"main": "index.php",
"repository": {

View File

@@ -926,6 +926,20 @@ class FormulaTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($result);
}
function testStringNewLine()
{
$item = json_decode('
{
"type": "value",
"value": "test\\ntest"
}
');
$result = $this->formula->process($item, $this->entity);
$this->assertEquals("test\ntest", $result);
}
function testVariable()
{
$item = json_decode('

View File

@@ -127,6 +127,45 @@ class HtmlizerTest extends \PHPUnit_Framework_TestCase
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('3,000', $html);
$template = "{{float_RAW}}";
$entity->set('float', 10000.50);
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('10000.5', $html);
$template = "{{numberFormat float_RAW}}";
$entity->set('float', 10000.60);
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('10,001', $html);
$template = "{{numberFormat float_RAW decimals=2}}";
$entity->set('float', 10000.601);
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('10,000.60', $html);
$template = "{{numberFormat float_RAW decimals=0}}";
$entity->set('float', 10000.1);
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('10,000', $html);
$template = "{{numberFormat float_RAW decimals=2 decimalPoint='.' thousandsSeparator=' '}}";
$entity->set('float', 10000.60);
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('10 000.60', $html);
$template = "{{file name}}";
$entity->set('name', '1');
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('?entryPoint=attachment&id=1', $html);
$template = "{{#ifEqual name '1'}}hello{{/ifEqual}}";
$entity->set('name', '1');
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('hello', $html);
$template = "{{#ifNotEqual name '1'}}hello{{else}}test{{/ifNotEqual}}";
$entity->set('name', '1');
$html = $this->htmlizer->render($entity, $template);
$this->assertEquals('test', $html);
}
}