shadoll/anemone

Library for Kommo (AmoCRM)


README

Latest Stable Version pipeline status coverage report License

Library for AmoCRM

Install

composer require shadoll/anemone

Поддерживает множественную авторизацию (работу с более чем 1 аккаунт).

Настройка

Библиотека работает с настройками по умолчанию. Вы можете их переопределить через переменные окружения. Описание переменных окружения:

  1. logging:
    • A_LOG_POWER - boolean, включение/отключение логирования запросов (по умолчанию true).
    • A_LOG_DRIVER - enum in 'daily' or 'stack', включение ротации логов по днях или в один файл (по умолчанию daily).
    • A_LOG_PATH - string, путь хранения логов (по умолчанию storage/logs/amo).
    • A_LOG_DAYS - integer, количество файлов для ротвций логов (по умолчанию 14).
    • A_LOG_CROP - boolean, ограничивать развер строк записываемих в лог (по умолчанию true).
  2. cookies:
    • A_COOKIES_PATH - string, путь хранения cookies (по умолчанию storage/cookies/amo).
  3. cache:
    • A_CACHE_POWER - boolean, включение/отключение кеша (по умолчанию true).
    • A_CACHE_PATH - string, путь хранения cache (по умолчанию storage/cache/amo).
    • A_CACHE_T_OTHER - integer, время кеширования (в сек) для ДРУГОЕ (по умолчанию 300).
    • A_CACHE_T_ACCOUNT - integer, время кеширования (в сек) для АККАУНТ (по умолчанию 600).
    • A_CACHE_T_LEAD - integer, время кеширования (в сек) для СДЕЛОК (по умолчанию 60).
    • A_CACHE_T_CUSTOMER - integer, время кеширования (в сек) для ПОКУПАТЕЛЯ (по умолчанию 60).
    • A_CACHE_T_CONTACT - integer, время кеширования (в сек) для КОНТАКТА (по умолчанию 60).
    • A_CACHE_T_COMPANY - integer, время кеширования (в сек) для КОМПАНИИ (по умолчанию 60).
    • A_CACHE_T_TASK - integer, время кеширования (в сек) для ЗАДАЧ (по умолчанию 60).
  4. auth (2020-03-14)

    • A_AUTH_CONNECTOR - string, класс коннектора для oauth2 обновлений токенов (по умолчанию \Anemone\Core\Auth\Connectors\JsonConnector) добавить свои - реализуя интерфейс \Anemone\Contracts\BeAuthConnector.
    • A_AUTH_PATH - string, директория для хранения файла коннектора (по умолчанию storage/oauth/amo).

(Документация была переделана с старой версии anemone - соответственно возможно где-то остались незамечены старые данные при действиях с тем или инными методами. Для болей точного понимания - необходимо ознакомится с официальной документацией амо апи и все станет на места. правки приветствуются!)

Client

Для начала работы с библиотекой - необходимо создать (зарегистрировать) Клиент пользователя:

OAuth2 Client (новый 2020-03-14)

Добавлен новый метод авторизации. Для пользователя библиотеки кроме входных параметров разницы от старого клиента нет. Все версии при инициализации, коллекции клиентов, добавление, удаление клиентов ... так же как и в старом клиенте.

Обязательно при использовании авторизации oauth2 достаточно указать лишь domain и access_token. Но при этом после просрачивания токена (время жизни одни сутки (2020-03-14)) - любой запрос будет сопровождаться выбросом исключения.

$client = new \Anemone\Client([
    "domain" => "jarvis.amocrm.ru",
    "access_token" => "access_token...",
]);

Как описано выше в параметрах .env пункта 5 - есть коннекторы (пока 1 для json) с помощью которых можно обновлять состояния токенов доступа и обновления. Чтобы запускались механизмы обновления и сохранения токенов в автоматическом режиме - необходимо при инициализации клиента добавить больше параметров:


$client = new \Anemone\Client(
    [
        "domain" => "jarvis.amocrm.ru",
        "token_type" => 'Bearer', // optional
        "access_token" => "access_token...",
        "refresh_token" => "refresh_token...",
        "client_secret" => 'f6oD33Bjxhl0ostKULaME7eUQJXrhBMp5v66W5M9nMkki1S2lXVDsLRUaLaBQEcY',
        "client_id" => 'c4c8e476-d280-47d4-b206-b5cc36ba772f',
        'redirect_uri' => 'https://redirect.server.com',
    ]
);

название параметров говорят сами за себя (обьяснению не подлежит, тем кто читал амо документацию).

Client по api key (старый)

$client = new \Anemone\Client([
    "domain" => "jarvis.amocrm.ru",
    "login" => "jarvis@google.com",
    "secret_key" => "jarvis_api_key",
]);

Можно инициализировать несколько клиентов одновременно передав коллекцию авторизационных данных:

$collection = new \Illuminate\Support\Collection([
    [
        "domain" => "jarvis.amocrm.ru",
        "login" => "jarvis@google.com",
        "secret_key" => "jarvis_api_key",
    ],
    [
        "domain" => "jarvis2.amocrm.ru",
        "login" => "jarvis2@google.com",
        "secret_key" => "jarvis2_api_key",
    ],
]);

\Anemone\Client::initClients($collection);

// в любом месте можете получить Клиент по domain
$client = \Anemone\Client::getInstance('jarvis2.amocrm.ru');
// коллекцию Клиентов по domain в массиве
$clients = \Anemone\Client::getInstance(['jarvis2.amocrm.ru', 'jarvis.amocrm.ru']);
// коллекцию всех доступных Клиентов
$clients = \Anemone\Client::getInstance();

При создании обьекта Клиента (new \Anemone\Client(...)) - он не будет доступен в статическом методе getInstance, по необходимости Клиент или коллекцию Клиентов можно будет добавить:

$client = new \Anemone\Client([
    "domain" => "jarvis.amocrm.ru",
    "login" => "jarvis@google.com",
    "secret_key" => "jarvis_api_key",
]);

$client2 = new \Anemone\Client([
    "domain" => "jarvis2.amocrm.ru",
    "login" => "jarvis2@google.com",
    "secret_key" => "jarvis2_api_key",
]);

$collection = new \Illuminate\Support\Collection([
    $client,
    $client2,
]);

\Anemone\Client::addInstance($collection);
// или
\Anemone\Client::addInstance($client);

Сам Клиент не много чего умеет, необходимо делегировать его определенному Инстансу. Пример:

  • $client->account - возвращает \Anemone\Models\Instances\AccountInstance для работы с аккаунтом клиента.
  • $client->leads - возвращает \Anemone\Models\Instances\LeadsInstance для работы с сделками клиента.
  • $client->customers - возвращает \Anemone\Models\Instances\CustomersInstance для работы с покупателями клиента.
  • $client->contacts - возвращает \Anemone\Models\Instances\ContactsInstance для работы с контактами клиента.
  • $client->companies - возвращает \Anemone\Models\Instances\CompaniesInstance для работы с компаниями клиента.
  • $client->tasks - возвращает \Anemone\Models\Instances\TasksInstance для работы с задачами клиента.

и т.д. ...

Инстансы, ModelInstance

Любой Инстанс - обьект интерфейса \Anemone\Contracts\BeInstanceModel, не является моделью, это больше средство для работы с моделями, коллекциями моделей, (прослойка между моделью и сырыми данными с сервера).

Все Инстансы имеют общего предка \Anemone\Models\Instances\ModelInstance.

Инстанс может получать данные (с учетом фильтров), создавать, обновлять, удалять данные.

Работа с коллекциями

В библиотеке почти все массивы данных работают на Коллекциях \Anemone\Core\Collection\Collection. Коллекция наследует \Illuminate\Support\Collection соответственно имеет в своем арсенале большой набор методов для обхода, изменений, фильтраций, трансформаций коллекции. illuminate/support

Модели

Практически все данные являются обьектами. В зависимости от реализации определенного интерфейса имеют свои свойства (\Anemone\Contracts\BeBaseModel, \Anemone\Contracts\BeStaticallyModel, \Anemone\Contracts\BeModel, \Anemone\Contracts\BeCustomField..)

Основные модели могут напрямую работать со своим Инстансом, если его (инстанс) делегировать внутрь модели. (через конструктор или метод setInstance) .

Все модели и коллекции моделей серриализуеми, что позволяет легко просмотреть данные выведя их в окно, или отдать коллекцию Frontend приложению.

Работа с Аккаунтом и AccountInstance

\Anemone\Models\Instances\AccountInstance

Для получения модели аккаунта Клиента:

/**
 * @var \Anemone\Models\Instances\AccountInstance $accountInstance
 * @var \Anemone\Models\Account $account
 */
$accountInstance = $client->account;
$account = $accountInstance->get();

Работа с LeadsInstance, CustomersInstance, ContactsInstance, CompaniesInstance, TasksInstance

Примечание: Некоторые фильтра не работают в связи перехода на v4. После тестирования фильтров компанией АМО СРМ и обновления документации - фильтра будут добавлены (обещают достаточно хорошие фильтра doc)

Для получения моделей (результат будет коллекция моделей \Anemone\Core\Collection\Collection):

// LEADS
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 * @var \Anemone\Core\Collection\Collection $leads
 */
$leadInstance = $client->leads;

// получить все сделки (возвращается коллекция моделей)
$leads = $leadInstance->get();

// получить все сделки с условием (возвращается коллекция моделей, даже если там одна модель, или пустая)
$leads = $leadInstance->find(12345)->get();

$leads = $leadInstance->find([12345, 54321])->get();

$leads = $leadInstance
    ->query('search')
    ->responsibleUser([111111, 222222]) // не работает (в ожидании фильров)
    ->with(['loss_reason_name', 'is_price_modified_by_robot'])
    ->status(55555)
    ->dateModify('13.09.2019', '14.09.2019')
    ->active(false)
    ->unTasks()
    ->limit(40)
    ->get();

$leads = $leadInstance
    ->query('search')
    ->responsibleUser(111111)
    ->with('loss_reason_name')
    ->status([55555, 666666])
    ->dateCreate('12.09.2019', '13.09.2019')
    ->active(true)
    ->noTasks()
    ->limit(100)
    ->page(2)
    ->get();


// CUSTOMERS
/**
 * @var \Anemone\Models\Instances\CustomersInstance $customerInstance
 * @var \Anemone\Core\Collection\Collection $customers
 */
$customerInstance = $client->customers;

// получить все покупатели (возвращается коллекция моделей)
$customers = $customerInstance->get();

// получить все покупатели с условием (возвращается коллекция моделей, даже если там одна модель, или пустая)
$customers = $customerInstance->find(12345)->get();

$customers = $customerInstance->find([12345, 54321])->get();

$customers = $customerInstance
    ->responsibleUser([111111, 222222])
    ->dateModify('13.09.2019', '14.09.2019')
    ->limit(40)
    ->get();

$customers = $customerInstance
    ->responsibleUser(111111)
    ->dateCreate('12.09.2019', '13.09.2019')
    ->limit(100)
    ->get();


// CONTACTS
/**
 * @var \Anemone\Models\Instances\ContactsInstance $contactInstance
 * @var \Anemone\Core\Collection\Collection $contacts
 */
$contactInstance = $client->contacts;

// получить все контакты (возвращается коллекция моделей)
$contacts = $contactInstance->get();

// получить все контакты с условием (возвращается коллекция моделей, даже если там одна модель, или пустая)
$contacts = $contactInstance->find(12345)->get();

$contacts = $contactInstance->find([12345, 54321])->get();

// переход на другую версию
$contactInstance->setVersion('2');

$contacts = $contactInstance
    ->query('search')
    ->responsibleUser([111111, 222222])
    ->limit(40)
    ->get();

// включаем автоматическую адаптацию под версии
$contactInstance->setFixedVersion(false);

$contacts = $contactInstance
    ->query('search')
    ->responsibleUser(111111)
    ->limit(100)
    ->get();


// COMPANIES
/**
 * @var \Anemone\Models\Instances\CompaniesInstance $companyInstance
 * @var \Anemone\Core\Collection\Collection $companies
 */
$companyInstance = $client->companies;

// получить все компании (возвращается коллекция моделей)
$companies = $companyInstance->get();

// получить все компании с условием (возвращается коллекция моделей, даже если там одна модель, или пустая)
$companies = $companyInstance->find(12345)->get();

$companies = $companyInstance->find([12345, 54321])->get();

$companies = $companyInstance
    ->query('search')
    ->responsibleUser([111111, 222222])
    ->limit(40)
    ->get();

$companies = $companyInstance
    ->query('search')
    ->responsibleUser(111111)
    ->limit(100)
    ->get();


// TASKS
/**
 * @var \Anemone\Models\Instances\TasksInstance $taskInstance
 * @var \Anemone\Core\Collection\Collection $tasks
 */
$taskInstance = $client->tasks;

// получить все задачи (возвращается коллекция моделей)
$tasks = $taskInstance->get();

// получить все задачи с условием (возвращается коллекция моделей, даже если там одна модель, или пустая)
$tasks = $taskInstance->find(12345)->get();

$tasks = $taskInstance->find([12345, 54321])->get();

$tasks = $leadInstance
    ->responsibleUser([111111, 222222])
    ->dateModify('13.09.2019', '14.09.2019')
    ->limit(40)
    ->pipe([
        [
            'pipeline' => 12345,
            'statuses' => [11111, 22222, 33333],
        ],
        [
            'pipeline' => 54321,
            'statuses' => [44444, 55555, 66666],
        ],
    ])
    ->get();

$tasks = $leadInstance
    ->responsibleUser(111111)
    ->dateCreate('12.09.2019', '13.09.2019')
    ->limit(100)
    ->withStatus(true)
    ->createdBy([1234567, 543212])
    ->taskType([1, 2])
    ->forTypeEntity('lead')
    ->forEntityID(98765)
    ->get();

Поиск по телефону и email (add 11.12.2019) (временно @deprecated)

Поиск доступен только для контактов и компаний

// CONTACTS
/**
 * @var \Anemone\Core\Collection\Collection $contacts
 */
$contacts = $client->contacts->findByPhone('0988888888');
$contacts = $client->contacts->findByEmail('jarvis@google.com');

/**
 * @var \Anemone\Core\Collection\Collection $companies
 */
$companies = $client->companies->findByPhone('0988888888');
$companies = $client->companies->findByEmail('jarvis@google.com');

Создать любую базовую модель (кроме аккаунта) можно 2 способами:

  • Через соответствующий Инстанс,
  • Через саму модель (по факту это так же через Инстанс ток в обвертке)

Все модели перед созданием (даже одну) нужно поместить в коллекцию (обязательно которая реализует интерфейс \Anemone\Contracts\BeCollection), для этого уже есть \Anemone\Core\Collection\Collection:

// Создание через инстанс
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 */
$leadInstance = $client->leads;

// store lead
$lead = new \Anemone\Models\Lead();
$lead->name = 'Lead stored by Jarvis';
$lead->responsible_user_id = 12345;
// ...

// коллекция сделок
$leadsCollection = new \Anemone\Core\Collection\Collection([
    new \Anemone\Models\Lead(null, [
        'name' => 'Lead stored by other Jarvis',
    ]),
    $lead,
]);

// создание
$status = $leadInstance->save($leadsCollection);

// Остальные сущности (customer, contact, company, task) создаются по аналогии


// Создание из модели
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 */
$leadInstance = $client->leads;

// store lead
$lead = new \Anemone\Models\Lead($leadInstance); // <- при создании через модель инстанс передается в конструктор
// или можно будет позже (но обязательно) через метод
$lead->setInstance($leadInstance);
$lead->name = 'Lead stored by Jarvis';
$lead->responsible_user_id = 12345;
$lead2->attachTags(new Tag(['name' => 'tagByJarvis']));
$lead2->detachTags('tagNotJarvis');
// ...

$lead2 = new \Anemone\Models\Lead($leadInstance, [
    'name' => 'Lead stored by other Jarvis',
]);
$lead2->attachTags(new \Anemone\Core\Collection\Collection([
    new Tag(['name' => 'tagByJarvis']),
    new Tag(['name' => 'tagNotJarvis']),
]));
$lead2->detachTags(['tagNotJarvis', 'tagByJarvis']);
// ...

// создание
$lead->save();
$lead2->save();

// Остальные сущности (customer, contact, company, task) создаются по аналогии

Обновить любую базовую модель (кроме аккаунта) можно 2 способами (если вы получили коллекцию моделей с сервера - нужный Инстанс уже внедрен, из кеша так же внедряется):

  • Через соответствующий Инстанс,
  • Через саму модель (по факту это так же через Инстанс ток в обвертке)

Все модели перед обновлением (даже одну) нужно поместить в коллекцию (обязательно которая реализует интерфейс \Anemone\Contracts\BeCollection), для этого уже есть \Anemone\Core\Collection\Collection:

// Обновление через инстанс
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 */
$leadInstance = $client->leads;

// получим список
$collect = $leadInstance->find([12345, 67890, 09876, 54321])->get();

$collectFiltered = $collect->filter(function($item) {
    return $item->id > 22222;
});

$collectFiltered->each(function($item) {
   $item->name = 'Name change by Jarvis';
});

// обновление
$status = $leadInstance->save($collectFiltered);

// Остальные сущности (customer, contact, company, task) обновляются по аналогии


// Обновление из модели
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 */
$leadInstance = $client->leads;

// получим список
$collect = $leadInstance->find([12345, 67890, 09876, 54321])->get();

$collectFiltered = $collect->filter(function($item) {
    return $item->id > 22222;
});

// обновление
$collectFiltered->each(function($item) {
    $item->name = 'Name change by Jarvis';
    $item->save();
});

// Остальные сущности (customer, contact, company, task) обновляются по аналогии

Deprecated

Удалить любую базовую модель (кроме аккаунта) можно 2 способами (если вы получили коллекцию моделей с сервера - нужный Инстанс уже внедрен, из кеша так же внедряется):

  • Через соответствующий Инстанс,
  • Через саму модель (по факту это так же через Инстанс ток в обвертке)

Как описано выше удалить модель можно только в версии _.

Все модели перед удалением (даже одну) нужно поместить в коллекцию (обязательно которая реализует интерфейс \Anemone\Contracts\BeCollection), для этого уже есть \Anemone\Core\Collection\Collection:

// Удаление через инстанс
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 */
$leadInstance = $client->leads;

// получим список
$collect = $leadInstance->find([12345, 67890, 09876, 54321])->get();

$collectFiltered = $collect->filter(function($item) {
    return $item->id > 22222;
});

$collectFiltered->each(function($item) {
   $item->name = 'Name change by Jarvis';
});

// переключаемся на версию _
$leadInstance->setVersion('_');

// удаление
$status = $leadInstance->delete($collectFiltered);

// Остальные сущности (customer, contact, company, task) удаляются по аналогии


// Удаление из модели
/**
 * @var \Anemone\Models\Instances\LeadsInstance $leadInstance
 */
$leadInstance = $client->leads;

// получим список
$collect = $leadInstance->find([12345, 67890, 09876, 54321])->get();

$collectFiltered = $collect->filter(function($item) {
    return $item->id > 22222;
});

// переключаемся на версию _
$leadInstance->setVersion('_');

// удаление
$collectFiltered->each(function($item) use ($leadInstance) {
    $item->name = 'Name change by Jarvis';
    $item->setInstance($leadInstance);
    $item->delete();
});

// Остальные сущности (customer, contact, company, task) удаляются по аналогии

Получить количество сущностей (add: 24.10.2019)

Следующие сущности поддерживают получение числа количества сущностей (в некоторых случаях поддерживается фильтр):

  • \Anemone\Models\Instances\LeadsInstance
  • \Anemone\Models\Instances\CustomersInstance
  • \Anemone\Models\Instances\ContactsInstance
  • \Anemone\Models\Instances\CompaniesInstance
  • \Anemone\Models\Instances\TasksInstance

$count = $client->leads->count();
$count = $client->customers->count();
$count = $client->contacts->count();
$count = $client->companies->count();
$count = $client->tasks->count();

// пример по с фильтром
$count = $client->leads->find('копия')->count();

поиск производится с автоматическим переключением на версию _ (вручную переключать надобность отсутствует), после получения количества - версия возвращается в ту которая была до запроса количества (автоматически). По этому фильтра будут работать только те которые поддерживает версия _.

Работа с примечаниями (События) (add: 16.10.2019)

Есть 2 способа работы с примечаниями:

  • через чужие инстансы (\Anemone\Models\Instances\LeadsInstance, ...) модели которых поддерживают Примечания - СДЕЛКИ, ПОКУПАТЕЛИ, КОНТАКТЫ, КОМПАНИИ, ЗАДАЧИ. В этом случае вы будете работать с примечаниями в рамках всех Сделок, Компаний, ....
  • через конкретную модель (\Anemone\Models\Lead, ...) которая поддерживает примечания (см. п.1). В этом случае вы будете работать с примечаниями конкретной сущности (но вы можете это поведение изменить).

Получение примечаний (список):

/** Список всех примечаниий всех сделок
 * @var \Anemone\Core\Collection\Collection $collection
 * */
$collection = $client->leads->notes()->get();
// то же с фильтрацией
$collection = $client->leads->notes()->entityID(106727)->noteType(4)->limit(10, 50)->get();

// список для конкретной модели
/**
 * @var \Anemone\Models\Lead $lead
 */
$lead = $client->leads->get()->first();
$collection = $lead->notes()->get();
// фильтрацию также можно добавить (метод entityID(__id__) сменить id модели)

Создание примечаний:

// инициализируем модель примечания
$note1 = new \Anemone\Models\Note([
    'params' => [
        'text' => 'notice for Jarvis',
    ],
    'element_id' => 106727,
    'note_type' => 'invoice_paid',
]);
$note2 = new \Anemone\Models\Note([
    'params' => [
        'text' => 'notice for Google',
    ],
    'element_id' => 106733,
    'note_type' => 'invoice_paid',
]);
$collect1 = new \Anemone\Core\Collection\Collection([
    $note1,
    $note2,
]);
// store
$status = $client->leads->notes()->save($collect1);

// для конкретной модели
// инициализируем модель примечания (element_id тут не обязателен)
$note3 = new \Anemone\Models\Note([
    'params' => [
        'text' => 'notice for Jarvis',
    ],
    'note_type' => 'invoice_paid',
]);
$note4 = new \Anemone\Models\Note([
    'params' => [
        'text' => 'notice for Google',
    ],
    'note_type' => 'invoice_paid',
]);

$collect2 = new \Anemone\Core\Collection\Collection([
    $note3,
    $note4,
]);

/**
 * @var \Anemone\Models\Lead $lead
 */
$lead = $client->leads->get()->first();
$status = $lead->notes()->save($collect2);

Обновление примечаний:

// получить все
$collect = $client->leads->notes()->noteType(4)->get();
$collect->each(function(\Anemone\Models\Note $item) {
    $item->setText($item->getText() . ' (updated)');
});
// update
$status = $client->leads->notes()->save($collect);

// для конкретной модели
/**
 * @var \Anemone\Models\Lead $lead
 */
$lead = $client->leads->get()->first();
$collect2 = $lead->notes()->noteType(13)->get();
$collect2->each(function(\Anemone\Models\Note $item) {
    // any actions
});
$status = $lead->notes()->save($collect2);

// можно совмещать обновление и создание примечаний (как и в любой другой модели)
$collect3 = $client->leads->notes()->noteType('invoice_paid')->get();
$collect3->each(function(\Anemone\Models\Note $item) {
    // any actions
});
$collect3->add(
    new \Anemone\Models\Note([
        'params' => [
            'text' => 'notice for Google',
        ],
        'element_id' => 106733,
        'note_type' => 'invoice_paid',
    ])
);
// update and store
$status = $client->leads->notes()->save($collect3);

Работа с Неразобранное (31.10.2019)

Для работы с Неразобранное есть инстанс \Anemone\Models\Instances\IncomingLeadsInstance.

Возможности:

  • Получить список всех Неразобранное (с необходимыми фильтрами)
  • Получить Summary Неразобранное
  • Создать Неразобранное (типа sip, и form)
  • Принятие неразобранных заявок
  • Отклонение неразобранных заявок

Получить список всех Неразобранное


/** Список всех Неразобранное
 * @var \Anemone\Core\Collection\Collection $collection
 * */
$collection = $client->incomingLeads->get();

/** Список всех Неразобранное с фильтров выборки
 * @var \Anemone\Core\Collection\Collection $collection
 * */
$collection = $client->incomingLeads->categories(['sip', 'mail'])->limit(250)->get();

Получить Summary Неразобранное


/** Summary Неразобранное
 * @var array $data
 * */
$data = $client->incomingLeads->summary();

/** Summary Неразобранное с периодом
 * @var array $data
 * */
$data = $client->incomingLeads->summary(1572514534, 1572522193);

Создать Неразобранное (можно через Инстанс или через модель \Anemone\Models\IncomingLead)


/** Создать Неразобранное через Инстанс
 * @var array $data
 * */
$IL1 = new \Anemone\Models\IncomingLead($client->incomingLeads, [
    'source_name' => 'souu',
    'source_uid' => 'source_uidsource_uid',
    'metadata' => [
        'form_name' => 'form_name',
        'form_id' => 'form_id',
        'form_page' => 'form_page',
        'ip' => '127.0.0.1',
        'form_sent_at' => time(),
    ]
]);

$IL1->created_at = 1455564344;
$IL1->metadata = [
    'form_id' => 654321,
    'form_page' => 'link_to_two',
];

$IL2 = clone $IL1;
$IL2->metadata = [
    'form_id' => 234567,
    'form_page' => 'super link',
];

$ILCall = new \Anemone\Models\IncomingLead($client->incomingLeads);
$ILCall->metadata = [
    'to' => 123456,
    'from' => '0989898999',
    'date_call' => 1572514534,
    'service_code' => 'binotel',
];

$collect = new \Anemone\Core\Collection\Collection([
    $IL1,
    $IL2,
    $ILCall,
]);

/** Создание
 * @var bool $status
 * */
$status = $client->incomingLeads->save($collect);


// Создание через модель
$IL3 = new \Anemone\Models\IncomingLead($client->incomingLeads, [
    'metadata' => [
        'form_id' => 123456,
        'form_page' => 'link_to_one',
    ],
]);
/** Создание
 * @var bool $status
 * */
$status = $IL3->save();

Принятие неразобранных заявок (через Инстанс (массово) или модель)


/** Список всех Неразобранное с фильтров выборки
 * @var \Anemone\Core\Collection\Collection $collection
 * */
$collection = $client->incomingLeads->categories(['form'])->get();

/**
 * @var array $data результат
 * */
// Принятие Через модель
$data = $collection->first()->accept();
// установить пользователя который принял
$data = $collection->first()->accept(12345);
// установить этап воронки
$data = $collection->first()->accept(null, 77665544);
// установить пользователя который принял и этап воронки
$data = $collection->first()->accept(12345, 77665544);


/**
 * @var \Anemone\Core\Collection\Collection $data коллекция результатов
 * */
// через инстанс
$data = $client->incomingLeads->accept($collection);
// установить пользователя который принял
$data = $client->incomingLeads->accept($collection, 12345);
// установить этап воронки
$data = $client->incomingLeads->accept($collection, null, 77665544);
// установить пользователя который принял и этап воронки
$data = $client->incomingLeads->accept($collection, 12345, 77665544);

Отклонение неразобранных заявок (через Инстанс (массово) или модель)


/** Список всех Неразобранное с фильтров выборки
 * @var \Anemone\Core\Collection\Collection $collection
 * */
$collection = $client->incomingLeads->categories(['sip'])->get();

/**
 * @var array $data результат
 * */
// Отклонение Через модель
$data = $collection->first()->decline();
// установить пользователя который отклонил
$data = $collection->first()->decline(12345);

/**
 * @var \Anemone\Core\Collection\Collection $data коллекция результатов
 * */
// Отклонение через инстанс
$data = $client->incomingLeads->decline($collection);
// установить пользователя который отклонил
$data = $client->incomingLeads->decline($collection, 12345);

Работа с API Телефонии (add 2020-02-05)

Можно только создать звонок


$client->calls->save(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\Call(
                null, [
                        'phone_number' => '380980000001',
                        'direction' => 'inbound',
                        'uniq' => 'uniquniquniquniq',
                        'duration' => '134',
                        'source' => 'tomato1',
                        'call_status' => '4',
                        'call_result' => 'какойто результат звонка',
                        'link' => 'http://link-to-call',
                        'responsible_user_id' => '3621055',
                        'created_by' => '3621055',
                    ]
            ),
        ]
    )
);

Работа с Событиями (add 2020-02-05)

Доступно только получить список событий (Коллекция моделей Anemone\Models\Event)


$collect = $client->events
    ->limit(1)
    ->with('contact_name')
    ->valueAfter(['leads_statuses' => [['pipeline_id' => 2274433, 'status_id' => 31525672]]])
    ->get();

// типы событий
$collection = $client->events->types();

Работа с WebHooks (add 2020-02-06)

Список WebHooks


$collection = $client->webhooks->get();


Создание/обновление WebHooks (создание и удаление временно недоступно)


$webhook = new \Anemone\Models\Webhook($client->webhooks, [
    'url' => 'https://link.for.hook'
]);

$webhook
    ->addCompany()
    ->addContact()
    ->deleteCustomer()
    ->deleteLead(true)
    ->deleteCustomer()
    ->addContact(false);

$webhook->save();

// или несколько штук
$client->webhooks->save(new \Anemone\Core\Collection\Collection([
    $webhook,
]));

Удаление WebHooks


$collection = $client->webhooks->get();

$collection->first()->delete();

// или несколько штук
$client->webhooks->delete($collection);

Работа с воронками и этапами воронок

Воронки и этапы существуют только в сделках

// коллекция воронок (моделей Anemone\Models\Pipeline)
$collect = $client->leads->pl();

// создать/обновить воронок
$client->leads->savePL(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\Pipeline(
                ['name' => 'Gg', 'is_main' => false, 'is_unsorted_on' => true, 'sort' => 3, '_embedded' => []]
            ),
            new \Anemone\Models\Pipeline(['name' => 'New name', 'id' => 3256180]),
        ]
    )
);

// удалить воронки
$client->leads->deletePL(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\Pipeline(
                ['name' => 'Gg', 'is_main' => false, 'is_unsorted_on' => true, 'sort' => 3]
            ),
            new \Anemone\Models\Pipeline(['name' => 'New name', 'id' => 3313405]),
        ]
    )
);
// первую пропустит, так как нет id


// коллекция этапов воронки (моделей Anemone\Models\StatusPL)
$collect = $client->leads->statusesPL(123456); // id воронки

// создать/обновить этапы
$client->leads->saveStatusesPL(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\StatusPL(
                ['name' => 'Gg', 'sort' => 3]
            ),
            new \Anemone\Models\StatusPL(['name' => 'New name', 'id' => 32936836]),
        ]
    ),
    3256180
);
// первый создаст, второй обновит

// удалить этапы
$client->leads->deleteStatusesPL(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\StatusPL(
                ['name' => 'Gg', 'sort' => 3]
            ),
            new \Anemone\Models\StatusPL(['name' => 'New name', 'id' => 32936836]),
        ]
    ),
    3256180
);
// первую пропустит

Работа с тегами

Теги представлены так же обьектами \Anemone\Models\Tag, получить коллекцию \Anemone\Core\Collection\Collection методом tags()

Добавить (открепить) тег(и) в (из) сущность (4 способа):

// ...
$lead->attachTags('new tag');
$lead->attachTags(['new tag1', 'new tag2']);

$tag1 = new \Anemone\Models\Tag();
$tag1->name = 'tagByJarvis';

$tag2 = new \Anemone\Models\Tag(['name' => 'tagByJarvisOver']);

$lead->attachTags($tag1);
$lead->attachTags(new \Anemone\Core\Collection\Collection([
    $tag1,
    $tag2,
]));

// метод detachTags работает точно так же как и attachTags ток открепляет тег(и))

Список всех тегов (add 12.11.2019)

теги можно получить из инстанса которы поддерживает теги (LeadsInstance, CustomersInstance, ContactsInstance, CompaniesInstance)

// ...
/**
 * @var \Anemone\Core\Collection\Collection<\Anemone\Models\Tag> $collection
 */
$collection = $client->leads->tags()->get();
$collection = $client->customers->tags()->get();
$collection = $client->contacts->tags()->get();
$collection = $client->companies->tags()->get();

Особенность: необходимо для получения списка тегов - переключиться на новую версию амо срм

Создание тега для типа сущностей (не для конкретной сущности)

$client->leads->tags()->save(
    new \Anemone\Core\Collection\Collection([
        new \Anemone\Models\Tag(['name' => 'yyyy'])]
    )
);

Работа с пользователями (2020-06-03)

// список (коллекция моделей Anemone\Models\User)
$collect = $client->users->get();

// сохранить (добавить, изменить)
$client->users->save(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\User(
                null,
                [
                    'name' => 'new user',
                    'email' => 'ddddddfff4R@gmail.com',
                    'password' => 'ddddddfff4R@gmail.com'
                ]
            ),
        ]
    )
);

Работа с кастомными полями

Кастомные поля как и теги так же являются обьектами интерфейса \Anemone\Contracts\BeCustomField и гранятся в коллекции \Anemone\Core\Collection\Collection в свойстве custom_fields_values

Получение коллекцию или конкретный кастомное поле:

// коллекция кастомных полей
$collect = $lead->custom_fields_values;

// коллекция кастомных полей с собственной функцией фильтрации
// необязательным феноменом этой функции - можете изменять значения каждого КП (кастомное поле)
// перед сохранением
$collectFiltered = $lead->cf(function(\Anemone\Contracts\BeCustomField $field) {
    return $field->id != 12345;
});

// получить КП по ID
$oneCF = $lead->cf(12345);

// получить КП по имени
$oneCF = $lead->cf('jarvis');

Устанавка, изменение значений КП:

// получить КП по ID (для примера)
// логично что он не будет одновременно всеми разновидностями \Anemone\Contracts\BeCustomField
$oneCF = $lead->cf(12345);

/**
 * @var \Anemone\Models\CF\UrlCustomField $urlCF
 */
$urlCF = $oneCF;
$urlCF->setValue('https://google.com');
$value = $urlCF->getValue();

/**
 * @var \Anemone\Models\CF\TextCustomField $textCF
 */
$textCF = $oneCF;
$textCF->setValue('I Jarvis!');
$value = $textCF->getValue();

/**
 * @var \Anemone\Models\CF\TextareaCustomField $textareaCF
 */
$textareaCF = $oneCF;
$textareaCF->setValue('I Long King Jarvis!');
$value = $textareaCF->getValue();

/**
 * @var \Anemone\Models\CF\StreetAddressCustomField $streetAddressCF
 */
$streetAddressCF = $oneCF;
$streetAddressCF->setValue('Kyiv city');
$value = $streetAddressCF->getValue();

/**
 * @var \Anemone\Models\CF\SelectCustomField $selectCF
 */
$selectCF = $oneCF;
$selectCF->setValue('Jarvis in ENUM');
$value = $selectCF->getValue();

/**
 * @var \Anemone\Models\CF\RadiobuttonCustomField $radioCF
 */
$radioCF = $oneCF;
$radioCF->setValue('Jarvis in ENUM');
$value = $radioCF->getValue();

/**
 * @var \Anemone\Models\CF\OrgLegalNameCustomField $olnCF
 */
$olnCF = $oneCF;
$olnCF->setValue(['Jarvis org 1', 'Jarvis org 2']);
$value = $olnCF->getValue();

/**
 * @var \Anemone\Models\CF\NumericCustomField $numericCF
 */
$numericCF = $oneCF;
$numericCF->setValue(911);
$value = $numericCF->getValue();

/**
 * @var \Anemone\Models\CF\MultiTextCustomField $emailOrPhoneCF
 */
$emailOrPhoneCF = $oneCF;
$emailOrPhoneCF->setValue(911, 'WORK'); // 'HOME', 'OTHER' ... то что в АМО (если упустить второй параметр - по умолчанию 'WORK')
$value = $emailOrPhoneCF->getValue();

/**
 * @var \Anemone\Models\CF\MultiSelectCustomField $multiselectCF
 */
$multiselectCF = $oneCF;
$multiselectCF->setValue(['Jarvis in ENUM', 'Google in ENUM']);
$value = $multiselectCF->getValue();

/**
 * @var \Anemone\Models\CF\DateCustomField $dateCF
 */
$dateCF = $oneCF;
$dateCF->setValue('12-09-2019');
$value = $dateCF->getValue();

/**
 * @var \Anemone\Models\CF\CheckboxCustomField $checkboxCF
 */
$checkboxCF = $oneCF;
$checkboxCF->setValue(true);
$value = $checkboxCF->getValue();

/**
 * @var \Anemone\Models\CF\BirthdayCustomField $birthdayCF
 */
$birthdayCF = $oneCF;
$birthdayCF->setValue('05-12-2019');
$value = $birthdayCF->getValue();

/**
 * @var \Anemone\Models\CF\SmartAddressCustomField $smartAddressCF
 */
$smartAddressCF = $oneCF;
// v1
$smartAddressCF->setValue(function(\Anemone\Models\CF\Helpers\SybSmartAddress $subSmartAddress) {
    $subSmartAddress->address_line_1 = 'Line for jarvis';
    $subSmartAddress->address_line_2 = 'Line for google';
    $subSmartAddress->city = 'Kyiv';
    $subSmartAddress->state = 'Other';
    $subSmartAddress->zip = 03151;
    $subSmartAddress->country = 'UA';
});
// v2
$smartAddressCF->setValue([
    'address_line_1' => 'Line for jarvis',
    'address_line_2' => 'Line for google',
    'city' => 'Kyiv',
    'state' => 'Other',
    'zip' => 03151,
    'country' => 'UA',
]);
// get \Anemone\Models\CF\Helpers\SybSmartAddress
$value = $smartAddressCF->getValue();
// get array
$value = $smartAddressCF->getValue(true);

/**
 * @var \Anemone\Models\CF\LegalEntityCustomField $legalCF
 */
$legalCF = $oneCF;
// v1
$legalCF->setValue(function (array $values) {
    $newLE = new \Anemone\Models\CF\Helpers\SubLegalEntity();
    $newLE->name = 'OOO Google inc.';
    $newLE->vat_id = 12345;
    $newLE->kpp = 54321;
    $values[] = $newLE;
    // ++
    return $values; // <- required
});
// v2
$legalCF->setValue([
    'name' => 'OOO Google inc.',
    'vat_id' => 12345,
    'kpp' => 54321,
]);
// get array in objects Anemone\Models\CF\Helpers\SubLegalEntity
$value = $legalCF->getValue();
// get arrays
$value = $legalCF->getValue(true);

Список доступных кастомных полей:

// Поля можно получить для каждого типа сущности отдельно

$collect = $leadsInstance->cf(); // для сделок
$collect = $contactsInstance->cf(); // для контактов
$collect = $customersInstance->cf(); // для покупателей
$collect = $companiesInstance->cf(); // для сделоккомпаний

Манипуляции с кастомными полями осуществляются через инстанс сущносты которые поддерживают КП

Добавление нового кастомного поля:


$fieldMultiSelect = new \Anemone\Models\CF\MultiSelectCustomField();
$fieldMultiSelect->name = 'More jarvis';
$fieldMultiSelect->enums = [
    [
        'value' => 'jarvis',
    ],
    [
        'value' => 'google',
    ],
];

$leadsInstance->saveCF(new \Anemone\Core\Collection\Collection([
    new \Anemone\Models\CF\TextCustomField(['name' => 'field by jarvis']),
    $fieldMultiSelect,
]));

Удаление существуещего кастомного поля :

// получаем КП относящихся к сделкам (коллекция)
// сначала получили модель Аккаунт, а с нее custom_fields
$leadCFCollect = $leadsInstance->cf();

$leadCFCollectFiltered = $leadCFCollect->filter(function(\Anemone\Contracts\BeCustomField $cf) {
    return $cf->type == 'radiobutton'; // все radiobutton
});

$leadsInstance->deleteCF($leadCFCollectFiltered);

Изменение существуещего кастомного поля:


// получаем КП относящихся к сделкам (коллекция)
$leadCFCollect = $leadsInstance->cf();

$leadCFCollect->each(function(\Anemone\Contracts\BeCustomField $cf) {
    if ($cf->type == 'radiobutton') { // все radiobutton
        $cf->name = 'mega companies';
        $cf->enums = [
            [
                'value' => 'jarvis',
            ],
            [
                'value' => 'google',
            ],
            [
                'value' => 'adobe',
            ],
        ];
    }
});

$leadsInstance->saveCF($leadCFCollect);

Добавлена возможность управлять группами кастомных полей

Список групп (Коллекция моделей Anemone\Models\GroupCF)


$collect = $cl->leads->groupsCF();

// аналогично другие сущности

Создание, обновление, удаление

// создание
$cl->leads->saveGroupCF(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\GroupCF(['name' => 'HH']),
            new \Anemone\Models\GroupCF(['name' => 'GG77']),
        ]
    )
);

// обновление
$cl->leads->saveGroupCF(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\GroupCF(['id' => 'leads_81281590768026', 'name' => 'HH']),
            new \Anemone\Models\GroupCF(['id' => 'leads_75941590767796', 'name' => 'GG77']),
        ]
    )
);

// удаление
$cl->leads->deleteGroupCF(
    new \Anemone\Core\Collection\Collection(
        [
            new \Anemone\Models\GroupCF(['id' => 'leads_81281590768026', 'name' => 'HH']),
            new \Anemone\Models\GroupCF(['id' => 'leads_75941590767796', 'name' => 'GG77']),
        ]
    )
);

Связанные модели

Некоторые модели (Lead, Customer...) могут иметь связь с другими моделями, чтобы их получить необходимо

// получить контакты привязанные к сделке (коллекция Contact)
$collectOfContacts = $lead->contacts();

$idsOfContacts = $lead->contactsId();
$idOfMainContact = $lead->mainContactId();

// получить компанию привязанную к сделке (модель Company)
$company = $lead->company();

// получить сделки привязанные к контакту (коллекция Lead)
$collectOfLeads = $contact->leads();

// получить компании привязанные к контакту (коллекция Customer)
$collectOfCustomers = $contact->customers();

// .. аналогично и в других моделях

Прикрепить модели метод - link,

Все работают одинаково и имеют по 4 варианта использования


$lead->link($collectOfContacts);

// так же для остальных сущностей

Открепить связанные модели метод - unlink,

// получить контакты привязанные к сделке (коллекция Contact)
$collectOfContacts = $lead->contacts();

$lead->unlink($collectOfContacts);

// так же для остальных сущностей

// получить задачи привязанные к контакту (аналогично сделке, компании, покупателю) (коллекция Task) $collectOfTasks = $contact->tasks();

Extensions (Дополнения)

Клиент NotApiClient

В некоторых случаях доступ к определенным методам АМО CRM не доступен по авторизации из API. Для этих целей появился \Anemone\Extensions\NotApiClient. На вход конструктора он принимает массив авторизационных данных:

{
  "user_login": "jarvis@google.com",
  "user_password": "password_for_jarvis"
}

и вторым параметром - домен.

Получите \Anemone\Extensions\Core\Services\HttpClientService (если надо) для выполнение своих нестандартных запросов.

$unClient = new \Anemone\Extensions\NotApiClient([
    'user_login' => 'jarvis@google.com',
    'user_password' => 'password_for_jarvis',
], 'jarvis.amocrn.ru');

/**
 * @var \Anemone\Extensions\Core\Services\HttpClientService $httpClientService
 * */
$httpClientService = $unClient->getHttpClientService();

$httpClientService->get(/*...*/);
$httpClientService->post(/*...*/);
$httpClientService->patch(/*...*/);
$httpClientService->delete(/*...*/);

Поддержка сервисов для этого клиента будет увеличиваться по мере....

SERVICE: Partners (Партнерский кабинет)

Сервис Anemone\Extensions\Partners\PartnerService дает возможность получать (в неких случаях и создавать) данные из (в) партнерского кабинета.

Для авторизации в партнерском кабинете - пользователь который инициализирует \Anemone\Extensions\NotApiClient должен быть зарегистрирован в партнерском кабинете. В противном случае - вы не сможете работать с Anemone\Extensions\Partners\PartnerService.

Возможности:

  • ПОлучить список всех своих партнерских пользователей (аккаунтов).
  • Получить конкретного своего партнерского пользователя (аккаунта).
  • Получить более детальную информацию о партнерском пользователе (аккаунте).
  • Зарегистрировать нового партнерского пользователя (аккаунта).
  • Продлить триальный перриод для своего партнерского пользователя (аккаунта).
  • Посмотреть подписку для любого пользователя (аккаунта) по ID (Информации не много).
$unClient = new \Anemone\Extensions\NotApiClient([
    'user_login' => 'jarvis@google.com',
    'user_password' => 'password_for_jarvis',
], 'jarvis.amocrm.ru');

/**
 * @var Anemone\Extensions\Partners\PartnerService $partnerService
 * */
$partnerService = $unClient->partnerService;

/**
 * @var \Illuminate\Support\Collection $collection
 * */
// Все партнеры
$collection = $partnerService->partnersList();
// Активные на триальной подписке партнеры
$collection = $partnerService->partnersList('trial');
// НЕАктивные приостановлены партнеры
$collection = $partnerService->partnersList('expired');
// Активные на платной подписке партнеры
$collection = $partnerService->partnersList('paid');

/**
 * @var \Anemone\Extensions\Partners\Models\Partner $one
 * */
// Модель по ID (с чужими ID работать не будет)
$one = $partnerService->partnerById(123456);

/**
 * @var array $tariffData
 * */
// Тариф аккаунта по ID (со всеми ID)
$tariffData = $partnerService->tariffData(123456);


// Зарегистрировать партнерского клиента
$partner = new \Anemone\Extensions\Partners\Models\Partner([
    'name' => 'newJarvis',
    'email' => 'jarvis@google.com',
    'phone' => '123456', // optional
], $unClient);

/**
 * @var \Anemone\Extensions\Partners\Models\Partner $storedPartner
 * */
// Регистрация
$storedPartner = $partner->store(555555); // partner ID

// Продлить триальный перриод
$onePartner = $collection->first();
$changedPartner = $onePartner->prolong(7); // один раз можно продлить
$changedPartner = $onePartner->prolong(14); // один раз можно продлить
// или
$changedPartner = $onePartner->prolong(7)->prolong(14);

// В противном случе -> ловите исключения

SERVICE: Widgets (Работа с виджетами)

Сервис \Anemone\Extensions\Widgets\WidgetsService

Сервис дает возможность:

  • Получить список всех виджетов, или с фильтрацией по категориям 'phone', 'mail', 'site', 'chats', 'useful', 'recommended', 'own_integrations',
  • Получить список ApiWidget - виджеты которые находятся в разделе API.
  • Создать новый виджет в аккаунте.
  • упаковать в архив виджет.

Получить список всех виджетов, или с фильтрацией по категориям:

// создать любой клиент
$clientAPI = new \Anemone\Client([
    "domain" => "jarvis.amocrm.ru",
    "login" => "jarvis@google.com",
    "secret_key" => "b2f0414de331177268cb09f720a0b36a076fe88e",
]);
// или
$unClient = new \Anemone\Extensions\NotApiClient([
    'user_login' => 'jarvis.amocrm.ru',
    'user_password' => 'zzfOPa7P',
], 'jarvis.amocrm.ru');

$widgetService = new \Anemone\Extensions\Widgets\WidgetsService($clientAPI); // или $unClient

/**
 * @var Illuminate\Support\Collection<\Anemone\Extensions\Widgets\Models\Widget|\Anemone\Extensions\Widgets\Models\Integration> $collection
 * */
// все виджеты кроме 'recommended', 'own_integrations'
$collection = $widgetService->all();

// виджеты с фильтрацией
$collection = $widgetService->all('mail');

Получить список ApiWidget - виджеты которые находятся в разделе API:

// ... $widgetService = new ...

/**
 * @var Illuminate\Support\Collection<\Anemone\Extensions\Widgets\Models\ApiWidget> $collection
 * */
// все API виджеты
$collection = $widgetService->allApi();

// или
$collection = \Anemone\Extensions\Widgets\Models\ApiWidget::all($clientAPI->getQueryService()); // или $unClient->getQueryService()

Создать новый виджет в аккаунте:

// ... $widgetService = new ...

/**
 * @var \Anemone\Extensions\Widgets\Models\ApiWidget $apiWidget
 * */
$apiWidget = $widgetService->storeApiWidget('code_new_widget');

// или
$apiWidget = new \Anemone\Extensions\Widgets\Models\ApiWidget(
    ['code' => 'code_new_widget'],
    $clientAPI->getQueryService()
); // или $unClient->getQueryService()

$storedApiWidget = $apiWidget->store();

упаковать в архив виджет:

// ... $widgetService = new ...

/**
 * @var string $pathToWidget
 * */
$pathToWidget = $widgetService->packWidget('path/to/widget/folder/or/zip', 'code_widget', 'secret_widget');

// или
$pathToWidget = \Anemone\Extensions\Widgets\Models\ApiWidget::pack(
    'path/to/widget/folder/or/zip', 'code_widget', 'secret_widget'
);

Дополнительные возможности \Anemone\Extensions\Widgets\Models\ApiWidget:

// кроме получения коллекции виджето методом all можно получить водин виджет по коду
$one = \Anemone\Extensions\Widgets\Models\ApiWidget::find($clientAPI->getQueryService(), 'code_widget');

// загрузить архив виджета на сервер
$one->upload('path/to/zip'); // return bool

// установить настройки для виджета (те что в разделе интеграций)
$one->setSettings(['backend' => 'https://jarvis.google.com', 'api' => 'jquery']); // return bool
$one->setSettings(['backend' => 'https://jarvis.google.com', 'api' => 'jquery'], true); // активировать виджет

// отдельно включить или отключить виджет
$one->power(false); // return bool
$one->power(true); // return bool

// помимо создания виджета (описано выше), виджет можно удалить
$one->destroy(); // return bool

SERVICE: Widgets (Работа с интеграциями) (2020-03-14)

Интеграции пришли на смену или расширение возможностей виджетов.

Для работы с интеграциями добавлен сервис \Anemone\Extensions\Widgets\IntegrationsService

Возможности:

  • Список интеграций
  • Поиск интеграции по ее uuid
  • Создание интеграции
  • Обновление интеграции
  • Обновление секрета интеграции (попытки получить авторизацию по старому секрету будут отклонены)
  • Удаление интеграции
  • Присоединение к интеграции виджета с архивом
  • Загрузка архива виджета и логотипа интеграции (соблюдайте структуру и разрешение лого см. документацию амо)
  • Упаковка виджета интеграции по новым требованиям
  • Настройка, включение, отключение виджета интеграции
  • Получение авторизационных данных (access_token, refresh_token,...), конвертация кода в токен доступа
  • Обновление токена по refresh_token, конвертация refresh_token в токен доступа

$service = new \Anemone\Extensions\Widgets\IntegrationsService($client);
// or not api client (from NotApiClient)
$service = $unClient->integrationsService;

Важно: Создание, обновление, удаление, загрузка архива виджета интеграций используйте клиент \Anemone\Extensions\NotApiClient или старый апи токен клиент так как (на даный момент) не хватает полномочий в oauth2 клиенте.


// ... $service

/** list of integrations
 * @var \Illuminate\Support\Collection<\Anemone\Extensions\Widgets\Models\Integration> $collection
 * */
$collection = $service->all();

/** one model
 * @var \Anemone\Extensions\Widgets\Models\Integration $model
 * */
$model = $service->find('uuid');

/** store
 * @var \Anemone\Extensions\Widgets\Models\Integration $model
 * */
$model = $service->save(
     ['ru' => 'ru_name', 'en' => 'en_name'],
     ['ru' => 'ru description', 'en' => 'en description'],
     ['crm', 'notifications'],
     'https://callback.com'
);

/** update
 * @var \Anemone\Extensions\Widgets\Models\Integration $model
 * */
$model = $service->save(
    ['ru' => 'ru_name', 'en' => 'en_name'],
    ['ru' => 'ru description new', 'en' => 'en description new'],
    ['crm', 'notifications'],
    'https://callback.com',
    'f52bfff8-8ace-4229-b661-aaceb1e62c40'
);

// available scopes
$scopes = [
    "crm",
    "notifications",
    "chats",
    "integrations_auth",
    "integrations_auth_mobile",
    "integrations_fb",
    "integrations_google",
    "integrations_vk",
    "mail",
    "push_notifications",
    "unsorted"
];

/** update secret
 * @var \Anemone\Extensions\Widgets\Models\Integration $model
 * */
$model = $service->find('be3e8638-771e-4942-aa1b-2373e93bdde5');

$service->refreshSecret($model);


/** delete
 * @var bool $status
 * */
$status = $service->delete($model); // $model or uuid of model

/** generate widget data (link widget)
 * @var array $data (widget code, secret, uuid of integration)
 * */
$data = $service->generateIntegrationData($model); // $model or uuid of model

/** upload widget to server
 * @var bool $status
 * */
$status = $service->upload(
    '/link/to/widget.zip',
    $data['code'],
    $data['secret_key'],
    $data['client_uuid']
);

/** upload icon integration
 * @var array $resultData
 * */
$resultData = $service->uploadLogo('/link/to/logo_main.png', $model); // $model or uuid of model

/** pack widget.zip
 * @var string $link
 * */
$link = $service->packIntegrationWidget('/path/to/api_widget');
// or
$link = $service->packIntegrationWidget('/path/to/api_widget/widget.zip');

/** set settings and power widget in integration
 * @var bool $status
 * */
$status = $service->setSettings($model, [ // $model or uuid of model
    'backend' => 'https://backend.com',
    'token_key' => 'token_key',
    // ....
]);
// and set power
$status = $service->setSettings($model, [ // $model or uuid of model
    'backend' => 'https://backend.com',
    'token_key' => 'token_key',
    // ....
], false); // set power


/** convert code to access_token and refresh_token
 * @var array $authData
 * */
$authData = $service->convertCodeToAccessToken($model);

/** convert refresh_token to new access_token and refresh_token
 * @var array $authData
 * */
$authData = $service->refreshToken($model, $refresh_token);

SERVICE: Notifications (Работа с нотификациями) (add: 24.10.2019)

Сервис \Anemone\Extensions\Notifications\NotificationService

Сервис дает возможность:

  • Получить список всех нотификаций (Ораничение: только используя \Anemone\Extensions\NotApiClient)
  • Создать новые оповещения.

Получить список всех нотификаций:

// создать клиент (только \Anemone\Extensions\NotApiClient)
$unClient = new \Anemone\Extensions\NotApiClient([
    'user_login' => 'jarvis.amocrm.ru',
    'user_password' => 'zzfOPa7P',
], 'jarvis.amocrm.ru');

$notityService = new \Anemone\Extensions\Notifications\NotificationService($unClient);
/**
 * @var \Anemone\Core\Collection\Collection<\Anemone\Extensions\Notifications\Models\ReturnedNotify> $collection
 * */
$collection = $notityService->get();

Создать новые оповещения:

// создать любой клиент
$clientAPI = new \Anemone\Client([
    "domain" => "jarvis.amocrm.ru",
    "login" => "jarvis@google.com",
    "secret_key" => "b2f0414de331177268cb09f720a0b36a076fe88e",
]);
// или
$unClient = new \Anemone\Extensions\NotApiClient([
    'user_login' => 'jarvis.amocrm.ru',
    'user_password' => 'zzfOPa7P',
], 'jarvis.amocrm.ru');

$notityService = new \Anemone\Extensions\Notifications\NotificationService($clientAPI); // или $unClient

$errorNotify = new \Anemone\Extensions\Notifications\Models\ErrorNotify([
    "date" => time(),
    "message" => "message Text",
    "header" => "header Text",
    "link" => "/contacts/list/?term=4951234567"
]);

$callNotify1 = new \Anemone\Extensions\Notifications\Models\CallNotify([
    "to" => "Смирнов+Алексей",
    "from" => "Петрова+Анна",
    "duration" => "04:10",
    "link" => "https://example.com/dialog.mp3",
    "user" => "3621055",
    "date" => "1534084300",
    "message" => "Звонок+от++7(999)888+55+33",
    "element" => [
        "id" => 18221265,
        "type" => "contact",
        "name" => "",
    ],
]);

$callNotify2 = new \Anemone\Extensions\Notifications\Models\CallNotify([
    "to" => "Смирнов+Алексей",
    "from" => "Петрова+Анна",
    "link" => "https://example.com/dialog.mp3",
    "user" => "3621055",
    "date" => "1534084400",
    "message" => "Звонок+от++7(999)888+55+33",
    "click_link" => "/contacts/add/?phone=9191234567",
]);

// сохранение (одиночное)
$notityService->store($errorNotify);
$notityService->store($callNotify1);

// сохранение (массовое)
$notityService->store(new \Anemone\Core\Collection\Collection([
    $errorNotify,
    $callNotify1,
    $callNotify2,
]);

SERVICE: Groups (Работа с группами кастомных полей) (add ..-12-2019)

Помечен как Deprecated , так как в новой 4 версии добавили методы работы с группами Возможность управлять вкладками групп в карточках сущностей


$groupsService = new \Anemone\Extensions\Groups\GroupsService($client);

/**
 * @var array $array
 * [
 *  'leads' => Collection<Group>,
 *  'contacts' => Collection<Group>,
 *  'companies' => Collection<Group>,
 *  'customers' => Collection<Group>,
 * ]
 * */
$array = $groupsService->all(); 

// или коллекция для сущности
/**
 * @var Collection<Group> $collection
 * */
$collection = $groupsService->all('leads'); 

// создать

$field1 = new \Anemone\Models\CF\TextCustomField(['name' => 'field by jarvis 1', 'element_type' => 2]);
$field2 = new \Anemone\Models\CF\TextCustomField(['name' => 'field by jarvis 2', 'element_type' => 2]);

$client->account->save(new \Anemone\Core\Collection\Collection([
    $field1,
    $field2,
]));

$group1 = new \Anemone\Extensions\Groups\Models\Group([
    'name' => 'group 1',
]);

$group1->fields = new Anemone\Core\Collection\Collection([$field1, $field2]);

// для сделки по умолчанию
$result = $groupsService->store(new \Anemone\Core\Collection\Collection([
    $group1,
    new \Anemone\Extensions\Groups\Models\Group([
        'name' => 'group 2',
    ]),
]));

// для контакта
$result = $groupsService->store(new \Anemone\Core\Collection\Collection([
    $group1,
]), 'contacts');

// после получения списка - можно обновить или удалить группу(ы)

$collect = $groupsService->all('leads');

$collect->each(function (Anemone\Extensions\Groups\Models\Group $group) use ($field1, $field2) {
    if ($group->id == 'leads_98451576865910') {
        $group->name = 'new name';
        $group->fields = new Anemone\Core\Collection\Collection([$field1, $field2]);
    }
});

$result = $groupsService->update($collect);

// delete
$collect = $groupsService->all('leads');


$filtered = $collect->filter(function (\Anemone\Extensions\Groups\Models\Group $group) {
    return $group->id == 'leads_44281576865561';
});

$result = $groupsService->destroy($filtered);

SERVICE: Distribution (Работа с распределением) (add 22.01.2020)

Поддерживается линейное и случайное распределение (будет больше)

Обект распределения должен реализовать интерфейс \Anemone\Contracts\BeDistribution, По умолчанию заложен класс этого интерфейса \Anemone\Extensions\Distribution\Distribution, который принимает данные определенной структуры, если у вас имеется своя структура данных - создайте свой класс от интерфейса (некоторую структуру все же нада будет сохранить)


$distributionService = new \Anemone\Extensions\Distribution\DistributionService($client);

// обязательные свойтства: type, source, data
$config1 = [
    'type' => 'linear',
    'source' => 'any',
    'data' => [
        ['id' => 5781673, 'config' => []],
    ],
    'excludes' => [],
    'default' => 5781670,
];

$config2 = [
    'type' => 'linear',
    'source' => 'group',
    'data' => [
        ['id' => 0, 'config' => ['data' => [
            ['id' => 5781673, 'config' => []],
        ]]],
    ],
    'excludes' => [5781670],
    'default' => 5781670,
];

$config3 = [
    'type' => 'random',
    'source' => 'any',
    'data' => [
        ['id' => 5781673, 'config' => []],
    ],
    'excludes' => [5781670, 5781673, 5776324],
    'default' => 5781670,
];

$config4 = [
    'type' => 'random',
    'source' => 'group',
    'data' => [
        ['id' => 0, 'config' => ['data' => [
            ['id' => 5781673, 'config' => []],
        ]]],
    ],
    'excludes' => [],
];

$distribution = new \Anemone\Extensions\Distribution\Distribution($config1);
$distributionService->init($distribution);

echo $distributionService->next();
// следующий
echo $distributionService->next();
// ...

$result = $distributionService->result();
// или
$result = $distribution->result();

// для получения структуры для хранения (актуально для линейного распределения)

Выполнение других запросов

Методы запросов обладают гибкостью добавления параметров для запроса (авторизационные данные добавляются автоматически)

$queryService = $client->getQueryService();

$result = $queryService->get('https://jarvis.amocrm.ru/tra-ta-ta', ['query' => 'value']);
$result = $queryService->post(/*...*/);
$result = $queryService->patch(/*...*/);
$result = $queryService->delete(/*...*/);

Особенности

  1. при клонировании сущности - сами забодьтесь о датах создания и других данных (полный клон) clone ссылки остаются (tags, custom-fields..) (в будущем возможно изменится поведение)

Глобальные функции хелперы

(врядли понадобятся)

Функции были созданы для работы самой библиотеки, а не для пользовательских решений (все имеют префикс a*).

  • aAppPath(): string - app path,
  • aLibPath(): string - anemone lib path,
  • aConfig(string $key.of.config): mixed - get val in global config (.dot is separate),
  • aEntryData(string $key.of.entry): mixed - get entry data (ex.: '4.lead')
  • aExtEntryData(string $key.of.entry): mixed - get entry data for extensions,
  • aEnv(string $key, string $default = ''): mixed - get env variables,
  • aAvailableVersion(): string[] - get available versions,
  • aLogger(Closure $closure = null): Monolog\Logger - get logger instance,