diff --git a/CHANGELOG.md b/CHANGELOG.md
index e315132..8d85fb8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.3.2] - 2026-10-07
+
+### Fixed
+
+- Tracking timestamps in logistics objects and shipment objects now accept offset-free Bling values through the generated `BlingDatetime` type. Naive timestamps use `America/Sao_Paulo` (including historical daylight saving time); explicit offsets are preserved, and JSON serialization emits an ISO timestamp with its offset. The generator and shared model namespace use the same type, with portable timezone data supplied by `tzdata`.
+- Tracking dates now normalize MySQL zero-date sentinels, empty strings and null to `None`, matching absent-date handling in `BlingDate`. This fixes a second failure confirmed in read-only live logistics objects. Other malformed dates still raise validation errors; the tracking timestamp key remains required, and unrelated DTO requirements are unchanged.
+
## [0.3.1] - 2026-10-06
### Fixed
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 36b4b82..4d6624f 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -114,6 +114,23 @@ with BlingClient.from_env() as client:
print(contato.get("data", {}).get("nome"))
```
+### Datas de rastreamento
+
+Os campos `rastreamento.ultima_alteracao` de objetos e remessas usam
+`BlingDatetime`. Datas sem fuso, como `"2026-10-07 11:24:02"`, são interpretadas
+no fuso IANA `America/Sao_Paulo`, incluindo suas regras históricas de horário
+de verão. Datas que já possuem fuso mantêm o offset informado pelo Bling.
+Na serialização JSON, o resultado inclui o offset:
+`"2026-10-07T11:24:02-03:00"`. A dependência `tzdata` fornece essas regras
+também em sistemas sem uma base de fusos instalada.
+
+Sentinelas de data ausente (`"0000-00-00 00:00:00"`, `"0000-00-00"`,
+`"0001-01-01"`, `"0001-01-01 00:00:00"`), strings vazias e `null` são
+representadas por `None`. `model_dump(mode="json")` preserva `null`;
+`to_json_object()` omite esses valores. Outras datas malformadas continuam
+causando erro de validação, e a chave `ultimaAlteracao` continua obrigatória
+no objeto de rastreamento.
+
### Paginação
Endpoints de listagem aceitam `page` e `limit`:
diff --git a/docs/response-validation-audit.md b/docs/response-validation-audit.md
new file mode 100644
index 0000000..4b7e8c7
--- /dev/null
+++ b/docs/response-validation-audit.md
@@ -0,0 +1,65 @@
+# Auditoria de validação de respostas — 2026-10-07
+
+Esta investigação partiu da falha de `GET /logisticas/objetos/{idObjeto}` no
+SDK 0.3.1: o Bling envia `rastreamento.ultimaAlteracao` sem offset, enquanto
+o modelo gerado exigia `AwareDatetime`.
+
+## Problemas confirmados e correções
+
+| Problema | Evidência | Correção |
+| --- | --- | --- |
+| Timestamp sem fuso rejeitado | Reprodução com `2026-10-07 11:24:02`; o próprio OpenAPI contém exemplo sem offset | `BlingDatetime` interpreta valores sem fuso como `America/Sao_Paulo` e preserva offsets explícitos |
+| Mesmo problema em remessas | `LogisticasRemessasRastreamentoDTO.ultimaAlteracao` também era `AwareDatetime` | Mesmo tipo aplicado pelo gerador; teste de leitura com rastreamento dentro de `objetos[]` |
+| Data zerada rejeitada | Cinco objetos reais apresentaram sentinela de data zerada durante a investigação | Sentinelas de ausência viram `None`; datas malformadas comuns continuam falhando |
+
+O tipo usa as regras IANA de São Paulo, incluindo o horário de verão histórico.
+A dependência `tzdata` permite a mesma interpretação em sistemas sem base de
+fusos. As chaves obrigatórias, os aliases e a proteção contra valores
+conflitantes continuam sendo validados.
+
+## Varredura dos modelos e do OpenAPI
+
+- Os dois campos acima eram os únicos campos gerados com `AwareDatetime`.
+- Há 52 propriedades com formato `date` nos componentes do OpenAPI. Seus
+ exemplos passaram pelo parser `BlingDate`, que já trata datas zeradas.
+- Quatro propriedades usam o formato não padronizado `datetime`:
+ `NotasFiscaisDadosBaseDTO.dataEmissao`, `dataOperacao` e
+ `NotificacoesDadosBaseDTO.dataEnvio`, `dataLeitura`. O gerador as mantém como
+ texto; elas não exigem timezone e não foram convertidas nesta correção.
+- Um teste percorre os exemplos `date-time` do OpenAPI e os valida com os
+ campos dos modelos gerados, para detectar novamente uma incompatibilidade
+ entre o exemplo oficial e o parser.
+
+## Amostragem real, somente leitura
+
+As consultas usaram `doppler run --project bling-sdk --config dev` e o
+transporte do SDK com `rate_limit_max_requests=1` e
+`rate_limit_period_seconds=2.1`. O limitador permaneceu habilitado, inclusive
+para retries. Os relatórios exibiram somente rotas sem IDs, tipos e locais
+de erros e resultados de validação. Payloads, identificadores, valores
+financeiros e credenciais não foram salvos. As fixtures são sintéticas.
+
+| Recurso | Resultado observado |
+| --- | --- |
+| Pedidos de venda, listagem e detalhe | Validação e serialização passaram |
+| Produtos, listagem e detalhe | Validação e serialização passaram |
+| Contatos, listagem e detalhe | Validação e serialização passaram |
+| NF-e, listagem e detalhe | Validação e serialização passaram |
+| Contas a pagar e a receber, listagem e detalhe | Validação e serialização passaram |
+| Logísticas, listagem | Validação e serialização passaram |
+| Objetos de logística | Oito leituras pelo método público passaram após as duas correções, com timestamp ausente representado por `None` |
+| NFS-e | Listagem validada; sem registros para verificar detalhe |
+| NFC-e | API retornou erro de autenticação/acesso; modelos não foram validados com payload real |
+| Remessas por logística | API retornou erro de validação nas duas logísticas consultadas; detalhes permanecem cobertos por fixture sintética e teste do método público |
+
+As amostras reais de rastreamento verificadas nesta execução tinham data
+zerada. Datas sem fuso válidas foram verificadas com o valor relatado, os
+exemplos oficiais e testes locais. A amostragem não prova que todos os
+payloads possíveis de todos os endpoints sejam aceitos.
+
+## Limite em relação ao Django
+
+A atualização do Django foi excluída desta etapa a pedido do usuário. O SDK
+corrige as duas falhas confirmadas de leitura. A persistência de NF-e/DANFE
+em `sync_order()` e a recuperação de fichas antigas dependem do aplicativo
+consumidor e não foram alteradas ou validadas aqui.
diff --git a/mkdocs.yml b/mkdocs.yml
index 7085292..dbeeb7a 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -64,6 +64,7 @@ nav:
- Autenticação: authentication.md
- Paginação: pagination.md
- Erros: errors.md
+ - Validação de respostas: response-validation-audit.md
- Recursos:
- resources/sales_orders.md
- resources/products.md
diff --git a/pyproject.toml b/pyproject.toml
index e2c9d41..e49e29a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,6 +24,7 @@ dependencies = [
"pydantic>=2.13.4,<3.0.0",
"pydantic-settings>=2.14.1,<3.0.0",
"python-dotenv>=1.2.2,<2.0.0",
+ "tzdata>=2025.2",
]
[project.urls]
diff --git a/scripts/generate_models.py b/scripts/generate_models.py
index ca39690..7201f8c 100644
--- a/scripts/generate_models.py
+++ b/scripts/generate_models.py
@@ -117,8 +117,8 @@
)
BUILTIN_TYPE_NAMES = {
"Any",
- "AwareDatetime",
"BlingDate",
+ "BlingDatetime",
"BlingModel",
"Field",
"None",
@@ -181,7 +181,7 @@
# Type that replaces bare ``date`` in all generated annotations.
DATE_TYPE_REWRITE = "BlingDate"
-DATE_IMPORT = "from bling_erp_api.models.fields import BlingDate"
+DATE_IMPORT = "from bling_erp_api.models.fields import BlingDate, BlingDatetime"
# ``Field(...)`` keywords that affect the wire format. Inserted redeclarations
# of parent-inherited fields only clone the parent's ``Field(...)`` call when
@@ -604,10 +604,10 @@ def _schema_module_content(
"",
"from __future__ import annotations",
"",
- "from bling_erp_api.models.fields import BlingDate",
+ DATE_IMPORT,
"from typing import TYPE_CHECKING, Any",
"",
- "from pydantic import AliasChoices, AwareDatetime, Field, RootModel",
+ "from pydantic import AliasChoices, Field, RootModel",
"",
"from bling_erp_api.models.base import BlingModel",
]
@@ -653,11 +653,9 @@ def _schema_init_content(
"",
"from __future__ import annotations",
"",
- "from bling_erp_api.models.fields import BlingDate",
+ DATE_IMPORT,
"from typing import Any",
"",
- "from pydantic import AwareDatetime",
- "",
]
for module, names in sorted(by_module.items()):
imports = ", ".join(names)
@@ -671,7 +669,7 @@ def _schema_init_content(
exports + "]",
"",
"_MODEL_NAMESPACE = {name: globals()[name] for name in __all__}",
- "_MODEL_NAMESPACE.update({'Any': Any, 'AwareDatetime': AwareDatetime, 'BlingDate': BlingDate})",
+ "_MODEL_NAMESPACE.update({'Any': Any, 'BlingDate': BlingDate, 'BlingDatetime': BlingDatetime})",
"for _model in _MODEL_NAMESPACE.values():",
" if isinstance(_model, type) and hasattr(_model, 'model_rebuild'):",
" _model.model_rebuild(_types_namespace=_MODEL_NAMESPACE)",
@@ -912,10 +910,11 @@ def _remove_pass_if_empty(node: ast.ClassDef) -> None:
def _rewrite_date_types(node: ast.ClassDef) -> None:
- """Replace ``date`` with ``BlingDate`` in all field annotations."""
+ """Use Bling date and datetime parsing in generated field annotations."""
+ replacements = {"date": "BlingDate", "AwareDatetime": "BlingDatetime"}
for stmt in ast.walk(node):
- if isinstance(stmt, ast.Name) and stmt.id == "date":
- stmt.id = "BlingDate"
+ if isinstance(stmt, ast.Name) and stmt.id in replacements:
+ stmt.id = replacements[stmt.id]
def _inherited_field_value(parent_decl: ast.AnnAssign | None, field_name: str) -> ast.expr:
diff --git a/src/bling_erp_api/_version.py b/src/bling_erp_api/_version.py
index a86b5c4..a79cb0d 100644
--- a/src/bling_erp_api/_version.py
+++ b/src/bling_erp_api/_version.py
@@ -1,3 +1,3 @@
"""Package version."""
-__version__ = "0.3.1"
+__version__ = "0.3.2"
diff --git a/src/bling_erp_api/models/fields.py b/src/bling_erp_api/models/fields.py
index f98f5e6..6f50ab3 100644
--- a/src/bling_erp_api/models/fields.py
+++ b/src/bling_erp_api/models/fields.py
@@ -2,9 +2,11 @@
from __future__ import annotations
-from datetime import date
+from datetime import date, datetime
from typing import Annotated
+from zoneinfo import ZoneInfo
+from pydantic import AfterValidator, BeforeValidator
from pydantic.functional_serializers import PlainSerializer
from pydantic.functional_validators import PlainValidator
@@ -44,3 +46,37 @@ def _serialize_bling_date(value: date | None) -> str | None:
PlainValidator(_parse_bling_date),
PlainSerializer(_serialize_bling_date, return_type=str | None, when_used="json"),
]
+
+
+def _normalize_bling_datetime(value: object) -> object:
+ """Map Bling's absent timestamp sentinels to None before datetime parsing."""
+ if isinstance(value, str):
+ stripped = value.strip()
+ if not stripped or stripped in {
+ "0000-00-00",
+ "0000-00-00 00:00:00",
+ "0001-01-01",
+ "0001-01-01 00:00:00",
+ }:
+ return None
+ return stripped
+ return value
+
+
+def _localize_bling_datetime(value: datetime | None) -> datetime | None:
+ """Interpret offset-free Bling timestamps in America/Sao_Paulo.
+
+ Preserve explicit offsets and use the IANA timezone rules for naive values,
+ including historical daylight saving time. Invalid timestamps still fail
+ Pydantic's normal datetime validation before this validator is called.
+ """
+ if value is not None and (value.tzinfo is None or value.utcoffset() is None):
+ return value.replace(tzinfo=ZoneInfo("America/Sao_Paulo"))
+ return value
+
+
+BlingDatetime = Annotated[
+ datetime | None,
+ BeforeValidator(_normalize_bling_datetime),
+ AfterValidator(_localize_bling_datetime),
+]
diff --git a/src/bling_erp_api/models/generated/schemas/__init__.py b/src/bling_erp_api/models/generated/schemas/__init__.py
index e167880..950ed4c 100644
--- a/src/bling_erp_api/models/generated/schemas/__init__.py
+++ b/src/bling_erp_api/models/generated/schemas/__init__.py
@@ -4,11 +4,9 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import Any
-from pydantic import AwareDatetime
-
from .anuncios import (
AnunciosAtributoDTO,
AnunciosCategoriaDTO,
@@ -1484,7 +1482,7 @@
]
_MODEL_NAMESPACE = {name: globals()[name] for name in __all__}
-_MODEL_NAMESPACE.update({"Any": Any, "AwareDatetime": AwareDatetime, "BlingDate": BlingDate})
+_MODEL_NAMESPACE.update({"Any": Any, "BlingDate": BlingDate, "BlingDatetime": BlingDatetime})
for _model in _MODEL_NAMESPACE.values():
if isinstance(_model, type) and hasattr(_model, "model_rebuild"):
_model.model_rebuild(_types_namespace=_MODEL_NAMESPACE)
diff --git a/src/bling_erp_api/models/generated/schemas/anuncios.py b/src/bling_erp_api/models/generated/schemas/anuncios.py
index 883e0b5..80271cf 100644
--- a/src/bling_erp_api/models/generated/schemas/anuncios.py
+++ b/src/bling_erp_api/models/generated/schemas/anuncios.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/anuncios_categorias.py b/src/bling_erp_api/models/generated/schemas/anuncios_categorias.py
index 7569a87..a7c8852 100644
--- a/src/bling_erp_api/models/generated/schemas/anuncios_categorias.py
+++ b/src/bling_erp_api/models/generated/schemas/anuncios_categorias.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/borderos.py b/src/bling_erp_api/models/generated/schemas/borderos.py
index 76f7575..582fe01 100644
--- a/src/bling_erp_api/models/generated/schemas/borderos.py
+++ b/src/bling_erp_api/models/generated/schemas/borderos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/caixas_bancos.py b/src/bling_erp_api/models/generated/schemas/caixas_bancos.py
index 32706f6..4ba5be6 100644
--- a/src/bling_erp_api/models/generated/schemas/caixas_bancos.py
+++ b/src/bling_erp_api/models/generated/schemas/caixas_bancos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/calculos_impostos.py b/src/bling_erp_api/models/generated/schemas/calculos_impostos.py
index 83338ad..23357e6 100644
--- a/src/bling_erp_api/models/generated/schemas/calculos_impostos.py
+++ b/src/bling_erp_api/models/generated/schemas/calculos_impostos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/campos_customizados.py b/src/bling_erp_api/models/generated/schemas/campos_customizados.py
index 403fe66..aad13bd 100644
--- a/src/bling_erp_api/models/generated/schemas/campos_customizados.py
+++ b/src/bling_erp_api/models/generated/schemas/campos_customizados.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/canais_venda.py b/src/bling_erp_api/models/generated/schemas/canais_venda.py
index 868e480..961e596 100644
--- a/src/bling_erp_api/models/generated/schemas/canais_venda.py
+++ b/src/bling_erp_api/models/generated/schemas/canais_venda.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/categorias_lojas.py b/src/bling_erp_api/models/generated/schemas/categorias_lojas.py
index 276468d..000eee3 100644
--- a/src/bling_erp_api/models/generated/schemas/categorias_lojas.py
+++ b/src/bling_erp_api/models/generated/schemas/categorias_lojas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/categorias_produtos.py b/src/bling_erp_api/models/generated/schemas/categorias_produtos.py
index 1e92d86..706f013 100644
--- a/src/bling_erp_api/models/generated/schemas/categorias_produtos.py
+++ b/src/bling_erp_api/models/generated/schemas/categorias_produtos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/categorias_receitas_despesas.py b/src/bling_erp_api/models/generated/schemas/categorias_receitas_despesas.py
index e4f7422..c3ed5b4 100644
--- a/src/bling_erp_api/models/generated/schemas/categorias_receitas_despesas.py
+++ b/src/bling_erp_api/models/generated/schemas/categorias_receitas_despesas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/common.py b/src/bling_erp_api/models/generated/schemas/common.py
index 888a1fa..2e60abe 100644
--- a/src/bling_erp_api/models/generated/schemas/common.py
+++ b/src/bling_erp_api/models/generated/schemas/common.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/configuracoes.py b/src/bling_erp_api/models/generated/schemas/configuracoes.py
index 20d15f5..52f7e0b 100644
--- a/src/bling_erp_api/models/generated/schemas/configuracoes.py
+++ b/src/bling_erp_api/models/generated/schemas/configuracoes.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contas.py b/src/bling_erp_api/models/generated/schemas/contas.py
index ed77166..32ace0d 100644
--- a/src/bling_erp_api/models/generated/schemas/contas.py
+++ b/src/bling_erp_api/models/generated/schemas/contas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contas_contabeis.py b/src/bling_erp_api/models/generated/schemas/contas_contabeis.py
index 8dfc91b..0ad5d6d 100644
--- a/src/bling_erp_api/models/generated/schemas/contas_contabeis.py
+++ b/src/bling_erp_api/models/generated/schemas/contas_contabeis.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contas_financeiras.py b/src/bling_erp_api/models/generated/schemas/contas_financeiras.py
index c4b3163..f996b1b 100644
--- a/src/bling_erp_api/models/generated/schemas/contas_financeiras.py
+++ b/src/bling_erp_api/models/generated/schemas/contas_financeiras.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contas_pagar.py b/src/bling_erp_api/models/generated/schemas/contas_pagar.py
index ddc134e..3e66b03 100644
--- a/src/bling_erp_api/models/generated/schemas/contas_pagar.py
+++ b/src/bling_erp_api/models/generated/schemas/contas_pagar.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contas_receber.py b/src/bling_erp_api/models/generated/schemas/contas_receber.py
index 0aa6163..98d678a 100644
--- a/src/bling_erp_api/models/generated/schemas/contas_receber.py
+++ b/src/bling_erp_api/models/generated/schemas/contas_receber.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contatos.py b/src/bling_erp_api/models/generated/schemas/contatos.py
index 300533b..4489366 100644
--- a/src/bling_erp_api/models/generated/schemas/contatos.py
+++ b/src/bling_erp_api/models/generated/schemas/contatos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/contratos.py b/src/bling_erp_api/models/generated/schemas/contratos.py
index 2630c79..45563f8 100644
--- a/src/bling_erp_api/models/generated/schemas/contratos.py
+++ b/src/bling_erp_api/models/generated/schemas/contratos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/depositos.py b/src/bling_erp_api/models/generated/schemas/depositos.py
index f78ce41..324a164 100644
--- a/src/bling_erp_api/models/generated/schemas/depositos.py
+++ b/src/bling_erp_api/models/generated/schemas/depositos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/empresas.py b/src/bling_erp_api/models/generated/schemas/empresas.py
index c9580fb..397e363 100644
--- a/src/bling_erp_api/models/generated/schemas/empresas.py
+++ b/src/bling_erp_api/models/generated/schemas/empresas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/estoques.py b/src/bling_erp_api/models/generated/schemas/estoques.py
index c2bf859..575b879 100644
--- a/src/bling_erp_api/models/generated/schemas/estoques.py
+++ b/src/bling_erp_api/models/generated/schemas/estoques.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/formas_pagamentos.py b/src/bling_erp_api/models/generated/schemas/formas_pagamentos.py
index 6d573bb..b247a70 100644
--- a/src/bling_erp_api/models/generated/schemas/formas_pagamentos.py
+++ b/src/bling_erp_api/models/generated/schemas/formas_pagamentos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/grupos_produtos.py b/src/bling_erp_api/models/generated/schemas/grupos_produtos.py
index 5d22f3c..4bc15ae 100644
--- a/src/bling_erp_api/models/generated/schemas/grupos_produtos.py
+++ b/src/bling_erp_api/models/generated/schemas/grupos_produtos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/homologacao.py b/src/bling_erp_api/models/generated/schemas/homologacao.py
index 5bd38ba..7441715 100644
--- a/src/bling_erp_api/models/generated/schemas/homologacao.py
+++ b/src/bling_erp_api/models/generated/schemas/homologacao.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/logisticas.py b/src/bling_erp_api/models/generated/schemas/logisticas.py
index a7f09a8..0ded4e5 100644
--- a/src/bling_erp_api/models/generated/schemas/logisticas.py
+++ b/src/bling_erp_api/models/generated/schemas/logisticas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/logisticas_etiquetas.py b/src/bling_erp_api/models/generated/schemas/logisticas_etiquetas.py
index 2a4e16c..8b466bf 100644
--- a/src/bling_erp_api/models/generated/schemas/logisticas_etiquetas.py
+++ b/src/bling_erp_api/models/generated/schemas/logisticas_etiquetas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/logisticas_objetos.py b/src/bling_erp_api/models/generated/schemas/logisticas_objetos.py
index b4a9485..876a742 100644
--- a/src/bling_erp_api/models/generated/schemas/logisticas_objetos.py
+++ b/src/bling_erp_api/models/generated/schemas/logisticas_objetos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
@@ -92,7 +92,7 @@ class LogisticasObjetosRastreamentoDTO(BlingModel):
situacao: Bling ``situacao``; type ``int``; obrigatório. `0` Postado
`1` Em andamento
`2` Não entregue
`3` Entregue
`4` Aguardando retirada
`5` Etiqueta comprada
`6` Vinculado
`7` Atrasado
`8` Não...
origem: Bling ``origem``; type ``str``; obrigatório. Cidade e estado de origem
destino: Bling ``destino``; type ``str``; obrigatório. Cidade e estado de destino
- ultima_alteracao: Bling ``ultimaAlteracao``; type ``AwareDatetime``; obrigatório. Data e hora em que ocorreu a atualização de rastreio.
+ ultima_alteracao: Bling ``ultimaAlteracao``; type ``BlingDatetime``; obrigatório. Data e hora em que ocorreu a atualização de rastreio.
url: Bling ``url``; type ``str``; obrigatório. URL de rastreamento"""
codigo: str = Field(..., examples=["EC272330554BR"])
@@ -100,7 +100,7 @@ class LogisticasObjetosRastreamentoDTO(BlingModel):
situacao: int = Field(..., examples=["8"])
origem: str = Field(..., examples=["São Paulo, SP"])
destino: str = Field(..., examples=["São Paulo, SP"])
- ultima_alteracao: AwareDatetime = Field(
+ ultima_alteracao: BlingDatetime = Field(
...,
validation_alias=AliasChoices("ultima_alteracao", "ultimaAlteracao"),
examples=["2020-11-11 16:40:33"],
diff --git a/src/bling_erp_api/models/generated/schemas/logisticas_remessas.py b/src/bling_erp_api/models/generated/schemas/logisticas_remessas.py
index aef41a0..f3f5c4a 100644
--- a/src/bling_erp_api/models/generated/schemas/logisticas_remessas.py
+++ b/src/bling_erp_api/models/generated/schemas/logisticas_remessas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
@@ -132,7 +132,7 @@ class LogisticasRemessasRastreamentoDTO(BlingModel):
situacao: Bling ``situacao``; type ``int``; obrigatório. `0` Postado
`1` Em andamento
`2` Não entregue
`3` Entregue
`4` Aguardando retirada
`5` Em aberto
`6` Vinculado
`7` Atrasado
`8` Não postado...
origem: Bling ``origem``; type ``str``; obrigatório. Cidade e estado de origem
destino: Bling ``destino``; type ``str``; obrigatório. Cidade e estado de destino
- ultima_alteracao: Bling ``ultimaAlteracao``; type ``AwareDatetime``; obrigatório. Data e hora em que ocorreu a atualização de rastreio.
+ ultima_alteracao: Bling ``ultimaAlteracao``; type ``BlingDatetime``; obrigatório. Data e hora em que ocorreu a atualização de rastreio.
url: Bling ``url``; type ``str``; obrigatório. URL de rastreamento"""
codigo: str = Field(..., examples=["EC272330554BR"])
@@ -140,7 +140,7 @@ class LogisticasRemessasRastreamentoDTO(BlingModel):
situacao: int = Field(..., examples=[1])
origem: str = Field(..., examples=["São Paulo, SP"])
destino: str = Field(..., examples=["São Paulo, SP"])
- ultima_alteracao: AwareDatetime = Field(
+ ultima_alteracao: BlingDatetime = Field(
...,
validation_alias=AliasChoices("ultima_alteracao", "ultimaAlteracao"),
examples=["2020-11-11 16:40:33"],
diff --git a/src/bling_erp_api/models/generated/schemas/logisticas_servicos.py b/src/bling_erp_api/models/generated/schemas/logisticas_servicos.py
index f2dd1c4..dae5471 100644
--- a/src/bling_erp_api/models/generated/schemas/logisticas_servicos.py
+++ b/src/bling_erp_api/models/generated/schemas/logisticas_servicos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/lotes.py b/src/bling_erp_api/models/generated/schemas/lotes.py
index 74ba238..5544047 100644
--- a/src/bling_erp_api/models/generated/schemas/lotes.py
+++ b/src/bling_erp_api/models/generated/schemas/lotes.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/lotes_lancamentos.py b/src/bling_erp_api/models/generated/schemas/lotes_lancamentos.py
index 0da96ec..cd8a22e 100644
--- a/src/bling_erp_api/models/generated/schemas/lotes_lancamentos.py
+++ b/src/bling_erp_api/models/generated/schemas/lotes_lancamentos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/naturezas_operacoes.py b/src/bling_erp_api/models/generated/schemas/naturezas_operacoes.py
index 4df623b..456b386 100644
--- a/src/bling_erp_api/models/generated/schemas/naturezas_operacoes.py
+++ b/src/bling_erp_api/models/generated/schemas/naturezas_operacoes.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/notas_fiscais.py b/src/bling_erp_api/models/generated/schemas/notas_fiscais.py
index 9426903..8816e3d 100644
--- a/src/bling_erp_api/models/generated/schemas/notas_fiscais.py
+++ b/src/bling_erp_api/models/generated/schemas/notas_fiscais.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/notas_fiscais_consumidor.py b/src/bling_erp_api/models/generated/schemas/notas_fiscais_consumidor.py
index 996cd28..0a10238 100644
--- a/src/bling_erp_api/models/generated/schemas/notas_fiscais_consumidor.py
+++ b/src/bling_erp_api/models/generated/schemas/notas_fiscais_consumidor.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/notas_servicos.py b/src/bling_erp_api/models/generated/schemas/notas_servicos.py
index 32ac19e..dfecc6b 100644
--- a/src/bling_erp_api/models/generated/schemas/notas_servicos.py
+++ b/src/bling_erp_api/models/generated/schemas/notas_servicos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/notificacoes.py b/src/bling_erp_api/models/generated/schemas/notificacoes.py
index f4fc3e7..ad2a9dc 100644
--- a/src/bling_erp_api/models/generated/schemas/notificacoes.py
+++ b/src/bling_erp_api/models/generated/schemas/notificacoes.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/orcamentos.py b/src/bling_erp_api/models/generated/schemas/orcamentos.py
index afd1a1d..59c6be3 100644
--- a/src/bling_erp_api/models/generated/schemas/orcamentos.py
+++ b/src/bling_erp_api/models/generated/schemas/orcamentos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/ordens_producao.py b/src/bling_erp_api/models/generated/schemas/ordens_producao.py
index c3415b8..b1e1005 100644
--- a/src/bling_erp_api/models/generated/schemas/ordens_producao.py
+++ b/src/bling_erp_api/models/generated/schemas/ordens_producao.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/pedidos_compras.py b/src/bling_erp_api/models/generated/schemas/pedidos_compras.py
index b6bbdb5..8ad641c 100644
--- a/src/bling_erp_api/models/generated/schemas/pedidos_compras.py
+++ b/src/bling_erp_api/models/generated/schemas/pedidos_compras.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/pedidos_vendas.py b/src/bling_erp_api/models/generated/schemas/pedidos_vendas.py
index 44fa44b..fbfe167 100644
--- a/src/bling_erp_api/models/generated/schemas/pedidos_vendas.py
+++ b/src/bling_erp_api/models/generated/schemas/pedidos_vendas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/produtos.py b/src/bling_erp_api/models/generated/schemas/produtos.py
index 5d17f71..a645374 100644
--- a/src/bling_erp_api/models/generated/schemas/produtos.py
+++ b/src/bling_erp_api/models/generated/schemas/produtos.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/produtos_estruturas.py b/src/bling_erp_api/models/generated/schemas/produtos_estruturas.py
index 9609483..54fd8b7 100644
--- a/src/bling_erp_api/models/generated/schemas/produtos_estruturas.py
+++ b/src/bling_erp_api/models/generated/schemas/produtos_estruturas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/produtos_fornecedores.py b/src/bling_erp_api/models/generated/schemas/produtos_fornecedores.py
index 88803b8..c2bdd3d 100644
--- a/src/bling_erp_api/models/generated/schemas/produtos_fornecedores.py
+++ b/src/bling_erp_api/models/generated/schemas/produtos_fornecedores.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/produtos_lojas.py b/src/bling_erp_api/models/generated/schemas/produtos_lojas.py
index a6bbba1..a46c608 100644
--- a/src/bling_erp_api/models/generated/schemas/produtos_lojas.py
+++ b/src/bling_erp_api/models/generated/schemas/produtos_lojas.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/produtos_variacoes.py b/src/bling_erp_api/models/generated/schemas/produtos_variacoes.py
index f47e843..be5695d 100644
--- a/src/bling_erp_api/models/generated/schemas/produtos_variacoes.py
+++ b/src/bling_erp_api/models/generated/schemas/produtos_variacoes.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/propostas_comerciais.py b/src/bling_erp_api/models/generated/schemas/propostas_comerciais.py
index cdca098..a6bec52 100644
--- a/src/bling_erp_api/models/generated/schemas/propostas_comerciais.py
+++ b/src/bling_erp_api/models/generated/schemas/propostas_comerciais.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/situacoes.py b/src/bling_erp_api/models/generated/schemas/situacoes.py
index 444beb6..d5fef87 100644
--- a/src/bling_erp_api/models/generated/schemas/situacoes.py
+++ b/src/bling_erp_api/models/generated/schemas/situacoes.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/usuarios.py b/src/bling_erp_api/models/generated/schemas/usuarios.py
index 01081db..9206a38 100644
--- a/src/bling_erp_api/models/generated/schemas/usuarios.py
+++ b/src/bling_erp_api/models/generated/schemas/usuarios.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/src/bling_erp_api/models/generated/schemas/vendedores.py b/src/bling_erp_api/models/generated/schemas/vendedores.py
index 9db9d1d..f309336 100644
--- a/src/bling_erp_api/models/generated/schemas/vendedores.py
+++ b/src/bling_erp_api/models/generated/schemas/vendedores.py
@@ -4,10 +4,10 @@
from __future__ import annotations
-from bling_erp_api.models.fields import BlingDate
+from bling_erp_api.models.fields import BlingDate, BlingDatetime
from typing import TYPE_CHECKING, Any
-from pydantic import AliasChoices, AwareDatetime, Field, RootModel
+from pydantic import AliasChoices, Field, RootModel
from bling_erp_api.models.base import BlingModel
diff --git a/tests/fixtures/responses/logisticas_objetos_get.json b/tests/fixtures/responses/logisticas_objetos_get.json
new file mode 100644
index 0000000..949eae6
--- /dev/null
+++ b/tests/fixtures/responses/logisticas_objetos_get.json
@@ -0,0 +1,24 @@
+{
+ "data": {
+ "pedidoVenda": {"id": 101},
+ "notaFiscal": {"id": 201},
+ "servico": {"id": 301},
+ "rastreamento": {
+ "codigo": "SYNTHETIC123",
+ "descricao": "Em andamento",
+ "situacao": 1,
+ "origem": "São Paulo, SP",
+ "destino": "Curitiba, PR",
+ "ultimaAlteracao": "2026-10-07 11:24:02",
+ "url": "https://example.com/tracking"
+ },
+ "dimensao": {"altura": 10, "largura": 10, "comprimento": 10, "diametro": 0, "peso": 1},
+ "embalagem": {"id": 401},
+ "dataSaida": "2026-10-07",
+ "prazoEntregaPrevisto": 5,
+ "fretePrevisto": 10,
+ "valorDeclarado": 50,
+ "avisoRecebimento": false,
+ "maoPropria": false
+ }
+}
diff --git a/tests/unit/test_bling_datetime.py b/tests/unit/test_bling_datetime.py
new file mode 100644
index 0000000..b8fd6c3
--- /dev/null
+++ b/tests/unit/test_bling_datetime.py
@@ -0,0 +1,215 @@
+"""Regression tests for Bling timestamps without UTC offsets."""
+
+from __future__ import annotations
+
+import inspect
+import json
+from datetime import UTC, datetime, timedelta
+from pathlib import Path
+from typing import TYPE_CHECKING, cast
+
+import httpx
+import pytest
+from pydantic import TypeAdapter, ValidationError
+
+from bling_erp_api import BlingClient
+from bling_erp_api.models.fields import BlingDatetime
+from bling_erp_api.models.generated import schemas
+from bling_erp_api.models.generated.schemas.logisticas_objetos import (
+ LogisticasObjetosIdObjetoGetResponse200,
+ LogisticasObjetosRastreamentoDTO,
+)
+from bling_erp_api.models.generated.schemas.logisticas_remessas import (
+ LogisticasRemessasIdRemessaGetResponse200,
+ LogisticasRemessasRastreamentoDTO,
+)
+from bling_erp_api.utils.serialization import to_json_object
+
+if TYPE_CHECKING:
+ from pytest_httpx import HTTPXMock
+
+ from bling_erp_api.models.base import BlingModel
+ from bling_erp_api.types import JsonObject
+
+FIXTURE = Path(__file__).parents[1] / "fixtures/responses/logisticas_objetos_get.json"
+SPEC = Path(__file__).parents[2] / "specs/bling-openapi-reference.json"
+TRACKING_MODELS = (LogisticasObjetosRastreamentoDTO, LogisticasRemessasRastreamentoDTO)
+
+
+def _object_payload() -> JsonObject:
+ return cast("JsonObject", json.loads(FIXTURE.read_text(encoding="utf-8")))
+
+
+def test_generated_datetime_fields_accept_openapi_examples() -> None:
+ """Every component date-time example must pass its generated field validator."""
+ spec = cast("JsonObject", json.loads(SPEC.read_text(encoding="utf-8")))
+ components = cast("JsonObject", spec["components"])
+ definitions = cast("JsonObject", components["schemas"])
+ checked = 0
+ for schema_name, definition in definitions.items():
+ properties = cast("JsonObject", cast("JsonObject", definition).get("properties", {}))
+ for wire_name, property_definition in properties.items():
+ prop = cast("JsonObject", property_definition)
+ if prop.get("format") != "date-time" or "example" not in prop:
+ continue
+ model_type = cast("type[BlingModel]", getattr(schemas, schema_name))
+ field = next(
+ field
+ for name, field in model_type.model_fields.items()
+ if (field.serialization_alias or name) == wire_name
+ )
+ parsed = TypeAdapter[datetime | None](field.rebuild_annotation()).validate_python(
+ prop["example"],
+ )
+ assert parsed is not None
+ assert parsed.utcoffset() is not None
+ checked += 1
+ assert checked >= 2
+
+
+@pytest.mark.parametrize(
+ ("value", "offset"),
+ [
+ ("2026-10-07 11:24:02", -3),
+ ("2026-10-07T11:24:02.123456", -3),
+ (datetime(2026, 10, 7, 11, 24, 2), -3), # noqa: DTZ001
+ ("2018-12-01 12:00:00", -2),
+ ("2026-10-07T14:24:02Z", 0),
+ ("2026-10-07T11:24:02-04:00", -4),
+ (datetime(2026, 10, 7, 14, 24, 2, tzinfo=UTC), 0),
+ ],
+)
+def test_bling_datetime_assigns_local_timezone_and_preserves_offsets(
+ value: str | datetime, offset: int
+) -> None:
+ """Offset-free dates use Sao Paulo rules; explicit offsets are preserved."""
+ parsed = TypeAdapter[datetime | None](BlingDatetime).validate_python(value)
+ assert parsed is not None
+ assert parsed.utcoffset() == timedelta(hours=offset)
+ if isinstance(value, datetime) and value.tzinfo is not None:
+ assert parsed is value
+
+
+@pytest.mark.parametrize("value", ["not-a-date", "2026-02-30 12:00:00", "2026-00-07 12:00:00"])
+def test_bling_datetime_rejects_invalid_timestamps(value: object) -> None:
+ """Do not turn malformed timestamps into silently accepted data."""
+ with pytest.raises(ValidationError):
+ TypeAdapter[datetime | None](BlingDatetime).validate_python(value)
+
+
+@pytest.mark.parametrize("model_type", TRACKING_MODELS)
+def test_tracking_models_accept_wire_and_python_field_names(
+ model_type: type[LogisticasObjetosRastreamentoDTO | LogisticasRemessasRastreamentoDTO],
+) -> None:
+ """Both affected DTOs parse aliases and serialize aware ISO timestamps."""
+ payload = cast("JsonObject", cast("JsonObject", _object_payload()["data"])["rastreamento"])
+ wire = model_type.model_validate(payload)
+ python_payload = {**payload}
+ python_payload["ultima_alteracao"] = python_payload.pop("ultimaAlteracao")
+ python_model = model_type.model_validate(python_payload)
+ assert python_model == wire
+ assert wire.ultima_alteracao is not None
+ assert wire.ultima_alteracao.utcoffset() == timedelta(hours=-3)
+ assert "ultima_alteracao" in inspect.signature(model_type).parameters
+ assert "ultimaAlteracao" not in inspect.signature(model_type).parameters
+ serialized = to_json_object(wire)
+ assert serialized["ultimaAlteracao"] == "2026-10-07T11:24:02-03:00"
+ assert "ultima_alteracao" not in serialized
+ assert model_type.model_validate(serialized) == wire
+ with pytest.raises(ValidationError, match="Conflicting values"):
+ model_type.model_validate({**payload, "ultima_alteracao": "2026-10-08 11:24:02"})
+
+
+@pytest.mark.parametrize("english_alias", [False, True])
+def test_logistics_object_resource_parses_naive_datetime(
+ httpx_mock: HTTPXMock, *, english_alias: bool
+) -> None:
+ """Exercise the public resource's two validation passes without live API calls."""
+ httpx_mock.add_response(json=_object_payload())
+ with BlingClient(auth=httpx.Auth()) as client:
+ response = (
+ client.logisticas_objetos.get(object_id=701)
+ if english_alias
+ else client.logisticas_objetos.obter(id_objeto=701)
+ )
+ assert isinstance(response, LogisticasObjetosIdObjetoGetResponse200)
+ assert response.data is not None
+ assert response.data.rastreamento is not None
+ assert response.data.rastreamento.ultima_alteracao is not None
+ assert response.data.rastreamento.ultima_alteracao.isoformat() == "2026-10-07T11:24:02-03:00"
+ request = httpx_mock.get_request()
+ assert request is not None
+ assert request.method == "GET"
+ assert request.url.path == "/Api/v3/logisticas/objetos/701"
+ assert not request.url.query
+ assert request.content == b""
+
+
+def test_logistics_shipment_resource_parses_nested_naive_datetime(httpx_mock: HTTPXMock) -> None:
+ """Remessas share the same timestamp issue inside objetos[].rastreamento."""
+ obj = cast("JsonObject", _object_payload()["data"])
+ obj["servico"] = {"id": 301, "nome": "Synthetic service", "codigo": "TEST"}
+ payload = {
+ "data": {
+ "id": 501,
+ "numeroPlp": "PLP-TEST",
+ "situacao": 1,
+ "descricao": "Synthetic shipment",
+ "dataCriacao": "2026-10-07",
+ "logistica": {"id": 301},
+ "objetos": [{"id": 701, **obj}],
+ },
+ }
+ httpx_mock.add_response(json=payload)
+ with BlingClient(auth=httpx.Auth()) as client:
+ response = client.logisticas_remessas.obter(id_remessa=501)
+ assert isinstance(response, LogisticasRemessasIdRemessaGetResponse200)
+ assert response.data is not None
+ assert response.data.objetos[0].rastreamento.ultima_alteracao is not None
+ assert response.data.objetos[0].rastreamento.ultima_alteracao.utcoffset() == timedelta(hours=-3)
+
+
+@pytest.mark.parametrize("model_type", TRACKING_MODELS)
+@pytest.mark.parametrize(
+ "value",
+ [None, "", " ", "0000-00-00", "0000-00-00 00:00:00", "0001-01-01", "0001-01-01 00:00:00"],
+)
+def test_tracking_models_accept_absent_timestamp_sentinels(
+ model_type: type[LogisticasObjetosRastreamentoDTO | LogisticasRemessasRastreamentoDTO],
+ value: str | None,
+) -> None:
+ """Absent tracking dates retain other fields and serialize without warnings."""
+ payload = cast("JsonObject", cast("JsonObject", _object_payload()["data"])["rastreamento"])
+ payload["ultimaAlteracao"] = value
+ model = model_type.model_validate(payload)
+ assert model.ultima_alteracao is None
+ assert model.codigo == "SYNTHETIC123"
+ assert model.situacao == 1
+ assert model.model_dump(mode="json", by_alias=True)["ultimaAlteracao"] is None
+ assert "ultimaAlteracao" not in to_json_object(model)
+ payload.pop("ultimaAlteracao")
+ with pytest.raises(ValidationError):
+ model_type.model_validate(payload)
+
+
+def test_logistics_object_resource_accepts_zero_timestamp(httpx_mock: HTTPXMock) -> None:
+ """The zero datetime observed in live objects no longer aborts resource reads."""
+ payload = _object_payload()
+ data = cast("JsonObject", payload["data"])
+ tracking = cast("JsonObject", data["rastreamento"])
+ tracking["ultimaAlteracao"] = "0000-00-00 00:00:00"
+ httpx_mock.add_response(json=payload)
+ with BlingClient(auth=httpx.Auth()) as client:
+ response = client.logisticas_objetos.obter(id_objeto=701)
+ assert response.data is not None
+ assert response.data.rastreamento is not None
+ assert response.data.rastreamento.ultima_alteracao is None
+ assert response.data.nota_fiscal.id == 201
+ assert to_json_object(response.data)["rastreamento"] == {
+ "codigo": "SYNTHETIC123",
+ "descricao": "Em andamento",
+ "situacao": 1,
+ "origem": "São Paulo, SP",
+ "destino": "Curitiba, PR",
+ "url": "https://example.com/tracking",
+ }
diff --git a/tests/unit/test_generate_models_overrides.py b/tests/unit/test_generate_models_overrides.py
index 4f4e4df..052d7ab 100644
--- a/tests/unit/test_generate_models_overrides.py
+++ b/tests/unit/test_generate_models_overrides.py
@@ -472,7 +472,7 @@ def test_schema_module_content_imports_alias_choices_for_inserted_field(
{"ParentDTO": "exemplo", "ChildDTO": "exemplo"},
)
- assert "from pydantic import AliasChoices, AwareDatetime, Field, RootModel" in content
+ assert "from pydantic import AliasChoices, Field, RootModel" in content
assert "validation_alias=AliasChoices('x', 'xStr')" in content
assert "serialization_alias='xStr'" in content
# ``alias='xStr'`` is a substring of ``serialization_alias='xStr'``; the
diff --git a/uv.lock b/uv.lock
index df317e2..473efa6 100644
--- a/uv.lock
+++ b/uv.lock
@@ -112,6 +112,7 @@ dependencies = [
{ name = "pydantic" },
{ name = "pydantic-settings" },
{ name = "python-dotenv" },
+ { name = "tzdata" },
]
[package.dev-dependencies]
@@ -139,6 +140,7 @@ requires-dist = [
{ name = "pydantic", specifier = ">=2.13.4,<3.0.0" },
{ name = "pydantic-settings", specifier = ">=2.14.1,<3.0.0" },
{ name = "python-dotenv", specifier = ">=1.2.2,<2.0.0" },
+ { name = "tzdata", specifier = ">=2025.2" },
]
[package.metadata.requires-dev]
@@ -1124,6 +1126,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
]
+[[package]]
+name = "tzdata"
+version = "2026.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d9/68/f1b440335057bfce71b6e50a9d09445aa2ecbd08359a337976627b8409e7/tzdata-2026.5.tar.gz", hash = "sha256:8cc73c0a0bfca7dbfa59235d60b2eff82231dee33f53d206db1acd9173cfc0a7", size = 200404, upload-time = "2026-10-03T09:23:14.143Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/94/21/1e5995a1c920cce14e4bffae20c665ec10e7ed03ab25e006cd741092b718/tzdata-2026.5-py2.py3-none-any.whl", hash = "sha256:b683bd1b6659ddcd810ff02ad09ba821d4bf1065072805063eb35c49617905ac", size = 347996, upload-time = "2026-10-03T09:23:12.535Z" },
+]
+
[[package]]
name = "urllib3"
version = "2.7.0"