roistat 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +18 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +757 -0
  6. data/Rakefile +12 -0
  7. data/docs/ru/README.md +142 -0
  8. data/lefthook.yml +8 -0
  9. data/lib/generators/roistat/install/install_generator.rb +13 -0
  10. data/lib/generators/roistat/install/templates/roistat.rb +13 -0
  11. data/lib/roistat/client.rb +220 -0
  12. data/lib/roistat/configuration.rb +17 -0
  13. data/lib/roistat/errors.rb +18 -0
  14. data/lib/roistat/resources/access.rb +25 -0
  15. data/lib/roistat/resources/analytics.rb +68 -0
  16. data/lib/roistat/resources/base.rb +31 -0
  17. data/lib/roistat/resources/billing.rb +17 -0
  18. data/lib/roistat/resources/calltracking.rb +102 -0
  19. data/lib/roistat/resources/channels.rb +28 -0
  20. data/lib/roistat/resources/clients.rb +38 -0
  21. data/lib/roistat/resources/dashboards.rb +13 -0
  22. data/lib/roistat/resources/emailtracking.rb +16 -0
  23. data/lib/roistat/resources/events.rb +42 -0
  24. data/lib/roistat/resources/indicators.rb +13 -0
  25. data/lib/roistat/resources/lead_hunter.rb +8 -0
  26. data/lib/roistat/resources/leads.rb +33 -0
  27. data/lib/roistat/resources/managers.rb +33 -0
  28. data/lib/roistat/resources/mediaplan.rb +23 -0
  29. data/lib/roistat/resources/orders.rb +76 -0
  30. data/lib/roistat/resources/projects.rb +30 -0
  31. data/lib/roistat/resources/proxy_leads.rb +18 -0
  32. data/lib/roistat/resources/sms.rb +15 -0
  33. data/lib/roistat/resources/speech.rb +68 -0
  34. data/lib/roistat/resources/statistics.rb +8 -0
  35. data/lib/roistat/resources/visits.rb +23 -0
  36. data/lib/roistat/resources/vpbx.rb +100 -0
  37. data/lib/roistat/resources/widgets.rb +17 -0
  38. data/lib/roistat/response.rb +88 -0
  39. data/lib/roistat/version.rb +5 -0
  40. data/lib/roistat.rb +66 -0
  41. data/mise.toml +14 -0
  42. data/sig/roistat.rbs +251 -0
  43. metadata +187 -0
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/docs/ru/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # Roistat — документация на русском
2
+
3
+ How-to для разработчиков, которые подключают гем `roistat` к приложению на Ruby или Rails.
4
+
5
+ **Предпосылки:** Ruby 3+, ключ API Roistat, id проекта. Полные таблицы методов — в [корневом README](../../README.md) (английский).
6
+
7
+ Официальные справочники Roistat:
8
+
9
+ - [help-ru](https://help-ru.roistat.com/API/methods/about/) — основная инвентаризация путей
10
+ - [help-en](https://help.roistat.com/API/methods/about/) — дашборды, виджеты и часть путей access/counter
11
+
12
+ ## Содержание
13
+
14
+ - [Установка](#установка)
15
+ - [Конфигурация](#конфигурация)
16
+ - [Клиенты](#клиенты)
17
+ - [Группы ресурсов](#группы-ресурсов)
18
+ - [Ответы и ошибки](#ответы-и-ошибки)
19
+ - [Разработка](#разработка)
20
+
21
+ ## Установка
22
+
23
+ Добавьте гем в Gemfile:
24
+
25
+ ```ruby
26
+ gem "roistat"
27
+ ```
28
+
29
+ Затем:
30
+
31
+ ```fish
32
+ bundle install
33
+ ```
34
+
35
+ ### Rails
36
+
37
+ ```fish
38
+ bundle exec rails generate roistat:install
39
+ ```
40
+
41
+ Генератор создаёт `config/initializers/roistat.rb` со всеми опциями и привязкой к ENV.
42
+
43
+ ## Конфигурация
44
+
45
+ ### Глобальная (удобно для Rails)
46
+
47
+ ```ruby
48
+ Roistat.configure do |config|
49
+ config.api_key = ENV.fetch("ROISTAT_API_KEY")
50
+ config.project = ENV.fetch("ROISTAT_PROJECT_ID")
51
+ end
52
+
53
+ Roistat.client.projects.list
54
+ ```
55
+
56
+ ### Опции
57
+
58
+ | Опция | Обязательна | По умолчанию | Назначение |
59
+ |-------|-------------|--------------|------------|
60
+ | `api_key` | да | — | ключ в заголовке `Api-key` |
61
+ | `project` | для project-scoped вызовов | — | query `project` |
62
+ | `base_url` | нет | `https://cloud.roistat.com/api/v1` | базовый URL |
63
+ | `timeout` | нет | `30` | таймаут запроса (сек) |
64
+ | `open_timeout` | нет | `10` | таймаут открытия соединения |
65
+ | `binary_tempfile_threshold` | нет | `1048576` (1 MiB) | порог для `Tempfile` |
66
+
67
+ Каждый запрос уходит с заголовком `Api-key`. Параметр `key` в query гем не использует.
68
+
69
+ ## Клиенты
70
+
71
+ ### Общий клиент
72
+
73
+ `Roistat.client` собирается из глобальной конфигурации.
74
+
75
+ ### Отдельный клиент
76
+
77
+ Удобно для нескольких проектов, джобов и скриптов:
78
+
79
+ ```ruby
80
+ client = Roistat::Client.new(
81
+ api_key: ENV.fetch("ROISTAT_API_KEY"),
82
+ project: "12345"
83
+ )
84
+ client.orders.list(limit: 10)
85
+ ```
86
+
87
+ ### Низкоуровневый HTTP
88
+
89
+ Если для пути ещё нет resource-метода:
90
+
91
+ ```ruby
92
+ client.get("project/calltracking/phone/list", params: {limit: 10})
93
+ client.post("project/events/send", body: {name: "purchase"})
94
+ ```
95
+
96
+ ## Группы ресурсов
97
+
98
+ Ниже — точки входа. Сигнатуры и примеры смотрите в [английском README](../../README.md#resource-apis).
99
+
100
+ | Группа | Клиент | Примеры задач |
101
+ |--------|--------|---------------|
102
+ | Projects | `client.projects` | список проектов, модули / counter list |
103
+ | Access | `client.access` | права пользователей (RU и EN пути) |
104
+ | Dashboards / Widgets | `client.dashboards`, `client.widgets` | дашборды и данные виджетов (EN) |
105
+ | Billing | `client.billing` | транзакции и Excel-экспорт |
106
+ | Calltracking | `client.calltracking` | скрипты, номера, звонки |
107
+ | Orders / proxy / leads | `client.orders`, `client.proxy_leads`, `client.leads` | сделки и лиды |
108
+ | Managers / lead hunter | `client.managers`, `client.lead_hunter` | менеджеры и охотник за лидами |
109
+ | Clients / visits / events | `client.clients`, `client.visits`, `client.events` | клиенты, визиты, события |
110
+ | Analytics / channels | `client.analytics`, `client.channels` | отчёты и источники |
111
+ | Statistics / indicators | `client.statistics`, `client.indicators` | дневная статистика и индикаторы |
112
+ | Email / SMS / mediaplan | `client.emailtracking`, `client.sms`, `client.mediaplan` | почта, SMS-отчёт, медиаплан |
113
+ | Speech / VPBX | `client.speech`, `client.vpbx` | речевая аналитика и облачная АТС |
114
+
115
+ Мутирующие методы (create / update / delete / buy / send) меняют данные в Roistat. Используйте их осознанно.
116
+
117
+ ## Ответы и ошибки
118
+
119
+ - JSON-эндпоинты возвращают разобранный Hash (строковые ключи).
120
+ - Бинарные ответы: `String`, если тело ≤ 1 MiB; иначе `Tempfile` (закройте и удалите файл после использования).
121
+
122
+ | Код Roistat `error` | Исключение |
123
+ |---------------------|------------|
124
+ | `authentication_failed` | `Roistat::AuthenticationError` |
125
+ | `authorization_failed` | `Roistat::AuthorizationError` |
126
+ | `access_denied` | `Roistat::AccessDeniedError` |
127
+ | `request_limit_error` | `Roistat::RateLimitError` |
128
+ | прочее | `Roistat::Error` |
129
+
130
+ Ошибки конфигурации (пустой ключ или project) поднимают `Roistat::ConfigurationError` до HTTP.
131
+
132
+ ## Разработка
133
+
134
+ ```fish
135
+ bin/setup
136
+ bundle exec rake
137
+ # или: mise test ; and mise lint
138
+ ```
139
+
140
+ Интерактивная консоль гема: `bin/console`.
141
+
142
+ Багрепорты и PR: https://github.com/alec-c4/roistat
data/lefthook.yml ADDED
@@ -0,0 +1,8 @@
1
+ pre-commit:
2
+ parallel: true
3
+ commands:
4
+ rubocop:
5
+ glob: "*.rb"
6
+ run: bundle exec rubocop --force-exclusion {staged_files}
7
+ rspec:
8
+ run: bundle exec rspec
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ class Roistat::Generators::InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates a Roistat initializer with all configuration options"
9
+
10
+ def create_initializer_file
11
+ template "roistat.rb", "config/initializers/roistat.rb"
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ Roistat.configure do |config|
4
+ # Required for project-scoped API calls.
5
+ config.api_key = ENV.fetch("ROISTAT_API_KEY")
6
+ config.project = ENV.fetch("ROISTAT_PROJECT_ID")
7
+
8
+ # Optional overrides.
9
+ # config.base_url = ENV.fetch("ROISTAT_BASE_URL", "https://cloud.roistat.com/api/v1")
10
+ # config.timeout = ENV.fetch("ROISTAT_TIMEOUT", 30).to_i
11
+ # config.open_timeout = ENV.fetch("ROISTAT_OPEN_TIMEOUT", 10).to_i
12
+ # config.binary_tempfile_threshold = ENV.fetch("ROISTAT_BINARY_TEMPFILE_THRESHOLD", 1_048_576).to_i
13
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "httpx"
4
+ require "json"
5
+
6
+ class Roistat::Client
7
+ attr_reader :api_key, :project, :base_url, :timeout, :open_timeout, :binary_tempfile_threshold
8
+
9
+ def initialize(
10
+ api_key:,
11
+ project: nil,
12
+ project_required: true,
13
+ base_url: nil,
14
+ timeout: nil,
15
+ open_timeout: nil,
16
+ binary_tempfile_threshold: nil
17
+ )
18
+ config = Roistat.configuration
19
+
20
+ @api_key = api_key
21
+ @project = project
22
+ @project_required = project_required
23
+ @base_url = base_url || config.base_url
24
+ @timeout = timeout || config.timeout
25
+ @open_timeout = open_timeout || config.open_timeout
26
+ @binary_tempfile_threshold = binary_tempfile_threshold || config.binary_tempfile_threshold
27
+
28
+ validate_credentials!
29
+ end
30
+
31
+ def get(path, params: {}, parse: :json)
32
+ request(:get, path, params: params, parse: parse)
33
+ end
34
+
35
+ def post(path, params: {}, body: nil, parse: :json)
36
+ request(:post, path, params: params, body: body, parse: parse)
37
+ end
38
+
39
+ def post_multipart(path, params: {}, form: {}, parse: :json)
40
+ validate_project! if @project_required
41
+
42
+ query = params.dup
43
+ query[:project] = project if project && !query.key?(:project) && !query.key?("project")
44
+
45
+ headers = {
46
+ "Api-key" => api_key,
47
+ "Accept" => "application/json"
48
+ }
49
+
50
+ http_response = session.request(
51
+ "POST",
52
+ url_for(path),
53
+ params: stringify_keys(query),
54
+ headers: headers,
55
+ form: normalize_multipart_form(form)
56
+ )
57
+ Roistat::Response.parse(
58
+ http_response,
59
+ parse: parse,
60
+ binary_tempfile_threshold: binary_tempfile_threshold
61
+ )
62
+ end
63
+
64
+ def request(method, path, params: {}, body: nil, parse: :json)
65
+ validate_project! if @project_required
66
+
67
+ query = params.dup
68
+ query[:project] = project if project && !query.key?(:project) && !query.key?("project")
69
+
70
+ headers = {
71
+ "Api-key" => api_key,
72
+ "Accept" => "application/json"
73
+ }
74
+
75
+ options = {params: stringify_keys(query), headers: headers}
76
+ if body
77
+ headers["Content-Type"] = "application/json"
78
+ options[:json] = body
79
+ end
80
+
81
+ http_response = session.request(method.to_s.upcase, url_for(path), **options)
82
+ Roistat::Response.parse(
83
+ http_response,
84
+ parse: parse,
85
+ binary_tempfile_threshold: binary_tempfile_threshold
86
+ )
87
+ end
88
+
89
+ def projects
90
+ @projects ||= Roistat::Resources::Projects.new(self)
91
+ end
92
+
93
+ def access
94
+ @access ||= Roistat::Resources::Access.new(self)
95
+ end
96
+
97
+ def dashboards
98
+ @dashboards ||= Roistat::Resources::Dashboards.new(self)
99
+ end
100
+
101
+ def widgets
102
+ @widgets ||= Roistat::Resources::Widgets.new(self)
103
+ end
104
+
105
+ def billing
106
+ @billing ||= Roistat::Resources::Billing.new(self)
107
+ end
108
+
109
+ def calltracking
110
+ @calltracking ||= Roistat::Resources::Calltracking.new(self)
111
+ end
112
+
113
+ def orders
114
+ @orders ||= Roistat::Resources::Orders.new(self)
115
+ end
116
+
117
+ def proxy_leads
118
+ @proxy_leads ||= Roistat::Resources::ProxyLeads.new(self)
119
+ end
120
+
121
+ def leads
122
+ @leads ||= Roistat::Resources::Leads.new(self)
123
+ end
124
+
125
+ def managers
126
+ @managers ||= Roistat::Resources::Managers.new(self)
127
+ end
128
+
129
+ def clients
130
+ @clients ||= Roistat::Resources::Clients.new(self)
131
+ end
132
+
133
+ def visits
134
+ @visits ||= Roistat::Resources::Visits.new(self)
135
+ end
136
+
137
+ def events
138
+ @events ||= Roistat::Resources::Events.new(self)
139
+ end
140
+
141
+ def analytics
142
+ @analytics ||= Roistat::Resources::Analytics.new(self)
143
+ end
144
+
145
+ def channels
146
+ @channels ||= Roistat::Resources::Channels.new(self)
147
+ end
148
+
149
+ def statistics
150
+ @statistics ||= Roistat::Resources::Statistics.new(self)
151
+ end
152
+
153
+ def indicators
154
+ @indicators ||= Roistat::Resources::Indicators.new(self)
155
+ end
156
+
157
+ def lead_hunter
158
+ @lead_hunter ||= Roistat::Resources::LeadHunter.new(self)
159
+ end
160
+
161
+ def emailtracking
162
+ @emailtracking ||= Roistat::Resources::Emailtracking.new(self)
163
+ end
164
+
165
+ def sms
166
+ @sms ||= Roistat::Resources::Sms.new(self)
167
+ end
168
+
169
+ def mediaplan
170
+ @mediaplan ||= Roistat::Resources::Mediaplan.new(self)
171
+ end
172
+
173
+ def speech
174
+ @speech ||= Roistat::Resources::Speech.new(self)
175
+ end
176
+
177
+ def vpbx
178
+ @vpbx ||= Roistat::Resources::Vpbx.new(self)
179
+ end
180
+
181
+ private
182
+
183
+ def validate_credentials!
184
+ raise Roistat::ConfigurationError, "api_key must be present" if blank?(api_key)
185
+ validate_project! if @project_required
186
+ end
187
+
188
+ def validate_project!
189
+ raise Roistat::ConfigurationError, "project must be present" if blank?(project)
190
+ end
191
+
192
+ def blank?(value)
193
+ value.nil? || value.to_s.strip.empty?
194
+ end
195
+
196
+ def url_for(path)
197
+ "#{base_url.to_s.chomp("/")}/#{path.to_s.delete_prefix("/")}"
198
+ end
199
+
200
+ def session
201
+ @session ||= HTTPX.with(
202
+ timeout: {
203
+ request_timeout: timeout,
204
+ connect_timeout: open_timeout
205
+ }
206
+ )
207
+ end
208
+
209
+ def stringify_keys(hash)
210
+ hash.transform_keys(&:to_s)
211
+ end
212
+
213
+ def normalize_multipart_form(form)
214
+ form.transform_keys(&:to_s).transform_values do |value|
215
+ next value if value.respond_to?(:read) || value.is_a?(String)
216
+
217
+ value.to_s
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Configuration
4
+ DEFAULT_BASE_URL = "https://cloud.roistat.com/api/v1"
5
+ DEFAULT_TIMEOUT = 30
6
+ DEFAULT_OPEN_TIMEOUT = 10
7
+ DEFAULT_BINARY_TEMPFILE_THRESHOLD = 1 * 1024 * 1024
8
+
9
+ attr_accessor :api_key, :project, :base_url, :timeout, :open_timeout, :binary_tempfile_threshold
10
+
11
+ def initialize
12
+ @base_url = DEFAULT_BASE_URL
13
+ @timeout = DEFAULT_TIMEOUT
14
+ @open_timeout = DEFAULT_OPEN_TIMEOUT
15
+ @binary_tempfile_threshold = DEFAULT_BINARY_TEMPFILE_THRESHOLD
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Error < StandardError
4
+ attr_reader :code, :http_status, :response_body
5
+
6
+ def initialize(message = nil, code: nil, http_status: nil, response_body: nil)
7
+ @code = code
8
+ @http_status = http_status
9
+ @response_body = response_body
10
+ super(message || code || self.class.name)
11
+ end
12
+ end
13
+
14
+ class Roistat::ConfigurationError < Roistat::Error; end
15
+ class Roistat::AuthenticationError < Roistat::Error; end
16
+ class Roistat::AuthorizationError < Roistat::Error; end
17
+ class Roistat::AccessDeniedError < Roistat::Error; end
18
+ class Roistat::RateLimitError < Roistat::Error; end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Resources::Access < Roistat::Resources::Base
4
+ # GET /project/permissions/user/list — help-ru.
5
+ def user_list
6
+ client.get("project/permissions/user/list")
7
+ end
8
+
9
+ # GET|POST /project/access/get-authorized-users — help-en.
10
+ def authorized_users(method: :get)
11
+ case method.to_sym
12
+ when :get
13
+ client.get("project/access/get-authorized-users")
14
+ when :post
15
+ client.post("project/access/get-authorized-users")
16
+ else
17
+ raise ArgumentError, "method must be :get or :post"
18
+ end
19
+ end
20
+
21
+ # POST /project/access/change — help-en.
22
+ def change(**body)
23
+ client.post("project/access/change", body: body)
24
+ end
25
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Resources::Analytics < Roistat::Resources::Base
4
+ # POST /project/analytics/data
5
+ def data(**body)
6
+ post_optional_body("project/analytics/data", body)
7
+ end
8
+
9
+ # POST /project/analytics/data/export/excel
10
+ def data_export_excel(**body)
11
+ client.post("project/analytics/data/export/excel", body: body, parse: :binary)
12
+ end
13
+
14
+ # POST /project/analytics/metrics-new
15
+ def metrics_new(**body)
16
+ post_optional_body("project/analytics/metrics-new", body)
17
+ end
18
+
19
+ # POST /project/analytics/dimensions
20
+ def dimensions(**body)
21
+ post_optional_body("project/analytics/dimensions", body)
22
+ end
23
+
24
+ # POST /project/analytics/dimension-values
25
+ def dimension_values(**body)
26
+ post_optional_body("project/analytics/dimension-values", body)
27
+ end
28
+
29
+ # POST /project/analytics/attribution-models
30
+ def attribution_models(**body)
31
+ post_optional_body("project/analytics/attribution-models", body)
32
+ end
33
+
34
+ # POST /project/analytics/list-orders
35
+ def list_orders(**body)
36
+ post_optional_body("project/analytics/list-orders", body)
37
+ end
38
+
39
+ # GET /project/analytics/metrics/custom/list
40
+ def custom_metrics_list(**params)
41
+ client.get("project/analytics/metrics/custom/list", params: params)
42
+ end
43
+
44
+ # POST /project/analytics/metrics/custom/manual/value/list
45
+ def custom_manual_value_list(**body)
46
+ post_optional_body("project/analytics/metrics/custom/manual/value/list", body)
47
+ end
48
+
49
+ # POST /project/analytics/metrics/custom/manual/value/add
50
+ def custom_manual_value_add(**body)
51
+ client.post("project/analytics/metrics/custom/manual/value/add", body: body)
52
+ end
53
+
54
+ # POST /project/analytics/metrics/custom/manual/value/delete
55
+ def custom_manual_value_delete(**body)
56
+ client.post("project/analytics/metrics/custom/manual/value/delete", body: body)
57
+ end
58
+
59
+ # POST /project/reports/funnel/data
60
+ def funnel_data(**body)
61
+ post_optional_body("project/reports/funnel/data", body)
62
+ end
63
+
64
+ # POST /project/analytics/event/add
65
+ def event_add(**body)
66
+ client.post("project/analytics/event/add", body: body)
67
+ end
68
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Resources::Base
4
+ attr_reader :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ private
11
+
12
+ def api_key_client
13
+ @api_key_client ||= Roistat::Client.new(
14
+ api_key: client.api_key,
15
+ project: nil,
16
+ project_required: false,
17
+ base_url: client.base_url,
18
+ timeout: client.timeout,
19
+ open_timeout: client.open_timeout,
20
+ binary_tempfile_threshold: client.binary_tempfile_threshold
21
+ )
22
+ end
23
+
24
+ def post_optional_body(path, body)
25
+ if body.nil? || body.empty?
26
+ client.post(path)
27
+ else
28
+ client.post(path, body: body)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Resources::Billing < Roistat::Resources::Base
4
+ # POST /user/billing/transactions/list
5
+ def transactions_list(period:)
6
+ client.post("user/billing/transactions/list", body: {period: period})
7
+ end
8
+
9
+ # POST /user/billing/transactions/list/export/excel
10
+ def transactions_export_excel(period:)
11
+ client.post(
12
+ "user/billing/transactions/list/export/excel",
13
+ body: {period: period},
14
+ parse: :binary
15
+ )
16
+ end
17
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Roistat::Resources::Calltracking < Roistat::Resources::Base
4
+ # POST /project/calltracking/script/list
5
+ def script_list(**body)
6
+ post("project/calltracking/script/list", body: body)
7
+ end
8
+
9
+ # POST /project/calltracking/script/create
10
+ def script_create(**body)
11
+ client.post("project/calltracking/script/create", body: body)
12
+ end
13
+
14
+ # POST /project/calltracking/script/update
15
+ def script_update(**body)
16
+ client.post("project/calltracking/script/update", body: body)
17
+ end
18
+
19
+ # POST /project/calltracking/script/delete
20
+ def script_delete(id:)
21
+ client.post("project/calltracking/script/delete", body: {id: id})
22
+ end
23
+
24
+ # POST /project/calltracking/phone/list
25
+ def phone_list(**body)
26
+ post("project/calltracking/phone/list", body: body)
27
+ end
28
+
29
+ # POST /project/calltracking/phone/prefix/list
30
+ def phone_prefix_list(**body)
31
+ post("project/calltracking/phone/prefix/list", body: body)
32
+ end
33
+
34
+ # POST /project/calltracking/phone/create
35
+ def phone_create(phones:)
36
+ client.post("project/calltracking/phone/create", body: {phones: phones})
37
+ end
38
+
39
+ # POST /project/calltracking/phone/buy
40
+ def phone_buy(prefix:, count:)
41
+ client.post("project/calltracking/phone/buy", body: {prefix: prefix, count: count})
42
+ end
43
+
44
+ # POST /project/calltracking/phone/update
45
+ def phone_update(**body)
46
+ client.post("project/calltracking/phone/update", body: body)
47
+ end
48
+
49
+ # POST /project/calltracking/phone/delete
50
+ def phone_delete(phones:)
51
+ client.post("project/calltracking/phone/delete", body: {phones: phones})
52
+ end
53
+
54
+ # POST /project/calltracking/call/list
55
+ def call_list(**body)
56
+ post("project/calltracking/call/list", body: body)
57
+ end
58
+
59
+ # POST /project/calltracking/call/update
60
+ def call_update(**body)
61
+ client.post("project/calltracking/call/update", body: body)
62
+ end
63
+
64
+ # POST /project/calltracking/call/delete
65
+ def call_delete(ids:)
66
+ client.post("project/calltracking/call/delete", body: {ids: ids})
67
+ end
68
+
69
+ # POST /project/calltracking/call/{callId}/file
70
+ def call_file(call_id:)
71
+ client.post("project/calltracking/call/#{call_id}/file", parse: :binary)
72
+ end
73
+
74
+ # POST /project/calltracking/call/xls/export
75
+ def call_xls_export(period:)
76
+ client.post(
77
+ "project/calltracking/call/xls/export",
78
+ body: {period: period},
79
+ parse: :binary
80
+ )
81
+ end
82
+
83
+ # POST /project/calltracking/data
84
+ def data(period:)
85
+ client.post("project/calltracking/data", body: {period: period})
86
+ end
87
+
88
+ # POST /project/phone-call
89
+ def phone_call(**body)
90
+ client.post("project/phone-call", body: body)
91
+ end
92
+
93
+ private
94
+
95
+ def post(path, body:)
96
+ if body.nil? || body.empty?
97
+ client.post(path)
98
+ else
99
+ client.post(path, body: body)
100
+ end
101
+ end
102
+ end