konecty_sdk_python 2.1.1__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.
- KonectySdkPython/__init__.py +41 -0
- KonectySdkPython/cli/__init__.py +38 -0
- KonectySdkPython/cli/apply.py +555 -0
- KonectySdkPython/cli/backup.py +161 -0
- KonectySdkPython/cli/pull.py +309 -0
- KonectySdkPython/lib/__init__.py +43 -0
- KonectySdkPython/lib/client.py +950 -0
- KonectySdkPython/lib/exceptions.py +26 -0
- KonectySdkPython/lib/feature_types/__init__.py +46 -0
- KonectySdkPython/lib/feature_types/cross_module_query.py +78 -0
- KonectySdkPython/lib/feature_types/kpi.py +21 -0
- KonectySdkPython/lib/feature_types/query_json.py +242 -0
- KonectySdkPython/lib/file_manager.py +248 -0
- KonectySdkPython/lib/filters.py +155 -0
- KonectySdkPython/lib/http.py +95 -0
- KonectySdkPython/lib/model.py +88 -0
- KonectySdkPython/lib/serialization.py +13 -0
- KonectySdkPython/lib/services/__init__.py +5 -0
- KonectySdkPython/lib/services/aggregation.py +142 -0
- KonectySdkPython/lib/services/auth.py +105 -0
- KonectySdkPython/lib/services/base.py +63 -0
- KonectySdkPython/lib/services/change_user.py +64 -0
- KonectySdkPython/lib/services/comments.py +89 -0
- KonectySdkPython/lib/services/export.py +54 -0
- KonectySdkPython/lib/services/files.py +59 -0
- KonectySdkPython/lib/services/notifications.py +41 -0
- KonectySdkPython/lib/services/query.py +192 -0
- KonectySdkPython/lib/services/stream.py +133 -0
- KonectySdkPython/lib/services/subscriptions.py +26 -0
- KonectySdkPython/lib/settings.py +152 -0
- KonectySdkPython/lib/types.py +418 -0
- konecty_sdk_python-2.1.1.dist-info/METADATA +155 -0
- konecty_sdk_python-2.1.1.dist-info/RECORD +35 -0
- konecty_sdk_python-2.1.1.dist-info/WHEEL +4 -0
- konecty_sdk_python-2.1.1.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Módulo para gerenciar configurações do Konecty."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any, Type, TypeVar
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from .client import KonectyClient
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T", bound=BaseModel)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _convert_value(value: str, field_type: Type[Any] | None) -> Any:
|
|
15
|
+
"""Converte um valor string para o tipo correto.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
value: Valor string a ser convertido
|
|
19
|
+
field_type: Tipo para converter o valor
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Valor convertido para o tipo correto
|
|
23
|
+
"""
|
|
24
|
+
if field_type is None:
|
|
25
|
+
return value
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
if field_type is bool:
|
|
29
|
+
return value.lower() == "true"
|
|
30
|
+
elif field_type is int:
|
|
31
|
+
return int(value)
|
|
32
|
+
elif field_type is float:
|
|
33
|
+
return float(value)
|
|
34
|
+
elif field_type is list:
|
|
35
|
+
return [item.strip() for item in value.split(",")]
|
|
36
|
+
elif field_type is dict:
|
|
37
|
+
return json.loads(value)
|
|
38
|
+
else:
|
|
39
|
+
return value
|
|
40
|
+
except (ValueError, TypeError, json.JSONDecodeError):
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
async def fill_settings(settings_class: Type[T]) -> T:
|
|
45
|
+
"""Preenche as configurações de uma classe com valores do Konecty.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
settings_class: Classe de configurações que herda de BaseModel.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Instância da classe de configurações preenchida com valores do Konecty.
|
|
52
|
+
"""
|
|
53
|
+
client = KonectyClient(
|
|
54
|
+
base_url=os.getenv("KONECTY_URL", "http://localhost:3000"),
|
|
55
|
+
token=os.getenv("KONECTY_TOKEN", "invalid_key"),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
settings_dict = {}
|
|
59
|
+
fields_to_fetch = []
|
|
60
|
+
|
|
61
|
+
# Primeiro verifica variáveis de ambiente e coleta campos que precisam ser buscados no Konecty
|
|
62
|
+
for field_name in settings_class.model_fields.keys():
|
|
63
|
+
field = settings_class.model_fields[field_name]
|
|
64
|
+
field_str = get_field_name(field, field_name)
|
|
65
|
+
|
|
66
|
+
env_value = os.getenv(field_str.upper())
|
|
67
|
+
if env_value is not None and env_value.strip():
|
|
68
|
+
field_type = field.annotation
|
|
69
|
+
converted_value = _convert_value(env_value, field_type)
|
|
70
|
+
if converted_value is not None:
|
|
71
|
+
settings_dict[field_name] = converted_value
|
|
72
|
+
else:
|
|
73
|
+
fields_to_fetch.append(field_name)
|
|
74
|
+
|
|
75
|
+
# Busca todas as configurações do Konecty de uma vez
|
|
76
|
+
if fields_to_fetch:
|
|
77
|
+
konecty_settings = await client.get_settings(
|
|
78
|
+
[field.upper() for field in fields_to_fetch]
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
for field_name in settings_class.model_fields.keys():
|
|
82
|
+
field = settings_class.model_fields[field_name]
|
|
83
|
+
field_str = get_field_name(field, field_name)
|
|
84
|
+
|
|
85
|
+
value = konecty_settings.get(field_str.upper())
|
|
86
|
+
if value is not None and value.strip():
|
|
87
|
+
field_type = field.annotation
|
|
88
|
+
converted_value = _convert_value(value, field_type)
|
|
89
|
+
if converted_value is not None:
|
|
90
|
+
settings_dict[field_name] = converted_value
|
|
91
|
+
|
|
92
|
+
return settings_class.model_construct(**settings_dict)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def fill_settings_sync(settings_class: Type[T]) -> T:
|
|
96
|
+
"""Versão síncrona de fill_settings.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
settings_class: Classe de configurações que herda de BaseModel.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Instância da classe de configurações preenchida com valores do Konecty.
|
|
103
|
+
"""
|
|
104
|
+
client = KonectyClient(
|
|
105
|
+
base_url=os.getenv("KONECTY_URL", "http://localhost:3000"),
|
|
106
|
+
token=os.getenv("KONECTY_TOKEN", "invalid_key"),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
settings_dict = {}
|
|
110
|
+
fields_to_fetch = []
|
|
111
|
+
|
|
112
|
+
# Primeiro verifica variáveis de ambiente e coleta campos que precisam ser buscados no Konecty
|
|
113
|
+
for field_name in settings_class.model_fields.keys():
|
|
114
|
+
field = settings_class.model_fields[field_name]
|
|
115
|
+
field_str = get_field_name(field, field_name)
|
|
116
|
+
|
|
117
|
+
env_value = os.getenv(field_str.upper())
|
|
118
|
+
if env_value is not None and env_value.strip():
|
|
119
|
+
field_type = field.annotation
|
|
120
|
+
converted_value = _convert_value(env_value, field_type)
|
|
121
|
+
if converted_value is not None:
|
|
122
|
+
settings_dict[field_name] = converted_value
|
|
123
|
+
else:
|
|
124
|
+
# Se não encontrou na variável de ambiente, adiciona à lista para buscar no Konecty
|
|
125
|
+
fields_to_fetch.append(field_name)
|
|
126
|
+
|
|
127
|
+
# Busca todas as configurações do Konecty de uma vez
|
|
128
|
+
if fields_to_fetch:
|
|
129
|
+
konecty_settings = client.get_settings_sync(
|
|
130
|
+
[field.upper() for field in fields_to_fetch]
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
for field_name in settings_class.model_fields.keys():
|
|
134
|
+
field = settings_class.model_fields[field_name]
|
|
135
|
+
field_str = get_field_name(field, field_name)
|
|
136
|
+
|
|
137
|
+
value = konecty_settings.get(field_str.upper())
|
|
138
|
+
if value is not None and value.strip():
|
|
139
|
+
field_type = field.annotation
|
|
140
|
+
converted_value = _convert_value(value, field_type)
|
|
141
|
+
if converted_value is not None:
|
|
142
|
+
settings_dict[field_name] = converted_value
|
|
143
|
+
|
|
144
|
+
return settings_class.model_construct(**settings_dict)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_field_name(field, default: str = None) -> str:
|
|
148
|
+
return (
|
|
149
|
+
field.validation_alias
|
|
150
|
+
if field.validation_alias
|
|
151
|
+
else field.alias if field.alias else default
|
|
152
|
+
)
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
from typing import Any, Dict, List, Optional, Self
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
from pydantic.json_schema import JsonSchemaValue
|
|
9
|
+
from pydantic_core import CoreSchema, core_schema
|
|
10
|
+
|
|
11
|
+
KonectyDict = Dict[str, Any]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class KonectyDateTimeError(Exception):
|
|
15
|
+
"""Exceção base para erros de data/hora."""
|
|
16
|
+
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class KonectyDateTimeFormatError(KonectyDateTimeError):
|
|
21
|
+
"""Exceção para erros de formato de data/hora."""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
super().__init__("Data em formato inválido")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class KonectyDateTimeTypeError(KonectyDateTimeError):
|
|
28
|
+
"""Exceção para erros de tipo de data/hora."""
|
|
29
|
+
|
|
30
|
+
def __init__(self):
|
|
31
|
+
super().__init__("Tipo inválido para KonectyDateTime")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class KonectyDateTime(datetime):
|
|
35
|
+
"""Classe personalizada para manipular datetime com o formato {'$date': 'ISO8601 string'}."""
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def from_datetime(cls, dt: datetime) -> Self:
|
|
39
|
+
return cls(
|
|
40
|
+
dt.year,
|
|
41
|
+
dt.month,
|
|
42
|
+
dt.day,
|
|
43
|
+
dt.hour,
|
|
44
|
+
dt.minute,
|
|
45
|
+
dt.second,
|
|
46
|
+
dt.microsecond,
|
|
47
|
+
dt.tzinfo,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def from_json(cls, json: dict[str, Any]) -> Self:
|
|
52
|
+
date_str = json["$date"]
|
|
53
|
+
date = datetime.fromisoformat(date_str.replace("Z", "+00:00"))
|
|
54
|
+
return cls(
|
|
55
|
+
date.year,
|
|
56
|
+
date.month,
|
|
57
|
+
date.day,
|
|
58
|
+
date.hour,
|
|
59
|
+
date.minute,
|
|
60
|
+
date.second,
|
|
61
|
+
date.microsecond,
|
|
62
|
+
date.tzinfo,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_any(cls, value: Any) -> Self:
|
|
67
|
+
if isinstance(value, dict) and "$date" in value:
|
|
68
|
+
return cls.from_json(value)
|
|
69
|
+
if isinstance(value, datetime):
|
|
70
|
+
return cls.from_datetime(value)
|
|
71
|
+
if isinstance(value, str):
|
|
72
|
+
return cls.from_isoformat(value)
|
|
73
|
+
raise KonectyDateTimeTypeError
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_isoformat(cls, value: str) -> Self:
|
|
77
|
+
date = datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
78
|
+
return cls(
|
|
79
|
+
date.year,
|
|
80
|
+
date.month,
|
|
81
|
+
date.day,
|
|
82
|
+
date.hour,
|
|
83
|
+
date.minute,
|
|
84
|
+
date.second,
|
|
85
|
+
date.microsecond,
|
|
86
|
+
date.tzinfo,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def __get_validators__(cls):
|
|
91
|
+
yield cls.validate
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def validate(cls, v):
|
|
95
|
+
if isinstance(v, dict) and "$date" in v:
|
|
96
|
+
try:
|
|
97
|
+
return datetime.fromisoformat(v["$date"].replace("Z", "+00:00"))
|
|
98
|
+
except Exception as e:
|
|
99
|
+
raise KonectyDateTimeFormatError from e
|
|
100
|
+
elif isinstance(v, datetime):
|
|
101
|
+
return v
|
|
102
|
+
raise KonectyDateTimeTypeError
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def __get_pydantic_core_schema__(cls, source_type: Any, handler: Any) -> CoreSchema:
|
|
106
|
+
"""Define o schema para serialização/deserialização do Pydantic."""
|
|
107
|
+
return core_schema.json_or_python_schema(
|
|
108
|
+
json_schema=core_schema.typed_dict_schema(
|
|
109
|
+
{
|
|
110
|
+
"$date": core_schema.typed_dict_field(core_schema.str_schema()),
|
|
111
|
+
},
|
|
112
|
+
total=True,
|
|
113
|
+
),
|
|
114
|
+
python_schema=core_schema.datetime_schema(),
|
|
115
|
+
serialization=core_schema.plain_serializer_function_ser_schema(
|
|
116
|
+
lambda x: {"$date": x.isoformat()}
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def __get_pydantic_json_schema__(
|
|
122
|
+
cls, core_schema: Any, handler: Any
|
|
123
|
+
) -> JsonSchemaValue:
|
|
124
|
+
"""Define o schema JSON para documentação."""
|
|
125
|
+
json_schema = handler(core_schema)
|
|
126
|
+
json_schema.update(
|
|
127
|
+
examples=["2023-01-01T00:00:00Z"],
|
|
128
|
+
type="string",
|
|
129
|
+
format="date-time",
|
|
130
|
+
)
|
|
131
|
+
return json_schema
|
|
132
|
+
|
|
133
|
+
def to_json(self):
|
|
134
|
+
return {"$date": self.isoformat()}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class Address(BaseModel):
|
|
138
|
+
"""Representa um endereço completo.
|
|
139
|
+
|
|
140
|
+
Esta classe modela informações detalhadas de um endereço, incluindo
|
|
141
|
+
dados geográficos e informações de localização específicas.
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
number: str | None = Field(None, description="Número do endereço.")
|
|
145
|
+
postal_code: str | None = Field(
|
|
146
|
+
None, description="Código postal ou CEP do endereço."
|
|
147
|
+
)
|
|
148
|
+
street: str | None = Field(None, description="Nome da rua, avenida ou logradouro.")
|
|
149
|
+
district: str | None = Field(None, description="Bairro ou distrito.")
|
|
150
|
+
city: str | None = Field(None, description="Cidade.")
|
|
151
|
+
state: str | None = Field(None, description="Estado ou província.")
|
|
152
|
+
place_type: str | None = Field(
|
|
153
|
+
None, description="Tipo de logradouro (por exemplo, Rua, Avenida, Praça)."
|
|
154
|
+
)
|
|
155
|
+
complement: str | None = Field(
|
|
156
|
+
None, description="Informações complementares do endereço."
|
|
157
|
+
)
|
|
158
|
+
country: str | None = Field(None, description="País.")
|
|
159
|
+
geo_location: tuple[float, float] | None = Field(
|
|
160
|
+
None, description="Localização geográfica do endereço."
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def to_dict(self) -> dict[str, Any]:
|
|
164
|
+
return self.model_dump(by_alias=True)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class KonectyUser(BaseModel):
|
|
168
|
+
"""Representa um usuário do Konecty."""
|
|
169
|
+
|
|
170
|
+
id: str = Field(alias="_id")
|
|
171
|
+
name: str = Field(alias="name")
|
|
172
|
+
active: bool = Field(alias="active")
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class KonectyBaseModel(BaseModel):
|
|
176
|
+
"""Modelo base para documentos do Konecty."""
|
|
177
|
+
|
|
178
|
+
class UserRef(BaseModel):
|
|
179
|
+
id: Optional[str] = Field(None, alias="_id")
|
|
180
|
+
name: Optional[str] = None
|
|
181
|
+
group: Optional[dict] = None
|
|
182
|
+
active: Optional[bool] = None
|
|
183
|
+
|
|
184
|
+
id: Optional[str] = Field(None, alias="_id")
|
|
185
|
+
code: Optional[int] = None
|
|
186
|
+
created_at: Optional[datetime] = Field(None, alias="_createdAt")
|
|
187
|
+
created_by: Optional[UserRef] = Field(None, alias="_createdBy")
|
|
188
|
+
updated_at: Optional[datetime] = Field(None, alias="_updatedAt")
|
|
189
|
+
updated_by: Optional[UserRef] = Field(None, alias="_updatedBy")
|
|
190
|
+
users: Optional[List[UserRef]] = Field(None, alias="_user")
|
|
191
|
+
|
|
192
|
+
model_config = {
|
|
193
|
+
"populate_by_name": True,
|
|
194
|
+
"json_encoders": {
|
|
195
|
+
datetime: lambda v: json.dumps({"$date": v.isoformat()}),
|
|
196
|
+
Decimal: lambda v: str(v),
|
|
197
|
+
},
|
|
198
|
+
"extra": "allow",
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@classmethod
|
|
202
|
+
def from_json(cls, json_str: str) -> Self:
|
|
203
|
+
"""Cria uma instância do modelo a partir de uma string JSON.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
json_str: String JSON válida representando o objeto
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
Uma instância do modelo
|
|
210
|
+
|
|
211
|
+
Raises:
|
|
212
|
+
ValueError: Se o JSON for inválido
|
|
213
|
+
ValidationError: Se os dados não corresponderem ao modelo
|
|
214
|
+
"""
|
|
215
|
+
try:
|
|
216
|
+
data = json.loads(json_str)
|
|
217
|
+
return cls.from_dict(data)
|
|
218
|
+
except json.JSONDecodeError as e:
|
|
219
|
+
raise ValueError(f"JSON inválido: {str(e)}")
|
|
220
|
+
|
|
221
|
+
@classmethod
|
|
222
|
+
def from_dict(cls, data: Dict[str, Any]) -> Self:
|
|
223
|
+
"""Cria uma instância do modelo a partir de um dicionário.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
data: Dicionário com os dados do objeto
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Uma instância do modelo
|
|
230
|
+
|
|
231
|
+
Raises:
|
|
232
|
+
ValidationError: Se os dados não corresponderem ao modelo
|
|
233
|
+
"""
|
|
234
|
+
return cls.model_validate(data)
|
|
235
|
+
|
|
236
|
+
def to_json(self, **kwargs) -> str:
|
|
237
|
+
"""Converte o modelo para uma string JSON.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
**kwargs: Argumentos adicionais para json.dumps
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
String JSON representando o objeto
|
|
244
|
+
"""
|
|
245
|
+
return json.dumps(self.to_dict(), **kwargs)
|
|
246
|
+
|
|
247
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
248
|
+
"""Converte o modelo para um dicionário.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Dicionário representando o objeto
|
|
252
|
+
"""
|
|
253
|
+
return self.model_dump(by_alias=True)
|
|
254
|
+
|
|
255
|
+
def to_update_dict(self) -> Dict[str, Any]:
|
|
256
|
+
"""Converte o modelo para um dicionário de atualização.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Dicionário representando o objeto
|
|
260
|
+
"""
|
|
261
|
+
return {"_id": self.id, "_updatedAt": self.updated_at or datetime.now()}
|
|
262
|
+
|
|
263
|
+
def extend(self, data: Dict[str, Any]):
|
|
264
|
+
"""Extende esse objeto, adcionando os dados recebidos"""
|
|
265
|
+
field_names = list(self.model_fields.keys())
|
|
266
|
+
|
|
267
|
+
for key, value in data.items():
|
|
268
|
+
if key in field_names:
|
|
269
|
+
setattr(self, key, value)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class KonectyLabel(BaseModel):
|
|
273
|
+
pt_br: str = Field(alias="pt_BR")
|
|
274
|
+
en: str = Field(alias="en")
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class KonectyPhone(BaseModel):
|
|
278
|
+
country_code: Optional[int] = Field(None, ge=1, le=999, alias="countryCode")
|
|
279
|
+
phone_number: Optional[str] = Field(
|
|
280
|
+
None, max_length=11, min_length=8, alias="phoneNumber"
|
|
281
|
+
)
|
|
282
|
+
type: Optional[str] = Field(
|
|
283
|
+
None,
|
|
284
|
+
description="Tipo do telefone (por exemplo, celular, fixo, comercial)",
|
|
285
|
+
alias="type",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
model_config = {
|
|
289
|
+
"populate_by_name": True,
|
|
290
|
+
"extra": "allow",
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
@classmethod
|
|
294
|
+
def empty(cls) -> Self:
|
|
295
|
+
return cls(countryCode=None, phoneNumber=None, type=None)
|
|
296
|
+
|
|
297
|
+
@classmethod
|
|
298
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
299
|
+
return cls.model_validate(data)
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def from_string(cls, value: str) -> Self:
|
|
303
|
+
return cls(
|
|
304
|
+
phoneNumber=re.sub(r"\D", "", value),
|
|
305
|
+
countryCode=55,
|
|
306
|
+
type="mobile",
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
@classmethod
|
|
310
|
+
def from_any(cls, value: Any) -> Self | None:
|
|
311
|
+
if value is None:
|
|
312
|
+
return None
|
|
313
|
+
if isinstance(value, cls):
|
|
314
|
+
return value
|
|
315
|
+
if isinstance(value, str):
|
|
316
|
+
return cls.from_string(value)
|
|
317
|
+
if isinstance(value, dict):
|
|
318
|
+
return cls.from_dict(value)
|
|
319
|
+
raise ValueError("Invalid value for KonectyPhone")
|
|
320
|
+
|
|
321
|
+
def to_dict(self) -> dict[str, Any]:
|
|
322
|
+
return self.model_dump(by_alias=True)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class KonectyLookup(BaseModel):
|
|
326
|
+
"""Representa uma referência a outro documento no Konecty."""
|
|
327
|
+
|
|
328
|
+
id: str = Field(alias="_id")
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class KonectyEmail(BaseModel):
|
|
332
|
+
"""Representa um endereço de e-mail."""
|
|
333
|
+
|
|
334
|
+
address: Optional[str] = Field(None, description="Endereço de e-mail válido")
|
|
335
|
+
|
|
336
|
+
model_config = {
|
|
337
|
+
"populate_by_name": True,
|
|
338
|
+
"extra": "allow",
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
@classmethod
|
|
342
|
+
def empty(cls) -> Self:
|
|
343
|
+
return cls(address=None)
|
|
344
|
+
|
|
345
|
+
@classmethod
|
|
346
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
347
|
+
return cls.model_validate(data)
|
|
348
|
+
|
|
349
|
+
@classmethod
|
|
350
|
+
def from_string(cls, value: str) -> Self:
|
|
351
|
+
return cls(address=value)
|
|
352
|
+
|
|
353
|
+
@classmethod
|
|
354
|
+
def from_any(cls, value: Any) -> Self | None:
|
|
355
|
+
if value is None:
|
|
356
|
+
return None
|
|
357
|
+
if isinstance(value, str):
|
|
358
|
+
return cls.from_string(value)
|
|
359
|
+
if isinstance(value, dict):
|
|
360
|
+
return cls.from_dict(value)
|
|
361
|
+
if isinstance(value, cls):
|
|
362
|
+
return value
|
|
363
|
+
raise ValueError("Invalid value for KonectyEmail")
|
|
364
|
+
|
|
365
|
+
def to_dict(self) -> dict[str, Any]:
|
|
366
|
+
return self.model_dump(by_alias=True)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class KonectyPersonName(BaseModel):
|
|
370
|
+
"""Representa um nome completo de pessoa."""
|
|
371
|
+
|
|
372
|
+
first: str | None = Field(None, description="Primeiro nome")
|
|
373
|
+
last: str | None = Field(None, description="Sobrenome")
|
|
374
|
+
full: str = Field(description="Nome completo")
|
|
375
|
+
|
|
376
|
+
@classmethod
|
|
377
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
378
|
+
return cls.model_validate(data)
|
|
379
|
+
|
|
380
|
+
@classmethod
|
|
381
|
+
def from_string(cls, value: str) -> Self:
|
|
382
|
+
name = value.split(" ")
|
|
383
|
+
return cls(first=name[0], last=" ".join(name[1:]), full=value)
|
|
384
|
+
|
|
385
|
+
@classmethod
|
|
386
|
+
def from_any(cls, value: Any) -> Self:
|
|
387
|
+
if isinstance(value, str):
|
|
388
|
+
return cls.from_string(value)
|
|
389
|
+
if isinstance(value, dict):
|
|
390
|
+
return cls.from_dict(value)
|
|
391
|
+
if isinstance(value, cls):
|
|
392
|
+
return value
|
|
393
|
+
raise ValueError("Invalid value for KonectyPersonName")
|
|
394
|
+
|
|
395
|
+
def to_dict(self) -> dict[str, Any]:
|
|
396
|
+
return self.model_dump(by_alias=True)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class KonectyUpdateId(BaseModel):
|
|
400
|
+
id: str = Field(alias="_id")
|
|
401
|
+
updatedAt: KonectyDateTime = Field(alias="_updatedAt")
|
|
402
|
+
|
|
403
|
+
model_config = ConfigDict(populate_by_name=True, extra="ignore")
|
|
404
|
+
|
|
405
|
+
@classmethod
|
|
406
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
407
|
+
id = data.get("_id", data.get("id", None))
|
|
408
|
+
updatedAt = data.get("_updatedAt", data.get("updatedAt", None))
|
|
409
|
+
if id is None or updatedAt is None:
|
|
410
|
+
raise ValueError("Invalid value for KonectyUpdateIds")
|
|
411
|
+
return cls(id=id, updatedAt=KonectyDateTime.from_any(updatedAt))
|
|
412
|
+
|
|
413
|
+
@classmethod
|
|
414
|
+
def from_list(cls, data: list[dict[str, Any]]) -> list[Self]:
|
|
415
|
+
return [cls.from_dict(item) for item in data]
|
|
416
|
+
|
|
417
|
+
def to_dict(self) -> dict[str, Any]:
|
|
418
|
+
return {"_id": self.id, "_updatedAt": self.updatedAt.to_json()}
|