Finance services company. Integration of Sugar CRM, modification of role access system

Deployment of SugarCRM. Customized import of events, students from various format excel files.

Garbage disposal company. Reports for control managers and operators activities, sales volume, customers debts, calculation of salary, bonuses. Data interchange between corporate CRM system ( Bitrix24 ) and accounting systems ( 1С7, 1C8 ). Interaction with telephony ( Asterisk )

Corporate portals support ( bitrix24 ), with CRM, ERP functions. Database, business-processes and documents management optimization, creation of different reports ( financial results, forecast, salary calculation ).

Construction company. TerraSoft CRM modification. Automation of property objects selection, cost calculation ( by bureau of technical inventory information), negotiation of agreements. Payments export to NavisionERP

Industrial safety, products certification Moscow company. Corporate portal support ( bitrix ). Telephony ( OkTell ) integration.

Deploying of vTigerCRM, exchange with 1С accounting databases.

Soft supply company. Development of new e-shop version ( bitrix ). Integration with Google Analytics, Assist, 1С. Chronological prices import. Licenses accounting.

Commercial property management in Saint-Petersburg. Interactive maps of shopping centers "French boulevard", "5 lakes", "CityMall", "London-Mall" etc. frbulvar.ru/magaziny trk-5ozer.ru/magaziny

Autoparts supplier. Uploading actual sales and plans in vTiger CRM from Business Intelligence system ( Pentaho ), and accounting database ( 1С8 ). Presentation dynamics of the sales by managers.

Production of alarm and access control systems company. Customization of Magento shop

Website development ( simplaCms ), integration with ERP ( 1С ), accounting in the context of the characteristics ( sizes, probes ) and suppliers, DB optimization

namespace iteamo\framework;
require_once(__DIR__ . '/core/app.php');
require_once(__DIR__ . '/libs/traits/withSingleton.php');
/**
 *
 */
class app extends core\app{
public function getLib($key = '', $arParams = [], $arOptions = ['checkParent' => true]) {
  $objLib = parent::getLib($key, $arParams);
  //
  if ($arOptions['checkParent'] && empty($objLib)) {
    if ($this->arClass['name'] != __class__) {
      $parentClass = $this->arClass['parent'];
      $objLib = $parentClass::get()->getLib($key, $arParams, $arOptions);
    }
  }
  //
  return $objLib;
}
//
public function getView($key = '', $arData = [], $arOptions = ['checkParent' => false]) {
  $strView = parent::getView($key, $arData);
  //
  if ($arOptions['checkParent'] && is_null($strView)) {
    if ($this->arClass['name'] != __class__) {
        $parentClass = $this->arClass['parent'];
        $strView = $parentClass::get()->getView($key, $arData, $arOptions);
    }
  }
  //
  return $strView;
}
static public function parsePaths($arItem = []) {
  $arItemResult = [];
  foreach($arItem as $key => $value) {
    if (stripos('prefix' . $key, '[')) {
      $fullPath = '[' . substr_replace($key, '][', stripos($key, '['), 1);
      eval("\$arItemResult" . $fullPath . " = \$value;");
    } else $arItemResult[$key] = $value;
  }
  return $arItemResult;
}
request = {
  getDataFromUrl: function(url) {
    var arData = {};
    if(typeof url != 'undefined' && url.indexOf('?')!== -1) {
      var urlSplit = url.split('?');
      var queryString = urlSplit[1];
      var queryParameters = queryString.split('&');
      for(var index=0; index < queryParameters.length; index++) {
      	var queryParam = queryParameters[index];
      	var queryParamComponents = queryParam.split('=');
      	arData[queryParamComponents[0]] = queryParamComponents[1];
      }
    }
    return arData;
  },
  send: function(path, arData, arParams) {
    if (empty(arData)) arParams = {};
    if (empty(arParams)) arParams = {};
    //
    arParamsDefault = {
      dataType: 'json',
      type: 'GET',
    };
    arParams = jQuery.extend(false, {}, arParamsDefault, arParams);
    //
    var aDeferred = jQuery.Deferred();
		var success = function(data, status, jqXHR) {
      aDeferred.resolve(data);
		}
		var error = function(jqXHR, textStatus, errorThrown){
      aDeferred.reject(textStatus, errorThrown);
		}
    //
    var arDataFromUrl = this.getDataFromUrl(path);
    arData = jQuery.extend(false, {}, arData, arDataFromUrl);
    arParams.data = arData;
    arParams.url = path;
    arParams.timeout = 30000;
		arParams.success = success;
		arParams.error = error;
    //
		jQuery.ajax(arParams);
    //
    return aDeferred.promise();
  },
};
  
templater = {
  parse : function(strTemplate, arData) {
    var strParsedTemplate =
      strTemplate.replace(/\{([a-zA-Z0-9 ]*)\}/g, function(m, key) {
        result = arData[key.trim()];
        return result;
    });
    return strParsedTemplate;
  }
};
init: function (context) {
  window.$this = (context != undefined)?context:this;
  $this.cancelDefaultModulePolling();
  $this.parent.init($this);
},
isPageToInitPhoneLinks: function() {
  var result = false;
  var url = window.location.toString();
  if (/(Leads|Contacts|Accounts|PBXManager)/i.test(url)) {
    result = true;
  }
  return result;
},
isPageToInitCallListeningRecords: function() {
  return $this.isPageToInitPhoneLinks();
},
startCallNotify: function(arResult) {
  var params = {'type' : 'error', 'text' :  app.vtranslate('JS_PBX_OUTGOING_FAILURE')};
  if(arResult.status){
    params = {'type' : 'info', 'text' :  app.vtranslate('JS_PBX_OUTGOING_SUCCESS')};
  } else {
    if(!empty(arResult.arErrors)){
      params.text += ': ' + implode(';', arResult.arErrors);
    }
  }
  notification.show(params);
},
namespace iteamo\framework\libs\traits;
use \iteamo\framework\app;
trait withSingleton {
static public function get($arParams = []) {
  static $objInstances = [];
  $class = get_called_class();
  if (empty($objInstances[$class])) {
    $objInstances[$class] = new $class($arParams);
  }
  return $objInstances[$class];
}
}
public function update($arItem = []) {
  $count = false;
  $arItem = $this->prepareData($arItem);
  $arItems = self::filter($this->arItems, $this->arFilters);
  foreach($arItems as $key => $arItem) {
    $this->arItems[$key] = arrays::mergeUpdate($this->arItems[$key], $arItem);
  }
  $count = count($arItems);
  $this->reset();
  //
  return $count;
}


class entity {
use \iteamo\framework\libs\traits\withEntityInterface{
  \iteamo\framework\libs\traits\withEntityInterface::getItem as traitGetItem;
  \iteamo\framework\libs\traits\withEntityInterface::prepareData as traitPrepareData;
  \iteamo\framework\libs\traits\withEntityInterface::filter as traitFilter;
}
public $arCorrespondence = [];
public $table = '';
public $moduleId = 0;
//
private $dbQueryDriver = null;
/**
 *
 */
public function __construct() {
  include_once 'include/Webservices/Utils.php';
  $this->dbQueryDriver = \iteamo\framework\init::getLib('database/queryDrivers/sql');
}
/**
 *
 */
function filter($arFilters = array()) {
  if (!empty($arFilters['anyPhone'])) {
    $objDb = \PearDatabase::getInstance();