diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d85fb8..e315132 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,6 @@ 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 4d6624f..36b4b82 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -114,23 +114,6 @@ 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 deleted file mode 100644 index 4b7e8c7..0000000 --- a/docs/response-validation-audit.md +++ /dev/null @@ -1,65 +0,0 @@ -# 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 dbeeb7a..7085292 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -64,7 +64,6 @@ 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 e49e29a..e2c9d41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,6 @@ 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 7201f8c..ca39690 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, BlingDatetime" +DATE_IMPORT = "from bling_erp_api.models.fields import BlingDate" # ``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", "", - DATE_IMPORT, + "from bling_erp_api.models.fields import BlingDate", "from typing import TYPE_CHECKING, Any", "", - "from pydantic import AliasChoices, Field, RootModel", + "from pydantic import AliasChoices, AwareDatetime, Field, RootModel", "", "from bling_erp_api.models.base import BlingModel", ] @@ -653,9 +653,11 @@ def _schema_init_content( "", "from __future__ import annotations", "", - DATE_IMPORT, + "from bling_erp_api.models.fields import BlingDate", "from typing import Any", "", + "from pydantic import AwareDatetime", + "", ] for module, names in sorted(by_module.items()): imports = ", ".join(names) @@ -669,7 +671,7 @@ def _schema_init_content( exports + "]", "", "_MODEL_NAMESPACE = {name: globals()[name] for name in __all__}", - "_MODEL_NAMESPACE.update({'Any': Any, 'BlingDate': BlingDate, 'BlingDatetime': BlingDatetime})", + "_MODEL_NAMESPACE.update({'Any': Any, 'AwareDatetime': AwareDatetime, 'BlingDate': BlingDate})", "for _model in _MODEL_NAMESPACE.values():", " if isinstance(_model, type) and hasattr(_model, 'model_rebuild'):", " _model.model_rebuild(_types_namespace=_MODEL_NAMESPACE)", @@ -910,11 +912,10 @@ def _remove_pass_if_empty(node: ast.ClassDef) -> None: def _rewrite_date_types(node: ast.ClassDef) -> None: - """Use Bling date and datetime parsing in generated field annotations.""" - replacements = {"date": "BlingDate", "AwareDatetime": "BlingDatetime"} + """Replace ``date`` with ``BlingDate`` in all field annotations.""" for stmt in ast.walk(node): - if isinstance(stmt, ast.Name) and stmt.id in replacements: - stmt.id = replacements[stmt.id] + if isinstance(stmt, ast.Name) and stmt.id == "date": + stmt.id = "BlingDate" 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 a79cb0d..a86b5c4 100644 --- a/src/bling_erp_api/_version.py +++ b/src/bling_erp_api/_version.py @@ -1,3 +1,3 @@ """Package version.""" -__version__ = "0.3.2" +__version__ = "0.3.1" diff --git a/src/bling_erp_api/models/fields.py b/src/bling_erp_api/models/fields.py index 6f50ab3..f98f5e6 100644 --- a/src/bling_erp_api/models/fields.py +++ b/src/bling_erp_api/models/fields.py @@ -2,11 +2,9 @@ from __future__ import annotations -from datetime import date, datetime +from datetime import date 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 @@ -46,37 +44,3 @@ 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 950ed4c..e167880 100644 --- a/src/bling_erp_api/models/generated/schemas/__init__.py +++ b/src/bling_erp_api/models/generated/schemas/__init__.py @@ -4,9 +4,11 @@ from __future__ import annotations -from bling_erp_api.models.fields import BlingDate, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import Any +from pydantic import AwareDatetime + from .anuncios import ( AnunciosAtributoDTO, AnunciosCategoriaDTO, @@ -1482,7 +1484,7 @@ ] _MODEL_NAMESPACE = {name: globals()[name] for name in __all__} -_MODEL_NAMESPACE.update({"Any": Any, "BlingDate": BlingDate, "BlingDatetime": BlingDatetime}) +_MODEL_NAMESPACE.update({"Any": Any, "AwareDatetime": AwareDatetime, "BlingDate": BlingDate}) 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 80271cf..883e0b5 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 a7c8852..7569a87 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 582fe01..76f7575 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 4ba5be6..32706f6 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 23357e6..83338ad 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 aad13bd..403fe66 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 961e596..868e480 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 000eee3..276468d 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 706f013..1e92d86 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 c3ed5b4..e4f7422 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 2e60abe..888a1fa 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 52f7e0b..20d15f5 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 32ace0d..ed77166 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 0ad5d6d..8dfc91b 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 f996b1b..c4b3163 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 3e66b03..ddc134e 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 98d678a..0aa6163 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 4489366..300533b 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 45563f8..2630c79 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 324a164..f78ce41 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 397e363..c9580fb 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 575b879..c2bf859 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 b247a70..6d573bb 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 4bc15ae..5d22f3c 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 7441715..5bd38ba 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 0ded4e5..a7f09a8 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 8b466bf..2a4e16c 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 876a742..b4a9485 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 ``BlingDatetime``; obrigatório. Data e hora em que ocorreu a atualização de rastreio. + ultima_alteracao: Bling ``ultimaAlteracao``; type ``AwareDatetime``; 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: BlingDatetime = Field( + ultima_alteracao: AwareDatetime = 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 f3f5c4a..aef41a0 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 ``BlingDatetime``; obrigatório. Data e hora em que ocorreu a atualização de rastreio. + ultima_alteracao: Bling ``ultimaAlteracao``; type ``AwareDatetime``; 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: BlingDatetime = Field( + ultima_alteracao: AwareDatetime = 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 dae5471..f2dd1c4 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 5544047..74ba238 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 cd8a22e..0da96ec 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 456b386..4df623b 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 8816e3d..9426903 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 0a10238..996cd28 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 dfecc6b..32ac19e 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 ad2a9dc..f4fc3e7 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 59c6be3..afd1a1d 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 b1e1005..c3415b8 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 8ad641c..b6bbdb5 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 fbfe167..44fa44b 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 a645374..5d17f71 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 54fd8b7..9609483 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 c2bdd3d..88803b8 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 a46c608..a6bbba1 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 be5695d..f47e843 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 a6bec52..cdca098 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 d5fef87..444beb6 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 9206a38..01081db 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 f309336..9db9d1d 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, BlingDatetime +from bling_erp_api.models.fields import BlingDate from typing import TYPE_CHECKING, Any -from pydantic import AliasChoices, Field, RootModel +from pydantic import AliasChoices, AwareDatetime, 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 deleted file mode 100644 index 949eae6..0000000 --- a/tests/fixtures/responses/logisticas_objetos_get.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "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 deleted file mode 100644 index b8fd6c3..0000000 --- a/tests/unit/test_bling_datetime.py +++ /dev/null @@ -1,215 +0,0 @@ -"""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 052d7ab..4f4e4df 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, Field, RootModel" in content + assert "from pydantic import AliasChoices, AwareDatetime, 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 473efa6..df317e2 100644 --- a/uv.lock +++ b/uv.lock @@ -112,7 +112,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "tzdata" }, ] [package.dev-dependencies] @@ -140,7 +139,6 @@ 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] @@ -1126,15 +1124,6 @@ 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"