amochka 0.4.7__py3-none-any.whl → 0.4.8__py3-none-any.whl
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.
- amochka/__init__.py +1 -1
- {amochka-0.4.7.dist-info → amochka-0.4.8.dist-info}/METADATA +1 -1
- {amochka-0.4.7.dist-info → amochka-0.4.8.dist-info}/RECORD +8 -8
- etl/config.py +11 -0
- etl/run_etl.py +14 -3
- etl/transformers.py +12 -4
- {amochka-0.4.7.dist-info → amochka-0.4.8.dist-info}/WHEEL +0 -0
- {amochka-0.4.7.dist-info → amochka-0.4.8.dist-info}/top_level.txt +0 -0
amochka/__init__.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
amochka/__init__.py,sha256=
|
|
1
|
+
amochka/__init__.py,sha256=yvD3BuCLtzagE2oTYt36fPKGYpcImv2mY590XqBsXwI,925
|
|
2
2
|
amochka/client.py,sha256=zQUy6DhoQfLDnO9q7CxXd28cjLQmwE15MtTGsGYYVSs,91571
|
|
3
3
|
amochka/errors.py,sha256=Rg4U9srjboQwgU3wwhAed0p3vGcc0ZhuyKHIDhYFnp8,1371
|
|
4
4
|
amochka/etl.py,sha256=tzdGPRGxR49aSAjLksic-FqechvDUTfK8ZUUJGuIU7M,8960
|
|
5
5
|
etl/__init__.py,sha256=bp9fPqbKlOc7xzs27diHEvysy1FgBrwlpX6GnR6GL9U,255
|
|
6
|
-
etl/config.py,sha256=
|
|
6
|
+
etl/config.py,sha256=eBQ5U9Kulyho-XMu8gRSJ47WrnONiiWyL2l3GtZhrNs,9416
|
|
7
7
|
etl/extractors.py,sha256=PqjzlmUa8FLZa1z85mP6Y0-s_TH3REqW58632JzRKUc,13047
|
|
8
8
|
etl/loaders.py,sha256=AA4XDCbre-Y8SrIji5Sk8olW9WvREM9CMuuknFVe5j0,32589
|
|
9
|
-
etl/run_etl.py,sha256=
|
|
10
|
-
etl/transformers.py,sha256=
|
|
9
|
+
etl/run_etl.py,sha256=wCpCs2vL9cxucxHjcpPQydja9JzFxaRlfc9CwpS9OGU,27270
|
|
10
|
+
etl/transformers.py,sha256=ML9iBtLRh8OgFtSK-1ngmRw6vJu_GXHCbln1U8d7sHc,18150
|
|
11
11
|
etl/migrations/001_create_tables.sql,sha256=YrSaZjpofC1smjYx0bM4eHQumboruIBY3fwRDlJLLSo,15749
|
|
12
|
-
amochka-0.4.
|
|
13
|
-
amochka-0.4.
|
|
14
|
-
amochka-0.4.
|
|
15
|
-
amochka-0.4.
|
|
12
|
+
amochka-0.4.8.dist-info/METADATA,sha256=gB8ZgvtYOkXy6wmxyQbV6gxhs8eHOx9H5-XTV9yrYao,7530
|
|
13
|
+
amochka-0.4.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
amochka-0.4.8.dist-info/top_level.txt,sha256=grRX8aLFG-yYKPsAqCD6sUBmdLSQeOMHsc9Dl6S7Lzo,12
|
|
15
|
+
amochka-0.4.8.dist-info/RECORD,,
|
etl/config.py
CHANGED
|
@@ -32,6 +32,12 @@ def _load_env_file(path: Path) -> Dict[str, str]:
|
|
|
32
32
|
return env
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def _get_bool(value: Optional[str], default: bool = False) -> bool:
|
|
36
|
+
if value is None:
|
|
37
|
+
return default
|
|
38
|
+
return value.strip().lower() in {"1", "true", "yes", "y", "on"}
|
|
39
|
+
|
|
40
|
+
|
|
35
41
|
@dataclass
|
|
36
42
|
class DatabaseConfig:
|
|
37
43
|
"""Конфигурация подключения к PostgreSQL."""
|
|
@@ -139,6 +145,7 @@ class ETLConfig:
|
|
|
139
145
|
batch_size: int = 100
|
|
140
146
|
window_minutes: int = 120 # Окно выгрузки по умолчанию (2 часа)
|
|
141
147
|
log_level: str = "INFO"
|
|
148
|
+
include_companies: bool = False
|
|
142
149
|
|
|
143
150
|
@classmethod
|
|
144
151
|
def from_env(cls, env_path: Optional[Path] = None) -> "ETLConfig":
|
|
@@ -180,12 +187,15 @@ class ETLConfig:
|
|
|
180
187
|
)
|
|
181
188
|
)
|
|
182
189
|
|
|
190
|
+
include_companies = _get_bool(os.environ.get("ETL_INCLUDE_COMPANIES"), False)
|
|
191
|
+
|
|
183
192
|
return cls(
|
|
184
193
|
database=db_config,
|
|
185
194
|
accounts=accounts,
|
|
186
195
|
batch_size=int(os.environ.get("ETL_BATCH_SIZE", "100") or "100"),
|
|
187
196
|
window_minutes=int(os.environ.get("ETL_WINDOW_MINUTES", "120") or "120"),
|
|
188
197
|
log_level=os.environ.get("ETL_LOG_LEVEL", "INFO") or "INFO",
|
|
198
|
+
include_companies=include_companies,
|
|
189
199
|
)
|
|
190
200
|
|
|
191
201
|
|
|
@@ -213,6 +223,7 @@ DEFAULT_CONFIG = ETLConfig(
|
|
|
213
223
|
],
|
|
214
224
|
batch_size=100,
|
|
215
225
|
window_minutes=120,
|
|
226
|
+
include_companies=False,
|
|
216
227
|
)
|
|
217
228
|
|
|
218
229
|
|
etl/run_etl.py
CHANGED
|
@@ -88,6 +88,7 @@ def sync_leads_with_contacts(
|
|
|
88
88
|
updated_from: Optional[datetime] = None,
|
|
89
89
|
updated_to: Optional[datetime] = None,
|
|
90
90
|
pipeline_ids: Optional[List[int]] = None,
|
|
91
|
+
include_companies: bool = False,
|
|
91
92
|
batch_size: int = 100,
|
|
92
93
|
) -> dict:
|
|
93
94
|
"""
|
|
@@ -101,11 +102,16 @@ def sync_leads_with_contacts(
|
|
|
101
102
|
Returns:
|
|
102
103
|
dict с ключами: leads_count, contacts_count
|
|
103
104
|
"""
|
|
104
|
-
contact_transformer = ContactTransformer(mybi_account_id)
|
|
105
|
+
contact_transformer = ContactTransformer(mybi_account_id, include_companies=include_companies)
|
|
105
106
|
|
|
106
107
|
# Загружаем справочники для денормализации
|
|
107
108
|
pipelines_map, statuses_map = extractor.load_pipelines_and_statuses()
|
|
108
|
-
lead_transformer = LeadTransformer(
|
|
109
|
+
lead_transformer = LeadTransformer(
|
|
110
|
+
mybi_account_id,
|
|
111
|
+
pipelines_map,
|
|
112
|
+
statuses_map,
|
|
113
|
+
include_companies=include_companies,
|
|
114
|
+
)
|
|
109
115
|
|
|
110
116
|
# 1. Собираем сделки и ID контактов из API
|
|
111
117
|
leads_iter = extractor.iter_leads(
|
|
@@ -261,6 +267,7 @@ def sync_contacts(
|
|
|
261
267
|
contact_ids: Optional[Set[int]] = None,
|
|
262
268
|
updated_from: Optional[datetime] = None,
|
|
263
269
|
updated_to: Optional[datetime] = None,
|
|
270
|
+
include_companies: bool = False,
|
|
264
271
|
batch_size: int = 100,
|
|
265
272
|
) -> int:
|
|
266
273
|
"""
|
|
@@ -279,7 +286,7 @@ def sync_contacts(
|
|
|
279
286
|
Returns:
|
|
280
287
|
Количество загруженных контактов
|
|
281
288
|
"""
|
|
282
|
-
contact_transformer = ContactTransformer(mybi_account_id)
|
|
289
|
+
contact_transformer = ContactTransformer(mybi_account_id, include_companies=include_companies)
|
|
283
290
|
|
|
284
291
|
# Загружаем все обновлённые контакты за период
|
|
285
292
|
contacts_iter = extractor.iter_contacts(
|
|
@@ -484,6 +491,7 @@ def run_etl_for_account(
|
|
|
484
491
|
entities: List[str],
|
|
485
492
|
window_minutes: int,
|
|
486
493
|
full_sync: bool = False,
|
|
494
|
+
include_companies: bool = False,
|
|
487
495
|
batch_size: int = 100,
|
|
488
496
|
) -> dict:
|
|
489
497
|
"""
|
|
@@ -537,6 +545,7 @@ def run_etl_for_account(
|
|
|
537
545
|
updated_from=leads_updated_from,
|
|
538
546
|
updated_to=updated_to,
|
|
539
547
|
pipeline_ids=account.pipeline_ids,
|
|
548
|
+
include_companies=include_companies,
|
|
540
549
|
batch_size=batch_size,
|
|
541
550
|
)
|
|
542
551
|
stats["leads"] = result["leads_count"]
|
|
@@ -578,6 +587,7 @@ def run_etl_for_account(
|
|
|
578
587
|
contact_ids=contact_ids_in_pipelines, # Только контакты из наших воронок
|
|
579
588
|
updated_from=contacts_updated_from,
|
|
580
589
|
updated_to=updated_to,
|
|
590
|
+
include_companies=include_companies,
|
|
581
591
|
batch_size=batch_size,
|
|
582
592
|
)
|
|
583
593
|
else:
|
|
@@ -677,6 +687,7 @@ def main():
|
|
|
677
687
|
entities,
|
|
678
688
|
config.window_minutes,
|
|
679
689
|
full_sync=args.full,
|
|
690
|
+
include_companies=config.include_companies,
|
|
680
691
|
batch_size=config.batch_size,
|
|
681
692
|
)
|
|
682
693
|
all_stats[account.name] = stats
|
etl/transformers.py
CHANGED
|
@@ -78,7 +78,13 @@ class TransformedEvent:
|
|
|
78
78
|
class LeadTransformer:
|
|
79
79
|
"""Трансформер для сделок (leads)."""
|
|
80
80
|
|
|
81
|
-
def __init__(
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
account_id: int,
|
|
84
|
+
pipelines_map: Optional[Dict[int, str]] = None,
|
|
85
|
+
statuses_map: Optional[Dict[int, Dict]] = None,
|
|
86
|
+
include_companies: bool = False,
|
|
87
|
+
):
|
|
82
88
|
"""
|
|
83
89
|
Инициализирует трансформер.
|
|
84
90
|
|
|
@@ -90,6 +96,7 @@ class LeadTransformer:
|
|
|
90
96
|
self.account_id = account_id
|
|
91
97
|
self.pipelines_map = pipelines_map or {}
|
|
92
98
|
self.statuses_map = statuses_map or {}
|
|
99
|
+
self.include_companies = include_companies
|
|
93
100
|
|
|
94
101
|
def transform(self, lead: Dict[str, Any]) -> TransformedLead:
|
|
95
102
|
"""
|
|
@@ -145,7 +152,7 @@ class LeadTransformer:
|
|
|
145
152
|
main_contact_id = contacts[0].get("id")
|
|
146
153
|
|
|
147
154
|
# Компания из _embedded.companies
|
|
148
|
-
companies = embedded.get("companies", [])
|
|
155
|
+
companies = embedded.get("companies", []) if self.include_companies else []
|
|
149
156
|
company_id = companies[0].get("id") if companies else None
|
|
150
157
|
|
|
151
158
|
lead_facts_record = {
|
|
@@ -221,8 +228,9 @@ class LeadTransformer:
|
|
|
221
228
|
class ContactTransformer:
|
|
222
229
|
"""Трансформер для контактов."""
|
|
223
230
|
|
|
224
|
-
def __init__(self, account_id: int):
|
|
231
|
+
def __init__(self, account_id: int, include_companies: bool = False):
|
|
225
232
|
self.account_id = account_id
|
|
233
|
+
self.include_companies = include_companies
|
|
226
234
|
|
|
227
235
|
def transform(self, contact: Dict[str, Any]) -> TransformedContact:
|
|
228
236
|
"""Преобразует контакт из amoCRM в структуру mybi."""
|
|
@@ -249,7 +257,7 @@ class ContactTransformer:
|
|
|
249
257
|
|
|
250
258
|
# Компания из _embedded
|
|
251
259
|
embedded = contact.get("_embedded", {})
|
|
252
|
-
companies = embedded.get("companies", [])
|
|
260
|
+
companies = embedded.get("companies", []) if self.include_companies else []
|
|
253
261
|
if companies:
|
|
254
262
|
contact_record["company"] = companies[0].get("name")
|
|
255
263
|
|
|
File without changes
|
|
File without changes
|