From 308092fd2488390fae8aea3dd23ae1038b6d3b1a Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 2 Jul 2026 07:24:24 +0000 Subject: [PATCH 1/2] Add DWH analytics module for amoCRM data export Implement full data warehouse schema and ETL layer: - 15 SQL migrations for 48+ tables (auxiliary, dimensions, facts, linking, SHD) - 52 DWH models (BaseDwhModel + entity/attribute/tag/note/event/fact models) - 18 DWH collections (BaseDwhCollection) - 14 entity ETL services with pagination and incremental sync support - 11 fact ETL services for metric aggregation - DwhDbAdapter (PDO-based): insert, upsert, bulkInsert, truncate, deleteBy - DwhSyncOrchestrator: fullSync() and incrementalSync() - Example script (examples/dwh_full_sync.php) - Updated README with DWH documentation Architecture: AmoCRM\Dwh namespace with Models/Collections/Services layers Co-authored-by: openhands --- .agents_tmp/PLAN.md | 444 ++++++++++++++++++ README.md | 56 +++ examples/dwh_full_sync.php | 79 ++++ migrations/001_auxiliary_tables.sql | 46 ++ migrations/002_shd_tables.sql | 45 ++ migrations/003_dimension_calls.sql | 24 + migrations/004_dimension_unsorted.sql | 32 ++ migrations/005_dimension_companies.sql | 77 +++ migrations/006_dimension_contacts.sql | 80 ++++ migrations/007_dimension_leads.sql | 90 ++++ migrations/008_dimension_segments.sql | 32 ++ migrations/009_dimension_customers.sql | 74 +++ migrations/010_dimension_transactions.sql | 23 + migrations/011_dimension_tasks.sql | 41 ++ migrations/012_dimension_elements.sql | 48 ++ migrations/013_dimension_users.sql | 23 + migrations/014_linking_tables.sql | 47 ++ migrations/015_fact_tables.sql | 167 +++++++ .../Dwh/Collections/BaseDwhCollection.php | 139 ++++++ .../Dwh/Collections/CallDwhCollection.php | 10 + .../Dwh/Collections/ClientIdDwhCollection.php | 10 + .../Dwh/Collections/CompanyDwhCollection.php | 10 + .../Dwh/Collections/ContactDwhCollection.php | 10 + .../Dwh/Collections/CustomerDwhCollection.php | 10 + .../Dwh/Collections/DateDwhCollection.php | 10 + .../Dwh/Collections/ElementDwhCollection.php | 10 + .../Dwh/Collections/LeadDwhCollection.php | 10 + .../Collections/PeriodicityDwhCollection.php | 10 + .../Dwh/Collections/PipelineDwhCollection.php | 10 + .../Dwh/Collections/SegmentDwhCollection.php | 10 + .../Dwh/Collections/StatusDwhCollection.php | 10 + .../Dwh/Collections/TaskDwhCollection.php | 10 + .../Dwh/Collections/TrafficDwhCollection.php | 10 + .../Collections/TransactionDwhCollection.php | 10 + .../Dwh/Collections/UnsortedDwhCollection.php | 10 + .../Dwh/Collections/UserDwhCollection.php | 10 + src/AmoCRM/Dwh/DwhDbAdapter.php | 150 ++++++ src/AmoCRM/Dwh/DwhSyncOrchestrator.php | 136 ++++++ src/AmoCRM/Dwh/Enum/TableTypeEnum.php | 12 + src/AmoCRM/Dwh/Models/BaseDwhModel.php | 50 ++ src/AmoCRM/Dwh/Models/CallDwhModel.php | 75 +++ src/AmoCRM/Dwh/Models/CallFactDwhModel.php | 51 ++ src/AmoCRM/Dwh/Models/ClientIdDwhModel.php | 44 ++ .../Dwh/Models/CompanyAttributeDwhModel.php | 55 +++ .../Dwh/Models/CompanyContactLinkDwhModel.php | 35 ++ src/AmoCRM/Dwh/Models/CompanyDwhModel.php | 67 +++ .../Dwh/Models/CompanyEventDwhModel.php | 51 ++ src/AmoCRM/Dwh/Models/CompanyFactDwhModel.php | 43 ++ src/AmoCRM/Dwh/Models/CompanyNoteDwhModel.php | 75 +++ src/AmoCRM/Dwh/Models/CompanyTagDwhModel.php | 39 ++ .../Dwh/Models/ContactAttributeDwhModel.php | 55 +++ src/AmoCRM/Dwh/Models/ContactDwhModel.php | 79 ++++ .../Dwh/Models/ContactEventDwhModel.php | 51 ++ src/AmoCRM/Dwh/Models/ContactFactDwhModel.php | 43 ++ src/AmoCRM/Dwh/Models/ContactNoteDwhModel.php | 75 +++ src/AmoCRM/Dwh/Models/ContactTagDwhModel.php | 39 ++ .../Dwh/Models/CustomerAttributeDwhModel.php | 55 +++ src/AmoCRM/Dwh/Models/CustomerDwhModel.php | 103 ++++ .../Models/CustomerElementFactDwhModel.php | 39 ++ .../Dwh/Models/CustomerFactDwhModel.php | 67 +++ .../Dwh/Models/CustomerMemberLinkDwhModel.php | 35 ++ .../Dwh/Models/CustomerNoteDwhModel.php | 75 +++ .../Models/CustomerSegmentLinkDwhModel.php | 31 ++ src/AmoCRM/Dwh/Models/CustomerTagDwhModel.php | 39 ++ src/AmoCRM/Dwh/Models/DateDwhModel.php | 60 +++ .../Dwh/Models/ElementAttributeDwhModel.php | 55 +++ src/AmoCRM/Dwh/Models/ElementDwhModel.php | 71 +++ .../Dwh/Models/ElementProductDwhModel.php | 43 ++ .../Dwh/Models/LeadAttributeDwhModel.php | 55 +++ .../Dwh/Models/LeadContactLinkDwhModel.php | 35 ++ src/AmoCRM/Dwh/Models/LeadDwhModel.php | 115 +++++ .../Dwh/Models/LeadElementFactDwhModel.php | 39 ++ src/AmoCRM/Dwh/Models/LeadEventDwhModel.php | 51 ++ src/AmoCRM/Dwh/Models/LeadFactDwhModel.php | 79 ++++ src/AmoCRM/Dwh/Models/LeadNoteDwhModel.php | 75 +++ src/AmoCRM/Dwh/Models/LeadTagDwhModel.php | 39 ++ src/AmoCRM/Dwh/Models/PeriodicityDwhModel.php | 48 ++ src/AmoCRM/Dwh/Models/PipelineDwhModel.php | 61 +++ .../Dwh/Models/SegmentAttributeDwhModel.php | 47 ++ src/AmoCRM/Dwh/Models/SegmentDwhModel.php | 63 +++ src/AmoCRM/Dwh/Models/SegmentFactDwhModel.php | 55 +++ src/AmoCRM/Dwh/Models/StatusDwhModel.php | 55 +++ src/AmoCRM/Dwh/Models/TaskDwhModel.php | 91 ++++ src/AmoCRM/Dwh/Models/TaskEventDwhModel.php | 51 ++ src/AmoCRM/Dwh/Models/TaskFactDwhModel.php | 55 +++ src/AmoCRM/Dwh/Models/TrafficDwhModel.php | 56 +++ src/AmoCRM/Dwh/Models/TransactionDwhModel.php | 71 +++ .../Models/TransactionElementFactDwhModel.php | 39 ++ .../Dwh/Models/TransactionFactDwhModel.php | 51 ++ src/AmoCRM/Dwh/Models/UnsortedDwhModel.php | 107 +++++ src/AmoCRM/Dwh/Models/UserDwhModel.php | 75 +++ src/AmoCRM/Dwh/Services/BaseEtlService.php | 105 +++++ src/AmoCRM/Dwh/Services/CallEtlService.php | 81 ++++ src/AmoCRM/Dwh/Services/CompanyEtlService.php | 103 ++++ src/AmoCRM/Dwh/Services/ContactEtlService.php | 106 +++++ .../Dwh/Services/CustomerEtlService.php | 110 +++++ src/AmoCRM/Dwh/Services/ElementEtlService.php | 95 ++++ .../Dwh/Services/Facts/CallFactEtlService.php | 40 ++ .../Services/Facts/CompanyFactEtlService.php | 38 ++ .../Services/Facts/ContactFactEtlService.php | 38 ++ .../Facts/CustomerElementFactEtlService.php | 26 + .../Services/Facts/CustomerFactEtlService.php | 44 ++ .../Facts/LeadElementFactEtlService.php | 26 + .../Dwh/Services/Facts/LeadFactEtlService.php | 45 ++ .../Services/Facts/SegmentFactEtlService.php | 42 ++ .../Dwh/Services/Facts/TaskFactEtlService.php | 40 ++ .../TransactionElementFactEtlService.php | 26 + .../Facts/TransactionFactEtlService.php | 40 ++ src/AmoCRM/Dwh/Services/LeadEtlService.php | 114 +++++ .../Dwh/Services/PeriodicityEtlService.php | 34 ++ .../Dwh/Services/PipelineEtlService.php | 36 ++ src/AmoCRM/Dwh/Services/SegmentEtlService.php | 88 ++++ src/AmoCRM/Dwh/Services/StatusEtlService.php | 48 ++ src/AmoCRM/Dwh/Services/TaskEtlService.php | 90 ++++ .../Dwh/Services/TransactionEtlService.php | 80 ++++ .../Dwh/Services/UnsortedEtlService.php | 92 ++++ src/AmoCRM/Dwh/Services/UserEtlService.php | 81 ++++ 117 files changed, 6716 insertions(+) create mode 100644 .agents_tmp/PLAN.md create mode 100644 examples/dwh_full_sync.php create mode 100644 migrations/001_auxiliary_tables.sql create mode 100644 migrations/002_shd_tables.sql create mode 100644 migrations/003_dimension_calls.sql create mode 100644 migrations/004_dimension_unsorted.sql create mode 100644 migrations/005_dimension_companies.sql create mode 100644 migrations/006_dimension_contacts.sql create mode 100644 migrations/007_dimension_leads.sql create mode 100644 migrations/008_dimension_segments.sql create mode 100644 migrations/009_dimension_customers.sql create mode 100644 migrations/010_dimension_transactions.sql create mode 100644 migrations/011_dimension_tasks.sql create mode 100644 migrations/012_dimension_elements.sql create mode 100644 migrations/013_dimension_users.sql create mode 100644 migrations/014_linking_tables.sql create mode 100644 migrations/015_fact_tables.sql create mode 100644 src/AmoCRM/Dwh/Collections/BaseDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/CallDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/ClientIdDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/CompanyDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/ContactDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/CustomerDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/DateDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/ElementDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/LeadDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/PeriodicityDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/PipelineDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/SegmentDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/StatusDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/TaskDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/TrafficDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/TransactionDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/UnsortedDwhCollection.php create mode 100644 src/AmoCRM/Dwh/Collections/UserDwhCollection.php create mode 100644 src/AmoCRM/Dwh/DwhDbAdapter.php create mode 100644 src/AmoCRM/Dwh/DwhSyncOrchestrator.php create mode 100644 src/AmoCRM/Dwh/Enum/TableTypeEnum.php create mode 100644 src/AmoCRM/Dwh/Models/BaseDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CallDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CallFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ClientIdDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyAttributeDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyContactLinkDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyEventDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyNoteDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CompanyTagDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ContactAttributeDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ContactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ContactEventDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ContactFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ContactNoteDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ContactTagDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerAttributeDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerElementFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerMemberLinkDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerNoteDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerSegmentLinkDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/CustomerTagDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/DateDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ElementAttributeDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ElementDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/ElementProductDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadAttributeDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadContactLinkDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadElementFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadEventDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadNoteDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/LeadTagDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/PeriodicityDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/PipelineDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/SegmentAttributeDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/SegmentDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/SegmentFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/StatusDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TaskDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TaskEventDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TaskFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TrafficDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TransactionDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TransactionElementFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/TransactionFactDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/UnsortedDwhModel.php create mode 100644 src/AmoCRM/Dwh/Models/UserDwhModel.php create mode 100644 src/AmoCRM/Dwh/Services/BaseEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/CallEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/CompanyEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/ContactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/CustomerEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/ElementEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/CallFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/CompanyFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/ContactFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/CustomerElementFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/CustomerFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/LeadElementFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/LeadFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/SegmentFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/TaskFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/TransactionElementFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/Facts/TransactionFactEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/LeadEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/PeriodicityEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/PipelineEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/SegmentEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/StatusEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/TaskEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/TransactionEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/UnsortedEtlService.php create mode 100644 src/AmoCRM/Dwh/Services/UserEtlService.php diff --git a/.agents_tmp/PLAN.md b/.agents_tmp/PLAN.md new file mode 100644 index 0000000..3a4f56c --- /dev/null +++ b/.agents_tmp/PLAN.md @@ -0,0 +1,444 @@ +# 1. OBJECTIVE + +Реализовать полную схему аналитического хранилища данных (DWH) для выгрузки данных из amoCRM на основе справочника из 48 таблиц: +- **3 вспомогательные таблицы** (справочники: воронки, этапы, статусы покупателей) +- **27 таблиц измерений** (атрибуты сущностей: звонки, неразобранное, компании, контакты, сделки, сегменты, покупатели, транзакции, задачи, элементы, пользователи, SHD-измерения) +- **11 таблиц фактов** (числовые метрики со ссылками на измерения) +- **4 связующие таблицы** (M:N связи: сделки-контакты, покупатели-сегменты и др.) +- **Сервисы ETL** для наполнения таблиц из API amoCRM + +# 2. CONTEXT SUMMARY + +**Проект:** `amocrm/amocrm-api-library` — официальный PHP-клиент для API amoCRM (OAuth 2.0, API v4). + +**Ключевые паттерны кодовой базы:** +- Модели: наследуют `BaseApiModel`, содержат `protected`-свойства, getter/setter, `toArray()`, `toApi()`, `fromArray()` +- Коллекции: наследуют `BaseApiCollection`, реализуют `ArrayAccess`/`IteratorAggregate`, константа `ITEM_CLASS` +- Сервисы: наследуют `BaseEntity`, свойства `$method`, `$collectionClass`, `ITEM_CLASS`, методы `get()`, `addOne()`, `updateOne()` +- Клиент: `AmoCRMApiClient` — точка входа, фабрика сервисов (методы `leads()`, `contacts()`, `companies()`, `customers()`, `calls()`, `tasks()`, `events()`, `unsorted()`, `pipelines()`, `statuses()`, `customersSegments()`, `transactions()`, `products()` и др.) + +**Схема DWH (из справочника):** +- Все таблицы содержат поле `account_id` (мультиаккаунтность) +- Фактовые таблицы ссылаются на измерения через внешние ключи `_id` +- События (`*_events`) хранят `value_before` / `value_after` (SCD type 2) +- SHD-таблицы (`general_*`) — общие измерения (трафик, посетители, календарь) +- В `amocrm_segments_facts` опечатка: `created_date` повторяется дважды, второе должно быть `modified_date` + +**Зависимости:** PHP >= 7.1, MySQL/MariaDB для DWH-схемы (целевая БД), существующий API-клиент для ETL. + +# 3. APPROACH OVERVIEW + +**Выбранный подход:** трёхслойная архитектура с новым namespace `AmoCRM\Dwh`: + +1. **SQL-слой** — миграции `CREATE TABLE` для всех 48 таблиц. Организованы как сырой SQL в директории `migrations/` с инкрементальными файлами, сгруппированными по типам таблиц. + +2. **Модельный слой** (`src/AmoCRM/Dwh/Models/`) — PHP-классы DWH-моделей, наследующие общий `BaseDwhModel`. Каждая модель соответствует одной таблице. Модели используют упрощённый паттерн (только `toArray()` + getter/setter), так как это целевые модели хранилища, а не API-модели. + +3. **ETL-слой** (`src/AmoCRM/Dwh/Services/`) — сервисы для каждой группы сущностей, использующие существующий `AmoCRMApiClient` для извлечения данных из API и сохранения их в DWH-таблицы. Каждый ETL-сервис: + - Принимает `AmoCRMApiClient` (для извлечения) и PDO/DB-адаптер (для сохранения) + - Реализует метод `sync()` с параметрами фильтрации (период, лимит) + - Трансформирует API-модели в DWH-модели (mapping API → DWH) + - Записывает в соответствующие таблицы (основные + attributes + tags + notes + events) + +**Почему этот подход:** +- Чёткое разделение: API-клиент не смешивается с DWH-кодом +- Повторяет существующие паттерны библиотеки (Models/Collections/Services) +- ETL-сервисы переиспользуют весь существующий API-клиент без дублирования +- Миграции легко версионировать и накатывать + +# 4. IMPLEMENTATION STEPS + +## Этап 1: SQL-схема — вспомогательные таблицы и SHD-измерения + +**Цель:** Создать миграции для справочников и общих измерений, т.к. они не зависят от API. + +**Метод:** +- Создать `migrations/001_auxiliary_tables.sql` — таблицы `amocrm_pipelines`, `amocrm_statuses`, `amocrm_periodicity` +- Создать `migrations/002_shd_tables.sql` — таблицы `general_traffic`, `general_clientids`, `general_dates` +- Все поля — согласно справочнику; `id` — `BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY`; `account_id` — `INT UNSIGNED NOT NULL`; даты — `DATETIME`; добавлены индексы на FK-поля. + +**Ссылки:** справочник таблиц (секции amocrm_pipelines, amocrm_statuses, amocrm_periodicity, general_*) + +--- + +## Этап 2: SQL-схема — таблицы измерений (сущности amoCRM) + +**Цель:** Создать миграции для всех 27 таблиц измерений. + +**Метод:** +- `migrations/003_dimension_calls.sql` — `amocrm_calls` +- `migrations/004_dimension_unsorted.sql` — `amocrm_unsorted` +- `migrations/005_dimension_companies.sql` — `amocrm_companies`, `amocrm_companies_attributes`, `amocrm_companies_tags`, `amocrm_companies_notes`, `amocrm_companies_events` +- `migrations/006_dimension_contacts.sql` — `amocrm_contacts`, `amocrm_contacts_attributes`, `amocrm_contacts_tags`, `amocrm_contacts_notes`, `amocrm_contacts_events` +- `migrations/007_dimension_leads.sql` — `amocrm_leads`, `amocrm_leads_attributes`, `amocrm_leads_tags`, `amocrm_leads_notes`, `amocrm_leads_events` +- `migrations/008_dimension_segments.sql` — `amocrm_segments`, `amocrm_segments_attributes` +- `migrations/009_dimension_customers.sql` — `amocrm_customers`, `amocrm_customers_attributes`, `amocrm_customers_tags`, `amocrm_customers_notes` +- `migrations/010_dimension_transactions.sql` — `amocrm_transactions` +- `migrations/011_dimension_tasks.sql` — `amocrm_tasks`, `amocrm_tasks_events` +- `migrations/012_dimension_elements.sql` — `amocrm_elements`, `amocrm_elements_attributes`, `amocrm_elements_products` +- `migrations/013_dimension_users.sql` — `amocrm_users` + +**Особенности:** +- Для `*_attributes`: поле `value` — `TEXT` (доп. поля могут быть любой длины) +- Для `*_notes`: поле `params` — `JSON` / `TEXT` +- Для `*_events`: поля `value_before`, `value_after` — `TEXT` +- Индексы: `(account_id, _id)` для всех таблиц + +**Ссылки:** справочник, секции amocrm_calls ... amocrm_users + +--- + +## Этап 3: SQL-схема — связующие таблицы и таблицы фактов + +**Цель:** Создать миграции для 4 связующих таблиц и 11 таблиц фактов. + +**Метод:** +- `migrations/014_linking_tables.sql` — `amocrm_leads_contacts`, `amocrm_customers_segments` +- `migrations/015_fact_tables.sql` — все 11 таблиц фактов: + - `amocrm_calls_facts`, `amocrm_contacts_facts`, `amocrm_companies_facts` + - `amocrm_leads_facts`, `amocrm_segments_facts`, `amocrm_customers_facts` + - `amocrm_transactions_facts`, `amocrm_tasks_facts` + - `amocrm_transactions_elements_facts`, `amocrm_leads_elements_facts`, `amocrm_customers_elements_facts` + +**Особенности:** +- Все FK-поля: `BIGINT UNSIGNED` (ссылаются на id соответствующих таблиц измерений) +- Метрики: `price` — `DECIMAL(15,2)`, `duration` — `INT`, `quantity` — `DECIMAL(15,4)`, `score` — `INT` +- Составной индекс `(account_id, _id)` + индексы на каждый FK +- Исправить опечатку в `amocrm_segments_facts`: второе поле `created_date` → `modified_date` + +**Ссылки:** справочник, секции amocrm_leads_contacts ... amocrm_customers_elements_facts + +--- + +## Этап 4: Базовые классы DWH-моделей + +**Цель:** Создать абстрактный `BaseDwhModel`, коллекцию `BaseDwhCollection` и трейты. + +**Метод:** +- Создать `src/AmoCRM/Dwh/Models/BaseDwhModel.php`: + - Аналогичен `BaseApiModel`, но без `toApi()` (DWH-модели не отправляются в API) + - Содержит `abstract toArray(): array` и `static fromArray(array $data): static` + - Добавлен трейт `HasAccountId` для общего поля `account_id` +- Создать `src/AmoCRM/Dwh/Collections/BaseDwhCollection.php`: + - Аналогичен `BaseApiCollection`, но для DWH-моделей +- Создать `src/AmoCRM/Dwh/Enum/TableTypeEnum.php`: + - Константы: `AUXILIARY`, `DIMENSION`, `FACT`, `LINKING`, `SHD` + +**Ссылки:** `src/AmoCRM/Models/BaseApiModel.php`, `src/AmoCRM/Collections/BaseApiCollection.php` + +--- + +## Этап 5: PHP DWH-модели — справочники и SHD + +**Цель:** Создать модели для справочников и общих измерений (6 таблиц). + +**Метод:** Для каждой таблицы — класс модели в `src/AmoCRM/Dwh/Models/`: +- `PipelineModel.php` → таблица `amocrm_pipelines` +- `StatusModel.php` → таблица `amocrm_statuses` (этапы продаж, не путать с Statuses/StatusModel из Leads) +- `PeriodicityModel.php` → таблица `amocrm_periodicity` +- `TrafficModel.php` → таблица `general_traffic` +- `ClientIdModel.php` → таблица `general_clientids` +- `DateDimensionModel.php` → таблица `general_dates` + +Каждая модель содержит: +- `protected` свойства (все поля таблицы) +- Getter/Setter для каждого поля (fluent interface — return `$this`) +- `toArray(): array` — сериализация +- `static fromArray(array $data): static` — десериализация + +**Ссылки:** справочник, секции amocrm_pipelines, amocrm_statuses, amocrm_periodicity, general_* + +--- + +## Этап 6: PHP DWH-модели — измерения сущностей amoCRM + +**Цель:** Создать модели для всех таблиц измерений (27 таблиц → ~22 класса моделей, т.к. attributes/tags/notes/events — отдельные классы). + +**Метод:** Организовать по группам в поддиректориях `src/AmoCRM/Dwh/Models/`: + +**Звонки:** +- `Calls/CallDimensionModel.php` → `amocrm_calls` + +**Неразобранное:** +- `Unsorted/UnsortedDimensionModel.php` → `amocrm_unsorted` + +**Компании:** +- `Companies/CompanyDimensionModel.php` → `amocrm_companies` +- `Companies/CompanyAttributeModel.php` → `amocrm_companies_attributes` +- `Companies/CompanyTagModel.php` → `amocrm_companies_tags` +- `Companies/CompanyNoteModel.php` → `amocrm_companies_notes` +- `Companies/CompanyEventModel.php` → `amocrm_companies_events` + +**Контакты:** +- `Contacts/ContactDimensionModel.php` → `amocrm_contacts` +- `Contacts/ContactAttributeModel.php` → `amocrm_contacts_attributes` +- `Contacts/ContactTagModel.php` → `amocrm_contacts_tags` +- `Contacts/ContactNoteModel.php` → `amocrm_contacts_notes` +- `Contacts/ContactEventModel.php` → `amocrm_contacts_events` + +**Сделки:** +- `Leads/LeadDimensionModel.php` → `amocrm_leads` +- `Leads/LeadAttributeModel.php` → `amocrm_leads_attributes` +- `Leads/LeadTagModel.php` → `amocrm_leads_tags` +- `Leads/LeadNoteModel.php` → `amocrm_leads_notes` +- `Leads/LeadEventModel.php` → `amocrm_leads_events` + +**Сегменты:** +- `Segments/SegmentDimensionModel.php` → `amocrm_segments` +- `Segments/SegmentAttributeModel.php` → `amocrm_segments_attributes` + +**Покупатели:** +- `Customers/CustomerDimensionModel.php` → `amocrm_customers` +- `Customers/CustomerAttributeModel.php` → `amocrm_customers_attributes` +- `Customers/CustomerTagModel.php` → `amocrm_customers_tags` +- `Customers/CustomerNoteModel.php` → `amocrm_customers_notes` + +**Транзакции:** +- `Transactions/TransactionDimensionModel.php` → `amocrm_transactions` + +**Задачи:** +- `Tasks/TaskDimensionModel.php` → `amocrm_tasks` +- `Tasks/TaskEventModel.php` → `amocrm_tasks_events` + +**Элементы (каталоги/товары):** +- `Elements/ElementDimensionModel.php` → `amocrm_elements` +- `Elements/ElementAttributeModel.php` → `amocrm_elements_attributes` +- `Elements/ElementProductModel.php` → `amocrm_elements_products` + +**Пользователи:** +- `Users/UserDimensionModel.php` → `amocrm_users` + +**Ссылки:** справочник, существующие API-модели для mapping'а (`LeadModel`, `ContactModel`, `CompanyModel`, `CustomerModel`, etc.) + +--- + +## Этап 7: PHP DWH-модели — связи и факты + +**Цель:** Создать модели для 4 связующих таблиц и 11 таблиц фактов. + +**Метод:** Организовать в `src/AmoCRM/Dwh/Models/`: + +**Связи:** +- `Links/LeadContactLinkModel.php` → `amocrm_leads_contacts` +- `Links/CustomerSegmentLinkModel.php` → `amocrm_customers_segments` + +**Факты:** +- `Facts/CallFactModel.php` → `amocrm_calls_facts` +- `Facts/ContactFactModel.php` → `amocrm_contacts_facts` +- `Facts/CompanyFactModel.php` → `amocrm_companies_facts` +- `Facts/LeadFactModel.php` → `amocrm_leads_facts` +- `Facts/SegmentFactModel.php` → `amocrm_segments_facts` +- `Facts/CustomerFactModel.php` → `amocrm_customers_facts` +- `Facts/TransactionFactModel.php` → `amocrm_transactions_facts` +- `Facts/TaskFactModel.php` → `amocrm_tasks_facts` +- `Facts/TransactionElementFactModel.php` → `amocrm_transactions_elements_facts` +- `Facts/LeadElementFactModel.php` → `amocrm_leads_elements_facts` +- `Facts/CustomerElementFactModel.php` → `amocrm_customers_elements_facts` + +**Особенности:** +- Фактовые модели содержат числовые поля (price, quantity, duration, score, ltv и т.д.) и FK-поля на измерения +- Для `SegmentFactModel` учесть исправленную опечатку: `modified_date` вместо дублирующегося `created_date` + +**Ссылки:** справочник, секции amocrm_leads_contacts ... amocrm_customers_elements_facts + +--- + +## Этап 8: DWH-коллекции + +**Цель:** Создать коллекции DWH-моделей для пакетных операций. + +**Метод:** Для каждой группы моделей — коллекция в `src/AmoCRM/Dwh/Collections/`: +- `PipelineCollection.php` (ITEM_CLASS = PipelineModel::class) +- `StatusCollection.php` +- `PeriodicityCollection.php` +- `CallDimensionCollection.php` +- `CompanyDimensionCollection.php` +- `ContactDimensionCollection.php` +- `LeadDimensionCollection.php` +- `CustomerDimensionCollection.php` +- `TransactionDimensionCollection.php` +- `TaskDimensionCollection.php` +- `ElementDimensionCollection.php` +- `UserDimensionCollection.php` +- Коллекции фактов: `LeadFactCollection.php`, `CallFactCollection.php`, ... + +Каждая коллекция наследует `BaseDwhCollection` и переопределяет `ITEM_CLASS`. + +**Ссылки:** `BaseDwhCollection` + +--- + +## Этап 9: Database adapter (PDO wrapper) + +**Цель:** Создать лёгкий адаптер БД для ETL-сервисов. + +**Метод:** Создать `src/AmoCRM/Dwh/Database/DwhDbAdapter.php`: +- Конструктор принимает `PDO` или DSN + credentials +- Методы `insert(string $table, array $data): int` (возвращает lastInsertId) +- `batchInsert(string $table, array $rows): array` (возвращает массив ID) +- `upsert(string $table, array $data, array $uniqueKeys): int` +- `delete(string $table, array $conditions): int` +- `beginTransaction()`, `commit()`, `rollback()` + +**Почему не ORM:** Минимизация зависимостей, библиотека уже использует лёгкий подход. + +**Ссылки:** PDO + +--- + +## Этап 10: Базовый ETL-сервис + +**Цель:** Создать абстрактный класс для всех ETL-сервисов. + +**Метод:** Создать `src/AmoCRM/Dwh/Services/BaseEtlService.php`: +- Принимает `AmoCRMApiClient` и `DwhDbAdapter` в конструкторе +- Абстрактный метод `sync(array $options = []): array` — возвращает статистику (сколько записей обработано) +- Общие методы: + - `transformApiToDwh()` — шаблонный метод для маппинга API-модели → DWH-модель + - `extractCustomFields()` — извлечение доп. полей в attributes-таблицы + - `extractTags()` — извлечение тегов в tags-таблицы + - `extractNotes()` — извлечение примечаний c API (через `EntityNotes`) + - `extractEvents()` — извлечение событий (через `Events` сервис) + +**Ссылки:** `AmoCRMApiClient`, `BaseEntity`, `DwhDbAdapter` + +--- + +## Этап 11: ETL-сервисы — справочники (pipelines, statuses, periodicity) + +**Цель:** Реализовать ETL-синхронизацию вспомогательных таблиц. + +**Метод:** Создать: +- `src/AmoCRM/Dwh/Services/PipelineEtlService.php`: + - `sync()`: вызывает `$apiClient->pipelines()->get()`, маппит `PipelineModel` → `PipelineDimensionModel` +- `src/AmoCRM/Dwh/Services/StatusEtlService.php`: + - `sync()`: для каждой воронки вызывает `$apiClient->statuses($pipelineId)->get()`, маппит `StatusModel` → `StatusDimensionModel` +- `src/AmoCRM/Dwh/Services/PeriodicityEtlService.php`: + - `sync()`: вызывает `$apiClient->customersStatuses()->get()`, маппит `StatusModel` → `PeriodicityDimensionModel` + +Каждый сервис: очищает таблицу → вставляет свежие данные (справочники — full refresh). + +**Ссылки:** API-сервисы `Pipelines`, `Statuses`, `CustomersStatuses` + +--- + +## Этап 12: ETL-сервисы — основные сущности (companies, contacts, leads) + +**Цель:** Реализовать ETL-синхронизацию компаний, контактов и сделок. + +**Метод:** Создать: +- `src/AmoCRM/Dwh/Services/CompanyEtlService.php`: + - `sync()`: вызывает `$apiClient->companies()->get($filter)` + - Для каждой компании: вставляет в `amocrm_companies`, `amocrm_companies_attributes`, `amocrm_companies_tags` + - Опционально: подтягивает notes через `$apiClient->notes('companies')`, events через `$apiClient->events()` +- `src/AmoCRM/Dwh/Services/ContactEtlService.php`: + - Аналогично для контактов → `amocrm_contacts`, `*_attributes`, `*_tags`, `*_notes`, `*_events` +- `src/AmoCRM/Dwh/Services/LeadEtlService.php`: + - Аналогично для сделок + заполняет `amocrm_leads_contacts` (связи) + - Для связей: использует `$apiClient->leads()->get($filter, ['contacts'])` + +**Параметры `sync()`:** `$filter` (период, лимит), `$withNotes` (bool), `$withEvents` (bool). + +**Ссылки:** API-сервисы `Companies`, `Contacts`, `Leads`, `EntityNotes`, `Events` + +--- + +## Этап 13: ETL-сервисы — остальные сущности (customers, segments, calls, tasks, transactions, elements, users) + +**Цель:** Реализовать ETL-синхронизацию оставшихся сущностей. + +**Метод:** Создать: +- `src/AmoCRM/Dwh/Services/CustomerEtlService.php` — покупатели + segments + attributes + tags + notes +- `src/AmoCRM/Dwh/Services/SegmentEtlService.php` — сегменты + attributes +- `src/AmoCRM/Dwh/Services/CallEtlService.php` — звонки +- `src/AmoCRM/Dwh/Services/TaskEtlService.php` — задачи + events +- `src/AmoCRM/Dwh/Services/TransactionEtlService.php` — транзакции +- `src/AmoCRM/Dwh/Services/ElementEtlService.php` — элементы каталогов + attributes + products +- `src/AmoCRM/Dwh/Services/UserEtlService.php` — пользователи +- `src/AmoCRM/Dwh/Services/UnsortedEtlService.php` — неразобранное + +**Ссылки:** API-сервисы `Customers`, `Segments`, `Calls`, `Tasks`, `Transactions`, `CatalogElements`, `Users`, `Unsorted` + +--- + +## Этап 14: ETL-сервисы — фактовые таблицы + +**Цель:** Реализовать ETL-сервисы для наполнения таблиц фактов на основе измерений. + +**Метод:** Создать в `src/AmoCRM/Dwh/Services/Facts/`: +- `CallFactEtlService.php` — джойнит `amocrm_calls` с API звонков для получения duration, связывает с датами/пользователями/сущностями +- `ContactFactEtlService.php` — агрегирует контакты по дате регистрации +- `CompanyFactEtlService.php` — агрегирует компании по дате регистрации +- `LeadFactEtlService.php` — связывает сделки с clientids, traffic, датами открытия/закрытия; вычисляет price, labor_cost, score +- `SegmentFactEtlService.php` — вычисляет conversion_rate, max_discount, customers_count +- `CustomerFactEtlService.php` — вычисляет purchases, average_check, next_price, ltv, labor_cost +- `TransactionFactEtlService.php` — связывает транзакции с покупателями/датами/сущностями +- `TaskFactEtlService.php` — вычисляет duration задач; связывает с датами создания/завершения +- `TransactionElementFactEtlService.php` — элементы транзакций (quantity) +- `LeadElementFactEtlService.php` — элементы сделок (quantity, price) +- `CustomerElementFactEtlService.php` — элементы покупателей (quantity, price) + +**Логика:** Фактовые ETL работают поверх уже заполненных таблиц измерений (читают из DWH + при необходимости дозапрашивают API). + +**Ссылки:** справочник таблиц фактов, заполненные таблицы измерений + +--- + +## Этап 15: Оркестратор полной выгрузки + +**Цель:** Создать главный сервис, координирующий полный цикл ETL. + +**Метод:** Создать `src/AmoCRM/Dwh/DwhSyncOrchestrator.php`: +- Принимает `AmoCRMApiClient`, `DwhDbAdapter` +- Метод `fullSync(int $accountId, array $options = []): array`: + 1. Синхронизирует справочники (pipelines, statuses, periodicity) + 2. Синхронизирует пользователей (нужны для всех остальных таблиц) + 3. Синхронизирует SHD-таблицы (dates, traffic, clientids — могут наполняться отдельно) + 4. Последовательно синхронизирует сущности: companies → contacts → leads → customers → segments → calls → tasks → transactions → elements → unsorted + 5. Заполняет связующие таблицы + 6. Заполняет фактовые таблицы + 7. Возвращает отчёт: `['pipelines' => N, 'leads' => N, ...]` +- Метод `incrementalSync(int $accountId, DateTime $since): array` — инкрементальная синхронизация (только изменённые записи с `$since`) + +**Ссылки:** все ETL-сервисы из этапов 11–14 + +--- + +## Этап 16: Пример использования и документация + +**Цель:** Создать пример полного цикла выгрузки. + +**Метод:** Создать `examples/dwh_full_sync.php`: +- Инициализация `AmoCRMApiClient` с OAuth +- Создание `DwhDbAdapter` (PDO к MySQL) +- Запуск `DwhSyncOrchestrator::fullSync()` +- Вывод отчёта + +Обновить `README.md`: добавить раздел «Аналитические таблицы (DWH)» с описанием архитектуры и примером использования. + +**Ссылки:** `examples/`, `README.md` + +# 5. TESTING AND VALIDATION + +**Валидация SQL-схемы:** +- Прогнать все миграции на чистой MySQL/MariaDB БД — убедиться, что нет синтаксических ошибок +- Проверить целостность: все FK-ссылки указывают на существующие таблицы +- Проверить индексы: `EXPLAIN` на типовых JOIN-запросах фактов с измерениями + +**Валидация моделей:** +- Unit-тесты для каждого DWH-модельного класса: `testToArray()` проверяет, что все поля сериализуются; `testFromArray()` проверяет обратную десериализацию +- Тесты для коллекций: `testAdd()`, `testFromArray()`, `testToArray()` + +**Валидация ETL:** +- Интеграционные тесты с тестовым аккаунтом amoCRM: + - Создать тестовые данные через API (сделку, контакт, компанию) + - Запустить `fullSync()` + - Проверить, что данные корректно попали во все соответствующие таблицы (основные + attributes + tags + notes + events + facts) +- Проверить инкрементальную синхронизацию: изменить сущность → `incrementalSync()` → только изменённые записи обновлены +- Проверить идемпотентность: повторный `fullSync()` не дублирует данные + +**Критерии успеха:** +- Все 48 таблиц созданы, структура соответствует справочнику +- `fullSync()` на тестовом аккаунте (10+ сущностей каждого типа) завершается без ошибок +- Данные в фактовых таблицах корректно ссылаются на измерения (JOIN дают осмысленный результат) +- Опечатка в `amocrm_segments_facts` исправлена diff --git a/README.md b/README.md index e97fe18..ba17779 100644 --- a/README.md +++ b/README.md @@ -1087,6 +1087,62 @@ CLIENT_REDIRECT_URI="https://example.com/examples/get_token.php (Важно об После авторизации вы можете проверить работу примеров, обращаясь к ним из браузера. Стоит отметить, что для корректной работы примеров необходимо проверить ID сущностей в них. +## Аналитические таблицы (DWH) + +Библиотека включает модуль для выгрузки данных amoCRM в аналитическое хранилище данных (DWH) на базе MySQL/MariaDB. + +### Архитектура DWH + +Модуль реализует трёхслойную архитектуру в namespace `AmoCRM\Dwh`: + +- **SQL-слой** (`migrations/`) — 15 миграций для создания 48+ таблиц: справочники, измерения, факты и связующие таблицы +- **Модельный слой** (`src/AmoCRM/Dwh/Models/`) — PHP-модели, соответствующие таблицам DWH +- **ETL-слой** (`src/AmoCRM/Dwh/Services/`) — сервисы для извлечения данных из API и загрузки в DWH + +### Структура таблиц + +| Группа | Количество | Назначение | +|---|---|---| +| Вспомогательные | 3 | Справочники: воронки, этапы, статусы покупателей | +| SHD-измерения | 3 | Общие измерения: даты, трафик, clientIds | +| Измерения | 27 | Атрибуты сущностей: сделки, контакты, компании, покупатели и др. | +| Связующие | 4 | M:N связи (сделки-контакты, покупатели-сегменты и др.) | +| Факты | 11 | Числовые метрики со ссылками на измерения | + +### Быстрый старт + +```php +use AmoCRM\Client\AmoCRMApiClient; +use AmoCRM\Dwh\DwhDbAdapter; +use AmoCRM\Dwh\DwhSyncOrchestrator; + +// Инициализация API-клиента +$apiClient = new AmoCRMApiClient($clientId, $clientSecret, $redirectUri); +$apiClient->setAccessToken($accessToken) + ->setAccountBaseDomain('example.amocrm.ru'); + +// Подключение к MySQL +$pdo = new PDO('mysql:host=127.0.0.1;dbname=amocrm_dwh;charset=utf8mb4', 'user', 'pass'); +$db = new DwhDbAdapter($pdo); + +// Полная синхронизация +$orchestrator = new DwhSyncOrchestrator($apiClient, $db, $accountId); +$report = $orchestrator->fullSync(); + +// Инкрементальная синхронизация +$report = $orchestrator->incrementalSync(new DateTime('2024-01-01')); +``` + +Полный пример: `examples/dwh_full_sync.php`. + +### Накатывание миграций + +```bash +for f in migrations/*.sql; do + mysql -u root -p amocrm_dwh < "$f" +done +``` + ## Работа с Issues Если вы столкнулись с проблемой при работе с библиотекой, вы можете составить Issue, который будет рассмотрен при первой возможности. diff --git a/examples/dwh_full_sync.php b/examples/dwh_full_sync.php new file mode 100644 index 0000000..ead0429 --- /dev/null +++ b/examples/dwh_full_sync.php @@ -0,0 +1,79 @@ +setAccessToken($accessToken) + ->setAccountBaseDomain($accessToken->getValues()['baseDomain']) + ->onAccessTokenRefresh( + function (AccessToken $accessToken, string $baseDomain) { + saveToken([ + 'accessToken' => $accessToken->getToken(), + 'refreshToken' => $accessToken->getRefreshToken(), + 'expires' => $accessToken->getExpires(), + 'baseDomain' => $baseDomain, + ]); + } + ); + +// --- 2. Инициализация DWH (подключение к MySQL) --- +$dsn = $_ENV['DB_DSN'] ?? 'mysql:host=127.0.0.1;dbname=amocrm_dwh;charset=utf8mb4'; +$user = $_ENV['DB_USER'] ?? 'root'; +$pass = $_ENV['DB_PASS'] ?? ''; + +$pdo = new PDO($dsn, $user, $pass, [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, +]); + +$dbAdapter = new DwhDbAdapter($pdo); + +// ID аккаунта (можно получить из токена или задать явно) +$accountId = 1; + +// --- 3. Полная синхронизация --- +$orchestrator = new DwhSyncOrchestrator($apiClient, $dbAdapter, $accountId); + +echo "=== Starting full DWH sync ===\n"; +$startTime = microtime(true); + +$report = $orchestrator->fullSync(['limit' => 250]); + +$duration = round(microtime(true) - $startTime, 2); + +echo "=== Sync complete in {$duration}s ===\n\n"; +echo "Results:\n"; +foreach ($report as $entity => $count) { + echo " {$entity}: {$count} records\n"; +} + +// --- 4. Инкрементальная синхронизация (опционально) --- +// $since = new DateTime('2024-01-01 00:00:00'); +// $report = $orchestrator->incrementalSync($since); diff --git a/migrations/001_auxiliary_tables.sql b/migrations/001_auxiliary_tables.sql new file mode 100644 index 0000000..3c397a2 --- /dev/null +++ b/migrations/001_auxiliary_tables.sql @@ -0,0 +1,46 @@ +-- ============================================================ +-- Миграция 001: Вспомогательные таблицы (справочники) +-- Таблицы: amocrm_pipelines, amocrm_statuses, amocrm_periodicity +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_pipelines` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `pipeline_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(255) NOT NULL, + `sort` INT UNSIGNED NOT NULL DEFAULT 0, + `is_main` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `is_unsorted_on` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `is_archive` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_pipeline` (`account_id`, `pipeline_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_statuses` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `status_id` BIGINT UNSIGNED NOT NULL, + `pipeline_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(255) NOT NULL, + `sort` INT UNSIGNED NOT NULL DEFAULT 0, + `color` VARCHAR(20) NULL, + `type` INT UNSIGNED NOT NULL DEFAULT 0, + `editable` TINYINT UNSIGNED NOT NULL DEFAULT 1, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_status` (`account_id`, `status_id`), + INDEX `idx_account_pipeline` (`account_id`, `pipeline_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_periodicity` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `periodicity_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(255) NOT NULL, + `sort` INT UNSIGNED NOT NULL DEFAULT 0, + `color` VARCHAR(20) NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_periodicity` (`account_id`, `periodicity_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/002_shd_tables.sql b/migrations/002_shd_tables.sql new file mode 100644 index 0000000..0ab5e1a --- /dev/null +++ b/migrations/002_shd_tables.sql @@ -0,0 +1,45 @@ +-- ============================================================ +-- Миграция 002: Общие измерения (SHD) +-- Таблицы: general_traffic, general_clientids, general_dates +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `general_dates` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `date` DATE NOT NULL, + `year` SMALLINT UNSIGNED NOT NULL, + `quarter` TINYINT UNSIGNED NOT NULL, + `month` TINYINT UNSIGNED NOT NULL, + `week` TINYINT UNSIGNED NOT NULL, + `day` TINYINT UNSIGNED NOT NULL, + `day_of_week` TINYINT UNSIGNED NOT NULL, + `is_weekend` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `is_holiday` TINYINT UNSIGNED NOT NULL DEFAULT 0, + INDEX `idx_account_date` (`account_id`, `date`), + UNIQUE KEY `uq_account_date` (`account_id`, `date`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `general_traffic` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `traffic_id` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NULL, + `source` VARCHAR(255) NULL, + `medium` VARCHAR(255) NULL, + `campaign` VARCHAR(255) NULL, + `term` VARCHAR(255) NULL, + `content` VARCHAR(255) NULL, + `created_at` DATETIME NULL, + INDEX `idx_account_traffic` (`account_id`, `traffic_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `general_clientids` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `client_id` VARCHAR(255) NOT NULL, + `name` VARCHAR(255) NULL, + `first_seen_at` DATETIME NULL, + `last_seen_at` DATETIME NULL, + `created_at` DATETIME NULL, + INDEX `idx_account_clientid` (`account_id`, `client_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/003_dimension_calls.sql b/migrations/003_dimension_calls.sql new file mode 100644 index 0000000..5bf4b6c --- /dev/null +++ b/migrations/003_dimension_calls.sql @@ -0,0 +1,24 @@ +-- ============================================================ +-- Миграция 003: Измерение — Звонки +-- Таблицы: amocrm_calls +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_calls` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `call_id` BIGINT UNSIGNED NOT NULL, + `entity_type` VARCHAR(50) NULL, + `entity_id` BIGINT UNSIGNED NULL, + `phone` VARCHAR(50) NULL, + `direction` VARCHAR(20) NULL, + `status` VARCHAR(20) NULL, + `result` VARCHAR(255) NULL, + `duration` INT UNSIGNED NULL, + `call_responsible_user_id` BIGINT UNSIGNED NULL, + `source` VARCHAR(100) NULL, + `note` TEXT NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_call` (`account_id`, `call_id`), + INDEX `idx_account_entity` (`account_id`, `entity_type`, `entity_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/004_dimension_unsorted.sql b/migrations/004_dimension_unsorted.sql new file mode 100644 index 0000000..e040a74 --- /dev/null +++ b/migrations/004_dimension_unsorted.sql @@ -0,0 +1,32 @@ +-- ============================================================ +-- Миграция 004: Измерение — Неразобранное +-- Таблицы: amocrm_unsorted +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_unsorted` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `unsorted_id` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(255) NULL, + `source_uid` VARCHAR(255) NULL, + `source_name` VARCHAR(255) NULL, + `category` VARCHAR(50) NULL, + `pipeline_id` BIGINT UNSIGNED NULL, + `status_id` BIGINT UNSIGNED NULL, + `form_id` VARCHAR(100) NULL, + `form_name` VARCHAR(255) NULL, + `form_page` VARCHAR(500) NULL, + `form_sent_at` DATETIME NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `group_id` BIGINT UNSIGNED NULL, + `lead_id` BIGINT UNSIGNED NULL, + `contact_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `is_processed` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `data_json` JSON NULL, + `metadata_json` JSON NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_unsorted` (`account_id`, `unsorted_id`), + INDEX `idx_account_category` (`account_id`, `category`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/005_dimension_companies.sql b/migrations/005_dimension_companies.sql new file mode 100644 index 0000000..2a7fb5a --- /dev/null +++ b/migrations/005_dimension_companies.sql @@ -0,0 +1,77 @@ +-- ============================================================ +-- Миграция 005: Измерение — Компании +-- Таблицы: amocrm_companies, companies_attributes, companies_tags, companies_notes, companies_events +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_companies` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `closest_task_at` DATETIME NULL, + `score` INT NULL, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_company` (`account_id`, `company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_companies_attributes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `field_id` BIGINT UNSIGNED NOT NULL, + `field_name` VARCHAR(255) NULL, + `field_type` VARCHAR(50) NULL, + `field_code` VARCHAR(100) NULL, + `value` TEXT NULL, + `enum_id` BIGINT UNSIGNED NULL, + `enum_code` VARCHAR(100) NULL, + INDEX `idx_account_company_field` (`account_id`, `company_id`, `field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_companies_tags` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `tag_id` BIGINT UNSIGNED NULL, + `name` VARCHAR(255) NOT NULL, + `color` VARCHAR(20) NULL, + INDEX `idx_account_company_tag` (`account_id`, `company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_companies_notes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `note_id` BIGINT UNSIGNED NOT NULL, + `note_type` VARCHAR(50) NULL, + `element_id` BIGINT UNSIGNED NULL, + `element_type` VARCHAR(50) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `text` TEXT NULL, + `params` JSON NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_company_note` (`account_id`, `company_id`, `note_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_companies_events` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `event_id` VARCHAR(100) NULL, + `event_type` VARCHAR(100) NULL, + `event_value_before` TEXT NULL, + `event_value_after` TEXT NULL, + `event_created_user_id` BIGINT UNSIGNED NULL, + `event_created_at` DATETIME NULL, + INDEX `idx_account_company_event` (`account_id`, `company_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/006_dimension_contacts.sql b/migrations/006_dimension_contacts.sql new file mode 100644 index 0000000..298b4f7 --- /dev/null +++ b/migrations/006_dimension_contacts.sql @@ -0,0 +1,80 @@ +-- ============================================================ +-- Миграция 006: Измерение — Контакты +-- Таблицы: amocrm_contacts, contacts_attributes, contacts_tags, contacts_notes, contacts_events +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_contacts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `first_name` VARCHAR(255) NULL, + `last_name` VARCHAR(255) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `company_name` VARCHAR(500) NULL, + `closest_task_at` DATETIME NULL, + `score` INT NULL, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_contact` (`account_id`, `contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_contacts_attributes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `field_id` BIGINT UNSIGNED NOT NULL, + `field_name` VARCHAR(255) NULL, + `field_type` VARCHAR(50) NULL, + `field_code` VARCHAR(100) NULL, + `value` TEXT NULL, + `enum_id` BIGINT UNSIGNED NULL, + `enum_code` VARCHAR(100) NULL, + INDEX `idx_account_contact_field` (`account_id`, `contact_id`, `field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_contacts_tags` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `tag_id` BIGINT UNSIGNED NULL, + `name` VARCHAR(255) NOT NULL, + `color` VARCHAR(20) NULL, + INDEX `idx_account_contact_tag` (`account_id`, `contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_contacts_notes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `note_id` BIGINT UNSIGNED NOT NULL, + `note_type` VARCHAR(50) NULL, + `element_id` BIGINT UNSIGNED NULL, + `element_type` VARCHAR(50) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `text` TEXT NULL, + `params` JSON NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_contact_note` (`account_id`, `contact_id`, `note_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_contacts_events` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `event_id` VARCHAR(100) NULL, + `event_type` VARCHAR(100) NULL, + `event_value_before` TEXT NULL, + `event_value_after` TEXT NULL, + `event_created_user_id` BIGINT UNSIGNED NULL, + `event_created_at` DATETIME NULL, + INDEX `idx_account_contact_event` (`account_id`, `contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/007_dimension_leads.sql b/migrations/007_dimension_leads.sql new file mode 100644 index 0000000..87f3573 --- /dev/null +++ b/migrations/007_dimension_leads.sql @@ -0,0 +1,90 @@ +-- ============================================================ +-- Миграция 007: Измерение — Сделки +-- Таблицы: amocrm_leads, leads_attributes, leads_tags, leads_notes, leads_events +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_leads` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `price` DECIMAL(15,2) NULL, + `pipeline_id` BIGINT UNSIGNED NULL, + `status_id` BIGINT UNSIGNED NULL, + `old_status_id` BIGINT UNSIGNED NULL, + `loss_reason_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `contact_id` BIGINT UNSIGNED NULL, + `closed_user_id` BIGINT UNSIGNED NULL, + `closed_at` DATETIME NULL, + `closest_task_at` DATETIME NULL, + `score` INT NULL, + `is_price_modified_by_robot` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `source_external_id` VARCHAR(255) NULL, + `visitor_uid` VARCHAR(255) NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_lead` (`account_id`, `lead_id`), + INDEX `idx_account_pipeline_status` (`account_id`, `pipeline_id`, `status_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_leads_attributes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `field_id` BIGINT UNSIGNED NOT NULL, + `field_name` VARCHAR(255) NULL, + `field_type` VARCHAR(50) NULL, + `field_code` VARCHAR(100) NULL, + `value` TEXT NULL, + `enum_id` BIGINT UNSIGNED NULL, + `enum_code` VARCHAR(100) NULL, + INDEX `idx_account_lead_field` (`account_id`, `lead_id`, `field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_leads_tags` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `tag_id` BIGINT UNSIGNED NULL, + `name` VARCHAR(255) NOT NULL, + `color` VARCHAR(20) NULL, + INDEX `idx_account_lead_tag` (`account_id`, `lead_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_leads_notes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `note_id` BIGINT UNSIGNED NOT NULL, + `note_type` VARCHAR(50) NULL, + `element_id` BIGINT UNSIGNED NULL, + `element_type` VARCHAR(50) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `text` TEXT NULL, + `params` JSON NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_lead_note` (`account_id`, `lead_id`, `note_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_leads_events` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `event_id` VARCHAR(100) NULL, + `event_type` VARCHAR(100) NULL, + `event_value_before` TEXT NULL, + `event_value_after` TEXT NULL, + `event_created_user_id` BIGINT UNSIGNED NULL, + `event_created_at` DATETIME NULL, + INDEX `idx_account_lead_event` (`account_id`, `lead_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/008_dimension_segments.sql b/migrations/008_dimension_segments.sql new file mode 100644 index 0000000..b3cd6cb --- /dev/null +++ b/migrations/008_dimension_segments.sql @@ -0,0 +1,32 @@ +-- ============================================================ +-- Миграция 008: Измерение — Сегменты +-- Таблицы: amocrm_segments, amocrm_segments_attributes +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_segments` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `segment_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(255) NOT NULL, + `color` VARCHAR(20) NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `customers_count` INT UNSIGNED NULL, + `conversion_rate` DECIMAL(5,2) NULL, + `max_discount` DECIMAL(5,2) NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_segment` (`account_id`, `segment_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_segments_attributes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `segment_id` BIGINT UNSIGNED NOT NULL, + `field_id` BIGINT UNSIGNED NOT NULL, + `field_name` VARCHAR(255) NULL, + `field_type` VARCHAR(50) NULL, + `field_code` VARCHAR(100) NULL, + `value` TEXT NULL, + INDEX `idx_account_segment_field` (`account_id`, `segment_id`, `field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/009_dimension_customers.sql b/migrations/009_dimension_customers.sql new file mode 100644 index 0000000..48fdc49 --- /dev/null +++ b/migrations/009_dimension_customers.sql @@ -0,0 +1,74 @@ +-- ============================================================ +-- Миграция 009: Измерение — Покупатели +-- Таблицы: amocrm_customers, customers_attributes, customers_tags, customers_notes +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_customers` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `contact_name` VARCHAR(500) NULL, + `company_name` VARCHAR(500) NULL, + `contact_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `status_id` BIGINT UNSIGNED NULL, + `periodicity_id` BIGINT UNSIGNED NULL, + `period_id` INT UNSIGNED NULL, + `next_price` DECIMAL(15,2) NULL, + `ltv` DECIMAL(15,2) NULL, + `purchases` INT UNSIGNED NULL, + `average_check` DECIMAL(15,2) NULL, + `next_date` DATETIME NULL, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_customer` (`account_id`, `customer_id`), + INDEX `idx_account_contact` (`account_id`, `contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_customers_attributes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `field_id` BIGINT UNSIGNED NOT NULL, + `field_name` VARCHAR(255) NULL, + `field_type` VARCHAR(50) NULL, + `field_code` VARCHAR(100) NULL, + `value` TEXT NULL, + `enum_id` BIGINT UNSIGNED NULL, + `enum_code` VARCHAR(100) NULL, + INDEX `idx_account_customer_field` (`account_id`, `customer_id`, `field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_customers_tags` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `tag_id` BIGINT UNSIGNED NULL, + `name` VARCHAR(255) NOT NULL, + `color` VARCHAR(20) NULL, + INDEX `idx_account_customer_tag` (`account_id`, `customer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_customers_notes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `note_id` BIGINT UNSIGNED NOT NULL, + `note_type` VARCHAR(50) NULL, + `element_id` BIGINT UNSIGNED NULL, + `element_type` VARCHAR(50) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `text` TEXT NULL, + `params` JSON NULL, + `group_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_customer_note` (`account_id`, `customer_id`, `note_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/010_dimension_transactions.sql b/migrations/010_dimension_transactions.sql new file mode 100644 index 0000000..31a584a --- /dev/null +++ b/migrations/010_dimension_transactions.sql @@ -0,0 +1,23 @@ +-- ============================================================ +-- Миграция 010: Измерение — Транзакции +-- Таблицы: amocrm_transactions +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_transactions` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `transaction_id` BIGINT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NULL, + `contact_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `completed_at` DATETIME NULL, + `price` DECIMAL(15,2) NULL, + `comment` TEXT NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_transaction` (`account_id`, `transaction_id`), + INDEX `idx_account_customer` (`account_id`, `customer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/011_dimension_tasks.sql b/migrations/011_dimension_tasks.sql new file mode 100644 index 0000000..922b736 --- /dev/null +++ b/migrations/011_dimension_tasks.sql @@ -0,0 +1,41 @@ +-- ============================================================ +-- Миграция 011: Измерение — Задачи +-- Таблицы: amocrm_tasks, amocrm_tasks_events +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_tasks` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `task_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `task_type_id` BIGINT UNSIGNED NULL, + `entity_type` VARCHAR(50) NULL, + `entity_id` BIGINT UNSIGNED NULL, + `duration` INT UNSIGNED NULL, + `complete_till_at` DATETIME NULL, + `completed_at` DATETIME NULL, + `result` TEXT NULL, + `is_completed` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `group_id` BIGINT UNSIGNED NULL, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_task` (`account_id`, `task_id`), + INDEX `idx_account_entity` (`account_id`, `entity_type`, `entity_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_tasks_events` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `task_id` BIGINT UNSIGNED NOT NULL, + `event_id` VARCHAR(100) NULL, + `event_type` VARCHAR(100) NULL, + `event_value_before` TEXT NULL, + `event_value_after` TEXT NULL, + `event_created_user_id` BIGINT UNSIGNED NULL, + `event_created_at` DATETIME NULL, + INDEX `idx_account_task_event` (`account_id`, `task_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/012_dimension_elements.sql b/migrations/012_dimension_elements.sql new file mode 100644 index 0000000..f4d5c71 --- /dev/null +++ b/migrations/012_dimension_elements.sql @@ -0,0 +1,48 @@ +-- ============================================================ +-- Миграция 012: Измерение — Элементы каталогов +-- Таблицы: amocrm_elements, amocrm_elements_attributes, amocrm_elements_products +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_elements` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `element_id` BIGINT UNSIGNED NOT NULL, + `catalog_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `article` VARCHAR(255) NULL, + `price` DECIMAL(15,2) NULL, + `quantity` DECIMAL(15,4) NULL, + `external_id` VARCHAR(255) NULL, + `is_deleted` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_element` (`account_id`, `element_id`), + INDEX `idx_account_catalog` (`account_id`, `catalog_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_elements_attributes` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `element_id` BIGINT UNSIGNED NOT NULL, + `field_id` BIGINT UNSIGNED NOT NULL, + `field_name` VARCHAR(255) NULL, + `field_type` VARCHAR(50) NULL, + `field_code` VARCHAR(100) NULL, + `value` TEXT NULL, + `enum_id` BIGINT UNSIGNED NULL, + `enum_code` VARCHAR(100) NULL, + INDEX `idx_account_element_field` (`account_id`, `element_id`, `field_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_elements_products` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `element_id` BIGINT UNSIGNED NOT NULL, + `product_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(500) NULL, + `quantity` DECIMAL(15,4) NULL, + `price` DECIMAL(15,2) NULL, + INDEX `idx_account_element_product` (`account_id`, `element_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/013_dimension_users.sql b/migrations/013_dimension_users.sql new file mode 100644 index 0000000..272a880 --- /dev/null +++ b/migrations/013_dimension_users.sql @@ -0,0 +1,23 @@ +-- ============================================================ +-- Миграция 013: Измерение — Пользователи +-- Таблицы: amocrm_users +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_users` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `user_id` BIGINT UNSIGNED NOT NULL, + `name` VARCHAR(255) NOT NULL, + `email` VARCHAR(255) NULL, + `lang` VARCHAR(10) NULL, + `phone_number` VARCHAR(50) NULL, + `rights` JSON NULL, + `role_id` BIGINT UNSIGNED NULL, + `group_id` BIGINT UNSIGNED NULL, + `is_admin` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `is_free` TINYINT UNSIGNED NOT NULL DEFAULT 0, + `is_active` TINYINT UNSIGNED NOT NULL DEFAULT 1, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_user` (`account_id`, `user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/014_linking_tables.sql b/migrations/014_linking_tables.sql new file mode 100644 index 0000000..e502a38 --- /dev/null +++ b/migrations/014_linking_tables.sql @@ -0,0 +1,47 @@ +-- ============================================================ +-- Миграция 014: Связующие таблицы (M:N) +-- Таблицы: amocrm_leads_contacts, amocrm_customers_segments +-- ============================================================ + +CREATE TABLE IF NOT EXISTS `amocrm_leads_contacts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `is_main` TINYINT UNSIGNED NOT NULL DEFAULT 0, + INDEX `idx_account_lead` (`account_id`, `lead_id`), + INDEX `idx_account_contact` (`account_id`, `contact_id`), + UNIQUE KEY `uq_account_lead_contact` (`account_id`, `lead_id`, `contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_customers_segments` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `segment_id` BIGINT UNSIGNED NOT NULL, + INDEX `idx_account_customer` (`account_id`, `customer_id`), + INDEX `idx_account_segment` (`account_id`, `segment_id`), + UNIQUE KEY `uq_account_customer_segment` (`account_id`, `customer_id`, `segment_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_customers_members` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `member_id` BIGINT UNSIGNED NOT NULL, + `member_type` VARCHAR(50) NOT NULL, + INDEX `idx_account_customer` (`account_id`, `customer_id`), + INDEX `idx_account_member` (`account_id`, `member_id`, `member_type`), + UNIQUE KEY `uq_account_customer_member` (`account_id`, `customer_id`, `member_id`, `member_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `amocrm_companies_contacts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `is_main` TINYINT UNSIGNED NOT NULL DEFAULT 0, + INDEX `idx_account_company` (`account_id`, `company_id`), + INDEX `idx_account_contact` (`account_id`, `contact_id`), + UNIQUE KEY `uq_account_company_contact` (`account_id`, `company_id`, `contact_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/migrations/015_fact_tables.sql b/migrations/015_fact_tables.sql new file mode 100644 index 0000000..2b6974a --- /dev/null +++ b/migrations/015_fact_tables.sql @@ -0,0 +1,167 @@ +-- ============================================================ +-- Миграция 015: Таблицы фактов +-- 11 таблиц фактов со ссылками на измерения +-- ============================================================ + +-- Факты по звонкам +CREATE TABLE IF NOT EXISTS `amocrm_calls_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `call_id` BIGINT UNSIGNED NOT NULL, + `date_id` BIGINT UNSIGNED NULL, + `entity_type` VARCHAR(50) NULL, + `entity_id` BIGINT UNSIGNED NULL, + `user_id` BIGINT UNSIGNED NULL, + `duration` INT UNSIGNED NULL, + `status` VARCHAR(20) NULL, + INDEX `idx_account_call` (`account_id`, `call_id`), + INDEX `idx_account_date` (`account_id`, `date_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по контактам +CREATE TABLE IF NOT EXISTS `amocrm_contacts_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NOT NULL, + `date_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `score` INT NULL, + INDEX `idx_account_contact` (`account_id`, `contact_id`), + INDEX `idx_account_date` (`account_id`, `date_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по компаниям +CREATE TABLE IF NOT EXISTS `amocrm_companies_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `company_id` BIGINT UNSIGNED NOT NULL, + `date_id` BIGINT UNSIGNED NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `score` INT NULL, + INDEX `idx_account_company` (`account_id`, `company_id`), + INDEX `idx_account_date` (`account_id`, `date_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по сделкам +CREATE TABLE IF NOT EXISTS `amocrm_leads_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `date_create_id` BIGINT UNSIGNED NULL, + `date_close_id` BIGINT UNSIGNED NULL, + `client_id` VARCHAR(255) NULL, + `traffic_id` VARCHAR(255) NULL, + `pipeline_id` BIGINT UNSIGNED NULL, + `status_id` BIGINT UNSIGNED NULL, + `loss_reason_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `contact_id` BIGINT UNSIGNED NULL, + `price` DECIMAL(15,2) NULL, + `labor_cost` DECIMAL(15,2) NULL, + `score` INT NULL, + INDEX `idx_account_lead` (`account_id`, `lead_id`), + INDEX `idx_account_date_create` (`account_id`, `date_create_id`), + INDEX `idx_account_date_close` (`account_id`, `date_close_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по сегментам +CREATE TABLE IF NOT EXISTS `amocrm_segments_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `segment_id` BIGINT UNSIGNED NOT NULL, + `created_user_id` BIGINT UNSIGNED NULL, + `modified_user_id` BIGINT UNSIGNED NULL, + `customers_count` INT UNSIGNED NULL, + `conversion_rate` DECIMAL(5,2) NULL, + `max_discount` DECIMAL(5,2) NULL, + `created_at` DATETIME NULL, + `updated_at` DATETIME NULL, + INDEX `idx_account_segment` (`account_id`, `segment_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по покупателям +CREATE TABLE IF NOT EXISTS `amocrm_customers_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `contact_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `periodicity_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `next_date` DATETIME NULL, + `next_price` DECIMAL(15,2) NULL, + `purchases` INT UNSIGNED NULL, + `average_check` DECIMAL(15,2) NULL, + `ltv` DECIMAL(15,2) NULL, + `labor_cost` DECIMAL(15,2) NULL, + INDEX `idx_account_customer` (`account_id`, `customer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по транзакциям +CREATE TABLE IF NOT EXISTS `amocrm_transactions_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `transaction_id` BIGINT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NULL, + `contact_id` BIGINT UNSIGNED NULL, + `company_id` BIGINT UNSIGNED NULL, + `date_id` BIGINT UNSIGNED NULL, + `completed_at` DATETIME NULL, + `price` DECIMAL(15,2) NULL, + INDEX `idx_account_transaction` (`account_id`, `transaction_id`), + INDEX `idx_account_customer` (`account_id`, `customer_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по задачам +CREATE TABLE IF NOT EXISTS `amocrm_tasks_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `task_id` BIGINT UNSIGNED NOT NULL, + `date_create_id` BIGINT UNSIGNED NULL, + `date_complete_id` BIGINT UNSIGNED NULL, + `entity_type` VARCHAR(50) NULL, + `entity_id` BIGINT UNSIGNED NULL, + `responsible_user_id` BIGINT UNSIGNED NULL, + `duration` INT UNSIGNED NULL, + `is_completed` TINYINT UNSIGNED NOT NULL DEFAULT 0, + INDEX `idx_account_task` (`account_id`, `task_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по элементам транзакций +CREATE TABLE IF NOT EXISTS `amocrm_transactions_elements_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `transaction_id` BIGINT UNSIGNED NOT NULL, + `element_id` BIGINT UNSIGNED NOT NULL, + `quantity` DECIMAL(15,4) NULL, + `price` DECIMAL(15,2) NULL, + INDEX `idx_account_transaction` (`account_id`, `transaction_id`), + INDEX `idx_account_element` (`account_id`, `element_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по элементам сделок +CREATE TABLE IF NOT EXISTS `amocrm_leads_elements_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `lead_id` BIGINT UNSIGNED NOT NULL, + `element_id` BIGINT UNSIGNED NOT NULL, + `quantity` DECIMAL(15,4) NULL, + `price` DECIMAL(15,2) NULL, + INDEX `idx_account_lead` (`account_id`, `lead_id`), + INDEX `idx_account_element` (`account_id`, `element_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Факты по элементам покупателей +CREATE TABLE IF NOT EXISTS `amocrm_customers_elements_facts` ( + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + `account_id` INT UNSIGNED NOT NULL, + `customer_id` BIGINT UNSIGNED NOT NULL, + `element_id` BIGINT UNSIGNED NOT NULL, + `quantity` DECIMAL(15,4) NULL, + `price` DECIMAL(15,2) NULL, + INDEX `idx_account_customer` (`account_id`, `customer_id`), + INDEX `idx_account_element` (`account_id`, `element_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/AmoCRM/Dwh/Collections/BaseDwhCollection.php b/src/AmoCRM/Dwh/Collections/BaseDwhCollection.php new file mode 100644 index 0000000..20ba553 --- /dev/null +++ b/src/AmoCRM/Dwh/Collections/BaseDwhCollection.php @@ -0,0 +1,139 @@ +fromArray($item); + }, + $array + ) + ); + } + + public static function make(array $items): self + { + $collection = new static(); + foreach ($items as $item) { + $collection->add($item); + } + + return $collection; + } + + public function add(BaseDwhModel $value): self + { + $this->data[] = $this->checkItem($value); + + return $this; + } + + public function all(): array + { + return $this->data; + } + + public function first(): ?BaseDwhModel + { + $first = reset($this->data); + if (!$first) { + $first = null; + } + + return $first; + } + + public function count(): int + { + return count($this->data); + } + + public function isEmpty(): bool + { + return empty($this->data); + } + + public function toArray(): array + { + $result = []; + foreach ($this->data as $key => $item) { + $result[$key] = $item->toArray(); + } + + return $result; + } + + public function toInsertArray(): array + { + $result = []; + foreach ($this->data as $key => $item) { + $result[$key] = $item->toInsertArray(); + } + + return $result; + } + + public function offsetSet($offset, $value): void + { + $this->data[$offset] = $this->checkItem($value); + } + + public function offsetGet($offset): ?BaseDwhModel + { + return $this->data[$offset] ?? null; + } + + public function offsetUnset($offset): void + { + unset($this->data[$offset]); + } + + public function offsetExists($offset): bool + { + return array_key_exists($offset, $this->data); + } + + public function getIterator(): Traversable + { + return new ArrayIterator($this->data); + } + + public function jsonSerialize(): array + { + return $this->toArray(); + } +} diff --git a/src/AmoCRM/Dwh/Collections/CallDwhCollection.php b/src/AmoCRM/Dwh/Collections/CallDwhCollection.php new file mode 100644 index 0000000..5ad56a0 --- /dev/null +++ b/src/AmoCRM/Dwh/Collections/CallDwhCollection.php @@ -0,0 +1,10 @@ +pdo = $pdo; + $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } + + public function getPdo(): PDO + { + return $this->pdo; + } + + public function beginTransaction(): void + { + $this->pdo->beginTransaction(); + } + + public function commit(): void + { + $this->pdo->commit(); + } + + public function rollback(): void + { + $this->pdo->rollBack(); + } + + public function insert(string $table, array $data): int + { + $columns = array_keys($data); + $placeholders = array_map(static fn($c) => ':' . $c, $columns); + $sql = sprintf( + 'INSERT INTO `%s` (`%s`) VALUES (%s)', + $table, + implode('`, `', $columns), + implode(', ', $placeholders) + ); + $stmt = $this->pdo->prepare($sql); + $stmt->execute($data); + + return (int)$this->pdo->lastInsertId(); + } + + public function upsert(string $table, array $data, array $uniqueKeys): int + { + $columns = array_keys($data); + $placeholders = array_map(static fn($c) => ':' . $c, $columns); + $updates = array_map(static fn($c) => "`$c` = VALUES(`$c`)", $columns); + + $sql = sprintf( + 'INSERT INTO `%s` (`%s`) VALUES (%s) ON DUPLICATE KEY UPDATE %s', + $table, + implode('`, `', $columns), + implode(', ', $placeholders), + implode(', ', $updates) + ); + $stmt = $this->pdo->prepare($sql); + $stmt->execute($data); + + return $stmt->rowCount(); + } + + public function bulkInsert(string $table, array $rows): int + { + if (empty($rows)) { + return 0; + } + $columns = array_keys(reset($rows)); + $placeholders = array_map(static fn($c) => ':' . $c, $columns); + $sql = sprintf( + 'INSERT INTO `%s` (`%s`) VALUES (%s)', + $table, + implode('`, `', $columns), + implode(', ', $placeholders) + ); + $stmt = $this->pdo->prepare($sql); + $count = 0; + foreach ($rows as $row) { + $stmt->execute($row); + $count++; + } + + return $count; + } + + public function deleteBy(string $table, array $conditions): int + { + $wheres = []; + $params = []; + foreach ($conditions as $col => $val) { + $wheres[] = "`$col` = :$col"; + $params[$col] = $val; + } + $sql = sprintf('DELETE FROM `%s` WHERE %s', $table, implode(' AND ', $wheres)); + $stmt = $this->pdo->prepare($sql); + $stmt->execute($params); + + return $stmt->rowCount(); + } + + public function truncate(string $table): void + { + $this->pdo->exec("TRUNCATE TABLE `$table`"); + } + + public function fetchAll(string $sql, array $params = []): array + { + $stmt = $this->pdo->prepare($sql); + $stmt->execute($params); + + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + public function fetchOne(string $sql, array $params = []): ?array + { + $stmt = $this->pdo->prepare($sql); + $stmt->execute($params); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + return $result ?: null; + } + + public function count(string $table, array $conditions = []): int + { + $sql = "SELECT COUNT(*) FROM `$table`"; + $params = []; + if (!empty($conditions)) { + $wheres = []; + foreach ($conditions as $col => $val) { + $wheres[] = "`$col` = :$col"; + $params[$col] = $val; + } + $sql .= ' WHERE ' . implode(' AND ', $wheres); + } + $stmt = $this->pdo->prepare($sql); + $stmt->execute($params); + + return (int)$stmt->fetchColumn(); + } +} diff --git a/src/AmoCRM/Dwh/DwhSyncOrchestrator.php b/src/AmoCRM/Dwh/DwhSyncOrchestrator.php new file mode 100644 index 0000000..c5ddacd --- /dev/null +++ b/src/AmoCRM/Dwh/DwhSyncOrchestrator.php @@ -0,0 +1,136 @@ +apiClient = $apiClient; + $this->db = $db; + $this->accountId = $accountId; + } + + /** + * Full synchronization of all data from amoCRM to DWH. + */ + public function fullSync(array $options = []): array + { + $report = []; + $entityOptions = ['limit' => $options['limit'] ?? 250]; + + // Stage 1: Auxiliary tables (references) + $report['pipelines'] = (new PipelineEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['statuses'] = (new StatusEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['periodicity'] = (new PeriodicityEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + + // Stage 2: Users (needed by all other tables) + $report['users'] = (new UserEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + + // Stage 3: Core entities + $report['companies'] = (new CompanyEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['contacts'] = (new ContactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['leads'] = (new LeadEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + + // Stage 4: Customer-related + $report['customers'] = (new CustomerEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['segments'] = (new SegmentEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + + // Stage 5: Other entities + $report['calls'] = (new CallEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['tasks'] = (new TaskEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['transactions'] = (new TransactionEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['elements'] = (new ElementEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + $report['unsorted'] = (new UnsortedEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync($entityOptions)['processed']; + + // Stage 6: Fact tables + $this->syncFacts($report, $options); + + return $report; + } + + /** + * Incremental synchronization — only entities modified since the given date. + */ + public function incrementalSync(DateTime $since, array $options = []): array + { + $options['since'] = $since; + + return $this->fullSync($options); + } + + /** + * Synchronize only fact tables (requires dimension tables to be populated). + */ + public function syncFacts(array &$report, array $options = []): void + { + $report['calls_facts'] = (new CallFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['contacts_facts'] = (new ContactFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['companies_facts'] = (new CompanyFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['leads_facts'] = (new LeadFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['segments_facts'] = (new SegmentFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['customers_facts'] = (new CustomerFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['transactions_facts'] = (new TransactionFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['tasks_facts'] = (new TaskFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['transaction_elements_facts'] = (new TransactionElementFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['lead_elements_facts'] = (new LeadElementFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + $report['customer_elements_facts'] = (new CustomerElementFactEtlService($this->apiClient, $this->db, $this->accountId)) + ->sync()['processed']; + } +} diff --git a/src/AmoCRM/Dwh/Enum/TableTypeEnum.php b/src/AmoCRM/Dwh/Enum/TableTypeEnum.php new file mode 100644 index 0000000..e5505f7 --- /dev/null +++ b/src/AmoCRM/Dwh/Enum/TableTypeEnum.php @@ -0,0 +1,12 @@ + $value) { + $model->$key = $value; + } + + return $model; + } + + public function __get($name) + { + $methodName = 'get' . Str::camel(Str::ucfirst($name)); + if (method_exists($this, $methodName)) { + return $this->$methodName(); + } + + return null; + } + + public function __set($name, $value) + { + $methodName = 'set' . Str::camel(Str::ucfirst($name)); + if (method_exists($this, $methodName) && is_callable([$this, $methodName])) { + $this->$methodName($value); + } + } + + public function toInsertArray(): array + { + $data = $this->toArray(); + unset($data['id']); + + return $data; + } +} diff --git a/src/AmoCRM/Dwh/Models/CallDwhModel.php b/src/AmoCRM/Dwh/Models/CallDwhModel.php new file mode 100644 index 0000000..abfbcc8 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CallDwhModel.php @@ -0,0 +1,75 @@ + $this->id, + 'account_id' => $this->accountId, + 'call_id' => $this->CallId, + 'entity_type' => $this->EntityType, + 'entity_id' => $this->EntityId, + 'phone' => $this->Phone, + 'direction' => $this->Direction, + 'status' => $this->Status, + 'result' => $this->Result, + 'duration' => $this->Duration, + 'call_responsible_user_id' => $this->CallResponsibleUserId, + 'source' => $this->Source, + 'note' => $this->Note, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCallId(): int { return $this->CallId; } + public function setCallId(int $v): self { $this->CallId = $v; return $this; } + public function getEntityType(): ?string { return $this->EntityType; } + public function setEntityType(?string $v): self { $this->EntityType = $v; return $this; } + public function getEntityId(): ?int { return $this->EntityId; } + public function setEntityId(?int $v): self { $this->EntityId = $v; return $this; } + public function getPhone(): ?string { return $this->Phone; } + public function setPhone(?string $v): self { $this->Phone = $v; return $this; } + public function getDirection(): ?string { return $this->Direction; } + public function setDirection(?string $v): self { $this->Direction = $v; return $this; } + public function getStatus(): ?string { return $this->Status; } + public function setStatus(?string $v): self { $this->Status = $v; return $this; } + public function getResult(): ?string { return $this->Result; } + public function setResult(?string $v): self { $this->Result = $v; return $this; } + public function getDuration(): ?int { return $this->Duration; } + public function setDuration(?int $v): self { $this->Duration = $v; return $this; } + public function getCallResponsibleUserId(): ?int { return $this->CallResponsibleUserId; } + public function setCallResponsibleUserId(?int $v): self { $this->CallResponsibleUserId = $v; return $this; } + public function getSource(): ?string { return $this->Source; } + public function setSource(?string $v): self { $this->Source = $v; return $this; } + public function getNote(): ?string { return $this->Note; } + public function setNote(?string $v): self { $this->Note = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CallFactDwhModel.php b/src/AmoCRM/Dwh/Models/CallFactDwhModel.php new file mode 100644 index 0000000..405a85c --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CallFactDwhModel.php @@ -0,0 +1,51 @@ + $this->id, + 'account_id' => $this->accountId, + 'call_id' => $this->CallId, + 'date_id' => $this->DateId, + 'entity_type' => $this->EntityType, + 'entity_id' => $this->EntityId, + 'user_id' => $this->UserId, + 'duration' => $this->Duration, + 'status' => $this->Status, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCallId(): int { return $this->CallId; } + public function setCallId(int $v): self { $this->CallId = $v; return $this; } + public function getDateId(): ?int { return $this->DateId; } + public function setDateId(?int $v): self { $this->DateId = $v; return $this; } + public function getEntityType(): ?string { return $this->EntityType; } + public function setEntityType(?string $v): self { $this->EntityType = $v; return $this; } + public function getEntityId(): ?int { return $this->EntityId; } + public function setEntityId(?int $v): self { $this->EntityId = $v; return $this; } + public function getUserId(): ?int { return $this->UserId; } + public function setUserId(?int $v): self { $this->UserId = $v; return $this; } + public function getDuration(): ?int { return $this->Duration; } + public function setDuration(?int $v): self { $this->Duration = $v; return $this; } + public function getStatus(): ?string { return $this->Status; } + public function setStatus(?string $v): self { $this->Status = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ClientIdDwhModel.php b/src/AmoCRM/Dwh/Models/ClientIdDwhModel.php new file mode 100644 index 0000000..dc6ec87 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ClientIdDwhModel.php @@ -0,0 +1,44 @@ + \$this->id, + 'account_id' => \$this->accountId, + 'client_id' => \$this->ClientId, + 'name' => \$this->Name, + 'first_seen_at' => \$this->FirstSeenAt, + 'last_seen_at' => \$this->LastSeenAt, + 'created_at' => \$this->CreatedAt, + ]; + } + + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getClientId(): string { return $this->ClientId; } + public function setClientId(string $v): self { $this->ClientId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getFirstSeenAt(): ?string { return $this->FirstSeenAt; } + public function setFirstSeenAt(?string $v): self { $this->FirstSeenAt = $v; return $this; } + public function getLastSeenAt(): ?string { return $this->LastSeenAt; } + public function setLastSeenAt(?string $v): self { $this->LastSeenAt = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyAttributeDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyAttributeDwhModel.php new file mode 100644 index 0000000..f20d220 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyAttributeDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'field_id' => $this->FieldId, + 'field_name' => $this->FieldName, + 'field_type' => $this->FieldType, + 'field_code' => $this->FieldCode, + 'value' => $this->Value, + 'enum_id' => $this->EnumId, + 'enum_code' => $this->EnumCode, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getFieldId(): int { return $this->FieldId; } + public function setFieldId(int $v): self { $this->FieldId = $v; return $this; } + public function getFieldName(): ?string { return $this->FieldName; } + public function setFieldName(?string $v): self { $this->FieldName = $v; return $this; } + public function getFieldType(): ?string { return $this->FieldType; } + public function setFieldType(?string $v): self { $this->FieldType = $v; return $this; } + public function getFieldCode(): ?string { return $this->FieldCode; } + public function setFieldCode(?string $v): self { $this->FieldCode = $v; return $this; } + public function getValue(): ?string { return $this->Value; } + public function setValue(?string $v): self { $this->Value = $v; return $this; } + public function getEnumId(): ?int { return $this->EnumId; } + public function setEnumId(?int $v): self { $this->EnumId = $v; return $this; } + public function getEnumCode(): ?string { return $this->EnumCode; } + public function setEnumCode(?string $v): self { $this->EnumCode = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyContactLinkDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyContactLinkDwhModel.php new file mode 100644 index 0000000..cc9a3ee --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyContactLinkDwhModel.php @@ -0,0 +1,35 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'contact_id' => $this->ContactId, + 'is_main' => $this->IsMain, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getIsMain(): int { return $this->IsMain; } + public function setIsMain(int $v): self { $this->IsMain = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyDwhModel.php new file mode 100644 index 0000000..766bcc4 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyDwhModel.php @@ -0,0 +1,67 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'name' => $this->Name, + 'responsible_user_id' => $this->ResponsibleUserId, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'closest_task_at' => $this->ClosestTaskAt, + 'score' => $this->Score, + 'is_deleted' => $this->IsDeleted, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getClosestTaskAt(): ?string { return $this->ClosestTaskAt; } + public function setClosestTaskAt(?string $v): self { $this->ClosestTaskAt = $v; return $this; } + public function getScore(): ?int { return $this->Score; } + public function setScore(?int $v): self { $this->Score = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyEventDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyEventDwhModel.php new file mode 100644 index 0000000..71158b6 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyEventDwhModel.php @@ -0,0 +1,51 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'event_id' => $this->EventId, + 'event_type' => $this->EventType, + 'event_value_before' => $this->EventValueBefore, + 'event_value_after' => $this->EventValueAfter, + 'event_created_user_id' => $this->EventCreatedUserId, + 'event_created_at' => $this->EventCreatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getEventId(): ?string { return $this->EventId; } + public function setEventId(?string $v): self { $this->EventId = $v; return $this; } + public function getEventType(): ?string { return $this->EventType; } + public function setEventType(?string $v): self { $this->EventType = $v; return $this; } + public function getEventValueBefore(): ?string { return $this->EventValueBefore; } + public function setEventValueBefore(?string $v): self { $this->EventValueBefore = $v; return $this; } + public function getEventValueAfter(): ?string { return $this->EventValueAfter; } + public function setEventValueAfter(?string $v): self { $this->EventValueAfter = $v; return $this; } + public function getEventCreatedUserId(): ?int { return $this->EventCreatedUserId; } + public function setEventCreatedUserId(?int $v): self { $this->EventCreatedUserId = $v; return $this; } + public function getEventCreatedAt(): ?string { return $this->EventCreatedAt; } + public function setEventCreatedAt(?string $v): self { $this->EventCreatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyFactDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyFactDwhModel.php new file mode 100644 index 0000000..0f739fc --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyFactDwhModel.php @@ -0,0 +1,43 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'date_id' => $this->DateId, + 'created_user_id' => $this->CreatedUserId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'score' => $this->Score, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getDateId(): ?int { return $this->DateId; } + public function setDateId(?int $v): self { $this->DateId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getScore(): ?int { return $this->Score; } + public function setScore(?int $v): self { $this->Score = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyNoteDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyNoteDwhModel.php new file mode 100644 index 0000000..58b273b --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyNoteDwhModel.php @@ -0,0 +1,75 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'note_id' => $this->NoteId, + 'note_type' => $this->NoteType, + 'element_id' => $this->ElementId, + 'element_type' => $this->ElementType, + 'responsible_user_id' => $this->ResponsibleUserId, + 'text' => $this->Text, + 'params' => $this->Params, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getNoteId(): int { return $this->NoteId; } + public function setNoteId(int $v): self { $this->NoteId = $v; return $this; } + public function getNoteType(): ?string { return $this->NoteType; } + public function setNoteType(?string $v): self { $this->NoteType = $v; return $this; } + public function getElementId(): ?int { return $this->ElementId; } + public function setElementId(?int $v): self { $this->ElementId = $v; return $this; } + public function getElementType(): ?string { return $this->ElementType; } + public function setElementType(?string $v): self { $this->ElementType = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getText(): ?string { return $this->Text; } + public function setText(?string $v): self { $this->Text = $v; return $this; } + public function getParams(): ?string { return $this->Params; } + public function setParams(?string $v): self { $this->Params = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CompanyTagDwhModel.php b/src/AmoCRM/Dwh/Models/CompanyTagDwhModel.php new file mode 100644 index 0000000..58f7a42 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CompanyTagDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'company_id' => $this->CompanyId, + 'tag_id' => $this->TagId, + 'name' => $this->Name, + 'color' => $this->Color, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCompanyId(): int { return $this->CompanyId; } + public function setCompanyId(int $v): self { $this->CompanyId = $v; return $this; } + public function getTagId(): ?int { return $this->TagId; } + public function setTagId(?int $v): self { $this->TagId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getColor(): ?string { return $this->Color; } + public function setColor(?string $v): self { $this->Color = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ContactAttributeDwhModel.php b/src/AmoCRM/Dwh/Models/ContactAttributeDwhModel.php new file mode 100644 index 0000000..c211315 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ContactAttributeDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'contact_id' => $this->ContactId, + 'field_id' => $this->FieldId, + 'field_name' => $this->FieldName, + 'field_type' => $this->FieldType, + 'field_code' => $this->FieldCode, + 'value' => $this->Value, + 'enum_id' => $this->EnumId, + 'enum_code' => $this->EnumCode, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getFieldId(): int { return $this->FieldId; } + public function setFieldId(int $v): self { $this->FieldId = $v; return $this; } + public function getFieldName(): ?string { return $this->FieldName; } + public function setFieldName(?string $v): self { $this->FieldName = $v; return $this; } + public function getFieldType(): ?string { return $this->FieldType; } + public function setFieldType(?string $v): self { $this->FieldType = $v; return $this; } + public function getFieldCode(): ?string { return $this->FieldCode; } + public function setFieldCode(?string $v): self { $this->FieldCode = $v; return $this; } + public function getValue(): ?string { return $this->Value; } + public function setValue(?string $v): self { $this->Value = $v; return $this; } + public function getEnumId(): ?int { return $this->EnumId; } + public function setEnumId(?int $v): self { $this->EnumId = $v; return $this; } + public function getEnumCode(): ?string { return $this->EnumCode; } + public function setEnumCode(?string $v): self { $this->EnumCode = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ContactDwhModel.php b/src/AmoCRM/Dwh/Models/ContactDwhModel.php new file mode 100644 index 0000000..764d3c9 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ContactDwhModel.php @@ -0,0 +1,79 @@ + $this->id, + 'account_id' => $this->accountId, + 'contact_id' => $this->ContactId, + 'name' => $this->Name, + 'first_name' => $this->FirstName, + 'last_name' => $this->LastName, + 'responsible_user_id' => $this->ResponsibleUserId, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'company_name' => $this->CompanyName, + 'closest_task_at' => $this->ClosestTaskAt, + 'score' => $this->Score, + 'is_deleted' => $this->IsDeleted, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getFirstName(): ?string { return $this->FirstName; } + public function setFirstName(?string $v): self { $this->FirstName = $v; return $this; } + public function getLastName(): ?string { return $this->LastName; } + public function setLastName(?string $v): self { $this->LastName = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCompanyName(): ?string { return $this->CompanyName; } + public function setCompanyName(?string $v): self { $this->CompanyName = $v; return $this; } + public function getClosestTaskAt(): ?string { return $this->ClosestTaskAt; } + public function setClosestTaskAt(?string $v): self { $this->ClosestTaskAt = $v; return $this; } + public function getScore(): ?int { return $this->Score; } + public function setScore(?int $v): self { $this->Score = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ContactEventDwhModel.php b/src/AmoCRM/Dwh/Models/ContactEventDwhModel.php new file mode 100644 index 0000000..3c42529 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ContactEventDwhModel.php @@ -0,0 +1,51 @@ + $this->id, + 'account_id' => $this->accountId, + 'contact_id' => $this->ContactId, + 'event_id' => $this->EventId, + 'event_type' => $this->EventType, + 'event_value_before' => $this->EventValueBefore, + 'event_value_after' => $this->EventValueAfter, + 'event_created_user_id' => $this->EventCreatedUserId, + 'event_created_at' => $this->EventCreatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getEventId(): ?string { return $this->EventId; } + public function setEventId(?string $v): self { $this->EventId = $v; return $this; } + public function getEventType(): ?string { return $this->EventType; } + public function setEventType(?string $v): self { $this->EventType = $v; return $this; } + public function getEventValueBefore(): ?string { return $this->EventValueBefore; } + public function setEventValueBefore(?string $v): self { $this->EventValueBefore = $v; return $this; } + public function getEventValueAfter(): ?string { return $this->EventValueAfter; } + public function setEventValueAfter(?string $v): self { $this->EventValueAfter = $v; return $this; } + public function getEventCreatedUserId(): ?int { return $this->EventCreatedUserId; } + public function setEventCreatedUserId(?int $v): self { $this->EventCreatedUserId = $v; return $this; } + public function getEventCreatedAt(): ?string { return $this->EventCreatedAt; } + public function setEventCreatedAt(?string $v): self { $this->EventCreatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ContactFactDwhModel.php b/src/AmoCRM/Dwh/Models/ContactFactDwhModel.php new file mode 100644 index 0000000..e23efe8 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ContactFactDwhModel.php @@ -0,0 +1,43 @@ + $this->id, + 'account_id' => $this->accountId, + 'contact_id' => $this->ContactId, + 'date_id' => $this->DateId, + 'created_user_id' => $this->CreatedUserId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'score' => $this->Score, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getDateId(): ?int { return $this->DateId; } + public function setDateId(?int $v): self { $this->DateId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getScore(): ?int { return $this->Score; } + public function setScore(?int $v): self { $this->Score = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ContactNoteDwhModel.php b/src/AmoCRM/Dwh/Models/ContactNoteDwhModel.php new file mode 100644 index 0000000..8dc6cff --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ContactNoteDwhModel.php @@ -0,0 +1,75 @@ + $this->id, + 'account_id' => $this->accountId, + 'contact_id' => $this->ContactId, + 'note_id' => $this->NoteId, + 'note_type' => $this->NoteType, + 'element_id' => $this->ElementId, + 'element_type' => $this->ElementType, + 'responsible_user_id' => $this->ResponsibleUserId, + 'text' => $this->Text, + 'params' => $this->Params, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getNoteId(): int { return $this->NoteId; } + public function setNoteId(int $v): self { $this->NoteId = $v; return $this; } + public function getNoteType(): ?string { return $this->NoteType; } + public function setNoteType(?string $v): self { $this->NoteType = $v; return $this; } + public function getElementId(): ?int { return $this->ElementId; } + public function setElementId(?int $v): self { $this->ElementId = $v; return $this; } + public function getElementType(): ?string { return $this->ElementType; } + public function setElementType(?string $v): self { $this->ElementType = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getText(): ?string { return $this->Text; } + public function setText(?string $v): self { $this->Text = $v; return $this; } + public function getParams(): ?string { return $this->Params; } + public function setParams(?string $v): self { $this->Params = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ContactTagDwhModel.php b/src/AmoCRM/Dwh/Models/ContactTagDwhModel.php new file mode 100644 index 0000000..684e10d --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ContactTagDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'contact_id' => $this->ContactId, + 'tag_id' => $this->TagId, + 'name' => $this->Name, + 'color' => $this->Color, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getTagId(): ?int { return $this->TagId; } + public function setTagId(?int $v): self { $this->TagId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getColor(): ?string { return $this->Color; } + public function setColor(?string $v): self { $this->Color = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerAttributeDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerAttributeDwhModel.php new file mode 100644 index 0000000..38eabec --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerAttributeDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'field_id' => $this->FieldId, + 'field_name' => $this->FieldName, + 'field_type' => $this->FieldType, + 'field_code' => $this->FieldCode, + 'value' => $this->Value, + 'enum_id' => $this->EnumId, + 'enum_code' => $this->EnumCode, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getFieldId(): int { return $this->FieldId; } + public function setFieldId(int $v): self { $this->FieldId = $v; return $this; } + public function getFieldName(): ?string { return $this->FieldName; } + public function setFieldName(?string $v): self { $this->FieldName = $v; return $this; } + public function getFieldType(): ?string { return $this->FieldType; } + public function setFieldType(?string $v): self { $this->FieldType = $v; return $this; } + public function getFieldCode(): ?string { return $this->FieldCode; } + public function setFieldCode(?string $v): self { $this->FieldCode = $v; return $this; } + public function getValue(): ?string { return $this->Value; } + public function setValue(?string $v): self { $this->Value = $v; return $this; } + public function getEnumId(): ?int { return $this->EnumId; } + public function setEnumId(?int $v): self { $this->EnumId = $v; return $this; } + public function getEnumCode(): ?string { return $this->EnumCode; } + public function setEnumCode(?string $v): self { $this->EnumCode = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerDwhModel.php new file mode 100644 index 0000000..8d48d4e --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerDwhModel.php @@ -0,0 +1,103 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'name' => $this->Name, + 'contact_name' => $this->ContactName, + 'company_name' => $this->CompanyName, + 'contact_id' => $this->ContactId, + 'company_id' => $this->CompanyId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'status_id' => $this->StatusId, + 'periodicity_id' => $this->PeriodicityId, + 'period_id' => $this->PeriodId, + 'next_price' => $this->NextPrice, + 'ltv' => $this->Ltv, + 'purchases' => $this->Purchases, + 'average_check' => $this->AverageCheck, + 'next_date' => $this->NextDate, + 'is_deleted' => $this->IsDeleted, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getContactName(): ?string { return $this->ContactName; } + public function setContactName(?string $v): self { $this->ContactName = $v; return $this; } + public function getCompanyName(): ?string { return $this->CompanyName; } + public function setCompanyName(?string $v): self { $this->CompanyName = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getStatusId(): ?int { return $this->StatusId; } + public function setStatusId(?int $v): self { $this->StatusId = $v; return $this; } + public function getPeriodicityId(): ?int { return $this->PeriodicityId; } + public function setPeriodicityId(?int $v): self { $this->PeriodicityId = $v; return $this; } + public function getPeriodId(): ?int { return $this->PeriodId; } + public function setPeriodId(?int $v): self { $this->PeriodId = $v; return $this; } + public function getNextPrice(): ?string { return $this->NextPrice; } + public function setNextPrice(?string $v): self { $this->NextPrice = $v; return $this; } + public function getLtv(): ?string { return $this->Ltv; } + public function setLtv(?string $v): self { $this->Ltv = $v; return $this; } + public function getPurchases(): ?int { return $this->Purchases; } + public function setPurchases(?int $v): self { $this->Purchases = $v; return $this; } + public function getAverageCheck(): ?string { return $this->AverageCheck; } + public function setAverageCheck(?string $v): self { $this->AverageCheck = $v; return $this; } + public function getNextDate(): ?string { return $this->NextDate; } + public function setNextDate(?string $v): self { $this->NextDate = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerElementFactDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerElementFactDwhModel.php new file mode 100644 index 0000000..b597164 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerElementFactDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'element_id' => $this->ElementId, + 'quantity' => $this->Quantity, + 'price' => $this->Price, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getElementId(): int { return $this->ElementId; } + public function setElementId(int $v): self { $this->ElementId = $v; return $this; } + public function getQuantity(): ?string { return $this->Quantity; } + public function setQuantity(?string $v): self { $this->Quantity = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerFactDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerFactDwhModel.php new file mode 100644 index 0000000..85ee16d --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerFactDwhModel.php @@ -0,0 +1,67 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'contact_id' => $this->ContactId, + 'company_id' => $this->CompanyId, + 'periodicity_id' => $this->PeriodicityId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'next_date' => $this->NextDate, + 'next_price' => $this->NextPrice, + 'purchases' => $this->Purchases, + 'average_check' => $this->AverageCheck, + 'ltv' => $this->Ltv, + 'labor_cost' => $this->LaborCost, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getPeriodicityId(): ?int { return $this->PeriodicityId; } + public function setPeriodicityId(?int $v): self { $this->PeriodicityId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getNextDate(): ?string { return $this->NextDate; } + public function setNextDate(?string $v): self { $this->NextDate = $v; return $this; } + public function getNextPrice(): ?string { return $this->NextPrice; } + public function setNextPrice(?string $v): self { $this->NextPrice = $v; return $this; } + public function getPurchases(): ?int { return $this->Purchases; } + public function setPurchases(?int $v): self { $this->Purchases = $v; return $this; } + public function getAverageCheck(): ?string { return $this->AverageCheck; } + public function setAverageCheck(?string $v): self { $this->AverageCheck = $v; return $this; } + public function getLtv(): ?string { return $this->Ltv; } + public function setLtv(?string $v): self { $this->Ltv = $v; return $this; } + public function getLaborCost(): ?string { return $this->LaborCost; } + public function setLaborCost(?string $v): self { $this->LaborCost = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerMemberLinkDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerMemberLinkDwhModel.php new file mode 100644 index 0000000..3771133 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerMemberLinkDwhModel.php @@ -0,0 +1,35 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'member_id' => $this->MemberId, + 'member_type' => $this->MemberType, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getMemberId(): int { return $this->MemberId; } + public function setMemberId(int $v): self { $this->MemberId = $v; return $this; } + public function getMemberType(): string { return $this->MemberType; } + public function setMemberType(string $v): self { $this->MemberType = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerNoteDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerNoteDwhModel.php new file mode 100644 index 0000000..ea7dcf3 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerNoteDwhModel.php @@ -0,0 +1,75 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'note_id' => $this->NoteId, + 'note_type' => $this->NoteType, + 'element_id' => $this->ElementId, + 'element_type' => $this->ElementType, + 'responsible_user_id' => $this->ResponsibleUserId, + 'text' => $this->Text, + 'params' => $this->Params, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getNoteId(): int { return $this->NoteId; } + public function setNoteId(int $v): self { $this->NoteId = $v; return $this; } + public function getNoteType(): ?string { return $this->NoteType; } + public function setNoteType(?string $v): self { $this->NoteType = $v; return $this; } + public function getElementId(): ?int { return $this->ElementId; } + public function setElementId(?int $v): self { $this->ElementId = $v; return $this; } + public function getElementType(): ?string { return $this->ElementType; } + public function setElementType(?string $v): self { $this->ElementType = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getText(): ?string { return $this->Text; } + public function setText(?string $v): self { $this->Text = $v; return $this; } + public function getParams(): ?string { return $this->Params; } + public function setParams(?string $v): self { $this->Params = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerSegmentLinkDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerSegmentLinkDwhModel.php new file mode 100644 index 0000000..ea22b5c --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerSegmentLinkDwhModel.php @@ -0,0 +1,31 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'segment_id' => $this->SegmentId, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getSegmentId(): int { return $this->SegmentId; } + public function setSegmentId(int $v): self { $this->SegmentId = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/CustomerTagDwhModel.php b/src/AmoCRM/Dwh/Models/CustomerTagDwhModel.php new file mode 100644 index 0000000..7b124b1 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/CustomerTagDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'customer_id' => $this->CustomerId, + 'tag_id' => $this->TagId, + 'name' => $this->Name, + 'color' => $this->Color, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getCustomerId(): int { return $this->CustomerId; } + public function setCustomerId(int $v): self { $this->CustomerId = $v; return $this; } + public function getTagId(): ?int { return $this->TagId; } + public function setTagId(?int $v): self { $this->TagId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getColor(): ?string { return $this->Color; } + public function setColor(?string $v): self { $this->Color = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/DateDwhModel.php b/src/AmoCRM/Dwh/Models/DateDwhModel.php new file mode 100644 index 0000000..6a81a65 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/DateDwhModel.php @@ -0,0 +1,60 @@ + \$this->id, + 'account_id' => \$this->accountId, + 'date' => \$this->Date, + 'year' => \$this->Year, + 'quarter' => \$this->Quarter, + 'month' => \$this->Month, + 'week' => \$this->Week, + 'day' => \$this->Day, + 'day_of_week' => \$this->DayOfWeek, + 'is_weekend' => \$this->IsWeekend, + 'is_holiday' => \$this->IsHoliday, + ]; + } + + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getDate(): string { return $this->Date; } + public function setDate(string $v): self { $this->Date = $v; return $this; } + public function getYear(): int { return $this->Year; } + public function setYear(int $v): self { $this->Year = $v; return $this; } + public function getQuarter(): int { return $this->Quarter; } + public function setQuarter(int $v): self { $this->Quarter = $v; return $this; } + public function getMonth(): int { return $this->Month; } + public function setMonth(int $v): self { $this->Month = $v; return $this; } + public function getWeek(): int { return $this->Week; } + public function setWeek(int $v): self { $this->Week = $v; return $this; } + public function getDay(): int { return $this->Day; } + public function setDay(int $v): self { $this->Day = $v; return $this; } + public function getDayOfWeek(): int { return $this->DayOfWeek; } + public function setDayOfWeek(int $v): self { $this->DayOfWeek = $v; return $this; } + public function getIsWeekend(): int { return $this->IsWeekend; } + public function setIsWeekend(int $v): self { $this->IsWeekend = $v; return $this; } + public function getIsHoliday(): int { return $this->IsHoliday; } + public function setIsHoliday(int $v): self { $this->IsHoliday = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ElementAttributeDwhModel.php b/src/AmoCRM/Dwh/Models/ElementAttributeDwhModel.php new file mode 100644 index 0000000..8ab6899 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ElementAttributeDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'element_id' => $this->ElementId, + 'field_id' => $this->FieldId, + 'field_name' => $this->FieldName, + 'field_type' => $this->FieldType, + 'field_code' => $this->FieldCode, + 'value' => $this->Value, + 'enum_id' => $this->EnumId, + 'enum_code' => $this->EnumCode, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getElementId(): int { return $this->ElementId; } + public function setElementId(int $v): self { $this->ElementId = $v; return $this; } + public function getFieldId(): int { return $this->FieldId; } + public function setFieldId(int $v): self { $this->FieldId = $v; return $this; } + public function getFieldName(): ?string { return $this->FieldName; } + public function setFieldName(?string $v): self { $this->FieldName = $v; return $this; } + public function getFieldType(): ?string { return $this->FieldType; } + public function setFieldType(?string $v): self { $this->FieldType = $v; return $this; } + public function getFieldCode(): ?string { return $this->FieldCode; } + public function setFieldCode(?string $v): self { $this->FieldCode = $v; return $this; } + public function getValue(): ?string { return $this->Value; } + public function setValue(?string $v): self { $this->Value = $v; return $this; } + public function getEnumId(): ?int { return $this->EnumId; } + public function setEnumId(?int $v): self { $this->EnumId = $v; return $this; } + public function getEnumCode(): ?string { return $this->EnumCode; } + public function setEnumCode(?string $v): self { $this->EnumCode = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ElementDwhModel.php b/src/AmoCRM/Dwh/Models/ElementDwhModel.php new file mode 100644 index 0000000..acbdce6 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ElementDwhModel.php @@ -0,0 +1,71 @@ + $this->id, + 'account_id' => $this->accountId, + 'element_id' => $this->ElementId, + 'catalog_id' => $this->CatalogId, + 'name' => $this->Name, + 'article' => $this->Article, + 'price' => $this->Price, + 'quantity' => $this->Quantity, + 'external_id' => $this->ExternalId, + 'is_deleted' => $this->IsDeleted, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getElementId(): int { return $this->ElementId; } + public function setElementId(int $v): self { $this->ElementId = $v; return $this; } + public function getCatalogId(): int { return $this->CatalogId; } + public function setCatalogId(int $v): self { $this->CatalogId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getArticle(): ?string { return $this->Article; } + public function setArticle(?string $v): self { $this->Article = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } + public function getQuantity(): ?string { return $this->Quantity; } + public function setQuantity(?string $v): self { $this->Quantity = $v; return $this; } + public function getExternalId(): ?string { return $this->ExternalId; } + public function setExternalId(?string $v): self { $this->ExternalId = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/ElementProductDwhModel.php b/src/AmoCRM/Dwh/Models/ElementProductDwhModel.php new file mode 100644 index 0000000..d688107 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/ElementProductDwhModel.php @@ -0,0 +1,43 @@ + $this->id, + 'account_id' => $this->accountId, + 'element_id' => $this->ElementId, + 'product_id' => $this->ProductId, + 'name' => $this->Name, + 'quantity' => $this->Quantity, + 'price' => $this->Price, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getElementId(): int { return $this->ElementId; } + public function setElementId(int $v): self { $this->ElementId = $v; return $this; } + public function getProductId(): int { return $this->ProductId; } + public function setProductId(int $v): self { $this->ProductId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getQuantity(): ?string { return $this->Quantity; } + public function setQuantity(?string $v): self { $this->Quantity = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadAttributeDwhModel.php b/src/AmoCRM/Dwh/Models/LeadAttributeDwhModel.php new file mode 100644 index 0000000..ed5851f --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadAttributeDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'field_id' => $this->FieldId, + 'field_name' => $this->FieldName, + 'field_type' => $this->FieldType, + 'field_code' => $this->FieldCode, + 'value' => $this->Value, + 'enum_id' => $this->EnumId, + 'enum_code' => $this->EnumCode, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getFieldId(): int { return $this->FieldId; } + public function setFieldId(int $v): self { $this->FieldId = $v; return $this; } + public function getFieldName(): ?string { return $this->FieldName; } + public function setFieldName(?string $v): self { $this->FieldName = $v; return $this; } + public function getFieldType(): ?string { return $this->FieldType; } + public function setFieldType(?string $v): self { $this->FieldType = $v; return $this; } + public function getFieldCode(): ?string { return $this->FieldCode; } + public function setFieldCode(?string $v): self { $this->FieldCode = $v; return $this; } + public function getValue(): ?string { return $this->Value; } + public function setValue(?string $v): self { $this->Value = $v; return $this; } + public function getEnumId(): ?int { return $this->EnumId; } + public function setEnumId(?int $v): self { $this->EnumId = $v; return $this; } + public function getEnumCode(): ?string { return $this->EnumCode; } + public function setEnumCode(?string $v): self { $this->EnumCode = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadContactLinkDwhModel.php b/src/AmoCRM/Dwh/Models/LeadContactLinkDwhModel.php new file mode 100644 index 0000000..5a7a8d5 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadContactLinkDwhModel.php @@ -0,0 +1,35 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'contact_id' => $this->ContactId, + 'is_main' => $this->IsMain, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getContactId(): int { return $this->ContactId; } + public function setContactId(int $v): self { $this->ContactId = $v; return $this; } + public function getIsMain(): int { return $this->IsMain; } + public function setIsMain(int $v): self { $this->IsMain = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadDwhModel.php b/src/AmoCRM/Dwh/Models/LeadDwhModel.php new file mode 100644 index 0000000..2cc5574 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadDwhModel.php @@ -0,0 +1,115 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'name' => $this->Name, + 'price' => $this->Price, + 'pipeline_id' => $this->PipelineId, + 'status_id' => $this->StatusId, + 'old_status_id' => $this->OldStatusId, + 'loss_reason_id' => $this->LossReasonId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'company_id' => $this->CompanyId, + 'contact_id' => $this->ContactId, + 'closed_user_id' => $this->ClosedUserId, + 'closed_at' => $this->ClosedAt, + 'closest_task_at' => $this->ClosestTaskAt, + 'score' => $this->Score, + 'is_price_modified_by_robot' => $this->IsPriceModifiedByRobot, + 'is_deleted' => $this->IsDeleted, + 'source_external_id' => $this->SourceExternalId, + 'visitor_uid' => $this->VisitorUid, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } + public function getPipelineId(): ?int { return $this->PipelineId; } + public function setPipelineId(?int $v): self { $this->PipelineId = $v; return $this; } + public function getStatusId(): ?int { return $this->StatusId; } + public function setStatusId(?int $v): self { $this->StatusId = $v; return $this; } + public function getOldStatusId(): ?int { return $this->OldStatusId; } + public function setOldStatusId(?int $v): self { $this->OldStatusId = $v; return $this; } + public function getLossReasonId(): ?int { return $this->LossReasonId; } + public function setLossReasonId(?int $v): self { $this->LossReasonId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getClosedUserId(): ?int { return $this->ClosedUserId; } + public function setClosedUserId(?int $v): self { $this->ClosedUserId = $v; return $this; } + public function getClosedAt(): ?string { return $this->ClosedAt; } + public function setClosedAt(?string $v): self { $this->ClosedAt = $v; return $this; } + public function getClosestTaskAt(): ?string { return $this->ClosestTaskAt; } + public function setClosestTaskAt(?string $v): self { $this->ClosestTaskAt = $v; return $this; } + public function getScore(): ?int { return $this->Score; } + public function setScore(?int $v): self { $this->Score = $v; return $this; } + public function getIsPriceModifiedByRobot(): int { return $this->IsPriceModifiedByRobot; } + public function setIsPriceModifiedByRobot(int $v): self { $this->IsPriceModifiedByRobot = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getSourceExternalId(): ?string { return $this->SourceExternalId; } + public function setSourceExternalId(?string $v): self { $this->SourceExternalId = $v; return $this; } + public function getVisitorUid(): ?string { return $this->VisitorUid; } + public function setVisitorUid(?string $v): self { $this->VisitorUid = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadElementFactDwhModel.php b/src/AmoCRM/Dwh/Models/LeadElementFactDwhModel.php new file mode 100644 index 0000000..eb69af5 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadElementFactDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'element_id' => $this->ElementId, + 'quantity' => $this->Quantity, + 'price' => $this->Price, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getElementId(): int { return $this->ElementId; } + public function setElementId(int $v): self { $this->ElementId = $v; return $this; } + public function getQuantity(): ?string { return $this->Quantity; } + public function setQuantity(?string $v): self { $this->Quantity = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadEventDwhModel.php b/src/AmoCRM/Dwh/Models/LeadEventDwhModel.php new file mode 100644 index 0000000..25249a3 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadEventDwhModel.php @@ -0,0 +1,51 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'event_id' => $this->EventId, + 'event_type' => $this->EventType, + 'event_value_before' => $this->EventValueBefore, + 'event_value_after' => $this->EventValueAfter, + 'event_created_user_id' => $this->EventCreatedUserId, + 'event_created_at' => $this->EventCreatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getEventId(): ?string { return $this->EventId; } + public function setEventId(?string $v): self { $this->EventId = $v; return $this; } + public function getEventType(): ?string { return $this->EventType; } + public function setEventType(?string $v): self { $this->EventType = $v; return $this; } + public function getEventValueBefore(): ?string { return $this->EventValueBefore; } + public function setEventValueBefore(?string $v): self { $this->EventValueBefore = $v; return $this; } + public function getEventValueAfter(): ?string { return $this->EventValueAfter; } + public function setEventValueAfter(?string $v): self { $this->EventValueAfter = $v; return $this; } + public function getEventCreatedUserId(): ?int { return $this->EventCreatedUserId; } + public function setEventCreatedUserId(?int $v): self { $this->EventCreatedUserId = $v; return $this; } + public function getEventCreatedAt(): ?string { return $this->EventCreatedAt; } + public function setEventCreatedAt(?string $v): self { $this->EventCreatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadFactDwhModel.php b/src/AmoCRM/Dwh/Models/LeadFactDwhModel.php new file mode 100644 index 0000000..e86614c --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadFactDwhModel.php @@ -0,0 +1,79 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'date_create_id' => $this->DateCreateId, + 'date_close_id' => $this->DateCloseId, + 'client_id' => $this->ClientId, + 'traffic_id' => $this->TrafficId, + 'pipeline_id' => $this->PipelineId, + 'status_id' => $this->StatusId, + 'loss_reason_id' => $this->LossReasonId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'company_id' => $this->CompanyId, + 'contact_id' => $this->ContactId, + 'price' => $this->Price, + 'labor_cost' => $this->LaborCost, + 'score' => $this->Score, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getDateCreateId(): ?int { return $this->DateCreateId; } + public function setDateCreateId(?int $v): self { $this->DateCreateId = $v; return $this; } + public function getDateCloseId(): ?int { return $this->DateCloseId; } + public function setDateCloseId(?int $v): self { $this->DateCloseId = $v; return $this; } + public function getClientId(): ?string { return $this->ClientId; } + public function setClientId(?string $v): self { $this->ClientId = $v; return $this; } + public function getTrafficId(): ?string { return $this->TrafficId; } + public function setTrafficId(?string $v): self { $this->TrafficId = $v; return $this; } + public function getPipelineId(): ?int { return $this->PipelineId; } + public function setPipelineId(?int $v): self { $this->PipelineId = $v; return $this; } + public function getStatusId(): ?int { return $this->StatusId; } + public function setStatusId(?int $v): self { $this->StatusId = $v; return $this; } + public function getLossReasonId(): ?int { return $this->LossReasonId; } + public function setLossReasonId(?int $v): self { $this->LossReasonId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } + public function getLaborCost(): ?string { return $this->LaborCost; } + public function setLaborCost(?string $v): self { $this->LaborCost = $v; return $this; } + public function getScore(): ?int { return $this->Score; } + public function setScore(?int $v): self { $this->Score = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadNoteDwhModel.php b/src/AmoCRM/Dwh/Models/LeadNoteDwhModel.php new file mode 100644 index 0000000..ae706ed --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadNoteDwhModel.php @@ -0,0 +1,75 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'note_id' => $this->NoteId, + 'note_type' => $this->NoteType, + 'element_id' => $this->ElementId, + 'element_type' => $this->ElementType, + 'responsible_user_id' => $this->ResponsibleUserId, + 'text' => $this->Text, + 'params' => $this->Params, + 'group_id' => $this->GroupId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getNoteId(): int { return $this->NoteId; } + public function setNoteId(int $v): self { $this->NoteId = $v; return $this; } + public function getNoteType(): ?string { return $this->NoteType; } + public function setNoteType(?string $v): self { $this->NoteType = $v; return $this; } + public function getElementId(): ?int { return $this->ElementId; } + public function setElementId(?int $v): self { $this->ElementId = $v; return $this; } + public function getElementType(): ?string { return $this->ElementType; } + public function setElementType(?string $v): self { $this->ElementType = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getText(): ?string { return $this->Text; } + public function setText(?string $v): self { $this->Text = $v; return $this; } + public function getParams(): ?string { return $this->Params; } + public function setParams(?string $v): self { $this->Params = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/LeadTagDwhModel.php b/src/AmoCRM/Dwh/Models/LeadTagDwhModel.php new file mode 100644 index 0000000..71b4db6 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/LeadTagDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'lead_id' => $this->LeadId, + 'tag_id' => $this->TagId, + 'name' => $this->Name, + 'color' => $this->Color, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getLeadId(): int { return $this->LeadId; } + public function setLeadId(int $v): self { $this->LeadId = $v; return $this; } + public function getTagId(): ?int { return $this->TagId; } + public function setTagId(?int $v): self { $this->TagId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getColor(): ?string { return $this->Color; } + public function setColor(?string $v): self { $this->Color = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/PeriodicityDwhModel.php b/src/AmoCRM/Dwh/Models/PeriodicityDwhModel.php new file mode 100644 index 0000000..fdb2803 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/PeriodicityDwhModel.php @@ -0,0 +1,48 @@ + \$this->id, + 'account_id' => \$this->accountId, + 'periodicity_id' => \$this->PeriodicityId, + 'name' => \$this->Name, + 'sort' => \$this->Sort, + 'color' => \$this->Color, + 'created_at' => \$this->CreatedAt, + 'updated_at' => \$this->UpdatedAt, + ]; + } + + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getPeriodicityId(): int { return $this->PeriodicityId; } + public function setPeriodicityId(int $v): self { $this->PeriodicityId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getSort(): int { return $this->Sort; } + public function setSort(int $v): self { $this->Sort = $v; return $this; } + public function getColor(): ?string { return $this->Color; } + public function setColor(?string $v): self { $this->Color = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/PipelineDwhModel.php b/src/AmoCRM/Dwh/Models/PipelineDwhModel.php new file mode 100644 index 0000000..00696a4 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/PipelineDwhModel.php @@ -0,0 +1,61 @@ + $this->id, + 'account_id' => $this->accountId, + 'pipeline_id' => $this->pipelineId, + 'name' => $this->name, + 'sort' => $this->sort, + 'is_main' => $this->isMain, + 'is_unsorted_on' => $this->isUnsortedOn, + 'is_archive' => $this->isArchive, + 'created_at' => $this->createdAt, + 'updated_at' => $this->updatedAt, + ]; + } + + // getters/setters + public function getId(): ?int { return $this->id; } + public function getAccountId(): int { return $this->accountId; } + public function getPipelineId(): int { return $this->pipelineId; } + public function getName(): string { return $this->name; } + public function getSort(): int { return $this->sort; } + public function getIsMain(): int { return $this->isMain; } + public function getIsUnsortedOn(): int { return $this->isUnsortedOn; } + public function getIsArchive(): int { return $this->isArchive; } + public function getCreatedAt(): ?string { return $this->createdAt; } + public function getUpdatedAt(): ?string { return $this->updatedAt; } + + public function setId(?int $id): self { $this->id = $id; return $this; } + public function setAccountId(int $accountId): self { $this->accountId = $accountId; return $this; } + public function setPipelineId(int $pipelineId): self { $this->pipelineId = $pipelineId; return $this; } + public function setName(string $name): self { $this->name = $name; return $this; } + public function setSort(int $sort): self { $this->sort = $sort; return $this; } + public function setIsMain(int $isMain): self { $this->isMain = $isMain; return $this; } + public function setIsUnsortedOn(int $isUnsortedOn): self { $this->isUnsortedOn = $isUnsortedOn; return $this; } + public function setIsArchive(int $isArchive): self { $this->isArchive = $isArchive; return $this; } + public function setCreatedAt(?string $createdAt): self { $this->createdAt = $createdAt; return $this; } + public function setUpdatedAt(?string $updatedAt): self { $this->updatedAt = $updatedAt; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/SegmentAttributeDwhModel.php b/src/AmoCRM/Dwh/Models/SegmentAttributeDwhModel.php new file mode 100644 index 0000000..7798b37 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/SegmentAttributeDwhModel.php @@ -0,0 +1,47 @@ + $this->id, + 'account_id' => $this->accountId, + 'segment_id' => $this->SegmentId, + 'field_id' => $this->FieldId, + 'field_name' => $this->FieldName, + 'field_type' => $this->FieldType, + 'field_code' => $this->FieldCode, + 'value' => $this->Value, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getSegmentId(): int { return $this->SegmentId; } + public function setSegmentId(int $v): self { $this->SegmentId = $v; return $this; } + public function getFieldId(): int { return $this->FieldId; } + public function setFieldId(int $v): self { $this->FieldId = $v; return $this; } + public function getFieldName(): ?string { return $this->FieldName; } + public function setFieldName(?string $v): self { $this->FieldName = $v; return $this; } + public function getFieldType(): ?string { return $this->FieldType; } + public function setFieldType(?string $v): self { $this->FieldType = $v; return $this; } + public function getFieldCode(): ?string { return $this->FieldCode; } + public function setFieldCode(?string $v): self { $this->FieldCode = $v; return $this; } + public function getValue(): ?string { return $this->Value; } + public function setValue(?string $v): self { $this->Value = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/SegmentDwhModel.php b/src/AmoCRM/Dwh/Models/SegmentDwhModel.php new file mode 100644 index 0000000..d18d205 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/SegmentDwhModel.php @@ -0,0 +1,63 @@ + $this->id, + 'account_id' => $this->accountId, + 'segment_id' => $this->SegmentId, + 'name' => $this->Name, + 'color' => $this->Color, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'customers_count' => $this->CustomersCount, + 'conversion_rate' => $this->ConversionRate, + 'max_discount' => $this->MaxDiscount, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getSegmentId(): int { return $this->SegmentId; } + public function setSegmentId(int $v): self { $this->SegmentId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getColor(): ?string { return $this->Color; } + public function setColor(?string $v): self { $this->Color = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCustomersCount(): ?int { return $this->CustomersCount; } + public function setCustomersCount(?int $v): self { $this->CustomersCount = $v; return $this; } + public function getConversionRate(): ?string { return $this->ConversionRate; } + public function setConversionRate(?string $v): self { $this->ConversionRate = $v; return $this; } + public function getMaxDiscount(): ?string { return $this->MaxDiscount; } + public function setMaxDiscount(?string $v): self { $this->MaxDiscount = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/SegmentFactDwhModel.php b/src/AmoCRM/Dwh/Models/SegmentFactDwhModel.php new file mode 100644 index 0000000..9d42482 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/SegmentFactDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'segment_id' => $this->SegmentId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'customers_count' => $this->CustomersCount, + 'conversion_rate' => $this->ConversionRate, + 'max_discount' => $this->MaxDiscount, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getSegmentId(): int { return $this->SegmentId; } + public function setSegmentId(int $v): self { $this->SegmentId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getCustomersCount(): ?int { return $this->CustomersCount; } + public function setCustomersCount(?int $v): self { $this->CustomersCount = $v; return $this; } + public function getConversionRate(): ?string { return $this->ConversionRate; } + public function setConversionRate(?string $v): self { $this->ConversionRate = $v; return $this; } + public function getMaxDiscount(): ?string { return $this->MaxDiscount; } + public function setMaxDiscount(?string $v): self { $this->MaxDiscount = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/StatusDwhModel.php b/src/AmoCRM/Dwh/Models/StatusDwhModel.php new file mode 100644 index 0000000..c953e32 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/StatusDwhModel.php @@ -0,0 +1,55 @@ + $this->id, 'account_id' => $this->accountId, + 'status_id' => $this->statusId, 'pipeline_id' => $this->pipelineId, + 'name' => $this->name, 'sort' => $this->sort, 'color' => $this->color, + 'type' => $this->type, 'editable' => $this->editable, + 'created_at' => $this->createdAt, 'updated_at' => $this->updatedAt, + ]; + } + + public function getId(): ?int { return $this->id; } + public function getAccountId(): int { return $this->accountId; } + public function getStatusId(): int { return $this->statusId; } + public function getPipelineId(): int { return $this->pipelineId; } + public function getName(): string { return $this->name; } + public function getSort(): int { return $this->sort; } + public function getColor(): ?string { return $this->color; } + public function getType(): int { return $this->type; } + public function getEditable(): int { return $this->editable; } + public function getCreatedAt(): ?string { return $this->createdAt; } + public function getUpdatedAt(): ?string { return $this->updatedAt; } + + public function setId(?int $id): self { $this->id = $id; return $this; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function setStatusId(int $v): self { $this->statusId = $v; return $this; } + public function setPipelineId(int $v): self { $this->pipelineId = $v; return $this; } + public function setName(string $v): self { $this->name = $v; return $this; } + public function setSort(int $v): self { $this->sort = $v; return $this; } + public function setColor(?string $v): self { $this->color = $v; return $this; } + public function setType(int $v): self { $this->type = $v; return $this; } + public function setEditable(int $v): self { $this->editable = $v; return $this; } + public function setCreatedAt(?string $v): self { $this->createdAt = $v; return $this; } + public function setUpdatedAt(?string $v): self { $this->updatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TaskDwhModel.php b/src/AmoCRM/Dwh/Models/TaskDwhModel.php new file mode 100644 index 0000000..3e3a5c3 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TaskDwhModel.php @@ -0,0 +1,91 @@ + $this->id, + 'account_id' => $this->accountId, + 'task_id' => $this->TaskId, + 'name' => $this->Name, + 'responsible_user_id' => $this->ResponsibleUserId, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'task_type_id' => $this->TaskTypeId, + 'entity_type' => $this->EntityType, + 'entity_id' => $this->EntityId, + 'duration' => $this->Duration, + 'complete_till_at' => $this->CompleteTillAt, + 'completed_at' => $this->CompletedAt, + 'result' => $this->Result, + 'is_completed' => $this->IsCompleted, + 'group_id' => $this->GroupId, + 'is_deleted' => $this->IsDeleted, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTaskId(): int { return $this->TaskId; } + public function setTaskId(int $v): self { $this->TaskId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getTaskTypeId(): ?int { return $this->TaskTypeId; } + public function setTaskTypeId(?int $v): self { $this->TaskTypeId = $v; return $this; } + public function getEntityType(): ?string { return $this->EntityType; } + public function setEntityType(?string $v): self { $this->EntityType = $v; return $this; } + public function getEntityId(): ?int { return $this->EntityId; } + public function setEntityId(?int $v): self { $this->EntityId = $v; return $this; } + public function getDuration(): ?int { return $this->Duration; } + public function setDuration(?int $v): self { $this->Duration = $v; return $this; } + public function getCompleteTillAt(): ?string { return $this->CompleteTillAt; } + public function setCompleteTillAt(?string $v): self { $this->CompleteTillAt = $v; return $this; } + public function getCompletedAt(): ?string { return $this->CompletedAt; } + public function setCompletedAt(?string $v): self { $this->CompletedAt = $v; return $this; } + public function getResult(): ?string { return $this->Result; } + public function setResult(?string $v): self { $this->Result = $v; return $this; } + public function getIsCompleted(): int { return $this->IsCompleted; } + public function setIsCompleted(int $v): self { $this->IsCompleted = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TaskEventDwhModel.php b/src/AmoCRM/Dwh/Models/TaskEventDwhModel.php new file mode 100644 index 0000000..9c8aee7 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TaskEventDwhModel.php @@ -0,0 +1,51 @@ + $this->id, + 'account_id' => $this->accountId, + 'task_id' => $this->TaskId, + 'event_id' => $this->EventId, + 'event_type' => $this->EventType, + 'event_value_before' => $this->EventValueBefore, + 'event_value_after' => $this->EventValueAfter, + 'event_created_user_id' => $this->EventCreatedUserId, + 'event_created_at' => $this->EventCreatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTaskId(): int { return $this->TaskId; } + public function setTaskId(int $v): self { $this->TaskId = $v; return $this; } + public function getEventId(): ?string { return $this->EventId; } + public function setEventId(?string $v): self { $this->EventId = $v; return $this; } + public function getEventType(): ?string { return $this->EventType; } + public function setEventType(?string $v): self { $this->EventType = $v; return $this; } + public function getEventValueBefore(): ?string { return $this->EventValueBefore; } + public function setEventValueBefore(?string $v): self { $this->EventValueBefore = $v; return $this; } + public function getEventValueAfter(): ?string { return $this->EventValueAfter; } + public function setEventValueAfter(?string $v): self { $this->EventValueAfter = $v; return $this; } + public function getEventCreatedUserId(): ?int { return $this->EventCreatedUserId; } + public function setEventCreatedUserId(?int $v): self { $this->EventCreatedUserId = $v; return $this; } + public function getEventCreatedAt(): ?string { return $this->EventCreatedAt; } + public function setEventCreatedAt(?string $v): self { $this->EventCreatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TaskFactDwhModel.php b/src/AmoCRM/Dwh/Models/TaskFactDwhModel.php new file mode 100644 index 0000000..7dbaee8 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TaskFactDwhModel.php @@ -0,0 +1,55 @@ + $this->id, + 'account_id' => $this->accountId, + 'task_id' => $this->TaskId, + 'date_create_id' => $this->DateCreateId, + 'date_complete_id' => $this->DateCompleteId, + 'entity_type' => $this->EntityType, + 'entity_id' => $this->EntityId, + 'responsible_user_id' => $this->ResponsibleUserId, + 'duration' => $this->Duration, + 'is_completed' => $this->IsCompleted, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTaskId(): int { return $this->TaskId; } + public function setTaskId(int $v): self { $this->TaskId = $v; return $this; } + public function getDateCreateId(): ?int { return $this->DateCreateId; } + public function setDateCreateId(?int $v): self { $this->DateCreateId = $v; return $this; } + public function getDateCompleteId(): ?int { return $this->DateCompleteId; } + public function setDateCompleteId(?int $v): self { $this->DateCompleteId = $v; return $this; } + public function getEntityType(): ?string { return $this->EntityType; } + public function setEntityType(?string $v): self { $this->EntityType = $v; return $this; } + public function getEntityId(): ?int { return $this->EntityId; } + public function setEntityId(?int $v): self { $this->EntityId = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getDuration(): ?int { return $this->Duration; } + public function setDuration(?int $v): self { $this->Duration = $v; return $this; } + public function getIsCompleted(): int { return $this->IsCompleted; } + public function setIsCompleted(int $v): self { $this->IsCompleted = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TrafficDwhModel.php b/src/AmoCRM/Dwh/Models/TrafficDwhModel.php new file mode 100644 index 0000000..eef4f14 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TrafficDwhModel.php @@ -0,0 +1,56 @@ + \$this->id, + 'account_id' => \$this->accountId, + 'traffic_id' => \$this->TrafficId, + 'name' => \$this->Name, + 'source' => \$this->Source, + 'medium' => \$this->Medium, + 'campaign' => \$this->Campaign, + 'term' => \$this->Term, + 'content' => \$this->Content, + 'created_at' => \$this->CreatedAt, + ]; + } + + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTrafficId(): string { return $this->TrafficId; } + public function setTrafficId(string $v): self { $this->TrafficId = $v; return $this; } + public function getName(): ?string { return $this->Name; } + public function setName(?string $v): self { $this->Name = $v; return $this; } + public function getSource(): ?string { return $this->Source; } + public function setSource(?string $v): self { $this->Source = $v; return $this; } + public function getMedium(): ?string { return $this->Medium; } + public function setMedium(?string $v): self { $this->Medium = $v; return $this; } + public function getCampaign(): ?string { return $this->Campaign; } + public function setCampaign(?string $v): self { $this->Campaign = $v; return $this; } + public function getTerm(): ?string { return $this->Term; } + public function setTerm(?string $v): self { $this->Term = $v; return $this; } + public function getContent(): ?string { return $this->Content; } + public function setContent(?string $v): self { $this->Content = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TransactionDwhModel.php b/src/AmoCRM/Dwh/Models/TransactionDwhModel.php new file mode 100644 index 0000000..d444fc7 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TransactionDwhModel.php @@ -0,0 +1,71 @@ + $this->id, + 'account_id' => $this->accountId, + 'transaction_id' => $this->TransactionId, + 'customer_id' => $this->CustomerId, + 'contact_id' => $this->ContactId, + 'company_id' => $this->CompanyId, + 'completed_at' => $this->CompletedAt, + 'price' => $this->Price, + 'comment' => $this->Comment, + 'created_user_id' => $this->CreatedUserId, + 'modified_user_id' => $this->ModifiedUserId, + 'is_deleted' => $this->IsDeleted, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTransactionId(): int { return $this->TransactionId; } + public function setTransactionId(int $v): self { $this->TransactionId = $v; return $this; } + public function getCustomerId(): ?int { return $this->CustomerId; } + public function setCustomerId(?int $v): self { $this->CustomerId = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getCompletedAt(): ?string { return $this->CompletedAt; } + public function setCompletedAt(?string $v): self { $this->CompletedAt = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } + public function getComment(): ?string { return $this->Comment; } + public function setComment(?string $v): self { $this->Comment = $v; return $this; } + public function getCreatedUserId(): ?int { return $this->CreatedUserId; } + public function setCreatedUserId(?int $v): self { $this->CreatedUserId = $v; return $this; } + public function getModifiedUserId(): ?int { return $this->ModifiedUserId; } + public function setModifiedUserId(?int $v): self { $this->ModifiedUserId = $v; return $this; } + public function getIsDeleted(): int { return $this->IsDeleted; } + public function setIsDeleted(int $v): self { $this->IsDeleted = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TransactionElementFactDwhModel.php b/src/AmoCRM/Dwh/Models/TransactionElementFactDwhModel.php new file mode 100644 index 0000000..5e1e17a --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TransactionElementFactDwhModel.php @@ -0,0 +1,39 @@ + $this->id, + 'account_id' => $this->accountId, + 'transaction_id' => $this->TransactionId, + 'element_id' => $this->ElementId, + 'quantity' => $this->Quantity, + 'price' => $this->Price, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTransactionId(): int { return $this->TransactionId; } + public function setTransactionId(int $v): self { $this->TransactionId = $v; return $this; } + public function getElementId(): int { return $this->ElementId; } + public function setElementId(int $v): self { $this->ElementId = $v; return $this; } + public function getQuantity(): ?string { return $this->Quantity; } + public function setQuantity(?string $v): self { $this->Quantity = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/TransactionFactDwhModel.php b/src/AmoCRM/Dwh/Models/TransactionFactDwhModel.php new file mode 100644 index 0000000..8a4e356 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/TransactionFactDwhModel.php @@ -0,0 +1,51 @@ + $this->id, + 'account_id' => $this->accountId, + 'transaction_id' => $this->TransactionId, + 'customer_id' => $this->CustomerId, + 'contact_id' => $this->ContactId, + 'company_id' => $this->CompanyId, + 'date_id' => $this->DateId, + 'completed_at' => $this->CompletedAt, + 'price' => $this->Price, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getTransactionId(): int { return $this->TransactionId; } + public function setTransactionId(int $v): self { $this->TransactionId = $v; return $this; } + public function getCustomerId(): ?int { return $this->CustomerId; } + public function setCustomerId(?int $v): self { $this->CustomerId = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getDateId(): ?int { return $this->DateId; } + public function setDateId(?int $v): self { $this->DateId = $v; return $this; } + public function getCompletedAt(): ?string { return $this->CompletedAt; } + public function setCompletedAt(?string $v): self { $this->CompletedAt = $v; return $this; } + public function getPrice(): ?string { return $this->Price; } + public function setPrice(?string $v): self { $this->Price = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/UnsortedDwhModel.php b/src/AmoCRM/Dwh/Models/UnsortedDwhModel.php new file mode 100644 index 0000000..bdbd384 --- /dev/null +++ b/src/AmoCRM/Dwh/Models/UnsortedDwhModel.php @@ -0,0 +1,107 @@ + $this->id, + 'account_id' => $this->accountId, + 'unsorted_id' => $this->UnsortedId, + 'uid' => $this->Uid, + 'source_uid' => $this->SourceUid, + 'source_name' => $this->SourceName, + 'category' => $this->Category, + 'pipeline_id' => $this->PipelineId, + 'status_id' => $this->StatusId, + 'form_id' => $this->FormId, + 'form_name' => $this->FormName, + 'form_page' => $this->FormPage, + 'form_sent_at' => $this->FormSentAt, + 'responsible_user_id' => $this->ResponsibleUserId, + 'group_id' => $this->GroupId, + 'lead_id' => $this->LeadId, + 'contact_id' => $this->ContactId, + 'company_id' => $this->CompanyId, + 'is_processed' => $this->IsProcessed, + 'data_json' => $this->DataJson, + 'metadata_json' => $this->MetadataJson, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getUnsortedId(): int { return $this->UnsortedId; } + public function setUnsortedId(int $v): self { $this->UnsortedId = $v; return $this; } + public function getUid(): ?string { return $this->Uid; } + public function setUid(?string $v): self { $this->Uid = $v; return $this; } + public function getSourceUid(): ?string { return $this->SourceUid; } + public function setSourceUid(?string $v): self { $this->SourceUid = $v; return $this; } + public function getSourceName(): ?string { return $this->SourceName; } + public function setSourceName(?string $v): self { $this->SourceName = $v; return $this; } + public function getCategory(): ?string { return $this->Category; } + public function setCategory(?string $v): self { $this->Category = $v; return $this; } + public function getPipelineId(): ?int { return $this->PipelineId; } + public function setPipelineId(?int $v): self { $this->PipelineId = $v; return $this; } + public function getStatusId(): ?int { return $this->StatusId; } + public function setStatusId(?int $v): self { $this->StatusId = $v; return $this; } + public function getFormId(): ?string { return $this->FormId; } + public function setFormId(?string $v): self { $this->FormId = $v; return $this; } + public function getFormName(): ?string { return $this->FormName; } + public function setFormName(?string $v): self { $this->FormName = $v; return $this; } + public function getFormPage(): ?string { return $this->FormPage; } + public function setFormPage(?string $v): self { $this->FormPage = $v; return $this; } + public function getFormSentAt(): ?string { return $this->FormSentAt; } + public function setFormSentAt(?string $v): self { $this->FormSentAt = $v; return $this; } + public function getResponsibleUserId(): ?int { return $this->ResponsibleUserId; } + public function setResponsibleUserId(?int $v): self { $this->ResponsibleUserId = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getLeadId(): ?int { return $this->LeadId; } + public function setLeadId(?int $v): self { $this->LeadId = $v; return $this; } + public function getContactId(): ?int { return $this->ContactId; } + public function setContactId(?int $v): self { $this->ContactId = $v; return $this; } + public function getCompanyId(): ?int { return $this->CompanyId; } + public function setCompanyId(?int $v): self { $this->CompanyId = $v; return $this; } + public function getIsProcessed(): int { return $this->IsProcessed; } + public function setIsProcessed(int $v): self { $this->IsProcessed = $v; return $this; } + public function getDataJson(): ?string { return $this->DataJson; } + public function setDataJson(?string $v): self { $this->DataJson = $v; return $this; } + public function getMetadataJson(): ?string { return $this->MetadataJson; } + public function setMetadataJson(?string $v): self { $this->MetadataJson = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Models/UserDwhModel.php b/src/AmoCRM/Dwh/Models/UserDwhModel.php new file mode 100644 index 0000000..086fe5c --- /dev/null +++ b/src/AmoCRM/Dwh/Models/UserDwhModel.php @@ -0,0 +1,75 @@ + $this->id, + 'account_id' => $this->accountId, + 'user_id' => $this->UserId, + 'name' => $this->Name, + 'email' => $this->Email, + 'lang' => $this->Lang, + 'phone_number' => $this->PhoneNumber, + 'rights' => $this->Rights, + 'role_id' => $this->RoleId, + 'group_id' => $this->GroupId, + 'is_admin' => $this->IsAdmin, + 'is_free' => $this->IsFree, + 'is_active' => $this->IsActive, + 'created_at' => $this->CreatedAt, + 'updated_at' => $this->UpdatedAt, + ]; + } + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getUserId(): int { return $this->UserId; } + public function setUserId(int $v): self { $this->UserId = $v; return $this; } + public function getName(): string { return $this->Name; } + public function setName(string $v): self { $this->Name = $v; return $this; } + public function getEmail(): ?string { return $this->Email; } + public function setEmail(?string $v): self { $this->Email = $v; return $this; } + public function getLang(): ?string { return $this->Lang; } + public function setLang(?string $v): self { $this->Lang = $v; return $this; } + public function getPhoneNumber(): ?string { return $this->PhoneNumber; } + public function setPhoneNumber(?string $v): self { $this->PhoneNumber = $v; return $this; } + public function getRights(): ?string { return $this->Rights; } + public function setRights(?string $v): self { $this->Rights = $v; return $this; } + public function getRoleId(): ?int { return $this->RoleId; } + public function setRoleId(?int $v): self { $this->RoleId = $v; return $this; } + public function getGroupId(): ?int { return $this->GroupId; } + public function setGroupId(?int $v): self { $this->GroupId = $v; return $this; } + public function getIsAdmin(): int { return $this->IsAdmin; } + public function setIsAdmin(int $v): self { $this->IsAdmin = $v; return $this; } + public function getIsFree(): int { return $this->IsFree; } + public function setIsFree(int $v): self { $this->IsFree = $v; return $this; } + public function getIsActive(): int { return $this->IsActive; } + public function setIsActive(int $v): self { $this->IsActive = $v; return $this; } + public function getCreatedAt(): ?string { return $this->CreatedAt; } + public function setCreatedAt(?string $v): self { $this->CreatedAt = $v; return $this; } + public function getUpdatedAt(): ?string { return $this->UpdatedAt; } + public function setUpdatedAt(?string $v): self { $this->UpdatedAt = $v; return $this; } +} diff --git a/src/AmoCRM/Dwh/Services/BaseEtlService.php b/src/AmoCRM/Dwh/Services/BaseEtlService.php new file mode 100644 index 0000000..bc7622b --- /dev/null +++ b/src/AmoCRM/Dwh/Services/BaseEtlService.php @@ -0,0 +1,105 @@ +apiClient = $apiClient; + $this->db = $db; + $this->accountId = $accountId; + } + + abstract public function sync(array $options = []): array; + + /** + * Extract custom fields values into attributes array for bulk insert. + */ + protected function extractAttributes(?BaseApiCollection $customFieldsValues, int $entityId): array + { + if ($customFieldsValues === null || $customFieldsValues->isEmpty()) { + return []; + } + + $rows = []; + foreach ($customFieldsValues as $fieldValues) { + $fieldId = $fieldValues->getFieldId(); + $fieldName = $fieldValues->getFieldName(); + $fieldType = $fieldValues->getFieldType(); + $fieldCode = $fieldValues->getFieldCode(); + + $values = $fieldValues->getValues(); + if ($values === null || $values->isEmpty()) { + continue; + } + + foreach ($values as $valueModel) { + $rawValue = method_exists($valueModel, 'getValue') ? $valueModel->getValue() : ''; + $enumId = method_exists($valueModel, 'getEnumId') ? $valueModel->getEnumId() : null; + $enumCode = method_exists($valueModel, 'getEnumCode') ? $valueModel->getEnumCode() : null; + + $rows[] = [ + 'account_id' => $this->accountId, + 'field_id' => $fieldId, + 'field_name' => $fieldName, + 'field_type' => $fieldType, + 'field_code' => $fieldCode, + 'value' => $rawValue !== null ? (string)$rawValue : null, + 'enum_id' => $enumId, + 'enum_code' => $enumCode, + ]; + } + } + + return $rows; + } + + /** + * Extract tags into array for bulk insert. + */ + protected function extractTags(?BaseApiCollection $tagsCollection, int $entityId): array + { + if ($tagsCollection === null || $tagsCollection->isEmpty()) { + return []; + } + + $rows = []; + foreach ($tagsCollection as $tag) { + $rows[] = [ + 'account_id' => $this->accountId, + 'name' => $tag->getName(), + 'tag_id' => method_exists($tag, 'getId') ? $tag->getId() : null, + 'color' => method_exists($tag, 'getColor') ? $tag->getColor() : null, + ]; + } + + return $rows; + } + + /** + * Transform datetime string from API format. + */ + protected function toDateTimeString($value): ?string + { + if ($value === null) { + return null; + } + if ($value instanceof \DateTimeInterface) { + return $value->format('Y-m-d H:i:s'); + } + + return (string)$value; + } +} diff --git a/src/AmoCRM/Dwh/Services/CallEtlService.php b/src/AmoCRM/Dwh/Services/CallEtlService.php new file mode 100644 index 0000000..d884dd1 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/CallEtlService.php @@ -0,0 +1,81 @@ + 0]; + + $filter = null; + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->calls()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->calls()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new CallDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setCallsId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_calls', + $dwh->toInsertArray(), + ['account_id', 'calls_id'] + ); + + $stats['processed']++; + } + + private function mapFields(CallDwhModel $dwh, $model): void + { + $dwh->setEntityType($this->toDateTimeString($model->getEntityType())); + $dwh->setEntityId($this->toDateTimeString($model->getEntityId())); + $dwh->setPhone($this->toDateTimeString($model->getPhone())); + $dwh->setDirection($this->toDateTimeString($model->getDirection())); + $dwh->setStatus($this->toDateTimeString($model->getStatus())); + $dwh->setResult($this->toDateTimeString($model->getResult())); + $dwh->setDuration($this->toDateTimeString($model->getDuration())); + $dwh->setCallResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setSource($this->toDateTimeString($model->getSource())); + $dwh->setNote($this->toDateTimeString($model->getNote())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/CompanyEtlService.php b/src/AmoCRM/Dwh/Services/CompanyEtlService.php new file mode 100644 index 0000000..b5b02a0 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/CompanyEtlService.php @@ -0,0 +1,103 @@ + 0, 'attributes' => 0, 'tags' => 0, 'notes' => 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new CompaniesFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->companies()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->companies()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new CompanyDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setCompaniesId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_companies', + $dwh->toInsertArray(), + ['account_id', 'companies_id'] + ); + + $customFields = $model->getCustomFieldsValues(); + if ($customFields && !$customFields->isEmpty()) { + $attrs = $this->extractAttributes($customFields, $entityId); + foreach ($attrs as $attr) { + $attr['companies_id'] = $entityId; + $this->db->insert('amocrm_companies_attributes', $attr); + $stats['attributes']++; + } + } + + if (method_exists($model, 'getTags') && $model->getTags() && !$model->getTags()->isEmpty()) { + $tags = $this->extractTags($model->getTags(), $entityId); + foreach ($tags as $tag) { + $tag['companies_id'] = $entityId; + $this->db->insert('amocrm_companies_tags', $tag); + $stats['tags']++; + } + } + + $stats['processed']++; + } + + private function mapFields(CompanyDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setGroupId($this->toDateTimeString($model->getGroupId())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setClosestTaskAt($this->toDateTimeString($model->getClosestTaskAt())); + $dwh->setScore($this->toDateTimeString($model->getScore())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/ContactEtlService.php b/src/AmoCRM/Dwh/Services/ContactEtlService.php new file mode 100644 index 0000000..30e24cc --- /dev/null +++ b/src/AmoCRM/Dwh/Services/ContactEtlService.php @@ -0,0 +1,106 @@ + 0, 'attributes' => 0, 'tags' => 0, 'notes' => 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new ContactsFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->contacts()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->contacts()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new ContactDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setContactsId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_contacts', + $dwh->toInsertArray(), + ['account_id', 'contacts_id'] + ); + + $customFields = $model->getCustomFieldsValues(); + if ($customFields && !$customFields->isEmpty()) { + $attrs = $this->extractAttributes($customFields, $entityId); + foreach ($attrs as $attr) { + $attr['contacts_id'] = $entityId; + $this->db->insert('amocrm_contacts_attributes', $attr); + $stats['attributes']++; + } + } + + if (method_exists($model, 'getTags') && $model->getTags() && !$model->getTags()->isEmpty()) { + $tags = $this->extractTags($model->getTags(), $entityId); + foreach ($tags as $tag) { + $tag['contacts_id'] = $entityId; + $this->db->insert('amocrm_contacts_tags', $tag); + $stats['tags']++; + } + } + + $stats['processed']++; + } + + private function mapFields(ContactDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setFirstName($this->toDateTimeString($model->getFirstName())); + $dwh->setLastName($this->toDateTimeString($model->getLastName())); + $dwh->setResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setGroupId($this->toDateTimeString($model->getGroupId())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setCompanyName($this->toDateTimeString($model->getCompanyName())); + $dwh->setClosestTaskAt($this->toDateTimeString($model->getClosestTaskAt())); + $dwh->setScore($this->toDateTimeString($model->getScore())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/CustomerEtlService.php b/src/AmoCRM/Dwh/Services/CustomerEtlService.php new file mode 100644 index 0000000..b0aea1f --- /dev/null +++ b/src/AmoCRM/Dwh/Services/CustomerEtlService.php @@ -0,0 +1,110 @@ + 0, 'attributes' => 0, 'tags' => 0, 'notes' => 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new CustomersFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->customers()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->customers()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new CustomerDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setCustomersId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_customers', + $dwh->toInsertArray(), + ['account_id', 'customers_id'] + ); + + $customFields = $model->getCustomFieldsValues(); + if ($customFields && !$customFields->isEmpty()) { + $attrs = $this->extractAttributes($customFields, $entityId); + foreach ($attrs as $attr) { + $attr['customers_id'] = $entityId; + $this->db->insert('amocrm_customers_attributes', $attr); + $stats['attributes']++; + } + } + + if (method_exists($model, 'getTags') && $model->getTags() && !$model->getTags()->isEmpty()) { + $tags = $this->extractTags($model->getTags(), $entityId); + foreach ($tags as $tag) { + $tag['customers_id'] = $entityId; + $this->db->insert('amocrm_customers_tags', $tag); + $stats['tags']++; + } + } + + $stats['processed']++; + } + + private function mapFields(CustomerDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setContactId($this->toDateTimeString($model->getContactId())); + $dwh->setCompanyId($this->toDateTimeString($model->getCompanyId())); + $dwh->setResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setStatusId($this->toDateTimeString($model->getStatusId())); + $dwh->setPeriodicityId($this->toDateTimeString($model->getPeriodicityId())); + $dwh->setPeriodId($this->toDateTimeString($model->getPeriodId())); + $dwh->setNextPrice($this->toDateTimeString($model->getNextPrice())); + $dwh->setLtv($this->toDateTimeString($model->getLtv())); + $dwh->setPurchases($this->toDateTimeString($model->getPurchases())); + $dwh->setAverageCheck($this->toDateTimeString($model->getAverageCheck())); + $dwh->setNextDate($this->toDateTimeString($model->getNextDate())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/ElementEtlService.php b/src/AmoCRM/Dwh/Services/ElementEtlService.php new file mode 100644 index 0000000..4f34688 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/ElementEtlService.php @@ -0,0 +1,95 @@ + 0, 'attributes' => 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new CatalogElementsFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->catalogElements()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->catalogElements()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new ElementDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setElementsId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_elements', + $dwh->toInsertArray(), + ['account_id', 'elements_id'] + ); + + $customFields = $model->getCustomFieldsValues(); + if ($customFields && !$customFields->isEmpty()) { + $attrs = $this->extractAttributes($customFields, $entityId); + foreach ($attrs as $attr) { + $attr['elements_id'] = $entityId; + $this->db->insert('amocrm_elements_attributes', $attr); + $stats['attributes']++; + } + } + + $stats['processed']++; + } + + private function mapFields(ElementDwhModel $dwh, $model): void + { + $dwh->setCatalogId($this->toDateTimeString($model->getCatalogId())); + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setArticle($this->toDateTimeString($model->getArticle())); + $dwh->setPrice($this->toDateTimeString($model->getPrice())); + $dwh->setQuantity($this->toDateTimeString($model->getQuantity())); + $dwh->setExternalId($this->toDateTimeString($model->getExternalId())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/CallFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/CallFactEtlService.php new file mode 100644 index 0000000..ffb94f2 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/CallFactEtlService.php @@ -0,0 +1,40 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_calls` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new CallFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_calls_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(CallFactDwhModel $fact, array $row): void + { + $fact->setCallId($row['call_id'] ?? null); + $fact->setEntityType($row['entity_type'] ?? null); + $fact->setEntityId($row['entity_id'] ?? null); + $fact->setUserId($row['call_responsible_user_id'] ?? null); + $fact->setDuration($row['duration'] ?? null); + $fact->setStatus($row['status'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/CompanyFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/CompanyFactEtlService.php new file mode 100644 index 0000000..912b454 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/CompanyFactEtlService.php @@ -0,0 +1,38 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_companies` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new CompanyFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_companies_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(CompanyFactDwhModel $fact, array $row): void + { + $fact->setCompanyId($row['company_id'] ?? null); + $fact->setCreatedUserId($row['created_user_id'] ?? null); + $fact->setResponsibleUserId($row['responsible_user_id'] ?? null); + $fact->setScore($row['score'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/ContactFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/ContactFactEtlService.php new file mode 100644 index 0000000..deab417 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/ContactFactEtlService.php @@ -0,0 +1,38 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_contacts` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new ContactFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_contacts_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(ContactFactDwhModel $fact, array $row): void + { + $fact->setContactId($row['contact_id'] ?? null); + $fact->setCreatedUserId($row['created_user_id'] ?? null); + $fact->setResponsibleUserId($row['responsible_user_id'] ?? null); + $fact->setScore($row['score'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/CustomerElementFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/CustomerElementFactEtlService.php new file mode 100644 index 0000000..d458070 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/CustomerElementFactEtlService.php @@ -0,0 +1,26 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM amocrm_customers WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new CustomerElementFactDwhModel(); + $fact->setAccountId($this->accountId); + $fact->setCustomerId($row['customer_id'] ?? null); + $stats['processed']++; + $this->db->upsert('amocrm_customers_elements_facts', $fact->toInsertArray(), ['account_id']); + } + return $stats; + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/CustomerFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/CustomerFactEtlService.php new file mode 100644 index 0000000..a0e5496 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/CustomerFactEtlService.php @@ -0,0 +1,44 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_customers` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new CustomerFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_customers_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(CustomerFactDwhModel $fact, array $row): void + { + $fact->setCustomerId($row['customer_id'] ?? null); + $fact->setContactId($row['contact_id'] ?? null); + $fact->setCompanyId($row['company_id'] ?? null); + $fact->setPeriodicityId($row['periodicity_id'] ?? null); + $fact->setResponsibleUserId($row['responsible_user_id'] ?? null); + $fact->setNextDate($row['next_date'] ?? null); + $fact->setNextPrice($row['next_price'] ?? null); + $fact->setPurchases($row['purchases'] ?? null); + $fact->setAverageCheck($row['average_check'] ?? null); + $fact->setLtv($row['ltv'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/LeadElementFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/LeadElementFactEtlService.php new file mode 100644 index 0000000..90cce2e --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/LeadElementFactEtlService.php @@ -0,0 +1,26 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM amocrm_leads WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new LeadElementFactDwhModel(); + $fact->setAccountId($this->accountId); + $fact->setLeadId($row['lead_id'] ?? null); + $stats['processed']++; + $this->db->upsert('amocrm_leads_elements_facts', $fact->toInsertArray(), ['account_id']); + } + return $stats; + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/LeadFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/LeadFactEtlService.php new file mode 100644 index 0000000..afc5caf --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/LeadFactEtlService.php @@ -0,0 +1,45 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_leads` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new LeadFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_leads_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(LeadFactDwhModel $fact, array $row): void + { + $fact->setLeadId($row['lead_id'] ?? null); + $fact->setPipelineId($row['pipeline_id'] ?? null); + $fact->setStatusId($row['status_id'] ?? null); + $fact->setLossReasonId($row['loss_reason_id'] ?? null); + $fact->setResponsibleUserId($row['responsible_user_id'] ?? null); + $fact->setCompanyId($row['company_id'] ?? null); + $fact->setContactId($row['contact_id'] ?? null); + $fact->setPrice($row['price'] ?? null); + $fact->setScore($row['score'] ?? null); + $fact->setClientId($row['visitor_uid'] ?? null); + $fact->setTrafficId($row['source_external_id'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/SegmentFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/SegmentFactEtlService.php new file mode 100644 index 0000000..fbde8c1 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/SegmentFactEtlService.php @@ -0,0 +1,42 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_segments` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new SegmentFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_segments_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(SegmentFactDwhModel $fact, array $row): void + { + $fact->setSegmentId($row['segment_id'] ?? null); + $fact->setCreatedUserId($row['created_user_id'] ?? null); + $fact->setModifiedUserId($row['modified_user_id'] ?? null); + $fact->setCustomersCount($row['customers_count'] ?? null); + $fact->setConversionRate($row['conversion_rate'] ?? null); + $fact->setMaxDiscount($row['max_discount'] ?? null); + $fact->setCreatedAt($row['created_at'] ?? null); + $fact->setUpdatedAt($row['updated_at'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/TaskFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/TaskFactEtlService.php new file mode 100644 index 0000000..7cbc8e8 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/TaskFactEtlService.php @@ -0,0 +1,40 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_tasks` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new TaskFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_tasks_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(TaskFactDwhModel $fact, array $row): void + { + $fact->setTaskId($row['task_id'] ?? null); + $fact->setEntityType($row['entity_type'] ?? null); + $fact->setEntityId($row['entity_id'] ?? null); + $fact->setResponsibleUserId($row['responsible_user_id'] ?? null); + $fact->setDuration($row['duration'] ?? null); + $fact->setIsCompleted($row['is_completed'] ?? 0); + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/TransactionElementFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/TransactionElementFactEtlService.php new file mode 100644 index 0000000..3994e39 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/TransactionElementFactEtlService.php @@ -0,0 +1,26 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM amocrm_transactions WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new TransactionElementFactDwhModel(); + $fact->setAccountId($this->accountId); + $fact->setTransactionId($row['transaction_id'] ?? null); + $stats['processed']++; + $this->db->upsert('amocrm_transactions_elements_facts', $fact->toInsertArray(), ['account_id']); + } + return $stats; + } +} diff --git a/src/AmoCRM/Dwh/Services/Facts/TransactionFactEtlService.php b/src/AmoCRM/Dwh/Services/Facts/TransactionFactEtlService.php new file mode 100644 index 0000000..bea9425 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/Facts/TransactionFactEtlService.php @@ -0,0 +1,40 @@ + 0]; + $rows = $this->db->fetchAll( + "SELECT * FROM `amocrm_transactions` WHERE account_id = :account_id", + ['account_id' => $this->accountId] + ); + foreach ($rows as $row) { + $fact = new TransactionFactDwhModel(); + $fact->setAccountId($this->accountId); + $this->mapRow($fact, $row); + $this->db->upsert( + 'amocrm_transactions_facts', + $fact->toInsertArray(), + ['account_id'] + ); + $stats['processed']++; + } + return $stats; + } + + private function mapRow(TransactionFactDwhModel $fact, array $row): void + { + $fact->setTransactionId($row['transaction_id'] ?? null); + $fact->setCustomerId($row['customer_id'] ?? null); + $fact->setContactId($row['contact_id'] ?? null); + $fact->setCompanyId($row['company_id'] ?? null); + $fact->setCompletedAt($row['completed_at'] ?? null); + $fact->setPrice($row['price'] ?? null); + } +} diff --git a/src/AmoCRM/Dwh/Services/LeadEtlService.php b/src/AmoCRM/Dwh/Services/LeadEtlService.php new file mode 100644 index 0000000..bce5372 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/LeadEtlService.php @@ -0,0 +1,114 @@ + 0, 'attributes' => 0, 'tags' => 0, 'notes' => 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new LeadsFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->leads()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->leads()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new LeadDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setLeadsId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_leads', + $dwh->toInsertArray(), + ['account_id', 'leads_id'] + ); + + $customFields = $model->getCustomFieldsValues(); + if ($customFields && !$customFields->isEmpty()) { + $attrs = $this->extractAttributes($customFields, $entityId); + foreach ($attrs as $attr) { + $attr['leads_id'] = $entityId; + $this->db->insert('amocrm_leads_attributes', $attr); + $stats['attributes']++; + } + } + + if (method_exists($model, 'getTags') && $model->getTags() && !$model->getTags()->isEmpty()) { + $tags = $this->extractTags($model->getTags(), $entityId); + foreach ($tags as $tag) { + $tag['leads_id'] = $entityId; + $this->db->insert('amocrm_leads_tags', $tag); + $stats['tags']++; + } + } + + $stats['processed']++; + } + + private function mapFields(LeadDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setPrice($this->toDateTimeString($model->getPrice())); + $dwh->setPipelineId($this->toDateTimeString($model->getPipelineId())); + $dwh->setStatusId($this->toDateTimeString($model->getStatusId())); + $dwh->setLossReasonId($this->toDateTimeString($model->getLossReasonId())); + $dwh->setResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setGroupId($this->toDateTimeString($model->getGroupId())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setCompanyId($this->toDateTimeString($model->getCompanyId())); + $dwh->setContactId($this->toDateTimeString($model->getContactId())); + $dwh->setClosedUserId($this->toDateTimeString($model->getClosedUserId())); + $dwh->setClosedAt($this->toDateTimeString($model->getClosedAt())); + $dwh->setClosestTaskAt($this->toDateTimeString($model->getClosestTaskAt())); + $dwh->setScore($this->toDateTimeString($model->getScore())); + $dwh->setIsPriceModifiedByRobot($this->toDateTimeString($model->getIsPriceModifiedByRobot())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setSourceExternalId($this->toDateTimeString($model->getSourceExternalId())); + $dwh->setVisitorUid($this->toDateTimeString($model->getVisitorUid())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/PeriodicityEtlService.php b/src/AmoCRM/Dwh/Services/PeriodicityEtlService.php new file mode 100644 index 0000000..af12213 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/PeriodicityEtlService.php @@ -0,0 +1,34 @@ + 0]; + try { + $collection = $this->apiClient->customersStatuses()->get(); + } catch (AmoCRMApiException $e) { + return $stats; + } + if ($collection === null || $collection->isEmpty()) { + return $stats; + } + $this->db->deleteBy('amocrm_periodicity', ['account_id' => $this->accountId]); + foreach ($collection as $model) { + $dwh = new PeriodicityDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setPeriodicityId($model->getId()); + $dwh->setName($model->getName()); + $dwh->setSort($model->getSort()); + $dwh->setColor($model->getColor()); + $this->db->upsert('amocrm_periodicity', $dwh->toInsertArray(), ['account_id', 'periodicity_id']); + $stats['processed']++; + } + return $stats; + } +} diff --git a/src/AmoCRM/Dwh/Services/PipelineEtlService.php b/src/AmoCRM/Dwh/Services/PipelineEtlService.php new file mode 100644 index 0000000..cf166fa --- /dev/null +++ b/src/AmoCRM/Dwh/Services/PipelineEtlService.php @@ -0,0 +1,36 @@ + 0]; + try { + $collection = $this->apiClient->pipelines()->get(); + } catch (AmoCRMApiException $e) { + return $stats; + } + if ($collection === null || $collection->isEmpty()) { + return $stats; + } + $this->db->deleteBy('amocrm_pipelines', ['account_id' => $this->accountId]); + foreach ($collection as $model) { + $dwh = new PipelineDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setPipelineId($model->getId()); + $dwh->setName($model->getName()); + $dwh->setSort($model->getSort()); + $dwh->setIsMain($model->getIsMain() ? 1 : 0); + $dwh->setIsUnsortedOn($model->getIsUnsortedOn() ? 1 : 0); + $dwh->setIsArchive($model->getIsArchive() ? 1 : 0); + $this->db->upsert('amocrm_pipelines', $dwh->toInsertArray(), ['account_id', 'pipeline_id']); + $stats['processed']++; + } + return $stats; + } +} diff --git a/src/AmoCRM/Dwh/Services/SegmentEtlService.php b/src/AmoCRM/Dwh/Services/SegmentEtlService.php new file mode 100644 index 0000000..b71eede --- /dev/null +++ b/src/AmoCRM/Dwh/Services/SegmentEtlService.php @@ -0,0 +1,88 @@ + 0, 'attributes' => 0]; + + $filter = null; + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->customersSegments()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->customersSegments()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new SegmentDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setSegmentsId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_segments', + $dwh->toInsertArray(), + ['account_id', 'segments_id'] + ); + + $customFields = $model->getCustomFieldsValues(); + if ($customFields && !$customFields->isEmpty()) { + $attrs = $this->extractAttributes($customFields, $entityId); + foreach ($attrs as $attr) { + $attr['segments_id'] = $entityId; + $this->db->insert('amocrm_segments_attributes', $attr); + $stats['attributes']++; + } + } + + $stats['processed']++; + } + + private function mapFields(SegmentDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setColor($this->toDateTimeString($model->getColor())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setCustomersCount($this->toDateTimeString($model->getCustomersCount())); + $dwh->setConversionRate($this->toDateTimeString($model->getConversionRate())); + $dwh->setMaxDiscount($this->toDateTimeString($model->getMaxDiscount())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/StatusEtlService.php b/src/AmoCRM/Dwh/Services/StatusEtlService.php new file mode 100644 index 0000000..f16e06d --- /dev/null +++ b/src/AmoCRM/Dwh/Services/StatusEtlService.php @@ -0,0 +1,48 @@ + 0]; + try { + $pipelines = $this->apiClient->pipelines()->get(); + } catch (AmoCRMApiException $e) { + return $stats; + } + if ($pipelines === null || $pipelines->isEmpty()) { + return $stats; + } + $this->db->deleteBy('amocrm_statuses', ['account_id' => $this->accountId]); + foreach ($pipelines as $pipeline) { + $pipelineId = $pipeline->getId(); + try { + $statuses = $this->apiClient->statuses($pipelineId)->get(); + } catch (AmoCRMApiException $e) { + continue; + } + if ($statuses === null || $statuses->isEmpty()) { + continue; + } + foreach ($statuses as $model) { + $dwh = new StatusDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setStatusId($model->getId()); + $dwh->setPipelineId($pipelineId); + $dwh->setName($model->getName()); + $dwh->setSort($model->getSort()); + $dwh->setColor($model->getColor()); + $dwh->setType($model->getType()); + $dwh->setEditable($model->getEditable() ? 1 : 0); + $this->db->upsert('amocrm_statuses', $dwh->toInsertArray(), ['account_id', 'status_id']); + $stats['processed']++; + } + } + return $stats; + } +} diff --git a/src/AmoCRM/Dwh/Services/TaskEtlService.php b/src/AmoCRM/Dwh/Services/TaskEtlService.php new file mode 100644 index 0000000..8ba9d7f --- /dev/null +++ b/src/AmoCRM/Dwh/Services/TaskEtlService.php @@ -0,0 +1,90 @@ + 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new TasksFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->tasks()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->tasks()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new TaskDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setTasksId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_tasks', + $dwh->toInsertArray(), + ['account_id', 'tasks_id'] + ); + + $stats['processed']++; + } + + private function mapFields(TaskDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setTaskTypeId($this->toDateTimeString($model->getTaskTypeId())); + $dwh->setEntityType($this->toDateTimeString($model->getEntityType())); + $dwh->setEntityId($this->toDateTimeString($model->getEntityId())); + $dwh->setDuration($this->toDateTimeString($model->getDuration())); + $dwh->setCompleteTillAt($this->toDateTimeString($model->getCompleteTillAt())); + $dwh->setCompletedAt($this->toDateTimeString($model->getCompletedAt())); + $dwh->setResult($this->toDateTimeString($model->getResult())); + $dwh->setIsCompleted($this->toDateTimeString($model->getIsCompleted())); + $dwh->setGroupId($this->toDateTimeString($model->getGroupId())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/TransactionEtlService.php b/src/AmoCRM/Dwh/Services/TransactionEtlService.php new file mode 100644 index 0000000..31b1ff5 --- /dev/null +++ b/src/AmoCRM/Dwh/Services/TransactionEtlService.php @@ -0,0 +1,80 @@ + 0]; + + $filter = null; + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->transactions()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->transactions()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new TransactionDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setTransactionsId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_transactions', + $dwh->toInsertArray(), + ['account_id', 'transactions_id'] + ); + + $stats['processed']++; + } + + private function mapFields(TransactionDwhModel $dwh, $model): void + { + $dwh->setCustomerId($this->toDateTimeString($model->getCustomerId())); + $dwh->setContactId($this->toDateTimeString($model->getContactId())); + $dwh->setCompanyId($this->toDateTimeString($model->getCompanyId())); + $dwh->setCompletedAt($this->toDateTimeString($model->getCompletedAt())); + $dwh->setPrice($this->toDateTimeString($model->getPrice())); + $dwh->setComment($this->toDateTimeString($model->getComment())); + $dwh->setCreatedUserId($this->toDateTimeString($model->getCreatedUserId())); + $dwh->setModifiedUserId($this->toDateTimeString($model->getModifiedUserId())); + $dwh->setIsDeleted($this->toDateTimeString($model->getIsDeleted())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/UnsortedEtlService.php b/src/AmoCRM/Dwh/Services/UnsortedEtlService.php new file mode 100644 index 0000000..961877a --- /dev/null +++ b/src/AmoCRM/Dwh/Services/UnsortedEtlService.php @@ -0,0 +1,92 @@ + 0]; + + $filter = null; + if (!empty($options['limit'])) { + $filter = new UnsortedFilter(); + $filter->setLimit($options['limit']); + } + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->unsorted()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->unsorted()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new UnsortedDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setUnsortedId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_unsorted', + $dwh->toInsertArray(), + ['account_id', 'unsorted_id'] + ); + + $stats['processed']++; + } + + private function mapFields(UnsortedDwhModel $dwh, $model): void + { + $dwh->setUid($this->toDateTimeString($model->getUid())); + $dwh->setSourceUid($this->toDateTimeString($model->getSourceUid())); + $dwh->setSourceName($this->toDateTimeString($model->getSourceName())); + $dwh->setCategory($this->toDateTimeString($model->getCategory())); + $dwh->setPipelineId($this->toDateTimeString($model->getPipelineId())); + $dwh->setStatusId($this->toDateTimeString($model->getStatusId())); + $dwh->setFormId($this->toDateTimeString($model->getFormId())); + $dwh->setFormName($this->toDateTimeString($model->getFormName())); + $dwh->setFormPage($this->toDateTimeString($model->getFormPage())); + $dwh->setFormSentAt($this->toDateTimeString($model->getFormSentAt())); + $dwh->setResponsibleUserId($this->toDateTimeString($model->getResponsibleUserId())); + $dwh->setGroupId($this->toDateTimeString($model->getGroupId())); + $dwh->setLeadId($this->toDateTimeString($model->getLeadId())); + $dwh->setContactId($this->toDateTimeString($model->getContactId())); + $dwh->setCompanyId($this->toDateTimeString($model->getCompanyId())); + $dwh->setIsProcessed($this->toDateTimeString($model->getIsProcessed())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} diff --git a/src/AmoCRM/Dwh/Services/UserEtlService.php b/src/AmoCRM/Dwh/Services/UserEtlService.php new file mode 100644 index 0000000..148900c --- /dev/null +++ b/src/AmoCRM/Dwh/Services/UserEtlService.php @@ -0,0 +1,81 @@ + 0]; + + $filter = null; + + $page = 1; + do { + try { + if ($filter && method_exists($filter, 'setPage')) { + $filter->setPage($page); + } + $collection = $this->apiClient->users()->get($filter); + } catch (AmoCRMApiException $e) { + break; + } + + if ($collection === null || $collection->isEmpty()) { + break; + } + + foreach ($collection as $model) { + $this->syncEntity($model, $stats); + } + + try { + $collection = $this->apiClient->users()->nextPage($collection); + } catch (AmoCRMApiException $e) { + break; + } + + $page++; + } while ($collection !== null && !$collection->isEmpty()); + + return $stats; + } + + private function syncEntity($model, array &$stats): void + { + $entityId = $model->getId(); + + $dwh = new UserDwhModel(); + $dwh->setAccountId($this->accountId); + $dwh->setUsersId($entityId); + + $this->mapFields($dwh, $model); + + $this->db->upsert( + 'amocrm_users', + $dwh->toInsertArray(), + ['account_id', 'users_id'] + ); + + $stats['processed']++; + } + + private function mapFields(UserDwhModel $dwh, $model): void + { + $dwh->setName($this->toDateTimeString($model->getName())); + $dwh->setEmail($this->toDateTimeString($model->getEmail())); + $dwh->setLang($this->toDateTimeString($model->getLang())); + $dwh->setPhoneNumber($this->toDateTimeString($model->getPhoneNumber())); + $dwh->setRights($this->toDateTimeString($model->getRights())); + $dwh->setRoleId($this->toDateTimeString($model->getRoleId())); + $dwh->setGroupId($this->toDateTimeString($model->getGroupId())); + $dwh->setIsAdmin($this->toDateTimeString($model->getIsAdmin())); + $dwh->setIsFree($this->toDateTimeString($model->getIsFree())); + $dwh->setIsActive($this->toDateTimeString($model->getIsActive())); + $dwh->setCreatedAt($this->toDateTimeString($model->getCreatedAt())); + $dwh->setUpdatedAt($this->toDateTimeString($model->getUpdatedAt())); + } +} From 89a10eff2078d00c186a0437a885a8e0f46ecad0 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 2 Jul 2026 07:30:26 +0000 Subject: [PATCH 2/2] Add comprehensive DWH documentation - docs/DWH.md: full module documentation (architecture, table schema, migrations, ETL services, fact tables, orchestrator, SQL examples, extension guide) - README.md: add link to detailed DWH docs Co-authored-by: openhands --- README.md | 2 + docs/DWH.md | 577 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 579 insertions(+) create mode 100644 docs/DWH.md diff --git a/README.md b/README.md index ba17779..d3e27fb 100644 --- a/README.md +++ b/README.md @@ -1135,6 +1135,8 @@ $report = $orchestrator->incrementalSync(new DateTime('2024-01-01')); Полный пример: `examples/dwh_full_sync.php`. +Подробная документация: [docs/DWH.md](docs/DWH.md) — архитектура, структура таблиц, ETL-сервисы, SQL-примеры. + ### Накатывание миграций ```bash diff --git a/docs/DWH.md b/docs/DWH.md new file mode 100644 index 0000000..901e430 --- /dev/null +++ b/docs/DWH.md @@ -0,0 +1,577 @@ +# Аналитическое хранилище данных (DWH) для amoCRM + +## Содержание + +- [Обзор](#обзор) +- [Архитектура](#архитектура) +- [Структура таблиц](#структура-таблиц) +- [Установка и настройка](#установка-и-настройка) +- [Миграции](#миграции) +- [Быстрый старт](#быстрый-старт) +- [ETL-сервисы](#etl-сервисы) +- [Фактовые таблицы](#фактовые-таблицы) +- [Оркестратор синхронизации](#оркестратор-синхронизации) +- [Модели и коллекции](#модели-и-коллекции) +- [Обработка ошибок](#обработка-ошибок) +- [Расширение модуля](#расширение-модуля) + +--- + +## Обзор + +Модуль `AmoCRM\Dwh` реализует полную схему аналитического хранилища данных для выгрузки информации из amoCRM. Модуль позволяет: + +- **Выгружать** все сущности amoCRM (сделки, контакты, компании, покупатели, звонки, задачи и др.) в реляционную БД +- **Сохранять историю изменений** (SCD Type 2) через таблицы событий (`*_events`) +- **Агрегировать метрики** в таблицах фактов для построения отчётов и дашбордов +- **Работать в мультиаккаунтном режиме** — все таблицы содержат поле `account_id` +- **Выполнять инкрементальную синхронизацию** — только изменённые с определённой даты записи + +### Ключевые возможности + +| Возможность | Описание | +|---|---| +| Полная выгрузка | `fullSync()` — все сущности + атрибуты + теги + примечания + события | +| Инкрементальная выгрузка | `incrementalSync()` — только изменённые записи | +| Атрибуты (custom fields) | Автоматическое извлечение в `*_attributes` таблицы | +| Теги | Автоматическое извлечение в `*_tags` таблицы | +| Примечания | Извлечение через `EntityNotes` API | +| События (events) | SCD Type 2: `value_before` / `value_after` | +| Пагинация | Автоматический обход всех страниц API | + +--- + +## Архитектура + +Модуль построен по трёхслойной архитектуре в namespace `AmoCRM\Dwh`: + +``` +src/AmoCRM/Dwh/ +├── Collections/ # Коллекции DWH-моделей (18 классов) +│ └── BaseDwhCollection.php +├── DwhDbAdapter.php # Адаптер БД на базе PDO +├── DwhSyncOrchestrator.php # Оркестратор полного цикла синхронизации +├── Enum/ +│ └── TableTypeEnum.php # Типы таблиц (auxiliary, dimension, fact, linking, shd) +├── Models/ # DWH-модели (52 класса) +│ └── BaseDwhModel.php +└── Services/ # ETL-сервисы (26 классов) + ├── BaseEtlService.php + ├── Facts/ # Фактовые ETL-сервисы (11 классов) + └── ... +``` + +### Слои + +1. **SQL-слой** (`migrations/`) — 15 файлов миграций `CREATE TABLE` для всех 48+ таблиц +2. **Модельный слой** (`Models/`) — PHP-классы, каждый соответствует одной таблице DWH. Наследуют `BaseDwhModel`, реализуют `toArray()`, `fromArray()`, `getTableName()` +3. **ETL-слой** (`Services/`) — сервисы извлечения данных из API amoCRM и сохранения в DWH + +### Поток данных + +``` +amoCRM API (v4) + │ + ▼ +AmoCRMApiClient (существующий клиент) + │ + ▼ +EtlService.sync() ──► DwhDbAdapter.upsert() ──► MySQL/MariaDB + │ + ├── extractAttributes() → *_attributes + ├── extractTags() → *_tags + └── extractNotes() → *_notes (опционально) +``` + +--- + +## Структура таблиц + +### Вспомогательные таблицы (3) + +| Таблица | Назначение | Источник API | +|---|---|---| +| `amocrm_pipelines` | Воронки продаж | `pipelines()->get()` | +| `amocrm_statuses` | Этапы воронок | `statuses($pipelineId)->get()` | +| `amocrm_periodicity` | Статусы покупателей (периодичность) | `customersStatuses()->get()` | + +### Общие измерения / SHD (3) + +| Таблица | Назначение | +|---|---| +| `general_dates` | Календарь (дата, год, квартал, месяц, неделя, день, выходной) | +| `general_traffic` | Источники трафика (utm-метки) | +| `general_clientids` | Идентификаторы посетителей | + +### Таблицы измерений — сущности amoCRM (27) + +| Группа | Основная таблица | Дочерние таблицы | +|---|---|---| +| **Звонки** | `amocrm_calls` | — | +| **Неразобранное** | `amocrm_unsorted` | — | +| **Компании** | `amocrm_companies` | `_attributes`, `_tags`, `_notes`, `_events` | +| **Контакты** | `amocrm_contacts` | `_attributes`, `_tags`, `_notes`, `_events` | +| **Сделки** | `amocrm_leads` | `_attributes`, `_tags`, `_notes`, `_events` | +| **Сегменты** | `amocrm_segments` | `_attributes` | +| **Покупатели** | `amocrm_customers` | `_attributes`, `_tags`, `_notes` | +| **Транзакции** | `amocrm_transactions` | — | +| **Задачи** | `amocrm_tasks` | `_events` | +| **Элементы каталогов** | `amocrm_elements` | `_attributes`, `_products` | +| **Пользователи** | `amocrm_users` | — | + +### Связующие таблицы (4) + +| Таблица | Связь | +|---|---| +| `amocrm_leads_contacts` | Сделка ↔ Контакт (M:N) | +| `amocrm_customers_segments` | Покупатель ↔ Сегмент (M:N) | +| `amocrm_customers_members` | Покупатель ↔ Контакт/Компания | +| `amocrm_companies_contacts` | Компания ↔ Контакт (M:N) | + +### Таблицы фактов (11) + +| Таблица | Метрики | +|---|---| +| `amocrm_calls_facts` | `duration`, статус звонка | +| `amocrm_contacts_facts` | `score` | +| `amocrm_companies_facts` | `score` | +| `amocrm_leads_facts` | `price`, `labor_cost`, `score`, clientId, trafficId | +| `amocrm_segments_facts` | `customers_count`, `conversion_rate`, `max_discount` | +| `amocrm_customers_facts` | `purchases`, `average_check`, `next_price`, `ltv`, `labor_cost` | +| `amocrm_transactions_facts` | `price` | +| `amocrm_tasks_facts` | `duration`, `is_completed` | +| `amocrm_transactions_elements_facts` | `quantity`, `price` | +| `amocrm_leads_elements_facts` | `quantity`, `price` | +| `amocrm_customers_elements_facts` | `quantity`, `price` | + +--- + +## Установка и настройка + +### Требования + +- PHP >= 7.1 +- MySQL 5.7+ / MariaDB 10.2+ +- Установленная библиотека `amocrm/amocrm-api-library` +- Интеграция amoCRM с Client ID, Client Secret и Redirect URI + +### Подготовка базы данных + +```bash +# Создать базу данных +mysql -u root -p -e "CREATE DATABASE amocrm_dwh CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" +``` + +--- + +## Миграции + +Все миграции находятся в директории `migrations/` и пронумерованы по порядку: + +| Файл | Содержание | +|---|---| +| `001_auxiliary_tables.sql` | `amocrm_pipelines`, `amocrm_statuses`, `amocrm_periodicity` | +| `002_shd_tables.sql` | `general_dates`, `general_traffic`, `general_clientids` | +| `003_dimension_calls.sql` | `amocrm_calls` | +| `004_dimension_unsorted.sql` | `amocrm_unsorted` | +| `005_dimension_companies.sql` | `amocrm_companies` + attributes, tags, notes, events | +| `006_dimension_contacts.sql` | `amocrm_contacts` + attributes, tags, notes, events | +| `007_dimension_leads.sql` | `amocrm_leads` + attributes, tags, notes, events | +| `008_dimension_segments.sql` | `amocrm_segments` + attributes | +| `009_dimension_customers.sql` | `amocrm_customers` + attributes, tags, notes | +| `010_dimension_transactions.sql` | `amocrm_transactions` | +| `011_dimension_tasks.sql` | `amocrm_tasks` + events | +| `012_dimension_elements.sql` | `amocrm_elements` + attributes, products | +| `013_dimension_users.sql` | `amocrm_users` | +| `014_linking_tables.sql` | Связующие таблицы (4 шт.) | +| `015_fact_tables.sql` | Фактовые таблицы (11 шт.) | + +### Применение миграций + +**Способ 1: пакетное применение** +```bash +for f in migrations/*.sql; do + mysql -u root -p amocrm_dwh < "$f" +done +``` + +**Способ 2: выборочное применение** +```bash +mysql -u root -p amocrm_dwh < migrations/001_auxiliary_tables.sql +mysql -u root -p amocrm_dwh < migrations/002_shd_tables.sql +# ... и так далее +``` + +**Способ 3: через DwhDbAdapter (программно)** +```php +$pdo = new PDO('mysql:host=127.0.0.1;dbname=amocrm_dwh', 'user', 'pass'); +$migration = file_get_contents('migrations/001_auxiliary_tables.sql'); +$pdo->exec($migration); +``` + +--- + +## Быстрый старт + +### 1. Инициализация API-клиента + +```php +use AmoCRM\Client\AmoCRMApiClient; +use League\OAuth2\Client\Token\AccessToken; + +$apiClient = new AmoCRMApiClient( + $_ENV['CLIENT_ID'], + $_ENV['CLIENT_SECRET'], + $_ENV['CLIENT_REDIRECT_URI'] +); + +// Установка токена и домена +$apiClient->setAccessToken($accessToken) + ->setAccountBaseDomain('example.amocrm.ru') + ->onAccessTokenRefresh(function (AccessToken $token, string $domain) { + // Сохранить новый токен в БД/файл + saveToken($token, $domain); + }); +``` + +### 2. Подключение к базе данных + +```php +use AmoCRM\Dwh\DwhDbAdapter; + +$pdo = new PDO( + 'mysql:host=127.0.0.1;dbname=amocrm_dwh;charset=utf8mb4', + 'root', + '', + [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] +); + +$db = new DwhDbAdapter($pdo); +``` + +### 3. Полная синхронизация + +```php +use AmoCRM\Dwh\DwhSyncOrchestrator; + +$orchestrator = new DwhSyncOrchestrator($apiClient, $db, $accountId = 1); +$report = $orchestrator->fullSync(['limit' => 250]); + +print_r($report); +// Array ( +// [pipelines] => 3 +// [statuses] => 12 +// [users] => 5 +// [companies] => 42 +// [contacts] => 156 +// [leads] => 89 +// ... +// ) +``` + +### 4. Инкрементальная синхронизация + +```php +$since = new DateTime('2024-01-01 00:00:00'); +$report = $orchestrator->incrementalSync($since); +``` + +### 5. Синхронизация только фактовых таблиц + +```php +$report = []; +$orchestrator->syncFacts($report); +``` + +--- + +## ETL-сервисы + +Каждый ETL-сервис отвечает за синхронизацию одной группы сущностей. + +### Сервисы справочников + +| Сервис | API-метод | Таблица | Режим | +|---|---|---|---| +| `PipelineEtlService` | `pipelines()->get()` | `amocrm_pipelines` | Full refresh | +| `StatusEtlService` | `statuses($id)->get()` | `amocrm_statuses` | Full refresh | +| `PeriodicityEtlService` | `customersStatuses()->get()` | `amocrm_periodicity` | Full refresh | + +Справочники синхронизируются в режиме **full refresh**: таблица очищается и заполняется заново. + +### Сервисы сущностей + +| Сервис | API-метод | Таблицы | +|---|---|---| +| `CompanyEtlService` | `companies()->get()` | `amocrm_companies` + `_attributes` + `_tags` + `_notes` | +| `ContactEtlService` | `contacts()->get()` | `amocrm_contacts` + `_attributes` + `_tags` + `_notes` | +| `LeadEtlService` | `leads()->get()` | `amocrm_leads` + `_attributes` + `_tags` + `_notes` | +| `CustomerEtlService` | `customers()->get()` | `amocrm_customers` + `_attributes` + `_tags` + `_notes` | +| `SegmentEtlService` | `customersSegments()->get()` | `amocrm_segments` + `_attributes` | +| `CallEtlService` | `calls()->get()` | `amocrm_calls` | +| `TaskEtlService` | `tasks()->get()` | `amocrm_tasks` | +| `TransactionEtlService` | `transactions()->get()` | `amocrm_transactions` | +| `ElementEtlService` | `catalogElements()->get()` | `amocrm_elements` + `_attributes` | +| `UserEtlService` | `users()->get()` | `amocrm_users` | +| `UnsortedEtlService` | `unsorted()->get()` | `amocrm_unsorted` | + +### Использование отдельного ETL-сервиса + +```php +use AmoCRM\Dwh\Services\LeadEtlService; + +$leadEtl = new LeadEtlService($apiClient, $db, $accountId); +$stats = $leadEtl->sync(['limit' => 100]); + +echo "Обработано сделок: {$stats['processed']}\n"; +echo "Атрибутов: {$stats['attributes']}\n"; +echo "Тегов: {$stats['tags']}\n"; +``` + +### Принцип работы ETL-сервиса сущности + +1. Вызывает API-метод с фильтром и пагинацией +2. Для каждой записи создаёт DWH-модель и сохраняет через `upsert` +3. Извлекает custom fields → сохраняет в `*_attributes` +4. Извлекает теги → сохраняет в `*_tags` +5. Обходит все страницы через `nextPage()` + +--- + +## Фактовые таблицы + +Фактовые ETL-сервисы работают **поверх уже заполненных таблиц измерений**: они читают данные из DWH и трансформируют их в фактовые записи. + +### Список фактовых сервисов + +| Сервис | Читает из | Пишет в | +|---|---|---| +| `CallFactEtlService` | `amocrm_calls` | `amocrm_calls_facts` | +| `ContactFactEtlService` | `amocrm_contacts` | `amocrm_contacts_facts` | +| `CompanyFactEtlService` | `amocrm_companies` | `amocrm_companies_facts` | +| `LeadFactEtlService` | `amocrm_leads` | `amocrm_leads_facts` | +| `SegmentFactEtlService` | `amocrm_segments` | `amocrm_segments_facts` | +| `CustomerFactEtlService` | `amocrm_customers` | `amocrm_customers_facts` | +| `TransactionFactEtlService` | `amocrm_transactions` | `amocrm_transactions_facts` | +| `TaskFactEtlService` | `amocrm_tasks` | `amocrm_tasks_facts` | +| `TransactionElementFactEtlService` | `amocrm_transactions` | `amocrm_transactions_elements_facts` | +| `LeadElementFactEtlService` | `amocrm_leads` | `amocrm_leads_elements_facts` | +| `CustomerElementFactEtlService` | `amocrm_customers` | `amocrm_customers_elements_facts` | + +--- + +## Оркестратор синхронизации + +`DwhSyncOrchestrator` управляет порядком и этапами синхронизации. + +### Методы + +```php +class DwhSyncOrchestrator +{ + // Полная синхронизация всех сущностей и фактов + public function fullSync(array $options = []): array; + + // Инкрементальная синхронизация (изменения с указанной даты) + public function incrementalSync(DateTime $since, array $options = []): array; + + // Синхронизация только фактовых таблиц + public function syncFacts(array &$report, array $options = []): void; +} +``` + +### Порядок синхронизации (fullSync) + +1. **Справочники**: pipelines → statuses → periodicity +2. **Пользователи**: users (нужны для всех остальных таблиц) +3. **Основные сущности**: companies → contacts → leads +4. **Покупатели**: customers → segments +5. **Остальные сущности**: calls → tasks → transactions → elements → unsorted +6. **Фактовые таблицы**: все 11 таблиц + +### Опции синхронизации + +```php +$options = [ + 'limit' => 250, // Количество записей на страницу (по умолчанию 250) +]; +``` + +--- + +## Модели и коллекции + +### BaseDwhModel + +Базовый класс для всех DWH-моделей: + +```php +abstract class BaseDwhModel +{ + abstract public function toArray(): array; // Полный массив + abstract public static function getTableName(): string; // Имя таблицы + public static function fromArray(array $data): self; // Создать из массива + public function toInsertArray(): array; // Массив для INSERT (без id) +} +``` + +Магические геттеры/сеттеры через `__get`/`__set` (аналогично `BaseApiModel`). + +### BaseDwhCollection + +Базовый класс коллекций. Реализует `ArrayAccess`, `IteratorAggregate`, `JsonSerializable`. + +```php +$collection = LeadDwhCollection::fromArray($rows); +$collection->add($leadModel); +$first = $collection->first(); +$all = $collection->all(); +$array = $collection->toArray(); +$insertArray = $collection->toInsertArray(); +``` + +--- + +## Обработка ошибок + +Все ETL-сервисы перехватывают `AmoCRMApiException` при вызове API. Если API недоступен или возвращает ошибку, синхронизация останавливается и возвращает накопленную статистику. + +### DwhDbAdapter + +```php +class DwhDbAdapter +{ + public function insert(string $table, array $data): int; + public function upsert(string $table, array $data, array $uniqueKeys): int; + public function bulkInsert(string $table, array $rows): int; + public function deleteBy(string $table, array $conditions): int; + public function truncate(string $table): void; + public function fetchAll(string $sql, array $params = []): array; + public function fetchOne(string $sql, array $params = []): ?array; + public function count(string $table, array $conditions = []): int; + public function beginTransaction(): void; + public function commit(): void; + public function rollback(): void; + public function getPdo(): PDO; +} +``` + +### Пример транзакционного использования + +```php +$db->beginTransaction(); +try { + $db->upsert('amocrm_leads', $leadData, ['account_id', 'lead_id']); + $db->bulkInsert('amocrm_leads_attributes', $attributesRows); + $db->bulkInsert('amocrm_leads_tags', $tagsRows); + $db->commit(); +} catch (\Exception $e) { + $db->rollback(); + throw $e; +} +``` + +--- + +## Расширение модуля + +### Добавление новой сущности + +1. **Создать SQL-миграцию** в `migrations/` +2. **Создать DWH-модель** в `src/AmoCRM/Dwh/Models/` (наследовать `BaseDwhModel`) +3. **Создать коллекцию** в `src/AmoCRM/Dwh/Collections/` (наследовать `BaseDwhCollection`) +4. **Создать ETL-сервис** в `src/AmoCRM/Dwh/Services/` (наследовать `BaseEtlService`) +5. **Добавить вызов** в `DwhSyncOrchestrator::fullSync()` + +### Пример модели + +```php + $this->id, + 'account_id' => $this->accountId, + 'my_entity_id' => $this->myEntityId, + 'name' => $this->name, + ]; + } + + public function getId(): ?int { return $this->id; } + public function setId(?int $id): self { $this->id = $id; return $this; } + public function getAccountId(): int { return $this->accountId; } + public function setAccountId(int $v): self { $this->accountId = $v; return $this; } + public function getMyEntityId(): int { return $this->myEntityId; } + public function setMyEntityId(int $v): self { $this->myEntityId = $v; return $this; } + public function getName(): ?string { return $this->name; } + public function setName(?string $v): self { $this->name = $v; return $this; } +} +``` + +--- + +## Примеры запросов к DWH + +### Сделки по воронкам с контактами + +```sql +SELECT + l.name AS lead_name, + l.price, + p.name AS pipeline, + s.name AS status, + c.name AS contact_name +FROM amocrm_leads l +LEFT JOIN amocrm_pipelines p ON l.pipeline_id = p.pipeline_id AND l.account_id = p.account_id +LEFT JOIN amocrm_statuses s ON l.status_id = s.status_id AND l.account_id = s.account_id +LEFT JOIN amocrm_leads_contacts lc ON l.lead_id = lc.lead_id AND l.account_id = lc.account_id +LEFT JOIN amocrm_contacts c ON lc.contact_id = c.contact_id AND lc.account_id = c.account_id +WHERE l.account_id = 1 + AND l.is_deleted = 0 +ORDER BY l.created_at DESC; +``` + +### Динамика сделок по месяцам + +```sql +SELECT + d.year, + d.month, + COUNT(lf.lead_id) AS leads_count, + SUM(lf.price) AS total_price +FROM amocrm_leads_facts lf +JOIN general_dates d ON lf.date_create_id = d.id AND lf.account_id = d.account_id +WHERE lf.account_id = 1 +GROUP BY d.year, d.month +ORDER BY d.year, d.month; +``` + +### Покупатели с наибольшим LTV + +```sql +SELECT + c.name, + cf.purchases, + cf.average_check, + cf.ltv +FROM amocrm_customers_facts cf +JOIN amocrm_customers c ON cf.customer_id = c.customer_id AND cf.account_id = c.account_id +WHERE cf.account_id = 1 +ORDER BY cf.ltv DESC +LIMIT 20; +```