Merge branch 'master' into feature/campaign
This commit is contained in:
@@ -231,27 +231,39 @@ class Record extends Base
|
||||
|
||||
public function actionCreateLink($params, $data)
|
||||
{
|
||||
if (empty($params['id']) || empty($params['link'])) {
|
||||
throw BadRequest();
|
||||
}
|
||||
|
||||
$id = $params['id'];
|
||||
$link = $params['link'];
|
||||
|
||||
$foreignIds = array();
|
||||
if (isset($data['id'])) {
|
||||
$foreignIds[] = $data['id'];
|
||||
}
|
||||
if (isset($data['ids']) && is_array($data['ids'])) {
|
||||
foreach ($data['ids'] as $foreignId) {
|
||||
$foreignIds[] = $foreignId;
|
||||
if (!empty($data['massRelate'])) {
|
||||
if (empty($data['where'])) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
$where = json_decode(json_encode($data['where']), true);
|
||||
return $this->getRecordService()->linkEntityMass($id, $link, $where);
|
||||
} else {
|
||||
$foreignIds = array();
|
||||
if (isset($data['id'])) {
|
||||
$foreignIds[] = $data['id'];
|
||||
}
|
||||
if (isset($data['ids']) && is_array($data['ids'])) {
|
||||
foreach ($data['ids'] as $foreignId) {
|
||||
$foreignIds[] = $foreignId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = false;
|
||||
foreach ($foreignIds as $foreignId) {
|
||||
if ($this->getRecordService()->linkEntity($id, $link, $foreignId)) {
|
||||
$result = $result || true;
|
||||
$result = false;
|
||||
foreach ($foreignIds as $foreignId) {
|
||||
if ($this->getRecordService()->linkEntity($id, $link, $foreignId)) {
|
||||
$result = true;
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Error();
|
||||
@@ -262,6 +274,10 @@ class Record extends Base
|
||||
$id = $params['id'];
|
||||
$link = $params['link'];
|
||||
|
||||
if (empty($params['id']) || empty($params['link'])) {
|
||||
throw BadRequest();
|
||||
}
|
||||
|
||||
$foreignIds = array();
|
||||
if (isset($data['id'])) {
|
||||
$foreignIds[] = $data['id'];
|
||||
|
||||
@@ -241,13 +241,20 @@ class Converter
|
||||
$table->addColumn('id', 'int', array('length'=>$this->defaultLength['int'], 'autoincrement' => true, 'notnull' => true,)); //'unique' => true,
|
||||
|
||||
//add midKeys to a schema
|
||||
$uniqueIndex = array();
|
||||
foreach($relationParams['midKeys'] as $index => $midKey) {
|
||||
|
||||
$usMidKey = Util::toUnderScore($midKey);
|
||||
$table->addColumn($usMidKey, $this->idParams['dbType'], array('length'=>$this->idParams['len']));
|
||||
$table->addIndex(array($usMidKey));
|
||||
|
||||
} //END: add midKeys to a schema
|
||||
$uniqueIndex[] = $usMidKey;
|
||||
}
|
||||
|
||||
if (!empty($uniqueIndex)) {
|
||||
$table->addUniqueIndex($uniqueIndex);
|
||||
}
|
||||
//END: add midKeys to a schema
|
||||
|
||||
//add additionalColumns
|
||||
if (isset($relationParams['additionalColumns'])) {
|
||||
|
||||
@@ -372,6 +372,69 @@ abstract class Mapper implements IMapper
|
||||
}
|
||||
}
|
||||
|
||||
public function massRelate(IEntity $entity, $relationName, array $params = array())
|
||||
{
|
||||
if (!$entity) {
|
||||
return false;
|
||||
}
|
||||
$id = $entity->id;
|
||||
|
||||
if (empty($id) || empty($relationName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$relOpt = $entity->relations[$relationName];
|
||||
|
||||
if (!isset($relOpt['entity']) || !isset($relOpt['type'])) {
|
||||
throw new \LogicException("Not appropriate defenition for relationship {$relationName} in " . $entity->getEntityType() . " entity");
|
||||
}
|
||||
|
||||
$relType = $relOpt['type'];
|
||||
|
||||
$className = (!empty($relOpt['class'])) ? $relOpt['class'] : $relOpt['entity'];
|
||||
$relEntity = $this->entityFactory->create($className);
|
||||
$foreignEntityType = $relEntity->getEntityType();
|
||||
|
||||
$keySet = $this->query->getKeys($entity, $relationName);
|
||||
|
||||
switch ($relType) {
|
||||
case IEntity::MANY_MANY:
|
||||
$key = $keySet['key'];
|
||||
$foreignKey = $keySet['foreignKey'];
|
||||
$nearKey = $keySet['nearKey'];
|
||||
$distantKey = $keySet['distantKey'];
|
||||
|
||||
$relTable = $this->toDb($relOpt['relationName']);
|
||||
|
||||
|
||||
$params['select'] = array('id');
|
||||
$subSql = $this->query->createSelectQuery($foreignEntityType, $params);
|
||||
|
||||
$fieldsPart = $this->toDb($nearKey);
|
||||
$valuesPart = $this->pdo->quote($entity->id);
|
||||
|
||||
if (!empty($relOpt['conditions']) && is_array($relOpt['conditions'])) {
|
||||
foreach ($relOpt['conditions'] as $f => $v) {
|
||||
$fieldsPart .= ", " . $this->toDb($f);
|
||||
$valuesPart .= ", " . $this->pdo->quote($v);
|
||||
}
|
||||
}
|
||||
$fieldsPart .= ", " . $this->toDb($distantKey);
|
||||
|
||||
$subSql = substr($subSql, 7);
|
||||
|
||||
$subSql = "SELECT " . $valuesPart . ", " . $subSql;
|
||||
|
||||
$sql = "INSERT INTO `".$relTable."` (".$fieldsPart.") (".$subSql.") ON DUPLICATE KEY UPDATE deleted = '0'";
|
||||
|
||||
if ($this->pdo->query($sql)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function addRelation(IEntity $entity, $relationName, $id = null, $relEntity = null, $data = null)
|
||||
{
|
||||
if (!is_null($relEntity)) {
|
||||
|
||||
@@ -274,6 +274,10 @@ class RDB extends \Espo\ORM\Repository
|
||||
return false;
|
||||
}
|
||||
|
||||
public function massRelate(Entity $entity, $relationName, array $params = array())
|
||||
{
|
||||
return $this->getMapper()->massRelate($entity, $relationName, $params);
|
||||
}
|
||||
|
||||
public function getAll()
|
||||
{
|
||||
|
||||
@@ -237,8 +237,7 @@ class EmailAddress extends \Espo\Core\ORM\Repositories\RDB
|
||||
$emailAddress = $this->getByAddress($address);
|
||||
if ($emailAddress) {
|
||||
$query = "
|
||||
UPDATE entity_email_address
|
||||
SET `deleted` = 1, `primary` = 0
|
||||
DELETE FROM entity_email_address
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
|
||||
@@ -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\Repositories;
|
||||
|
||||
@@ -27,8 +27,8 @@ use Espo\ORM\Entity;
|
||||
class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
{
|
||||
public function getIds($arr = array())
|
||||
{
|
||||
$ids = array();
|
||||
{
|
||||
$ids = array();
|
||||
if (!empty($arr)) {
|
||||
$a = array_map(function ($item) {
|
||||
return $item;
|
||||
@@ -58,19 +58,19 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
|
||||
public function getPhoneNumberData(Entity $entity)
|
||||
{
|
||||
$data = array();
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sql = "
|
||||
SELECT phone_number.name, phone_number.type, entity_phone_number.primary
|
||||
SELECT phone_number.name, phone_number.type, entity_phone_number.primary
|
||||
FROM entity_phone_number
|
||||
JOIN phone_number ON phone_number.id = entity_phone_number.phone_number_id AND phone_number.deleted = 0
|
||||
WHERE
|
||||
entity_phone_number.entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_phone_number.entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
WHERE
|
||||
entity_phone_number.entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_phone_number.entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
entity_phone_number.deleted = 0
|
||||
ORDER BY entity_phone_number.primary DESC
|
||||
";
|
||||
@@ -82,112 +82,111 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
$obj->phoneNumber = $row['name'];
|
||||
$obj->primary = ($row['primary'] == '1') ? true : false;
|
||||
$obj->type = $row['type'];
|
||||
|
||||
|
||||
$data[] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function getByNumber($number)
|
||||
{
|
||||
return $this->where(array('name' => $number))->findOne();
|
||||
}
|
||||
|
||||
|
||||
public function storeEntityPhoneNumber(Entity $entity)
|
||||
{
|
||||
$phone = trim($entity->get('phoneNumber'));
|
||||
$phoneNumberData = null;
|
||||
|
||||
|
||||
if ($entity->has('phoneNumberData')) {
|
||||
$phoneNumberData = $entity->get('phoneNumberData');
|
||||
}
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
|
||||
if ($phoneNumberData !== null && is_array($phoneNumberData)) {
|
||||
$previousPhoneNumberData = array();
|
||||
if (!$entity->isNew()) {
|
||||
$previousPhoneNumberData = $this->getPhoneNumberData($entity);
|
||||
}
|
||||
|
||||
|
||||
$hash = array();
|
||||
foreach ($phoneNumberData as $row) {
|
||||
$key = $row->phoneNumber;
|
||||
if (!empty($key)) {
|
||||
$hash[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'type' => $row->type,
|
||||
'type' => $row->type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$hashPrev = array();
|
||||
foreach ($previousPhoneNumberData as $row) {
|
||||
$key = $row->phoneNumber;
|
||||
if (!empty($key)) {
|
||||
$hashPrev[$key] = array(
|
||||
'primary' => $row->primary ? true : false,
|
||||
'type' => $row->type,
|
||||
'type' => $row->type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$primary = false;
|
||||
}
|
||||
|
||||
$primary = false;
|
||||
$toCreate = array();
|
||||
$toUpdate = array();
|
||||
$toUpdate = array();
|
||||
$toRemove = array();
|
||||
|
||||
|
||||
|
||||
foreach ($hash as $key => $data) {
|
||||
$new = true;
|
||||
$changed = false;
|
||||
|
||||
|
||||
if ($hash[$key]['primary']) {
|
||||
$primary = $key;
|
||||
}
|
||||
|
||||
|
||||
if (array_key_exists($key, $hashPrev)) {
|
||||
$new = false;
|
||||
$changed = $hash[$key]['type'] != $hashPrev[$key]['type'];
|
||||
$changed = $hash[$key]['type'] != $hashPrev[$key]['type'];
|
||||
if ($hash[$key]['primary']) {
|
||||
if ($hash[$key]['primary'] == $hashPrev[$key]['primary']) {
|
||||
$primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($new) {
|
||||
$toCreate[] = $key;
|
||||
}
|
||||
}
|
||||
if ($changed) {
|
||||
$toUpdate[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($hashPrev as $key => $data) {
|
||||
|
||||
foreach ($hashPrev as $key => $data) {
|
||||
if (!array_key_exists($key, $hash)) {
|
||||
$toRemove[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($toRemove as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if ($phoneNumber) {
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `deleted` = 1, `primary` = 0
|
||||
DELETE FROM entity_phone_number
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
phone_number_id = ".$pdo->quote($phoneNumber->id)."
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($toUpdate as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if ($phoneNumber) {
|
||||
@@ -197,16 +196,16 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
$this->save($phoneNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($toCreate as $number) {
|
||||
$phoneNumber = $this->getByNumber($number);
|
||||
if (!$phoneNumber) {
|
||||
$phoneNumber = $this->get();
|
||||
|
||||
|
||||
$phoneNumber->set(array(
|
||||
'name' => $number,
|
||||
'type' => $hash[$number]['type'],
|
||||
));
|
||||
));
|
||||
$this->save($phoneNumber);
|
||||
} else {
|
||||
if ($phoneNumber->get('type') != $hash[$number]['type']) {
|
||||
@@ -216,9 +215,9 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
$this->save($phoneNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$query = "
|
||||
INSERT entity_phone_number
|
||||
INSERT entity_phone_number
|
||||
(entity_id, entity_type, phone_number_id, `primary`)
|
||||
VALUES
|
||||
(
|
||||
@@ -231,7 +230,7 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
|
||||
|
||||
if ($primary) {
|
||||
$phoneNumber = $this->getByNumber($primary);
|
||||
if ($phoneNumber) {
|
||||
@@ -241,12 +240,12 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
WHERE
|
||||
entity_id = ".$pdo->quote($entity->id)." AND
|
||||
entity_type = ".$pdo->quote($entity->getEntityName())." AND
|
||||
`primary` = 1 AND
|
||||
`primary` = 1 AND
|
||||
deleted = 0
|
||||
";
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
|
||||
|
||||
$query = "
|
||||
UPDATE entity_phone_number
|
||||
SET `primary` = 1
|
||||
@@ -259,9 +258,7 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
$entityRepository = $this->getEntityManager()->getRepository($entity->getEntityName());
|
||||
if (!empty($phone)) {
|
||||
@@ -271,11 +268,11 @@ class PhoneNumber extends \Espo\Core\ORM\Repositories\RDB
|
||||
$isNewPhoneNumber = false;
|
||||
if (!$phoneNumberNew) {
|
||||
$phoneNumberNew = $this->get();
|
||||
$phoneNumberNew->set('name', $phone);
|
||||
$phoneNumberNew->set('name', $phone);
|
||||
$defaultType = $this->getEntityManager()->getEspoMetadata()->get('entityDefs.' . $entity->getEntityName() . '.fields.phoneNumber.defaultType');
|
||||
|
||||
|
||||
$phoneNumberNew->set('type', $defaultType);
|
||||
|
||||
|
||||
$this->save($phoneNumberNew);
|
||||
$isNewPhoneNumber = true;
|
||||
}
|
||||
|
||||
@@ -140,7 +140,8 @@
|
||||
"Close": "Close",
|
||||
"Yes": "Yes",
|
||||
"No": "No",
|
||||
"View": "View"
|
||||
"View": "View",
|
||||
"Select All Result": "Select All Result"
|
||||
},
|
||||
"messages": {
|
||||
"notModified": "You have not modified the record",
|
||||
|
||||
@@ -598,6 +598,34 @@ class Record extends \Espo\Core\Services\Base
|
||||
}
|
||||
}
|
||||
|
||||
public function linkEntityMass($id, $link, $where)
|
||||
{
|
||||
$entity = $this->getEntity($id);
|
||||
|
||||
$entityType = $entity->getEntityType();
|
||||
$foreignEntityType = $entity->relations[$link]['entity'];
|
||||
|
||||
if (!$this->getAcl()->check($entity, 'edit')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
if (empty($foreignEntityType)) {
|
||||
throw new Error();
|
||||
}
|
||||
if (!$this->getAcl()->check($foreignEntityType, 'edit')) {
|
||||
throw new Forbidden();
|
||||
}
|
||||
|
||||
if (!is_array($where)) {
|
||||
$where = array();
|
||||
}
|
||||
$params['where'] = $where;
|
||||
|
||||
|
||||
$selectParams = $this->getRecordService($foreignEntityType)->getSelectParams($params);
|
||||
|
||||
return $this->getRepository()->massRelate($entity, $link, $selectParams);
|
||||
}
|
||||
|
||||
public function massUpdate($attributes = array(), $ids = array(), $where = array())
|
||||
{
|
||||
$idsUpdated = array();
|
||||
|
||||
@@ -32,10 +32,22 @@
|
||||
<thead>
|
||||
<tr>
|
||||
{{#if checkboxes}}
|
||||
<th width="5%"><input type="checkbox" class="selectAll"></th>
|
||||
<th width="5%">
|
||||
<input type="checkbox" class="select-all">
|
||||
{{#if checkAllResultEnabled}}
|
||||
<div class="btn-group checkbox-dropdown">
|
||||
<a class="btn btn-link btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="javascript:" data-action="selectAllResult">{{translate 'Select All Result'}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{{/if}}
|
||||
</th>
|
||||
{{/if}}
|
||||
{{#each headerDefs}}
|
||||
<th {{#if width}} width="{{width}}%"{{/if}}{{#if align}} style="text-align: {{align}};"{{/if}}>
|
||||
<th {{#if width}} width="{{width}}%"{{/if}}{{#if align}} style="text-align: {{align}};"{{/if}}>
|
||||
{{#if this.sortable}}
|
||||
<a href="javascript:" class="sort" data-name="{{this.name}}">
|
||||
{{#if this.hasCustomLabel}}
|
||||
|
||||
@@ -27,12 +27,18 @@
|
||||
this.type = type || 'list';
|
||||
this.dateTime = dateTime;
|
||||
|
||||
this.data = this.defaultData = defaultData || {
|
||||
this.emptyData = {
|
||||
textFilter: '',
|
||||
bool: {},
|
||||
advanced: {},
|
||||
};
|
||||
|
||||
if (defaultData) {
|
||||
defaultData = Espo.Utils.clone(defaultData);
|
||||
}
|
||||
|
||||
this.data = this.defaultData = defaultData || this.emptyData;
|
||||
|
||||
this.sanitizeData();
|
||||
};
|
||||
|
||||
@@ -127,7 +133,7 @@
|
||||
},
|
||||
|
||||
loadStored: function () {
|
||||
this.data = this.storage.get(this.type + 'Search', this.scope) || _.clone(this.defaultData);
|
||||
this.data = this.storage.get(this.type + 'Search', this.scope) || Espo.Utils.clone(this.defaultData);
|
||||
this.sanitizeData();
|
||||
return this;
|
||||
},
|
||||
@@ -137,6 +143,7 @@
|
||||
},
|
||||
|
||||
setAdvanced: function (advanced) {
|
||||
this.data = Espo.Utils.clone(this.data);
|
||||
this.data.advanced = advanced;
|
||||
},
|
||||
|
||||
@@ -147,8 +154,15 @@
|
||||
}
|
||||
},
|
||||
|
||||
empty: function () {
|
||||
this.data = Espo.Utils.clone(this.emptyData);
|
||||
if (this.storage) {
|
||||
this.storage.clear(this.type + 'Search', this.scope);
|
||||
}
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
this.data = _.clone(this.defaultData);
|
||||
this.data = Espo.Utils.clone(this.defaultData);
|
||||
if (this.storage) {
|
||||
this.storage.clear(this.type + 'Search', this.scope);
|
||||
}
|
||||
|
||||
@@ -223,13 +223,25 @@ Espo.define('Views.Detail', 'Views.Main', function (Dep) {
|
||||
|
||||
actionSelectRelated: function (data) {
|
||||
var link = data.link;
|
||||
|
||||
if (!this.model.defs['links'][link]) {
|
||||
throw new Error('Link ' + link + ' does not exist.');
|
||||
}
|
||||
var scope = this.model.defs['links'][link].entity;
|
||||
var foreign = this.model.defs['links'][link].foreign;
|
||||
|
||||
var massRelateEnabled = false;
|
||||
if (foreign) {
|
||||
var foreignType = this.getMetadata().get('entityDefs.' + scope + '.links.' + foreign + '.type');
|
||||
if (foreignType == 'hasMany') {
|
||||
massRelateEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
var attributes = {};
|
||||
|
||||
var filters = this.selectRelatedFilters[link] || null;
|
||||
var filters = Espo.Utils.cloneDeep(this.selectRelatedFilters[link]) || null;
|
||||
|
||||
for (var filterName in filters) {
|
||||
if (typeof filters[filterName] == 'function') {
|
||||
@@ -243,6 +255,7 @@ Espo.define('Views.Detail', 'Views.Main', function (Dep) {
|
||||
multiple: true,
|
||||
createButton: false,
|
||||
filters: filters,
|
||||
massRelateEnabled: massRelateEnabled
|
||||
}, function (dialog) {
|
||||
dialog.render();
|
||||
this.notify(false);
|
||||
@@ -255,7 +268,12 @@ Espo.define('Views.Detail', 'Views.Main', function (Dep) {
|
||||
});
|
||||
data.ids = ids;
|
||||
} else {
|
||||
data.id = selectObj.id;
|
||||
if (selectObj.massRelate) {
|
||||
data.massRelate = true;
|
||||
data.where = selectObj.where;
|
||||
} else {
|
||||
data.id = selectObj.id;
|
||||
}
|
||||
}
|
||||
$.ajax({
|
||||
url: self.scope + '/' + self.model.id + '/' + link,
|
||||
|
||||
@@ -59,6 +59,8 @@ Espo.define('Views.Modals.SelectRecords', 'Views.Modal', function (Dep) {
|
||||
this.createButton = this.options.createButton;
|
||||
}
|
||||
|
||||
this.massRelateEnabled = this.options.massRelateEnabled;
|
||||
|
||||
this.buttons = [
|
||||
{
|
||||
name: 'cancel',
|
||||
@@ -66,7 +68,7 @@ Espo.define('Views.Modals.SelectRecords', 'Views.Modal', function (Dep) {
|
||||
onClick: function (dialog) {
|
||||
dialog.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (this.multiple) {
|
||||
@@ -75,9 +77,19 @@ Espo.define('Views.Modals.SelectRecords', 'Views.Modal', function (Dep) {
|
||||
style: 'primary',
|
||||
label: 'Select',
|
||||
onClick: function (dialog) {
|
||||
var list = this.getView('list').getSelected();
|
||||
if (list.length) {
|
||||
this.trigger('select', list);
|
||||
var listView = this.getView('list');
|
||||
|
||||
if (listView.allResultIsChecked) {
|
||||
var where = this.collection.where;
|
||||
this.trigger('select', {
|
||||
massRelate: true,
|
||||
where: where
|
||||
});
|
||||
} else {
|
||||
var list = listView.getSelected();
|
||||
if (list.length) {
|
||||
this.trigger('select', list);
|
||||
}
|
||||
}
|
||||
dialog.close();
|
||||
}.bind(this),
|
||||
@@ -100,6 +112,8 @@ Espo.define('Views.Modals.SelectRecords', 'Views.Modal', function (Dep) {
|
||||
|
||||
collection.maxSize = this.getConfig().get('recordsPerPageSmall') || 5;
|
||||
|
||||
this.collection = collection;
|
||||
|
||||
var searchManager = new SearchManager(collection, 'listSelect', null, this.getDateTime());
|
||||
searchManager.setAdvanced(this.filters);
|
||||
collection.where = searchManager.getWhere();
|
||||
@@ -121,6 +135,7 @@ Espo.define('Views.Modals.SelectRecords', 'Views.Modal', function (Dep) {
|
||||
rowActionsView: false,
|
||||
type: 'listSmall',
|
||||
searchManager: searchManager,
|
||||
checkAllResultEnabled: this.massRelateEnabled
|
||||
}, function (list) {
|
||||
list.once('select', function (model) {
|
||||
this.trigger('select', model);
|
||||
|
||||
@@ -84,7 +84,7 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
this.collection.once('sync', function () {
|
||||
this.notify(false);
|
||||
this.trigger('sort', {sortBy: field, asc: asc});
|
||||
}.bind(this));
|
||||
}, this);
|
||||
this.collection.sort(field, asc);
|
||||
this.deactivate();
|
||||
},
|
||||
@@ -112,18 +112,21 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
var id = target.data('id');
|
||||
this._checkRecord(id, e.currentTarget.checked, target);
|
||||
},
|
||||
'click .selectAll': function (e) {
|
||||
'click .select-all': function (e) {
|
||||
this.checkedList = [];
|
||||
|
||||
if (e.currentTarget.checked) {
|
||||
this.$el.find('input.record-checkbox').prop('checked', true);
|
||||
this.$el.find('.actions-button').removeAttr('disabled');
|
||||
_.each(this.collection.models, function (model) {
|
||||
this.collection.models.forEach(function (model) {
|
||||
this.checkedList.push(model.id);
|
||||
}.bind(this));
|
||||
}, this);
|
||||
|
||||
this.$el.find('.list > table tbody tr').addClass('active');
|
||||
} else {
|
||||
if (this.allResultIsChecked) {
|
||||
this.unselectAllResult();
|
||||
}
|
||||
this.$el.find('input.record-checkbox').prop('checked', false);
|
||||
this.$el.find('.actions-button').attr('disabled', true);
|
||||
this.$el.find('.list > table tbody tr').removeClass('active');
|
||||
@@ -142,6 +145,9 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
var data = $target.data();
|
||||
this.quickRemove(id, data);
|
||||
},
|
||||
'click .checkbox-dropdown [data-action="selectAllResult"]': function (e) {
|
||||
this.selectAllResult();
|
||||
},
|
||||
},
|
||||
|
||||
actions: [],
|
||||
@@ -177,6 +183,10 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
|
||||
checkedList: null,
|
||||
|
||||
checkAllResultEnabled: false,
|
||||
|
||||
allResultIsChecked: false,
|
||||
|
||||
data: function () {
|
||||
var paginationTop = this.pagination === 'both' || this.pagination === true || this.pagination === 'top';
|
||||
var paginationBottom = this.pagination === 'both' || this.pagination === true || this.pagination === 'bottom';
|
||||
@@ -197,6 +207,7 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
rows: this.rows,
|
||||
topBar: paginationTop || this.checkboxes,
|
||||
bottomBar: paginationBottom,
|
||||
checkAllResultEnabled: this.checkAllResultEnabled
|
||||
};
|
||||
},
|
||||
|
||||
@@ -209,6 +220,24 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
this.selectable = _.isUndefined(this.options.selectable) ? this.selectable : this.options.selectable;
|
||||
this.rowActionsView = _.isUndefined(this.options.rowActionsView) ? this.rowActionsView : this.options.rowActionsView;
|
||||
this.showMore = _.isUndefined(this.options.showMore) ? this.showMore : this.options.showMore;
|
||||
|
||||
if ('checkAllResultEnabled' in this.options) {
|
||||
this.checkAllResultEnabled = this.options.checkAllResultEnabled;
|
||||
}
|
||||
},
|
||||
|
||||
selectAllResult: function () {
|
||||
this.allResultIsChecked = true;
|
||||
|
||||
this.$el.find('input.record-checkbox').prop('checked', true).attr('disabled', 'disabled');
|
||||
this.$el.find('input.select-all').prop('checked', true);
|
||||
},
|
||||
|
||||
unselectAllResult: function () {
|
||||
this.allResultIsChecked = false;
|
||||
|
||||
this.$el.find('input.record-checkbox').prop('checked', false).removeAttr('disabled');
|
||||
this.$el.find('input.select-all').prop('checked', false);
|
||||
},
|
||||
|
||||
deactivate: function () {
|
||||
@@ -417,6 +446,8 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
this.noRebuild = null;
|
||||
return;
|
||||
}
|
||||
this.checkedList = [];
|
||||
this.allResultIsChecked = false;
|
||||
this.buildRows(function () {
|
||||
this.render();
|
||||
}.bind(this));
|
||||
@@ -711,6 +742,10 @@ Espo.define('Views.Record.List', 'View', function (Dep) {
|
||||
}
|
||||
$showMore.children('a').removeClass('disabled');
|
||||
|
||||
if (this.allResultIsChecked) {
|
||||
this.$el.find('input.record-checkbox').attr('disabled', 'disabled').prop('checked', true);
|
||||
}
|
||||
|
||||
this.notify(false);
|
||||
}.bind(this);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*
|
||||
* 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.Record.Search', 'View', function (Dep) {
|
||||
|
||||
@@ -65,14 +65,14 @@ Espo.define('Views.Record.Search', 'View', function (Dep) {
|
||||
return this.fields != null && this.moreFields != null;
|
||||
}.bind(this));
|
||||
|
||||
this.boolFilters = this.getMetadata().get('clientDefs.' + this.scope + '.boolFilters') || [];
|
||||
this.boolFilters = Espo.Utils.clone(this.getMetadata().get('clientDefs.' + this.scope + '.boolFilters') || []);
|
||||
|
||||
this._helper.layoutManager.get(this.scope, 'filters', function (list) {
|
||||
this.moreFields = list;
|
||||
this.tryReady();
|
||||
}.bind(this));
|
||||
|
||||
this.presetFilters = _.clone(this.getMetadata().get('clientDefs.' + this.scope + '.presetFilters') || []);
|
||||
this.presetFilters = Espo.Utils.clone(this.getMetadata().get('clientDefs.' + this.scope + '.presetFilters') || []);
|
||||
((this.getPreferences().get('presetFilters') || {})[this.scope] || []).forEach(function (item) {
|
||||
this.presetFilters.push(item);
|
||||
}, this);
|
||||
@@ -224,7 +224,7 @@ Espo.define('Views.Record.Search', 'View', function (Dep) {
|
||||
|
||||
this.presetName = null;
|
||||
|
||||
this.searchManager.reset();
|
||||
this.searchManager.empty();
|
||||
this.loadSearchData();
|
||||
|
||||
this.render();
|
||||
|
||||
@@ -85,7 +85,12 @@ div.list-expanded > ul > li > div.expanded-row > .cell:first-child {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
table.table > thead th a {
|
||||
.list .checkbox-dropdown > a {
|
||||
padding: 0;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
table.table > thead th > a {
|
||||
color: @gray-light;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -52,7 +52,7 @@ class DBMapperTest extends PHPUnit_Framework_TestCase
|
||||
$args = func_get_args();
|
||||
return "'" . $args[0] . "'";
|
||||
}));
|
||||
|
||||
|
||||
|
||||
$this->entityFactory = $this->getMockBuilder('\\Espo\\ORM\\EntityFactory')->disableOriginalConstructor()->getMock();
|
||||
$this->entityFactory->expects($this->any())
|
||||
@@ -64,7 +64,7 @@ class DBMapperTest extends PHPUnit_Framework_TestCase
|
||||
}));
|
||||
|
||||
$this->query = new Query($this->pdo, $this->entityFactory);
|
||||
|
||||
|
||||
$this->db = new MysqlMapper($this->pdo, $this->entityFactory, $this->query);
|
||||
$this->db->setReturnCollection(true);
|
||||
|
||||
@@ -432,6 +432,21 @@ class DBMapperTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertEquals($value, 10);
|
||||
}
|
||||
|
||||
public function testMassRelate()
|
||||
{
|
||||
$query = "INSERT INTO `post_tag` (post_id, tag_id) (SELECT '1', tag.id AS `id` FROM `tag` WHERE tag.name = 'test' AND tag.deleted = '0') ON DUPLICATE KEY UPDATE deleted = '0'";
|
||||
$return = true;
|
||||
$this->mockQuery($query, $return);
|
||||
|
||||
$this->post->id = '1';
|
||||
|
||||
$this->db->massRelate($this->post, 'tags', array(
|
||||
'whereClause' => array(
|
||||
'name' => 'test'
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user