diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..31f30c6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +# Keep the build context small and avoid leaking sibling repos / local junk. +.git +.github +# Local dev symlinks to sibling repos (would be dangling inside the container). +client-nodejs +client-php +nfeio-docs +# Build/test artifacts (regenerated inside the container). +coverage +pkg +tmp +.bundle +.steep +*.gem +Gemfile.lock +.env diff --git a/.env.docker.example b/.env.docker.example new file mode 100644 index 0000000..ecdd8fc --- /dev/null +++ b/.env.docker.example @@ -0,0 +1,12 @@ +# Copy to .env (one-time) so the container user matches your host UID/GID and +# bind-mount-written files (Gemfile.lock, coverage/) stay owned by you. +# +# cp .env.docker.example .env +# +# On Linux, set these to your own ids: `id -u` and `id -g`. +UID=1000 +GID=1000 + +# Optional SDK credentials forwarded into the container (for future E2E scripts): +# NFE_API_KEY= +# NFE_DATA_API_KEY= diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..96d00ea --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Generated artifacts (from the OpenAPI pipeline) — collapse diffs on GitHub. +lib/nfe/generated/** linguist-generated=true +sig/nfe/generated/** linguist-generated=true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5cd3958 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: CI + +on: + push: + branches: [master, next] + pull_request: + branches: [master, next] + +permissions: + contents: read + +jobs: + test: + name: Ruby ${{ matrix.ruby }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby: ["3.2", "3.3", "3.4"] + steps: + - uses: actions/checkout@v5 + + - name: Set up Ruby ${{ matrix.ruby }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: RSpec (fails if coverage < 80%) + run: bundle exec rspec + + - name: RuboCop + run: bundle exec rubocop + + - name: RBS validate + run: bundle exec rbs validate + + - name: Steep type-check + run: bundle exec steep check + + - name: OpenAPI generated code is in sync + run: bundle exec rake generate:check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..31495fa --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,208 @@ +name: Release + +# Disparado pelo push de uma tag de versão (forma com hífen): +# v1.0.0, v1.0.0-rc.1, v1.0.0-beta.2 +# +# Pipeline: +# verify -> roda o MESMO gate do ci.yml na matrix Ruby 3.2/3.3/3.4. +# publish -> needs: verify; constrói o gem, publica no RubyGems via OIDC +# (trusted publishing) e cria o GitHub Release com o .gem + .sha256. +# +# A versão do gem (Nfe::VERSION) usa a forma com PONTO (1.0.0.rc.1); a tag usa +# a forma com HÍFEN (v1.0.0-rc.1). O job publish deriva a forma pontilhada da +# tag e aborta se o gem construído divergir. + +on: + push: + tags: + - "v*" + +# Permissão mínima no nível do workflow; o job publish eleva o que precisa. +permissions: + contents: read + +jobs: + # --------------------------------------------------------------------------- + # Gate de CI: idêntico ao ci.yml. Falha aqui = release abortado (publish não roda). + # --------------------------------------------------------------------------- + verify: + name: Verify (Ruby ${{ matrix.ruby }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby: ["3.2", "3.3", "3.4"] + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Set up Ruby ${{ matrix.ruby }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: RSpec (fails if coverage < 80%) + run: bundle exec rake spec + + - name: RuboCop + run: bundle exec rubocop + + - name: RBS validate + run: bundle exec rbs validate + + - name: Steep type-check + run: bundle exec steep check + + - name: OpenAPI generated code is in sync + run: bundle exec rake generate:check + + # --------------------------------------------------------------------------- + # Build + publish. Só roda se TODA a matrix verify passar. + # --------------------------------------------------------------------------- + publish: + name: Build & publish to RubyGems + needs: verify + runs-on: ubuntu-latest + permissions: + contents: write # criar o GitHub Release e anexar artefatos + id-token: write # OIDC para RubyGems trusted publishing + # Opcional: para exigir aprovação manual antes de publicar, crie um GitHub + # Environment (Settings > Environments) e descomente a linha abaixo. + # environment: rubygems + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Set up Ruby 3.3 + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + # A tag é a forma com hífen (refs/tags/v1.0.0-rc.1). Derivamos: + # TAG_VERSION = 1.0.0-rc.1 (sem o 'v') + # DOTTED_VERSION = 1.0.0.rc.1 (forma do RubyGems; primeiro '-' vira '.') + # PRERELEASE = true|false (tag contém '-rc.'/'-beta.') + - name: Derive version from tag + id: ver + run: | + set -euo pipefail + tag="${GITHUB_REF_NAME}" + tag_version="${tag#v}" + dotted_version="${tag_version/-/.}" + if [[ "$tag_version" == *-rc.* || "$tag_version" == *-beta.* ]]; then + prerelease=true + else + prerelease=false + fi + { + echo "tag=$tag" + echo "tag_version=$tag_version" + echo "dotted_version=$dotted_version" + echo "prerelease=$prerelease" + } >> "$GITHUB_OUTPUT" + echo "tag=$tag dotted=$dotted_version prerelease=$prerelease" + + # Garante que Nfe::VERSION (e portanto o gem) bate com a tag empurrada. + # Aborta o publish em qualquer divergência ANTES de construir/publicar. + - name: Assert Nfe::VERSION matches tag + run: | + set -euo pipefail + gem_version="$(ruby -r ./lib/nfe/version -e 'print Nfe::VERSION')" + expected="${{ steps.ver.outputs.dotted_version }}" + echo "Nfe::VERSION='$gem_version' esperado='$expected'" + if [[ "$gem_version" != "$expected" ]]; then + echo "::error::Nfe::VERSION ('$gem_version') não bate com a versão derivada da tag ('$expected'). Abortando." + exit 1 + fi + + - name: Build gem + id: build + run: | + set -euo pipefail + gem build nfe-io.gemspec + gem_file="$(ls -1 nfe-io-*.gem | head -n1)" + echo "gem_file=$gem_file" >> "$GITHUB_OUTPUT" + echo "Built $gem_file" + + # Sanidade: a versão DENTRO do .gem construído deve bater com a esperada. + - name: Assert built gem version + run: | + set -euo pipefail + # `gem specification FILE version` imprime o YAML do objeto Gem::Version; + # a linha 'version: X.Y.Z[.rc.N]' carrega o valor. Extraímos esse campo. + built="$(gem specification "${{ steps.build.outputs.gem_file }}" version | awk '/^version:/ {print $2; exit}')" + expected="${{ steps.ver.outputs.dotted_version }}" + echo "gem interno='$built' esperado='$expected'" + if [[ "$built" != "$expected" ]]; then + echo "::error::Versão do gem construído ('$built') != esperada ('$expected'). Abortando." + exit 1 + fi + + - name: Checksum (SHA-256) + run: | + set -euo pipefail + sha256sum "${{ steps.build.outputs.gem_file }}" > "${{ steps.build.outputs.gem_file }}.sha256" + cat "${{ steps.build.outputs.gem_file }}.sha256" + + # Extrai as notas da versão do CHANGELOG (forma pontilhada) para o Release. + - name: Extract changelog notes + id: notes + run: | + set -euo pipefail + ver="${{ steps.ver.outputs.dotted_version }}" + notes_file="RELEASE_NOTES.md" + awk -v ver="$ver" ' + $0 ~ "^## \\[" ver "\\]" { capture = 1; next } + capture && /^## / { exit } + capture { print } + ' CHANGELOG.md > "$notes_file" || true + if [[ ! -s "$notes_file" ]]; then + echo "Release ${{ steps.ver.outputs.tag }}." > "$notes_file" + fi + echo "notes_file=$notes_file" >> "$GITHUB_OUTPUT" + + # ----- Publicação no RubyGems via OIDC (Trusted Publishing) ------------ + # Nenhuma API key de longa duração. Requer um Trusted Publisher cadastrado + # na página do gem nfe-io no RubyGems, vinculado a: + # repository = nfe/client-ruby workflow = release.yml environment = (vazio) + # A action troca o token OIDC do GitHub; o RubyGems confere os claims + # (repo + workflow) contra o Trusted Publisher — sem role-to-assume. + - name: Configure RubyGems credentials (OIDC trusted publishing) + id: oidc + continue-on-error: true + uses: rubygems/configure-rubygems-credentials@v2.1.0 + + - name: Push gem to RubyGems (OIDC) + if: steps.oidc.outcome == 'success' + run: gem push "${{ steps.build.outputs.gem_file }}" + + # ----- Fallback: API key em secret (se OIDC não estiver configurado) ---- + # Ative cadastrando o secret RUBYGEMS_API_KEY no repositório. Só roda se + # o passo OIDC acima falhar (ex.: trusted publisher ainda não vinculado). + - name: Push gem to RubyGems (API key fallback) + if: steps.oidc.outcome != 'success' + env: + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} + run: | + set -euo pipefail + if [[ -z "${GEM_HOST_API_KEY:-}" ]]; then + echo "::error::OIDC trusted publishing indisponível e o secret RUBYGEMS_API_KEY não está configurado. Configure um dos dois." + exit 1 + fi + gem push "${{ steps.build.outputs.gem_file }}" + + # ----- GitHub Release com o .gem + .sha256 ----------------------------- + # Pré-releases (-rc/-beta) são marcadas como prerelease e NÃO viram latest. + - name: Create GitHub Release + uses: softprops/action-gh-release@v2.0.8 + with: + tag_name: ${{ steps.ver.outputs.tag }} + name: ${{ steps.ver.outputs.tag }} + body_path: ${{ steps.notes.outputs.notes_file }} + prerelease: ${{ steps.ver.outputs.prerelease }} + make_latest: ${{ steps.ver.outputs.prerelease == 'false' }} + files: | + ${{ steps.build.outputs.gem_file }} + ${{ steps.build.outputs.gem_file }}.sha256 diff --git a/.gitignore b/.gitignore index d353bbd..86bcc82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,20 @@ /.idea/ /.bundle/ /.yardoc -/Gemfile.lock /_yardoc/ /coverage/ /doc/ +/docs/api/ /pkg/ -/spec/reports/ /tmp/ -/nfe-io-*.gem +/spec/reports/ +Gemfile.lock +*.gem +.env +.steep/ +.rbs_collection.lock +.rbs_collection.yaml +# Local dev symlinks to sibling repos (references / source of truth) — not part of the gem. +/nfeio-docs +/client-nodejs +/client-php diff --git a/.rspec b/.rspec index 8c18f1a..7a2cc1a 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ +--require spec_helper --format documentation --color diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..047bc45 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,126 @@ +plugins: + - rubocop-rspec + +AllCops: + TargetRubyVersion: 3.2 + NewCops: enable + SuggestExtensions: false + Exclude: + - "lib/nfe/generated/**/*" + - "lib/nfe/generated.rb" + - "samples/**/*" + - "docs/**/*" + - "bin/**/*" + - "vendor/**/*" + - "client-nodejs/**/*" + - "client-php/**/*" + - "nfeio-docs/**/*" + +# Double quotes throughout — consistent, matches the existing code, and avoids +# churn when string interpolation is later introduced. +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/QuotedSymbols: + EnforcedStyle: double_quotes + +# Every source file must declare frozen string literals (zero-dep, immutable-first). +Style/FrozenStringLiteralComment: + Enabled: true + EnforcedStyle: always + +# Public API is documented with RDoc prose, not enforced per-class by RuboCop. +Style/Documentation: + Enabled: false + +# Allow Steep/RBS inline type annotations (`#: Type`), which by design have no +# space after the `#`. +Layout/LeadingCommentSpace: + AllowRBSInlineAnnotation: true + +# Keyword-argument constructors (Configuration, Client) are config objects whose +# named options are intentionally many and self-documenting. +Metrics/ParameterLists: + CountKeywordArgs: false + +Metrics/MethodLength: + Max: 25 + +Metrics/AbcSize: + Max: 25 + +Metrics/ClassLength: + Max: 250 + +Metrics/ModuleLength: + Max: 120 + +Metrics/CyclomaticComplexity: + Max: 10 + +Metrics/PerceivedComplexity: + Max: 10 + +# get_* method names intentionally mirror the Node SDK surface (parity). +Naming/AccessorMethodName: + Enabled: false + +Metrics/BlockLength: + Exclude: + - "spec/**/*" + - "*.gemspec" + - "Rakefile" + +# Development dependencies live in the gemspec by design (single source of truth). +Gemspec/DevelopmentDependencies: + Enabled: false + +RSpec/ExampleLength: + Max: 20 + +RSpec/MultipleExpectations: + Max: 10 + +RSpec/MultipleMemoizedHelpers: + Max: 8 + +# Spec files are organized by unit (version_spec, client_spec, ...), not strictly +# by the described constant. +RSpec/SpecFilePathFormat: + Enabled: false + +# Collaborators (logger, transport) are intentionally duck-typed; a verifying +# double cannot be built against a duck type. +RSpec/VerifiedDoubles: + Enabled: false + +# Value objects use `class X < Data.define(...)` (not the `X = Data.define do…end` +# block form) because Steep resolves instance methods to the class only in the +# inheritance form. This cop prefers the block form, so it is disabled. +Style/DataInheritance: + Enabled: false + +# The HTTP Request value object exposes the verb as `request.method`, which +# intentionally shadows Object#method (never relied upon by the value object). +Lint/DataDefineOverride: + Enabled: false + +# `q` is the API's documented free-text search query parameter (productinvoices +# list); allow it as a short keyword-argument name alongside RuboCop's defaults. +Naming/MethodParameterName: + AllowedNames: + - q + - id + - io + - to + - by + - on + - in + - at + - ip + - db + - os + - pp + - ce + - cc + - ph diff --git a/.ruby-gemset b/.ruby-gemset deleted file mode 100644 index 87cf9ea..0000000 --- a/.ruby-gemset +++ /dev/null @@ -1 +0,0 @@ -nfe_io diff --git a/.ruby-version b/.ruby-version index 55bc983..2f4b607 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-2.4.1 +3.4 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1129a5d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: ruby -rvm: - - 2.1.5 -before_install: gem install bundler -v 1.10.6 diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..6140fbf --- /dev/null +++ b/.yardopts @@ -0,0 +1,11 @@ +--template-path docs/yard-theme +--output-dir docs/api +--markup markdown +--readme README.md +--no-private +--title "nfe-io 1.0.0 - SDK Ruby (API)" +--exclude lib/nfe/generated/.* +lib/**/*.rb +- +CHANGELOG.md +MIGRATION.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..6619e6f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,60 @@ +# Changelog + +Todas as mudanças relevantes deste projeto são documentadas aqui. + +O formato segue o [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/), +e o projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/). + +## [Não lançado] + +## [1.0.0] - 2026-07-02 + +### Adicionado + +- `Nfe::Client.new(api_key:)` — entrypoint por instância (estilo Stripe), com fallback de + credencial via `ENV["NFE_API_KEY"]` / `ENV["NFE_DATA_API_KEY"]` (o argumento explícito vence). +- 19 acessores de recurso `snake_case` e lazy — 17 canônicos (`service_invoices`, + `product_invoices`, `consumer_invoices`, `transportation_invoices`, + `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, + `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, + `natural_person_lookup`, `tax_calculation`, `tax_codes`, `state_taxes`) mais 2 RTC + (`service_invoices_rtc`, `product_invoices_rtc`). +- Modelos imutáveis `Data.define` gerados a partir das specs OpenAPI, com assinaturas RBS + (`sig/**/*.rbs`) verificáveis pelo Steep e empacotadas na gem para type-check no consumidor. +- Contrato assíncrono 202 discriminado: `create` retorna um `*Pending` + (`pending? -> true`/`issued? -> false`) ou um `*Issued` (`issued? -> true`); polling via + `retrieve` até `Nfe::FlowStatus.terminal?(flow_status)`. +- Emissão RTC com tributos IBS/CBS/IS (`service_invoices_rtc`, `product_invoices_rtc`). +- Verificação de webhook HMAC-SHA1 sobre os bytes crus da requisição + (`Nfe::Webhook.verify_signature`, comparação timing-safe, nunca levanta exceção) e + `Nfe::Webhook.construct_event`. +- Roteamento multi-host automático por recurso (`api.nfe.io`, `api.nfse.io`, + `address.api.nfe.io`, `legalentity.api.nfe.io`, `naturalperson.api.nfe.io`, `nfe.api.nfe.io`). +- Retry com backoff configurável (`max_retries`) para falhas transitórias. +- Downloads binários (String `ASCII-8BIT`) para a maioria dos recursos; exceção: + `product_invoices` e `product_invoices_rtc` retornam `Nfe::NfeFileResource` (value object `{uri}`). +- `Nfe::DateNormalizer` para normalização consistente de datas. +- Modelo de duas chaves (`api_key` + `data_api_key`) com seleção automática por família de recurso. + +### Alterado + +- Namespace unificado em `Nfe`. +- Piso de Ruby elevado para **3.2+**. +- Paginação suporta os dois estilos da API: por página (`service_invoices`) e por cursor + (`product`/`consumer`/`state_taxes`), via `Nfe::ListResponse`/`Nfe::ListPage`. +- Configuração migrada da API global para `Nfe::Client` por instância — ver `MIGRATION.md`. + +### Removido + +- Dependência de runtime `rest-client`. +- Configuração global `Nfe.api_key`. +- Classes achatadas da série `0.3.x` (ex.: `Nfe::ServiceInvoice.company_id(...).create`), + preservadas no branch `0.x-legacy`. + +## [0.3.2] + +- Última versão da série `0.x` (legada, baseada em `rest-client`). Congelada, sem manutenção. + +[Não lançado]: https://github.com/nfe/client-ruby/compare/v1.0.0...HEAD +[1.0.0]: https://github.com/nfe/client-ruby/compare/v0.3.2...v1.0.0 +[0.3.2]: https://github.com/nfe/client-ruby/releases/tag/v0.3.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7cbc1d8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,115 @@ +# Contribuindo com o `nfe-io` + +Obrigado por contribuir com o SDK Ruby da NFE.io. Este guia cobre branches, +setup local, toolchain, convenções de código, arquivos gerados, commits e a +cadência de release. + +## Branches + +- **`master`** — a `v1` **ativa**. Toda contribuição (features, correções, docs) + vai aqui. +- **`0.x-legacy`** — a série `0.x` **congelada** (baseada em `rest-client`). Não + recebe manutenção nem backports. **PRs contra ela serão fechados.** + +Abra a sua branch a partir de `master` e direcione o PR para `master`. + +## Setup local + +Requer **Ruby 3.2+** (CI roda em 3.2, 3.3 e 3.4). Use um gerenciador de versão: + +```sh +# rbenv +rbenv install 3.3.0 && rbenv local 3.3.0 + +# ou asdf +asdf install ruby 3.3.0 && asdf local ruby 3.3.0 +``` + +Instale as dependências de desenvolvimento (a gem tem **zero dependências de +runtime**; tudo abaixo é só ferramenta de dev): + +```sh +bundle install +# atalho equivalente, se preferir: +bin/setup +``` + +## Toolchain + +| Comando | Faz | +|---|---| +| `bundle exec rake spec` | Roda os testes (RSpec) com gate de cobertura **SimpleCov ≥ 80%**. | +| `bundle exec rake rubocop` | Lint (RuboCop + `rubocop-rspec`). | +| `bundle exec rake steep` | Type-check de `lib/` contra `sig/` (Steep). | +| `bundle exec rake rbs` | Valida as assinaturas RBS em `sig/`. | +| `bundle exec rake generate` | Gera value objects + RBS a partir de `openapi/*.{yaml,json}`. | +| `bundle exec rake generate:check` | Falha se o código gerado divergir das specs OpenAPI. | +| `bundle exec rake` | Pipeline completo: `generate:check` → `spec` → `rubocop` → `steep` → `rbs`. | + +Rode `bundle exec rake` antes de abrir o PR — é o mesmo conjunto de gates que o +CI executa. + +## Convenções de código + +- Todo arquivo `.rb` começa com `# frozen_string_literal: true`. +- **Strings com aspas duplas.** +- Nomes de métodos e variáveis em `snake_case`. +- **Argumentos nomeados** (keyword args) na API pública. +- Value objects **imutáveis** via `Data.define`. +- Documentação e comentários em **pt-BR**. + +O RuboCop é a fonte da verdade para estilo; rode `bundle exec rake rubocop` (e +`-A` para autocorreções seguras) antes de commitar. + +## Arquivos gerados + +Parte do código é **gerado** a partir das specs OpenAPI e **nunca deve ser +editada à mão**: + +- `lib/nfe/generated/**` — value objects gerados. +- A parte gerada de `sig/**` (assinaturas RBS dos modelos). + +Para alterar um modelo gerado: + +1. Atualize a spec correspondente em `openapi/*.{yaml,json}`. +2. Rode `bundle exec rake generate` para regenerar código + RBS. +3. **Commite a spec e o código gerado juntos**, no mesmo PR. + +O CI roda `generate:check` e **falha** se o gerado divergir das specs — ou seja, +um PR que edita o gerado à mão sem atualizar a spec não passa. + +> Os DTOs **escritos à mão** (ex.: `Nfe::Company`, `Nfe::ServiceInvoice`, +> `Nfe::NfeFileResource`) ficam fora de `lib/nfe/generated/` e podem ser editados +> normalmente. + +## Commits + +Use [Conventional Commits](https://www.conventionalcommits.org/pt-br/): + +``` +feat: adiciona suporte a inutilização em lote de NFC-e +fix: corrige extração de invoice_id no Location de 202 +docs: expande seção de webhooks no README +chore(release): 1.1.0 +``` + +Tipos comuns: `feat`, `fix`, `docs`, `chore` (use `chore(release)` para o commit +de release). + +## Fluxo OpenSpec + +Mudanças de contrato/comportamento passam pelo OpenSpec: as propostas ficam em +`openspec/changes/` (e os specs arquivados em `openspec/specs/`). Abra/atualize a +change correspondente ao seu PR quando a alteração mudar o contrato do SDK. + +## Cadência de release + +O projeto segue [SemVer](https://semver.org/lang/pt-BR/): + +- **patch** (`1.0.x`) — correções. Liberadas direto após o CI ficar verde. +- **minor** / **major** — novas capacidades / quebras de contrato. Precedidas de + um ciclo de **release candidate** (`-rc.N`) e **beta** (`-beta.N`) antes do + release estável. + +Atualize o [`CHANGELOG.md`](CHANGELOG.md) (formato Keep a Changelog) no mesmo PR +da mudança. diff --git a/Gemfile b/Gemfile index 327478e..8bf338e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,6 @@ -source 'https://rubygems.org' +# frozen_string_literal: true -# Specify your gem's dependencies in nfe.gemspec +source "https://rubygems.org" + +# Runtime + development dependencies are declared in nfe-io.gemspec. gemspec diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 0000000..01a4339 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,793 @@ +# Guia de migração — `0.x` → `1.0` + +> ⚠️ A `v1.0.0` é uma **reescrita greenfield, sem camada de compatibilidade**. +> Nenhum símbolo da série `0.x` foi mantido. Não existe modo de transição, alias +> ou shim: o código `0.x` **não compila** contra a `1.0`. Migre de forma +> deliberada, recurso a recurso. + +A `0.x` está **congelada** no branch `0.x-legacy` (sem backports — correções e +novos recursos só na `1.0+`). O branch `master` passa a ser a `v1`. + +## Sumário + +A `1.0` substitui o estado global por instância (`Nfe.api_key`, +`Nfe::ServiceInvoice.company_id`) por um **cliente único** (`Nfe::Client`), +remove a dependência `rest-client` (agora **zero dependências de runtime**, +apenas a stdlib), exige **Ruby 3.2+**, troca os objetos dinâmicos por +**value objects imutáveis** (`Data.define`, `snake_case`) e introduz uma +**hierarquia de erros tipada** sob `Nfe::Error`. A emissão de notas passa a ter +um contrato **assíncrono explícito** (resposta `202` → `Pending`/`Issued`). + +--- + +## 1. Visão geral das mudanças + +| Tema | `0.x` (legado) | `1.0` | +|---|---|---| +| Entrada | API global: `Nfe.api_key("...")` + estado por classe | Cliente único: `Nfe::Client.new(api_key: "...")` | +| Configuração | `Nfe.configure { \|c\| c.url = ...; c.user_agent = ... }` | argumentos do construtor de `Nfe::Client` / `Nfe::Configuration` | +| Escopo de empresa | `Nfe::ServiceInvoice.company_id("...")` (estado mutável por classe) | `company_id:` por chamada | +| Roteamento de host | uma única `configuration.url` global | host **roteado por recurso** (multi-host automático) | +| Segunda chave de API | inexistente | `data_api_key:` com fallback para `api_key` | +| HTTP | dependência `rest-client` | zero deps — `Net::HTTP` da stdlib | +| Modelos | `NfeObject` dinâmico (`method_missing`, `reflesh_object`) | value objects imutáveis (`Data.define`), `snake_case` | +| Ruby | 2.x | 3.2 / 3.3 / 3.4 | +| Erros | `Nfe::NfeError` único (`http_status`, `json_message`) | hierarquia tipada sob `Nfe::Error` | +| Emissão | `create` retornava o objeto (sem distinção de `202`) | `create` retorna `*Pending` (202) **ou** `*Issued` (201) | +| Downloads | `download(id, :pdf).body` (objeto RestClient) | `String` binária (`ASCII-8BIT`) — exceto `product_invoices` (→ `NfeFileResource`) | +| Webhooks | esquema legado documentado (`X-NFe-Signature` / SHA-256) — **errado** | `X-Hub-Signature` + HMAC-SHA1 sobre os bytes crus | +| Thread-safety | estado global compartilhado (não seguro) | um `Nfe::Client` é seguro para compartilhar entre threads | + +--- + +## 2. Instalação + +Mudança de major — quebra intencional. + +```ruby +# 0.x — Gemfile +gem "nfe-io", "~> 0.3" + +# 1.0 — Gemfile +gem "nfe-io", "~> 1.0" +``` + +```ruby +# require permanece igual +require "nfe-io" # ou require "nfe" +``` + +A `1.0` **não declara nenhuma dependência de runtime**. As bibliotecas +`rest-client` e `json` (gem) deixam de ser exigidas; a `1.0` usa apenas a +biblioteca padrão: `net/http`, `json`, `openssl`, `uri`, `securerandom`, +`stringio`, `time`, `zlib`, `cgi`, `date`, `base64`. + +## 3. Versão do Ruby + +| | `0.x` | `1.0` | +|---|---|---| +| Ruby mínimo | 2.x | **3.2** (`required_ruby_version = ">= 3.2"`) | +| Testado em CI | — | 3.2, 3.3, 3.4 | + +A `1.0` usa `Data.define` (Ruby 3.2+), métodos de endpoint de uma linha +(`def x = ...`) e argumentos nomeados de forma generalizada. Não há +compatibilidade com Ruby 2.x. + +--- + +## 4. Configuração + +### 4.1 Chave de API e cliente + +Na `0.x`, a chave era um estado **global de processo** e a empresa um estado +**mutável por classe**. Na `1.0`, ambos são explícitos: a chave vai no +construtor do `Nfe::Client` e a empresa em cada chamada. + +```ruby +# 0.x — estado global + estado por classe +Nfe.api_key("c73d49f9649046eeba36dcf69f6334fd") +Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") + +# 1.0 — cliente único; nenhum estado global +client = Nfe::Client.new(api_key: "c73d49f9649046eeba36dcf69f6334fd") +``` + +Construtor completo (todos os argumentos são nomeados, com os defaults reais): + +```ruby +client = Nfe::Client.new( + api_key: "...", # chave principal; fallback ENV NFE_API_KEY + data_api_key: nil, # chave de dados; fallback ENV NFE_DATA_API_KEY + environment: :production, # SÍMBOLO :production|:development (reservado p/ uso futuro) + timeout: 30, # read timeout (segundos) + max_retries: 3, # tentativas após a inicial + logger: nil, # objeto com #info/#warn/#error + user_agent_suffix: nil # sufixo anexado ao User-Agent do SDK +) +``` + +> **`environment:` está reservado para uso futuro.** Hoje é validado mas não +> altera endpoints, chaves ou comportamento. A separação produção/teste +> (homologação) é definida na configuração da sua conta em https://app.nfe.io +> (lado servidor) — não pela chave de API nem pelo SDK; não existe "URL de +> sandbox". É um **símbolo** (`:production`), não uma string. + +#### Fallback por variável de ambiente + +A chave pode vir do argumento **ou** do ambiente — o argumento explícito sempre +vence; um valor vazio é tratado como ausente. + +```ruby +ENV["NFE_API_KEY"] # usado por api_key quando o argumento é nil/vazio +ENV["NFE_DATA_API_KEY"] # usado por data_api_key quando o argumento é nil/vazio +``` + +#### Configuração avançada + +Argumentos que não estão no atalho do `Client` (como `open_timeout`, +`base_url_overrides`, `ca_file`, `ca_path`, `proxy`) vivem em +`Nfe::Configuration`. Monte a configuração e injete-a: + +```ruby +config = Nfe::Configuration.new( + api_key: "...", + open_timeout: 10, # connect timeout (s) + base_url_overrides: { main: "https://api.exemplo" }, # escape hatch por família + ca_file: "/caminho/ca-bundle.crt", # ADICIONA CAs ao trust store + proxy: "http://proxy.interno:3128" +) +client = Nfe::Client.new(configuration: config) +# quando configuration: é passado, os demais atalhos do Client são ignorados. +``` + +> **TLS:** `ca_file`/`ca_path` só **adicionam/substituem** o bundle de CAs usado +> para verificar o servidor. **Não existe** API para desativar a verificação do +> peer (sem `VERIFY_NONE`, sem `insecure_ssl`). + +### 4.2 Configuração global → por instância + +| `0.x` | `1.0` | +|---|---| +| `Nfe.api_key("...")` | `Nfe::Client.new(api_key: "...")` | +| `Nfe.configure { \|c\| c.url = "..." }` | `Nfe::Configuration.new(base_url_overrides: { ... })` | +| `Nfe.configure { \|c\| c.user_agent = "..." }` | `Nfe::Client.new(user_agent_suffix: "...")` | +| `Nfe.configuration` / `Nfe.access_keys` | (removidos — sem estado global) | +| `Nfe::Configuration#url` (uma URL única) | host roteado por recurso (ver §4.4) | + +### 4.3 Escopo de empresa: por classe → por chamada + +```ruby +# 0.x — estado mutável por classe (não seguro entre threads) +Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") +Nfe::ServiceInvoice.create(params) + +# 1.0 — company_id é argumento de cada chamada +client.service_invoices.create(company_id: "55df4dc6b6cd9007e4f13ee8", data: { ... }) +``` + +### 4.4 URL global → roteamento por recurso + +Na `0.x` havia uma única `configuration.url` (`https://api.nfe.io`). Na `1.0` +**cada recurso declara sua família** e o host é resolvido automaticamente — você +não monta mais URLs. + +| Família / host | Recursos roteados | +|---|---| +| `https://api.nfe.io` (`/v1`) | `service_invoices`, `companies`, `legal_people`, `natural_people`, `webhooks`, `service_invoices_rtc` | +| `https://api.nfse.io` (`/v2`) | `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `tax_calculation`, `tax_codes`, `state_taxes`, `product_invoices_rtc` | +| `https://address.api.nfe.io/v2` | `addresses` | +| `https://legalentity.api.nfe.io` | `legal_entity_lookup` | +| `https://naturalperson.api.nfe.io` | `natural_person_lookup` | +| `https://nfe.api.nfe.io` | `product_invoice_query`, `consumer_invoice_query` | + +Para sobrescrever um host (ambiente de testes, proxy reverso), use +`base_url_overrides:` em `Nfe::Configuration` (chave = símbolo da família). + +### 4.5 Segunda chave de API (`data_api_key`) + +Novidade da `1.0`. As **famílias de dados** preferem `data_api_key` e caem para +`api_key` quando ela não é informada; todas as outras usam `api_key`. + +```ruby +client = Nfe::Client.new(api_key: "EMISSAO", data_api_key: "CONSULTA") +``` + +Famílias que usam `data_api_key` (com fallback para `api_key`): + +- `addresses` (consulta de endereços) +- `legal_entity_lookup` (consulta de pessoa jurídica) +- `natural_person_lookup` (consulta de pessoa física) +- `product_invoice_query` e `consumer_invoice_query` (consulta de NF-e/NFC-e) + +> ⚠️ A família `:cte` (`api.nfse.io` — emissão de NF-e/NFC-e/CT-e + tax-rules / +> tax-codes / state-taxes) usa a **`api_key` principal** e **não** é uma família +> de dados. Isso é uma divergência deliberada do SDK Node (que roteia +> `api.nfse.io` pela cadeia de fallback da chave de dados) — documentada em +> `lib/nfe/configuration.rb`. + +--- + +## 5. Mapeamento de classes (`0.x` → acessores da `1.0`) + +Na `0.x` você chamava métodos de classe diretamente (`Nfe::ServiceInvoice`, +`Nfe::Company`, ...). Na `1.0` tudo passa pelos **acessores `snake_case`**, +preguiçosos e memoizados, do `Nfe::Client`. + +| Classe `0.x` | Acessor `1.0` | +|---|---| +| `Nfe::ServiceInvoice` | `client.service_invoices` | +| `Nfe::Company` | `client.companies` | +| `Nfe::NaturalPeople` | `client.natural_people` | +| `Nfe::LegalPeople` | `client.legal_people` | +| `Nfe::NfeObject` (base dinâmica) | value objects imutáveis (`Nfe::ServiceInvoice`, `Nfe::Company`, ... — apenas leitura) | +| `Nfe::NfeError` | hierarquia `Nfe::Error` (ver §10) | + +A `1.0` expõe **19 acessores** (17 canônicos + 2 addons RTC), muito além das +classes da `0.x`: + +``` +service_invoices product_invoice_query legal_entity_lookup +product_invoices consumer_invoice_query natural_person_lookup +consumer_invoices companies tax_calculation +transportation_invoices legal_people tax_codes +inbound_product_invoices natural_people state_taxes +webhooks addresses +service_invoices_rtc product_invoices_rtc (addons RTC) +``` + +> ⚠️ Note a colisão de nomes: na `0.x`, `Nfe::ServiceInvoice` e `Nfe::Company` +> eram classes **ativas** (com métodos de criação). Na `1.0`, `Nfe::ServiceInvoice` +> e `Nfe::Company` são apenas **value objects de leitura**; o comportamento mora +> nos acessores `client.service_invoices` / `client.companies`. + +--- + +## 6. Mapeamento de métodos por recurso + +As notações abaixo refletem as assinaturas reais implementadas. Na `0.x`, os +recursos compartilhavam operações genéricas (`ApiOperations::Create`, `List`, +`Retrieve`, `Cancel`, `Update`, `Download`). Na `1.0`, cada método é explícito. + +### 6.1 Service invoices (NFS-e) — `client.service_invoices` + +| `0.x` | `1.0` | +|---|---| +| `Nfe::ServiceInvoice.create(params)` | `client.service_invoices.create(company_id:, data:, idempotency_key: nil, request_options: nil)` | +| `Nfe::ServiceInvoice.list_all(params)` | `client.service_invoices.list(company_id:, **options)` | +| `Nfe::ServiceInvoice.retrieve(id)` | `client.service_invoices.retrieve(company_id:, invoice_id:)` | +| `Nfe::ServiceInvoice.cancel(id)` | `client.service_invoices.cancel(company_id:, invoice_id:)` | +| `Nfe::ServiceInvoice.update(...)` | `client.service_invoices.send_email(company_id:, invoice_id:)` (e demais ações dedicadas) | +| `Nfe::ServiceInvoice.download(id, :pdf)` | `client.service_invoices.download_pdf(company_id:, invoice_id: nil)` | +| `Nfe::ServiceInvoice.download(id, :xml)` | `client.service_invoices.download_xml(company_id:, invoice_id: nil)` | +| — (sem equivalente) | `client.service_invoices.get_status(company_id:, invoice_id:)` → `StatusResult` | + +Opções de `list`: `page_index`, `page_count`, `issued_begin`, `issued_end`, +`created_begin`, `created_end`, `has_totals` (paginação **page-style**). +`download_pdf`/`download_xml` com `invoice_id: nil` baixam o **ZIP** da empresa. + +### 6.2 Companies — `client.companies` + +| `0.x` | `1.0` | +|---|---| +| `Nfe::Company.create(params)` | `client.companies.create(data)` | +| `Nfe::Company.list_all(params)` | `client.companies.list(page_index: 0, page_count: 100)` | +| — | `client.companies.list_all` / `client.companies.list_each` (auto-paginação) | +| `Nfe::Company.retrieve(id)` | `client.companies.retrieve(company_id)` | +| `Nfe::Company.update(...)` | `client.companies.update(company_id, data)` | +| `Nfe::Company` + `ApiOperations::Delete` (`delete`) | `client.companies.remove(company_id)` → `{ deleted: true, id: }` | +| — | `client.companies.find_by_tax_number(tax_number)` | +| — | `client.companies.find_by_name(name)` | + +Certificado digital (novo na `1.0`): + +```ruby +client.companies.validate_certificate(file:, password:) # local, sem HTTP +client.companies.upload_certificate(company_id, file:, password:, filename: nil) +client.companies.replace_certificate(company_id, file:, password:, filename: nil) # alias de upload +client.companies.get_certificate_status(company_id) +client.companies.check_certificate_expiration(company_id, threshold_days: 30) +client.companies.get_companies_with_certificates +client.companies.get_companies_with_expiring_certificates(threshold_days: 30) +``` + +> ⚠️ **`delete` virou `remove`.** Em `companies`, a remoção chama-se `#remove` +> (paridade com os SDKs Node/PHP), não `#delete`. + +### 6.3 Legal people (PJ) — `client.legal_people` + +| `0.x` | `1.0` | +|---|---| +| `Nfe::LegalPeople.company_id(id)` + `list_all` | `client.legal_people.list(company_id)` | +| `Nfe::LegalPeople.retrieve(id)` | `client.legal_people.retrieve(company_id, legal_person_id)` | +| — (não existia na `0.x`) | `client.legal_people.create(company_id, data)` | +| — | `client.legal_people.update(company_id, legal_person_id, data)` | +| — | `client.legal_people.delete(company_id, legal_person_id)` | +| — | `client.legal_people.create_batch(company_id, list)` (sequencial) | +| — | `client.legal_people.find_by_tax_number(company_id, federal_tax_number)` | + +### 6.4 Natural people (PF) — `client.natural_people` + +| `0.x` | `1.0` | +|---|---| +| `Nfe::NaturalPeople.company_id(id)` + `list_all` | `client.natural_people.list(company_id)` | +| `Nfe::NaturalPeople.retrieve(id)` | `client.natural_people.retrieve(company_id, natural_person_id)` | +| — | `client.natural_people.create(company_id, data)` | +| — | `client.natural_people.update(company_id, natural_person_id, data)` | +| — | `client.natural_people.delete(company_id, natural_person_id)` | +| — | `client.natural_people.create_batch(company_id, list)` | +| — | `client.natural_people.find_by_tax_number(company_id, federal_tax_number)` | + +### 6.5 Recursos novos na `1.0` (sem equivalente na `0.x`) + +Product invoices (NF-e) — `client.product_invoices`: + +```ruby +create(company_id:, data:, idempotency_key: nil, request_options: nil) +create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) +list(company_id:, environment:, **options) # environment: "Production"/"Test" OBRIGATÓRIO +retrieve(company_id:, invoice_id:) +cancel(company_id:, invoice_id:, reason: nil) +list_items(company_id:, invoice_id:, limit: nil, starting_after: nil) +list_events(company_id:, invoice_id:, limit: nil, starting_after: nil) +send_correction_letter(company_id:, invoice_id:, reason:) # reason 15..1000 chars +disable(company_id:, invoice_id:, reason: nil) +disable_range(company_id:, data:) +download_pdf / download_xml / download_rejection_xml / download_epec_xml # → NfeFileResource (URI) +download_correction_letter_pdf / download_correction_letter_xml # → NfeFileResource (URI) +``` + +Consumer invoices (NFC-e) — `client.consumer_invoices`: `create`, +`create_with_state_tax`, `list`, `retrieve`, `cancel`, `list_items`, +`list_events`, `disable_range`, `download_pdf`, `download_xml`, +`download_rejection_xml`. (Sem `send_correction_letter`, `download_epec_xml` ou +`disable` por documento — restrições da legislação para NFC-e.) + +Transportation invoices (CT-e recebidos) — `client.transportation_invoices`: +`enable`, `disable`, `get_settings`, `retrieve(company_id:, access_key:)`, +`download_xml`, `get_event`, `download_event_xml`. + +Inbound product invoices (NF-e recebidas) — `client.inbound_product_invoices`: +`enable_auto_fetch`, `disable_auto_fetch`, `get_settings`, `get_details`, +`get_product_invoice_details`, `get_event_details`, +`get_product_invoice_event_details`, `get_xml`, `get_event_xml`, `get_pdf`, +`get_json`, `manifest(company_id:, access_key:, tp_event: 210210)`, +`reprocess_webhook`. + +Consultas — `client.product_invoice_query`: `retrieve(access_key)`, +`download_pdf(access_key)`, `download_xml(access_key)`, +`list_events(access_key)`. `client.consumer_invoice_query`: +`retrieve(access_key)`, `download_xml(access_key)`. + +Lookups (famílias de dados): + +```ruby +client.addresses.lookup_by_postal_code(cep) +client.addresses.lookup_by_term(term) +client.addresses.search(filter: nil) +client.legal_entity_lookup.get_basic_info(cnpj, update_address: nil, update_city_code: nil) +client.legal_entity_lookup.get_state_tax_info(state, cnpj) +client.legal_entity_lookup.get_state_tax_for_invoice(state, cnpj) +client.legal_entity_lookup.get_suggested_state_tax_for_invoice(state, cnpj) +client.natural_person_lookup.get_status(cpf, birth_date) +``` + +Fiscais (família `:cte`): + +```ruby +client.tax_calculation.calculate(tenant_id, request) # request: Hash +client.tax_codes.list_operation_codes(page_index: nil, page_count: nil) +client.tax_codes.list_acquisition_purposes(...) +client.tax_codes.list_issuer_tax_profiles(...) +client.tax_codes.list_recipient_tax_profiles(...) +client.state_taxes.list(company_id, starting_after: nil, ending_before: nil, limit: nil) +client.state_taxes.create(company_id, data) +client.state_taxes.retrieve(company_id, state_tax_id) +client.state_taxes.update(company_id, state_tax_id, data) +client.state_taxes.delete(company_id, state_tax_id) +``` + +RTC (Reforma Tributária do Consumo) — addons da `1.0`: +`client.service_invoices_rtc` (`create`, `retrieve`, `cancel`, +`download_cancellation_xml`) e `client.product_invoices_rtc` (mesmo conjunto do +`product_invoices`). O layout RTC é selecionado pela **presença do grupo +`ibsCbs`** (NFS-e) ou `items[].tax.IBSCBS` (NF-e/NFC-e) no payload — mesmo +endpoint dos recursos clássicos, sem header/param discriminador. + +> ⚠️ **`list` de product invoices exige `environment:`.** Em +> `client.product_invoices.list` e `client.product_invoices_rtc.list`, +> `environment:` é uma **String separada** (`"Production"`/`"Test"`), +> **distinta** do `environment:` do `Client` (que é um símbolo e seleciona a +> chave). Omiti-la levanta `Nfe::InvalidRequestError`. + +--- + +## 7. Remoção do `rest-client` + +A `0.x` dependia da gem `rest-client`; a `1.0` usa `Net::HTTP` da stdlib. Toda +exceção do `rest-client` que vazava do SDK desaparece. + +| `0.x` (`rest-client`) | `1.0` | +|---|---| +| `RestClient::Exception` (rede/conexão) | `Nfe::ApiConnectionError` | +| timeout de conexão/leitura | `Nfe::TimeoutError` (subclasse de `ApiConnectionError`) | +| `RestClient::ExceptionWithResponse` (HTTP 4xx/5xx) | subclasse de `Nfe::Error` por status (ver §10) | +| `request.execute` retornando o objeto-resposta | objetos hidratados (`Data.define`) ou bytes (downloads) | + +```ruby +# 0.x +begin + Nfe::ServiceInvoice.create(params) +rescue RestClient::Exception => e + # tratar erro de rede/HTTP +end + +# 1.0 +begin + client.service_invoices.create(company_id:, data:) +rescue Nfe::ApiConnectionError => e # rede (inclui TimeoutError) + # ... +rescue Nfe::Error => e # qualquer erro do SDK + # ... +end +``` + +--- + +## 8. Tratamento de erros + +A `0.x` tinha um único `Nfe::NfeError(http_status, json_message, http_message, +message)`. A `1.0` traz uma **hierarquia tipada** sob `Nfe::Error` — capture a +base para pegar toda a família, ou subclasses específicas para tratar casos. + +```ruby +begin + client.service_invoices.create(company_id:, data:) +rescue Nfe::RateLimitError => e + sleep(e.retry_after || 5); retry +rescue Nfe::InvalidRequestError => e + logger.warn(e.to_h) # to_h é seguro para log (sem corpo/headers crus) +rescue Nfe::Error => e + # rede comum: status_code, request_id, error_code, response_body, response_headers +end +``` + +| Classe `1.0` | Status HTTP | Quando | +|---|---|---| +| `Nfe::Error` | — | base de toda a hierarquia | +| `Nfe::AuthenticationError` | 401 | chave ausente ou inválida | +| `Nfe::AuthorizationError` | 403 | chave válida, mas sem permissão | +| `Nfe::InvalidRequestError` | 400 / 422 | requisição malformada ou inválida | +| `Nfe::NotFoundError` | 404 | recurso inexistente | +| `Nfe::ConflictError` | 409 | conflito com o estado atual | +| `Nfe::RateLimitError` | 429 | excesso de requisições (`#retry_after`) | +| `Nfe::ServerError` | 5xx | falha do servidor | +| `Nfe::ApiConnectionError` | — | falha de rede (DNS, conexão, TLS, reset) | +| `Nfe::TimeoutError` | — | timeout (subclasse de `ApiConnectionError`) | +| `Nfe::SignatureVerificationError` | — | assinatura de webhook inválida ou payload não-JSON | +| `Nfe::ConfigurationError` | — | SDK mal configurado (chave ausente, `environment` inválido) — antes de qualquer HTTP | +| `Nfe::InvoiceProcessingError` | — | resposta `202` sem `Location` utilizável | + +Atributos disponíveis em erros derivados de resposta: `status_code`, +`request_id`, `error_code`, `response_body`, `response_headers`. O método +`#to_h` é **seguro para log** (omite `response_body`/`response_headers`, que +podem conter segredos/PII). + +> ⚠️ Nomes que **não existem**: `Nfe::ConnectionError`, `Nfe::ValidationError`, +> `Nfe::PollingTimeoutError`. Use os nomes da tabela acima. + +--- + +## 9. Respostas `202` (emissão assíncrona) + +Na `0.x`, `create` simplesmente devolvia o objeto, sem distinguir emissão +síncrona de assíncrona. Na `1.0` o contrato é explícito: `create` retorna um +**resultado discriminado**. + +- **HTTP 202** → `*Pending` (`invoice_id`, `location`; `pending? == true`, + `issued? == false`). A nota está enfileirada; o `invoice_id` vem do header + `Location`. +- **HTTP 201/200** → `*Issued` (`resource`; `issued? == true`, + `pending? == false`). A nota foi materializada na hora. + +(Recursos: `ServiceInvoicePending`/`ServiceInvoiceIssued`, +`ProductInvoicePending`/`ProductInvoiceIssued`, e as variantes Consumer e RTC.) + +```ruby +result = client.service_invoices.create(company_id:, data:) + +case result +in Nfe::Resources::ServiceInvoicePending => pending + # acompanhar via polling (ver abaixo) +in Nfe::Resources::ServiceInvoiceIssued => issued + nota = issued.resource +end +``` + +### Loop de polling + +Não há `create_and_wait`/`create_batch` na `1.0` (ver §12). Faça o polling +manualmente com `Nfe::FlowStatus.terminal?`: + +```ruby +result = client.service_invoices.create(company_id:, data:) + +if result.pending? + invoice = nil + loop do + invoice = client.service_invoices.retrieve( + company_id:, invoice_id: result.invoice_id + ) + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + sleep 2 + end + # invoice.flow_status ∈ Issued | IssueFailed | Cancelled | CancelFailed +end +``` + +Estados **terminais** (param o polling): `Issued`, `IssueFailed`, `Cancelled`, +`CancelFailed`. Para `service_invoices` há ainda o atalho +`client.service_invoices.get_status(company_id:, invoice_id:)`, que devolve um +`StatusResult` com `#complete?` e `#failed?` (derivado de `retrieve`, sem HTTP +extra além do `retrieve`). + +--- + +## 10. Verificação de webhook + +> ⚠️ A documentação **antiga** falava em header `X-NFe-Signature`, HMAC-**SHA256** +> e Base64. **Isso está errado** para o SDK `1.0` (e para o que a NFE.io de fato +> envia). O esquema correto é `X-Hub-Signature` + HMAC-**SHA1** sobre os **bytes +> crus** do corpo, em hex. + +A verificação é **estática** (não precisa de `Nfe::Client`, não lê configuração, +não faz rede): + +```ruby +raw = request.body.read # BYTES CRUS — leia ANTES de parsear o JSON +sig = request.get_header("HTTP_X_HUB_SIGNATURE") # ou request.headers["X-Hub-Signature"] + +if Nfe::Webhook.verify_signature(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) + event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) + # event.type, event.data, event.id, event.created_at +end +``` + +Pontos críticos: + +- **Bytes crus.** A NFE.io assina exatamente os bytes que entregou. Leia + `request.body.read` (ou `request.raw_post`) **antes** de parsear. **Nunca** + re-serialize um objeto parseado (`payload.to_json`) — ordem de chaves e espaços + diferem dos bytes assinados e a verificação falha de forma imprevisível. +- **HMAC-SHA1, hex, prefixo `sha1=`.** Comparação **case-insensitive** e + **timing-safe** (`OpenSSL.secure_compare`). Um header `sha256=` é rejeitado. +- **`verify_signature` NUNCA levanta exceção:** retorna `false` para qualquer + entrada ausente, malformada, algoritmo errado ou não-hex. +- **`construct_event` levanta `Nfe::SignatureVerificationError`** quando a + assinatura não confere ou o payload não é JSON válido. +- **Validade ≠ frescor.** A NFE.io não envia timestamp/nonce anti-replay. Uma + assinatura válida prova autenticidade, **não** frescor — seus handlers + **precisam ser idempotentes** e deduplicar por `event.id` (ou pelo id da nota). + +Há ainda o atalho `client.webhooks.verify_signature(payload:, signature:, +secret:)`, mera delegação a `Nfe::Webhook` (a API canônica é o módulo). + +--- + +## 11. Downloads + +Na `0.x`, `download(id, :pdf)` retornava o objeto de resposta do `rest-client` +(você acessava `.body`). Na `1.0`, os métodos de download retornam a **`String` +binária** diretamente (encoding `ASCII-8BIT`), pronta para `File.binwrite` ou +`send_data`. + +```ruby +# 0.x +bytes = Nfe::ServiceInvoice.download("59443a...", :pdf).body + +# 1.0 — String binária (bytes), sem .body +bytes = client.service_invoices.download_pdf(company_id: "55df...", invoice_id: "59443a...") +File.binwrite("nota.pdf", bytes) +``` + +Retornam `String` binária (`ASCII-8BIT`): `service_invoices`, +`consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, +`product_invoice_query`, `consumer_invoice_query` (e +`service_invoices_rtc.download_cancellation_xml`). + +> ⚠️ **Exceção — `product_invoices` e `product_invoices_rtc`.** Seus +> `download_*` **não** retornam bytes: retornam um `Nfe::NfeFileResource` (value +> object com `uri`, `name`, `content_type`, `size`). O host `api.nfse.io/v2` +> responde com um envelope JSON `{ uri }` apontando para o arquivo — baixe os +> bytes a partir de `resource.uri` por conta própria. + +```ruby +file = client.product_invoices.download_pdf(company_id:, invoice_id:) +file.uri # => "https://.../danfe.pdf" (não são bytes) +``` + +--- + +## 12. Recursos diferidos na `1.0` + +Funcionalidades que existiam (ou se esperariam) e foram **deliberadamente +adiadas** na `1.0`, com o respectivo contorno: + +| Diferido | Contorno na `1.0` | +|---|---| +| `create_and_wait` (emitir e aguardar) | emitir + loop de polling com `Nfe::FlowStatus.terminal?` (ver §9) | +| `create_batch` para notas | iterar `create` na sua aplicação (há `create_batch` apenas em `legal_people`/`natural_people`, e sequencial) | +| `getStatus` como chamada dedicada | derivado de `retrieve`: `client.service_invoices.get_status(...)` (sem HTTP extra) ou `Nfe::FlowStatus.terminal?(invoice.flow_status)` | +| upload/replace de certificado via multipart "rico" | `upload_certificate` / `replace_certificate` já existem (multipart simples + validação local fail-fast); não há ainda fluxo multipart estendido | +| `validate` de certificado server-side | `validate_certificate(file:, password:)` valida **localmente** (sem HTTP) | + +--- + +## Apêndice A — Exemplo vanilla, lado a lado (emissão de NFS-e + polling) + +### `0.x` + +```ruby +require "nfe-io" + +Nfe.api_key("c73d49f9649046eeba36dcf69f6334fd") +Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") + +invoice = Nfe::ServiceInvoice.create( + borrower: { name: "Cliente Exemplo", federalTaxNumber: 12_345_678_000_199 }, + cityServiceCode: "2690", + description: "Serviço de consultoria", + servicesAmount: 100.0 +) + +# sem distinção de 202; sem contrato de polling padronizado +pdf = Nfe::ServiceInvoice.download(invoice["id"], :pdf).body +File.open("nota.pdf", "wb") { |f| f.write(pdf) } +``` + +### `1.0` + +```ruby +require "nfe-io" + +client = Nfe::Client.new(api_key: "c73d49f9649046eeba36dcf69f6334fd") +company_id = "55df4dc6b6cd9007e4f13ee8" + +result = client.service_invoices.create( + company_id: company_id, + data: { + borrower: { name: "Cliente Exemplo", federalTaxNumber: "12345678000199" }, + cityServiceCode: "2690", + description: "Serviço de consultoria", + servicesAmount: 100.0 + } +) + +invoice = + if result.pending? + loop do + current = client.service_invoices.retrieve( + company_id: company_id, invoice_id: result.invoice_id + ) + break current if Nfe::FlowStatus.terminal?(current.flow_status) + sleep 2 + end + else + result.resource + end + +unless invoice.flow_status == "Issued" + raise "emissão falhou: #{invoice.flow_status}" +end + +bytes = client.service_invoices.download_pdf( + company_id: company_id, invoice_id: invoice.id +) +File.binwrite("nota.pdf", bytes) +``` + +--- + +## Apêndice B — Exemplo Rails + +### Initializer (`config/initializers/nfe.rb`) — `Nfe::Client` memoizado + +Um único `Nfe::Client` é **seguro para compartilhar entre threads** (cada +acessor de recurso e cada transport é memoizado sob `Mutex`). Memoize-o: + +```ruby +# config/initializers/nfe.rb +require "nfe-io" + +module NfeClient + def self.instance + @instance ||= Nfe::Client.new( + api_key: Rails.application.credentials.dig(:nfe, :api_key), + data_api_key: Rails.application.credentials.dig(:nfe, :data_api_key), + environment: Rails.env.production? ? :production : :development, + logger: Rails.logger + ) + end +end +``` + +### Controller de webhook — validando sobre `request.raw_post` + +```ruby +# app/controllers/nfe_webhooks_controller.rb +class NfeWebhooksController < ApplicationController + skip_before_action :verify_authenticity_token + + def create + raw = request.raw_post # BYTES CRUS — não parsear antes + sig = request.headers["X-Hub-Signature"] + secret = Rails.application.credentials.dig(:nfe, :webhook_secret) + + event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: secret) + + # idempotência: a NFE.io não envia anti-replay — deduplique por event.id + return head(:ok) if WebhookReceipt.exists?(event_id: event.id) + WebhookReceipt.create!(event_id: event.id, event_type: event.type) + + ProcessNfeEventJob.perform_later(event.type, event.data) + head :ok + rescue Nfe::SignatureVerificationError + head :bad_request + end +end +``` + +--- + +## Resumo de breaking changes + +**Entrada e configuração** + +- Removido o estado global: `Nfe.api_key`, `Nfe.configure`, `Nfe.configuration`, + `Nfe.access_keys`. Use `Nfe::Client.new(api_key:)`. +- Removido o estado mutável por classe (`Nfe::ServiceInvoice.company_id(...)`). + `company_id:` agora é argumento de cada chamada. +- Removida a URL global única; o host é roteado por recurso (multi-host). +- Novo `data_api_key:` (com fallback para `api_key`) para famílias de dados. +- `environment:` (`:production`/`:development`) é um **símbolo reservado para uso + futuro** — hoje sem efeito; produção/teste é definido na conta em app.nfe.io. + +**Dependências e runtime** + +- Removida a dependência `rest-client` (e a gem `json`). Zero deps de runtime. +- Ruby mínimo passa de 2.x para **3.2**. + +**Modelos e API** + +- `NfeObject` dinâmico → value objects imutáveis (`Data.define`), atributos + `snake_case`. +- `Nfe::ServiceInvoice`/`Nfe::Company` deixam de ser classes ativas e viram + value objects de leitura; o comportamento mora nos acessores do `Client`. +- `companies` usa `#remove` (não `#delete`). +- `create` de notas retorna um resultado discriminado `*Pending`/`*Issued` + (antes retornava o objeto direto). +- `list` de `product_invoices`/`product_invoices_rtc` exige `environment:` + (String `"Production"`/`"Test"`). + +**Erros** + +- `Nfe::NfeError` único → hierarquia tipada sob `Nfe::Error`. +- Exceções do `rest-client` → `Nfe::ApiConnectionError`/`Nfe::TimeoutError`. + +**Webhooks** + +- Esquema corrigido para `X-Hub-Signature` + HMAC-SHA1 sobre bytes crus + (documentação antiga com `X-NFe-Signature`/SHA-256/Base64 estava errada). +- Handlers precisam ser idempotentes (sem anti-replay no provedor). + +**Downloads** + +- Retorno passa a ser `String` binária (`ASCII-8BIT`), sem `.body`. +- Exceção: `product_invoices`/`product_invoices_rtc` retornam + `Nfe::NfeFileResource` (`uri`), não bytes. + +**Recursos diferidos** + +- Sem `create_and_wait`/`create_batch` para notas; faça polling com + `Nfe::FlowStatus.terminal?`. + + diff --git a/README.md b/README.md index 37b4340..b05a3e1 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,445 @@ -# Cliente Ruby para emissão de notas fiscais - NFe.io +# nfe-io — SDK Ruby oficial da NFE.io -## Onde acessar a documentação da API? +> Emissão e gestão de documentos fiscais eletrônicos brasileiros (NFS-e, NF-e, +> NFC-e, CT-e) em Ruby, com ergonomia estilo Stripe e **zero dependências de runtime**. -> Acesse a [nossa documentação](https://nfe.io/doc/rest-api/nfe-v1) para mais detalhes e referências. +[![Versão da gem](https://img.shields.io/gem/v/nfe-io.svg)](https://rubygems.org/gems/nfe-io) +[![CI](https://github.com/nfe/client-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/nfe/client-ruby/actions/workflows/ci.yml) +[![Cobertura](https://img.shields.io/badge/cobertura-%E2%89%A580%25-brightgreen.svg)](https://github.com/nfe/client-ruby/actions/workflows/ci.yml) +[![Licença: MIT](https://img.shields.io/badge/licen%C3%A7a-MIT-blue.svg)](LICENSE.txt) -## Como realizar a instalação do pacote? +> ⚠️ **v1 é uma reescrita greenfield.** A `v1.0.0` quebra **totalmente** a +> compatibilidade com a série `0.x`. A versão legada (`0.3.2`, baseada em +> `rest-client`) está **congelada** no branch [`0.x-legacy`](https://github.com/nfe/client-ruby/tree/0.x-legacy) +> e não recebe manutenção nem backports. Para fixá-la: `gem "nfe-io", "~> 0.3"`. +> Veja o [guia de migração](MIGRATION.md). -Para executar a instalação do nosso pacote, você deverá incluir essa linha no Gemfile da sua aplicação: +SDK oficial da [NFE.io](https://nfe.io) para Ruby. + +- **Ergonomia estilo Stripe** — um único `Nfe::Client` com acessores de recurso `snake_case`. +- **Zero dependências de runtime** — apenas a stdlib do Ruby. +- **Tipado** — assinaturas RBS empacotadas em `sig/`, type-check com Steep. +- **Modelos imutáveis** (`Data.define`) gerados a partir das specs OpenAPI da documentação oficial. + +## Requisitos + +- **Ruby 3.2+** (CI em 3.2, 3.3 e 3.4). +- **Zero dependências de runtime.** O SDK usa apenas a biblioteca padrão do Ruby: + `net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, + `zlib`, `cgi`, `date` e `base64`. + +## Instalação + +Via Bundler (recomendado): + +```ruby +# Gemfile +gem "nfe-io", "~> 1.0" +``` + +```sh +bundle install +# ou, sem editar o Gemfile manualmente: +bundle add nfe-io +``` + +Ou instalação direta: + +```sh +gem install nfe-io +``` + +## Quickstart + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV["NFE_API_KEY"]) + +# Emite uma NFS-e (retorno discriminado por tipo — ver "Emissão assíncrona"). +result = client.service_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + cityServiceCode: "2690", + description: "Manutenção e suporte técnico", + servicesAmount: 100.0, + borrower: { federalTaxNumber: "191", name: "Banco do Brasil SA" } + } +) + +# Quando enfileirada (HTTP 202), use o invoice_id para reconsultar. +invoice = client.service_invoices.retrieve( + company_id: "55df4dc6b6cd9007e4f13ee8", + invoice_id: result.pending? ? result.invoice_id : result.resource.id +) +puts invoice.flow_status +``` + +## Configuração + +`Nfe::Client.new` aceita os seguintes argumentos nomeados: + +| Argumento | Default | Descrição | +|---|---|---| +| `api_key:` | _(ENV)_ | Chave principal. Fallback: `ENV["NFE_API_KEY"]`. | +| `data_api_key:` | `nil` | Chave das famílias de **dados**. Fallback: `ENV["NFE_DATA_API_KEY"]`, depois `api_key`. | +| `environment:` | `:production` | **Símbolo** `:production` \| `:development`. **Reservado para uso futuro** — hoje não altera endpoints/chaves (ver "Sandbox vs. Produção"). | +| `timeout:` | `30` | Timeout de leitura (segundos). | +| `max_retries:` | `3` | Orçamento de retentativas (inteiro ≥ 0). | +| `logger:` | `nil` | Logger opcional. | +| `user_agent_suffix:` | `nil` | Sufixo anexado ao `User-Agent` do SDK. | +| `configuration:` | `nil` | Um `Nfe::Configuration` já montado (veja "Opções avançadas"). Quando fornecido, os argumentos acima são ignorados. | + +### Opções avançadas (`Nfe::Configuration`) + +`open_timeout:` (timeout de conexão), `base_url_overrides:` (override de host por +família), `ca_file:`/`ca_path:` (CA bundle adicional — apenas **adiciona** confiança +TLS, nunca desabilita a verificação do peer) e `proxy:` (`String`/`URI` repassada +ao `Net::HTTP`) são definidos em um `Nfe::Configuration` e injetados via +`configuration:`: + +```ruby +config = Nfe::Configuration.new( + api_key: ENV["NFE_API_KEY"], + open_timeout: 5, + ca_file: "/etc/ssl/custom-ca.pem", + proxy: ENV["HTTPS_PROXY"] +) +client = Nfe::Client.new(configuration: config) +``` + +```ruby +client = Nfe::Client.new( + api_key: ENV["NFE_API_KEY"], + data_api_key: ENV["NFE_DATA_API_KEY"], + timeout: 60, + user_agent_suffix: "minha-app/2.1" +) +``` + +### Precedência das chaves (ENV fallback) + +1. **Argumento explícito** não vazio (`api_key:` / `data_api_key:`) sempre vence. +2. Caso contrário, a variável de ambiente correspondente (`NFE_API_KEY` / + `NFE_DATA_API_KEY`), quando presente. +3. As famílias de **dados** caem da `data_api_key` para a `api_key` quando a + primeira não foi resolvida. + +Se nenhuma chave resolver, `Nfe::Client.new` levanta `Nfe::ConfigurationError` +(antes de qualquer requisição). + +## Sandbox vs. Produção + +> **Importante:** a separação **produção vs. teste (homologação)** é definida na +> configuração da sua conta em [app.nfe.io](https://app.nfe.io) (lado servidor) — +> **não** pela chave de API nem pelo SDK — e **não existe URL de sandbox**. +> O argumento `environment:` do `Nfe::Client` (`:production` / `:development`) +> está **reservado para uso futuro**: hoje ele é validado mas **não** altera +> endpoints, chaves ou comportamento. + +Há um segundo conceito de "ambiente", **distinto e independente** do anterior: +NF-e/NFC-e (`product_invoices`, `consumer_invoices`, `product_invoices_rtc`) +aceitam um parâmetro `environment:` do tipo **String** (`"Production"` ou +`"Test"`) na **listagem** e na **emissão**, para escolher se o documento é +homologação ou produção na SEFAZ. ```ruby -gem 'nfe-io' +# String "Production"/"Test" — NÃO confundir com o :production/:development do Client. +client.product_invoices.list(company_id: "co_1", environment: "Test", limit: 50) + +# Emissão de teste (homologação SEFAZ): +client.product_invoices.create( + company_id: "co_1", + data: { + environment: "Test", + serie: 1, + number: 1, + # ... demais campos da NF-e + } +) ``` -E depois executar: +## Mapa de recursos + +A `v1` expõe **17 recursos canônicos** no `Nfe::Client` (mais 2 addons RTC). - $ bundle +| Acessor | Host | Escopo | Operações principais | +|---|---|---|---| +| `service_invoices` | `api.nfe.io` (`/v1`) | NFS-e | `create`, `retrieve`, `list`, `cancel`, `send_email`, `get_status`, `download_pdf`/`download_xml` | +| `companies` | `api.nfe.io` (`/v1`) | Empresas + certificado | `create`, `retrieve`, `list`, `update`, `remove`, `upload_certificate`, `get_certificate_status` | +| `legal_people` | `api.nfe.io` (`/v1`) | Pessoas jurídicas (tomadores) | `create`, `retrieve`, `list`, `update`, `delete`, `create_batch`, `find_by_tax_number` | +| `natural_people` | `api.nfe.io` (`/v1`) | Pessoas físicas (tomadores) | `create`, `retrieve`, `list`, `update`, `delete`, `create_batch`, `find_by_tax_number` | +| `webhooks` | `api.nfe.io` (`/v1`) | Assinaturas de webhook | `create`, `retrieve`, `list`, `update`, `delete`, `test`, `verify_signature` | +| `product_invoices` | `api.nfse.io` (`/v2`) | NF-e | `create`, `create_with_state_tax`, `list`, `retrieve`, `cancel`, `send_correction_letter`, `disable`, `download_*` | +| `consumer_invoices` | `api.nfse.io` (`/v2`) | NFC-e | `create`, `create_with_state_tax`, `list`, `retrieve`, `cancel`, `disable_range`, `download_pdf`/`download_xml` | +| `transportation_invoices` | `api.nfse.io` (`/v2`) | CT-e (recepção) | `enable`, `disable`, `get_settings`, `retrieve`, `download_xml`, `get_event` | +| `inbound_product_invoices` | `api.nfse.io` (`/v2`) | NF-e de entrada / manifestação | `enable_auto_fetch`, `get_details`, `get_xml`, `get_pdf`, `manifest` | +| `tax_calculation` | `api.nfse.io` (`/v2`) | Motor de impostos | `calculate` | +| `tax_codes` | `api.nfse.io` (`/v2`) | Tabelas fiscais | `list_operation_codes`, `list_acquisition_purposes`, `list_issuer_tax_profiles` | +| `state_taxes` | `api.nfse.io` (`/v2`) | Inscrições estaduais (CRUD) | `create`, `retrieve`, `list`, `update`, `delete` | +| `product_invoice_query` | `nfe.api.nfe.io` | Consulta NF-e por chave | `retrieve`, `download_pdf`, `download_xml`, `list_events` | +| `consumer_invoice_query` | `nfe.api.nfe.io` | Consulta NFC-e por chave | `retrieve`, `download_xml` | +| `addresses` | `address.api.nfe.io` (`/v2`) | CEP / endereços | `lookup_by_postal_code`, `search`, `lookup_by_term` | +| `legal_entity_lookup` | `legalentity.api.nfe.io` | Consulta CNPJ | `get_basic_info`, `get_state_tax_info`, `get_state_tax_for_invoice` | +| `natural_person_lookup` | `naturalperson.api.nfe.io` | Consulta CPF | `get_status` | -Ou se preferir, instale diretamente via comando: +> **Addons RTC (opt-in):** `service_invoices_rtc` e `product_invoices_rtc` +> emitem no leiaute da **Reforma Tributária (IBS/CBS)** — mesmos endpoints e +> mesmo fluxo discriminado/polling dos clássicos. São selecionados pela presença +> do grupo `ibsCbs` (NFS-e) ou `items[].tax.IBSCBS` (produto) no payload, sem +> header/parâmetro discriminador. - $ gem install nfe-io +> **Roteamento multi-host** (automático, por recurso): cada família resolve seu +> próprio host — entidades e NFS-e em `api.nfe.io`; NF-e/NFC-e/CT-e e impostos em +> `api.nfse.io`; e os dados em hosts dedicados (`address.api.nfe.io`, +> `legalentity.api.nfe.io`, `naturalperson.api.nfe.io`, `nfe.api.nfe.io`). As +> quatro famílias de **dados dedicadas** (`addresses`, `legal_entity_lookup`, +> `natural_person_lookup`, `*_query`) usam a `data_api_key` (com fallback para +> `api_key`). -## Exemplos de uso +> **Não confundir:** `consumer_invoice_query` **consulta** um cupom NFC-e já +> emitido por chave de acesso (host `nfe.api.nfe.io`); `consumer_invoices` +> **emite** NFC-e (host `api.nfse.io`). Hosts e versões distintos. -> Em construção! +## Recursos -### Como emitir uma Nota Fiscal de Serviço? -Abaixo, temos um código-exemplo para realizar uma Emissão de Nota Fiscal de Serviço: +Um exemplo curto por recurso: ```ruby -# Define a API Key, conforme está no painel -Nfe.api_key('c73d49f9649046eeba36dcf69f6334fd') - -# ID da empresa, você encontra no painel -Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") - -# Dados do Tomador dos Serviços -customer_params = { - borrower: { - federalTaxNumber: '191', # CNPJ ou CPF (opcional para tomadores no exterior) - name: 'BANCO DO BRASIL SA', # Nome da pessoa física ou Razão Social da Empresa - email: 'nfe-io@mailinator.com', # Email para onde deverá ser enviado a nota fiscal - # Endereço do tomador - address: { - country: 'BRA', # Código do pais com três letras - postalCode: '70073901', # CEP do endereço (opcional para tomadores no exterior) - street: 'Rua Do Cliente', # Logradouro - number: 'S/N', # Número (opcional) - additionalInformation: 'QUADRA 01 BLOCO G', # Complemento (opcional) - district: 'Asa Sul', # Bairro - city: { # Cidade é opcional para tomadores no exterior - code: 4204202, # Código do IBGE para a Cidade - name: 'Brasilia' # Nome da Cidade - }, - state: 'DF' - } +# NFS-e — emissão e download +client.service_invoices.create(company_id: "co_1", data: { ... }) # => Pending | Issued +bytes = client.service_invoices.download_pdf(company_id: "co_1", invoice_id: "in_1") + +# NF-e — emissão (environment String obrigatório no list) +client.product_invoices.create(company_id: "co_1", data: { ... }) # => Pending | Issued +client.product_invoices.list(company_id: "co_1", environment: "Production") + +# NFC-e +client.consumer_invoices.create(company_id: "co_1", data: { ... }) +client.consumer_invoices.download_xml(company_id: "co_1", invoice_id: "in_1") + +# CT-e (recepção) e NF-e de entrada +client.transportation_invoices.enable(company_id: "co_1") +client.inbound_product_invoices.manifest(company_id: "co_1", access_key: "352...") + +# Empresas + certificado digital +company = client.companies.create(name: "Acme", federalTaxNumber: "12345678000199") +client.companies.upload_certificate(company.id, file: "cert.pfx", password: "senha") +client.companies.remove(company.id) # delete chama-se "remove" + +# Tomadores +client.legal_people.create("co_1", { federalTaxNumber: "12345678000199", name: "Cliente SA" }) +client.natural_people.find_by_tax_number("co_1", "39053344705") + +# Impostos +client.tax_calculation.calculate("tenant_1", { operationType: "...", items: [...] }) +client.tax_codes.list_operation_codes +client.state_taxes.list("co_1") + +# Consulta por chave de acesso (44 dígitos) +client.product_invoice_query.retrieve("3525...") # NF-e +client.consumer_invoice_query.retrieve("3525...") # NFC-e + +# Dados +client.addresses.lookup_by_postal_code("01310100") +client.legal_entity_lookup.get_basic_info("12345678000199") +client.natural_person_lookup.get_status("39053344705", "1990-01-31") + +# Emissão RTC (Reforma Tributária / IBS-CBS) +client.product_invoices_rtc.create( + company_id: "co_1", + data: { + items: [{ + description: "Produto", + tax: { IBSCBS: { situationCode: "000", classCode: "000001" } } + }], + payment: { ... } } -} +) +``` + +## Emissão assíncrona (HTTP 202) + +A emissão geralmente é **assíncrona**. `create` devolve um **resultado +discriminado**: + +- `*Pending` (HTTP 202, enfileirado) — expõe `invoice_id` e `location`; + `pending?` ⇒ `true`, `issued?` ⇒ `false`. +- `*Issued` (HTTP 201, já materializado) — expõe `resource`; `issued?` ⇒ `true`. + +Não há `create_and_wait` nem `create_batch` na v1.0 — faça **polling** chamando +`retrieve` até um estado terminal, usando `Nfe::FlowStatus.terminal?`. Os estados +terminais são: `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`. + +```ruby +result = client.service_invoices.create(company_id: "co_1", data: { ... }) + +case result +in Nfe::Resources::ServiceInvoicePending => pending + invoice = nil + loop do + invoice = client.service_invoices.retrieve( + company_id: "co_1", invoice_id: pending.invoice_id + ) + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + + sleep 2 + end + invoice +in Nfe::Resources::ServiceInvoiceIssued => issued + issued.resource # NFS-e já materializada (HTTP 201) +end +``` + +> **Atalho:** `service_invoices.get_status(company_id:, invoice_id:)` devolve um +> snapshot (`#complete?` / `#failed?` / `#invoice`) derivado de um único +> `retrieve` — útil dentro do loop de polling. + +Os addons RTC seguem exatamente o mesmo contrato (`ProductInvoiceRtcPending` | +`ProductInvoiceRtcIssued`, polling com `product_invoices_rtc.retrieve`). -# Dados da nota fiscal de serviço -service_params = { - cityServiceCode: '2690', # Código do serviço de acordo com o a cidade - description: 'Teste, para manutenção e suporte técnico.', # Descrição dos serviços prestados - servicesAmount: 0.1 # Valor total do serviços -} +## Tratamento de erros -# Emite a nota fiscal -invoice_create_result = Nfe::ServiceInvoice.create(customer_params.merge(service_params)) +Toda exceção do SDK deriva de `Nfe::Error`, então `rescue Nfe::Error` captura a +família inteira. Erros vindos de uma resposta HTTP carregam contexto de +diagnóstico (`#status_code`, `#request_id`, `#error_code`); `#to_h` devolve uma +representação **segura para log** (sem corpo nem headers crus, que podem conter +segredos/PII). + +```ruby +begin + client.service_invoices.create(company_id: "co_1", data: { ... }) +rescue Nfe::RateLimitError => e + sleep(e.retry_after || 5) + retry +rescue Nfe::InvalidRequestError => e + warn "Payload inválido: #{e.message} (#{e.error_code})" +rescue Nfe::Error => e + warn e.to_h.inspect +end ``` -### Como cancelar uma nota? -Abaixo, temos um código-exemplo para efetuar o cancelamento de uma nota: +| Erro | HTTP / origem | Quando ocorre | +|---|---|---| +| `Nfe::AuthenticationError` | 401 | Chave ausente ou inválida. | +| `Nfe::AuthorizationError` | 403 | Chave válida, sem permissão para o recurso. | +| `Nfe::InvalidRequestError` | 400 / 422 | Requisição malformada ou reprovada na validação. | +| `Nfe::NotFoundError` | 404 | Recurso inexistente. | +| `Nfe::ConflictError` | 409 | Conflito com o estado atual do recurso. | +| `Nfe::RateLimitError` | 429 | Excesso de requisições. Expõe `#retry_after`. | +| `Nfe::ServerError` | 5xx | Falha no servidor da API. | +| `Nfe::ApiConnectionError` | rede | Falha de conexão (DNS, recusa, TLS, reset). | +| `Nfe::TimeoutError` | rede | Timeout (subclasse de `ApiConnectionError`). | +| `Nfe::SignatureVerificationError` | webhook | Assinatura de webhook inválida (em `construct_event`). | +| `Nfe::ConfigurationError` | local | Configuração inválida (chave faltando, `environment` inválido). | +| `Nfe::InvoiceProcessingError` | protocolo 202 | Resposta 202 sem `Location` utilizável. | + +## Downloads + +A maioria dos downloads devolve a **String binária** (`ASCII-8BIT`) com os bytes +do documento, pronta para `File.binwrite` ou `send_data`: ```ruby -# Define a API Key, conforme está no painel -Nfe.api_key('c73d49f9649046eeba36dcf69f6334fd') -# ID da empresa, você encontra no painel -Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") -# O parâmetro é o ID da nota -invoice = Nfe::ServiceInvoice.cancel("59443a0e2a8b6806986d7a2d") -# A resposta são os dados da nota com a mudança de estado para "WaitingSendCancel" +bytes = client.service_invoices.download_pdf(company_id: "co_1", invoice_id: "in_1") +File.binwrite("nota.pdf", bytes) ``` -### Criar uma Empresa para Emissão de Notas ->Em construção! +Devolvem bytes: `service_invoices`, `consumer_invoices`, +`transportation_invoices`, `inbound_product_invoices` e os recursos de consulta +`product_invoice_query` / `consumer_invoice_query`. + +> **Exceção:** `product_invoices.download_*` e `product_invoices_rtc.download_*` +> devolvem um **`Nfe::NfeFileResource`** (um value object com a `uri` do arquivo), +> **não** os bytes: +> +> ```ruby +> file = client.product_invoices.download_pdf(company_id: "co_1", invoice_id: "in_1") +> file.uri # => "https://.../danfe.pdf" +> ``` + +## Webhooks + +Crie a assinatura e **verifique a assinatura** de cada entrega. + +```ruby +client.webhooks.create("co_1", { + url: "https://minha-app.com/webhooks/nfe", + events: ["invoice.issued", "invoice.cancelled", "invoice.failed"], + secret: ENV["NFE_WEBHOOK_SECRET"] +}) +``` -### Como efetuar o download de uma nota em PDF? -Abaixo, temos um código exemplo para baixar uma nota em PDF: +A verificação é **HMAC-SHA1 sobre os bytes crus** da requisição (header +`X-Hub-Signature`, comparação case-insensitive e timing-safe). Leia o corpo bruto +**antes** de fazer parse do JSON — reserializar (`payload.to_json`) muda +ordem/whitespace e quebra a verificação. ```ruby -# Define a API Key, conforme está no painel -Nfe.api_key('c73d49f9649046eeba36dcf69f6334fd') -# ID da empresa, você encontra no painel -Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") -# Os formatos suportados são :pdf e :xml, e o primeiro parâmetro é o ID da nota -invoice = Nfe::ServiceInvoice.download("59443a0e2a8b6806986d7a2d", :pdf) -# O conteúdo do PDF/XML pode ser acessado da seguinte forma -invoice.body -# Caso você esteja utilizando Rails, pode usar o método send_data para retornar -# o conteúdo da Nota Fiscal diretamente para o usuário -# Note que neste caso o arquivo é o PDF, mas poderia ser o XML, mude se necessário -send_data(invoice.body, filename: 'invoice.pdf', type: 'application/pdf') -``` - -### Como validar o Webhook? +# Exemplo Rack/Rails +raw = request.body.read +sig = request.get_header("HTTP_X_HUB_SIGNATURE") + +if Nfe::Webhook.verify_signature(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) + event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) + # processe event.type / event.data +end +``` + +- `Nfe::Webhook.verify_signature(...)` ⇒ `Boolean`. **Nunca levanta exceção** — + qualquer entrada ausente/malformada/algoritmo errado retorna `false`. +- `Nfe::Webhook.construct_event(...)` ⇒ `Nfe::WebhookEvent` (levanta + `Nfe::SignatureVerificationError` se a assinatura ou o JSON forem inválidos). + +> **Validade ≠ atualidade.** A NFE.io **não** envia timestamp/nonce +> anti-replay. Uma assinatura válida prova autenticidade, **não** frescor. Seus +> handlers **devem ser idempotentes** e deduplicar pelo id do evento/da nota. + +## Versionamento + +O projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/). + +- **patch** (`1.0.x`): correções, liberadas direto após CI verde. +- **minor**/**major**: novas capacidades / quebras de contrato, precedidas de + ciclo de **release candidate** (`-rc.N`) e **beta** (`-beta.N`). + +Consulte o [`CHANGELOG.md`](CHANGELOG.md) para o histórico e o +[`MIGRATION.md`](MIGRATION.md) para o guia de migração da `0.x`. + +## Type checking + +A gem **empacota** as assinaturas RBS em `sig/`. Quem consome o SDK pode +type-checkar o próprio código contra elas com [Steep](https://github.com/soutaro/steep): + ```ruby -def request_is_authentic? - body = request.body.read - signature = request.headers['X-NFEIO-Signature'] +# Gemfile +gem "steep", require: false +``` - hash = 'sha1=' + Base64.strict_encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), ENV.fetch("NFEIO_WEBHOOK_SECRET"), body)) +```ruby +# Steepfile +target :app do + signature "sig" + check "lib" - ActiveSupport::SecurityUtils.secure_compare(hash, signature) + library "nfe-io" # usa as assinaturas empacotadas com a gem end ``` + +```sh +bundle exec steep check +``` + +## Migração da `0.x` + +Veja [`MIGRATION.md`](MIGRATION.md). Em resumo: a API global (`Nfe.api_key(...)`, +`Nfe::ServiceInvoice.create`) dá lugar a `Nfe::Client.new(api_key:)` + +`client.service_invoices.create`, sem `rest-client` e com value objects imutáveis. + +## Contribuindo + +Veja [`CONTRIBUTING.md`](CONTRIBUTING.md) para setup local, toolchain (`rake spec`, +`rubocop`, `steep check`, `rake generate`), convenções e fluxo de release. + +## Licença + +MIT. Veja [`LICENSE.txt`](LICENSE.txt). diff --git a/Rakefile b/Rakefile index b7e9ed5..8303061 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,60 @@ +# frozen_string_literal: true + require "bundler/gem_tasks" require "rspec/core/rake_task" +require "rubocop/rake_task" RSpec::Core::RakeTask.new(:spec) +RuboCop::RakeTask.new(:rubocop) + +# API reference (YARD) -> docs/api/ (config in .yardopts). Optional: the task is +# only defined when YARD is installed, so it never breaks the core tasks. +begin + require "yard" + YARD::Rake::YardocTask.new(:doc) +rescue LoadError + nil +end + +desc "Type-check lib/ against sig/ with Steep" +task :steep do + sh "bundle exec steep check" +end + +desc "Validate RBS signatures in sig/" +task :rbs do + sh "bundle exec rbs validate" +end + +desc "Generate Ruby value objects + RBS from openapi/*.{yaml,json}" +task :generate do + sh "ruby scripts/generate.rb" +end + +namespace :generate do + desc "Fail if lib/nfe/generated + sig/nfe/generated drift from the OpenAPI specs" + task :check do + sh "ruby scripts/generate.rb --check" + end +end + +namespace :openapi do + desc "Refresh openapi/ specs from nfeio-docs (NFEIO_DOCS_PATH); does not generate or commit" + task :sync do + require "fileutils" + src = File.join(ENV.fetch("NFEIO_DOCS_PATH", "nfeio-docs"), "static", "api") + raise "OpenAPI source not found: #{src}" unless File.directory?(src) + + Dir.glob("openapi/*.{yaml,json}").each do |dest| + candidate = File.join(src, File.basename(dest)) + next puts(" missing-in-docs #{File.basename(dest)}") unless File.file?(candidate) + + changed = File.read(dest) != File.read(candidate) + FileUtils.cp(candidate, dest) + puts(changed ? " updated #{File.basename(dest)}" : " unchanged #{File.basename(dest)}") + end + puts "Done. Review the diff, then run `rake generate`." + end +end -task :default => :spec +task default: ["generate:check", :spec, :rubocop, :steep, :rbs] diff --git a/Steepfile b/Steepfile new file mode 100644 index 0000000..8b0315f --- /dev/null +++ b/Steepfile @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +target :lib do + signature "sig" + check "lib" + + # Generated value objects (from the OpenAPI pipeline) are trusted by + # construction and excluded from the strict check; refine as codegen matures. + ignore "lib/nfe/generated" + + # Standard-library signatures used by the HTTP transport layer. + library "json", "uri", "net-http", "zlib", "openssl", "stringio", "timeout", "socket", "time", "date", "cgi" +end diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c7915f3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,65 @@ +# Docker-based dev environment for the NFE.io Ruby SDK. +# +# Quick start: +# cp .env.docker.example .env # one-time, sets UID/GID +# docker compose build ruby34 # build the default (Ruby 3.4) image +# docker compose run --rm ruby34 bundle install +# docker compose run --rm ruby34 bundle exec rake # spec + rubocop + steep + rbs +# +# Reproduce the CI matrix locally: +# docker compose run --rm ruby32 bundle exec rake +# docker compose run --rm ruby33 bundle exec rake +# docker compose run --rm ruby34 bundle exec rake +# +# ruby34 (matches .ruby-version) is the primary dev service; 3.2 is the floor. + +x-ruby-defaults: &ruby-defaults + volumes: + - .:/app + - bundle-cache:/home/app/bundle + working_dir: /app + init: true + tty: true + # Forward .env into the container so SDK env vars (NFE_API_KEY, NFE_DATA_API_KEY, + # etc.) are available to scripts running inside the container. + env_file: + - path: .env + required: false + +services: + ruby32: + <<: *ruby-defaults + build: + context: . + dockerfile: docker/Dockerfile + args: + RUBY_VERSION: "3.2" + UID: "${UID:-1000}" + GID: "${GID:-1000}" + image: nfe-client-ruby:3.2 + + ruby33: + <<: *ruby-defaults + build: + context: . + dockerfile: docker/Dockerfile + args: + RUBY_VERSION: "3.3" + UID: "${UID:-1000}" + GID: "${GID:-1000}" + image: nfe-client-ruby:3.3 + + ruby34: + <<: *ruby-defaults + build: + context: . + dockerfile: docker/Dockerfile + args: + RUBY_VERSION: "3.4" + UID: "${UID:-1000}" + GID: "${GID:-1000}" + image: nfe-client-ruby:3.4 + +volumes: + bundle-cache: + driver: local diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..6649e13 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,32 @@ +# Dev/CI image for the NFE.io Ruby SDK. +# +# The Ruby version is set at build time (default 3.4 = the dev .ruby-version; +# the supported floor is 3.2). The full `ruby` image (not slim/alpine) is used +# so native extensions — e.g. the rbs parser — compile without extra apt work. +ARG RUBY_VERSION=3.4 +FROM ruby:${RUBY_VERSION} + +# git: used by bundler git sources and rake. build tools ship in the full image. +RUN apt-get update \ + && apt-get install -y --no-install-recommends git \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Non-root user matching the host UID/GID so files written through the bind +# mount (Gemfile.lock, coverage/) stay owned by the developer, not root. +ARG UID=1000 +ARG GID=1000 +RUN (getent group "${GID}" || groupadd --system --gid "${GID}" app) \ + && (getent passwd "${UID}" || useradd --uid "${UID}" --gid "${GID}" --create-home --shell /bin/bash app) + +# Bundler installs into a cached, user-owned path (a named volume in compose), +# namespaced by Ruby ABI so 3.2/3.3/3.4 can share the same volume safely. +ENV BUNDLE_PATH=/home/app/bundle \ + BUNDLE_APP_CONFIG=/home/app/bundle \ + BUNDLE_JOBS=4 +RUN mkdir -p /home/app/bundle && chown -R "${UID}:${GID}" /home/app + +USER ${UID}:${GID} +WORKDIR /app + +CMD ["ruby", "-v"] diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md new file mode 100644 index 0000000..0368150 --- /dev/null +++ b/docs/MAINTAINING.md @@ -0,0 +1,60 @@ +# Manutenção da documentação (interno) + +> Documento **interno** do repositório (não é uma página da docs — não tem +> frontmatter e não deve ser copiado para o `nfeio-docs`). + +Esta pasta `docs/` é a **residência canônica** da documentação do SDK Ruby. Os +arquivos já vêm com o frontmatter e as convenções do **Docusaurus 3** para um +`copy/paste` direto na documentação oficial (`nfeio-docs`). + +## Estrutura + +| Caminho | Papel | +|---|---| +| `docs/README.md` | Página de entrada (landing). Frontmatter `layout_type: IntegrationLayout`, espelhando `bibliotecas/php.md`. | +| `docs/*.md` | Guias temáticos (configuração, 202/polling, erros, webhooks, paginação, downloads, multi-host, RTC). | +| `docs/recursos/*.md` | Cookbook — uma página por recurso (17 canônicos + RTC). | +| `docs/_category_.json`, `docs/recursos/_category_.json` | Categorias da sidebar do Docusaurus. | +| `docs/api/` | Referência da API gerada pelo YARD (HTML). **Gitignorada** — gere com `rake doc`. | +| `docs/yard-theme/` | Tema YARD com a identidade NFE.io (CSS + `headers.erb` + `setup.rb`). Versionado. | + +## Gerar a referência da API (YARD) + +```sh +bundle exec rake doc +``` + +Saída em `docs/api/` (122+ páginas HTML, tema NFE.io). É **self-contained** +(logos em data-URI), então a pasta funciona em qualquer lugar. + +## Sincronizar com o `nfeio-docs` (Docusaurus 3.8) + +O destino principal destes arquivos é o `nfeio-docs`. Enquanto não há automação, +o fluxo é manual: + +1. **Guias + cookbook** → copie `docs/*.md` e `docs/recursos/` para + `docs/docs/desenvolvedores/bibliotecas/ruby/` no `nfeio-docs`. Renomeie + `README.md` para `index.md` (ou `ruby.md`) — o frontmatter `IntegrationLayout` + já está pronto. Adicione o `heroImage` `static/img/bibliotecas/ruby.svg`. +2. **Referência da API** → rode `rake doc` e copie `docs/api/` para + `static/api/ruby/` no `nfeio-docs`. O link na landing (`/api/ruby/`) já aponta + para lá. +3. Revise a sidebar — os `_category_.json` e os `sidebar_position` já definem a + ordem. + +## Convenções ao editar (mantêm o copy/paste sem retrabalho) + +- **Frontmatter** em toda página: `title`, `sidebar_label`, `sidebar_position`, + `description` (a landing usa o bloco `IntegrationLayout`). +- **`slug`** explícito em pt-BR em toda página (relativo ao diretório), para a + URL não depender do nome (em inglês) do arquivo — ex.: `slug: configuracao`, + `docs/recursos/companies.md` → `slug: empresas` → `.../recursos/empresas`. A + landing (`README.md` → `index.md`) usa `slug` **absoluto** + `/desenvolvedores/bibliotecas/ruby` (igual ao `nodejs/index.md`). + A categoria `recursos/` tem um `generated-index` em `slug: recursos`. +- **MDX-safe** (Docusaurus 3 lê `.md` como MDX): todo código em blocos cercados + (` ```ruby `, ` ```sh `) ou crase inline; **nunca** `<` ou `{` soltos na prosa. +- **Callouts** como admonitions do Docusaurus: `:::note`, `:::tip`, `:::warning`. +- **Links** relativos entre páginas: `./outra.md`, `../guia.md`. +- **Precisão**: nomes de método/kwargs vêm do código (`lib/nfe/resources/`). + Nada de método inventado. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..20d5e9d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,90 @@ +--- +title: Biblioteca NFE.io em Ruby para Emissão de Notas Fiscais (NFS-e, NF-e, NFC-e, CT-e) +description: SDK Ruby oficial da NFE.io — Ruby 3.2+, zero dependências de runtime, cliente estilo Stripe, tipos RBS e modelos imutáveis. +sidebar_label: Biblioteca Ruby +slug: /desenvolvedores/bibliotecas/ruby +provider: NFE.io +badge: SDK +layout_type: IntegrationLayout +heroImage: /docs/img/bibliotecas/ruby.svg +ctaLabel: GitHub NFE.io Ruby +ctaUrl: https://github.com/nfe/client-ruby +--- + +# Biblioteca Ruby NFE.io + +SDK oficial da [NFE.io](https://nfe.io) para Ruby: emissão e gestão de documentos +fiscais eletrônicos brasileiros (NFS-e, NF-e, NFC-e, CT-e) com ergonomia estilo +Stripe e **zero dependências de runtime**. + +- **Cliente único** `Nfe::Client` com acessores `snake_case` por recurso. +- **Tipado** — assinaturas RBS empacotadas no gem; type-check com Steep. +- **Modelos imutáveis** (`Data.define`) gerados das specs OpenAPI oficiais. + +## Requisitos + +- Ruby **3.2** ou superior. +- **Zero dependências de runtime** — apenas a biblioteca padrão do Ruby. + +## Instalação + +```ruby +# Gemfile +gem "nfe-io", "~> 1.0" +``` + +```sh +bundle install # ou: gem install nfe-io +``` + +## Primeiros passos + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) + +result = client.service_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + cityServiceCode: "2690", + description: "Manutenção e suporte técnico", + servicesAmount: 100.0, + borrower: { federalTaxNumber: "191", name: "Banco do Brasil SA" } + } +) +``` + +O fluxo completo (retorno discriminado + polling) está em +[Primeiros passos](./getting-started.md). + +## Guias + +| Guia | Conteúdo | +|---|---| +| [Primeiros passos](./getting-started.md) | Instalação, cliente, primeira emissão e polling. | +| [Configuração](./configuration.md) | Todas as opções, modelo de duas chaves, fallback de ENV, TLS/proxy. | +| [Emissão assíncrona e polling](./async-and-polling.md) | Contrato 202 `Pending`/`Issued` e o laço de polling com `FlowStatus`. | +| [Tratamento de erros](./errors.md) | Hierarquia `Nfe::Error` e padrões de `rescue`. | +| [Webhooks](./webhooks.md) | Verificação HMAC-SHA1 e idempotência/replay. | +| [Paginação](./pagination.md) | Estilos page e cursor; `ListResponse` enumerável. | +| [Downloads](./downloads.md) | Bytes binários vs. `NfeFileResource`. | +| [Roteamento multi-host](./multi-host-routing.md) | Os hosts por família de recurso. | +| [Emissão RTC](./rtc-emission.md) | IBS/CBS/IS; leiaute `ibsCbs`/`IBSCBS`. | +| [Cookbook por recurso](./recursos/) | Um exemplo por recurso (os 17 canônicos + RTC). | + +## Referência da API + +A referência completa de classes e métodos é gerada com **YARD** a partir do +código-fonte (e dos comentários YARD): + +```sh +bundle exec rake doc # gera docs/api/ +``` + +A versão publicada fica em [`/api/ruby/`](https://nfe.io/api/ruby/) (HTML estático). + +## Migração + +Vindo da série `0.x`? Veja o [guia de migração](../MIGRATION.md) — a `v1.0` é uma +reescrita greenfield, sem camada de compatibilidade. diff --git a/docs/_category_.json b/docs/_category_.json new file mode 100644 index 0000000..4b5e15a --- /dev/null +++ b/docs/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Biblioteca Ruby", + "position": 4, + "collapsed": true +} diff --git a/docs/async-and-polling.md b/docs/async-and-polling.md new file mode 100644 index 0000000..a168769 --- /dev/null +++ b/docs/async-and-polling.md @@ -0,0 +1,134 @@ +--- +title: Emissão assíncrona e polling no SDK Ruby da NFE.io +sidebar_label: Assíncrono e polling +sidebar_position: 3 +slug: emissao-assincrona-e-polling +description: Entenda o contrato HTTP 202, os resultados Pending e Issued, o pattern matching com pending?/issued? e como montar um loop de polling com FlowStatus.terminal?. +--- + +# Emissão assíncrona e polling + +A emissão de documentos fiscais é, em geral, **assíncrona**: a API aceita a +requisição (HTTP 202) e segue processando. Esta página explica o contrato de +retorno, os dois tipos de resultado e como acompanhar o processamento até um +estado terminal. + +## O contrato HTTP 202 + +Quando a API responde **202 Accepted**, o documento ainda **não** foi +materializado — ela apenas aceitou o pedido. Quando responde **201/200**, o +documento já está pronto. O `create` traduz isso em um **resultado discriminado**: +um de dois tipos. + +| Resposta HTTP | Tipo de resultado | Significado | +| --- | --- | --- | +| 202 Accepted | `Nfe::*Pending` | Em processamento; reconsulte depois. | +| 201 / 200 | `Nfe::*Issued` | Documento já materializado. | + +:::note `*Pending` e `*Issued` por recurso +Cada recurso expõe seu par de resultados (por exemplo, +`Nfe::Resources::ServiceInvoicePending` e `Nfe::Resources::ServiceInvoiceIssued`). +O tipo base `Nfe::Pending` carrega `invoice_id` e `location`; o `Nfe::Issued` +carrega `resource`. +::: + +## Os dois tipos de resultado + +### `*Pending` (202) + +- `#invoice_id` — id extraído do último segmento do header `Location`; use-o para + reconsultar enquanto processa. +- `#location` — o valor bruto do header `Location`. +- `#pending?` → `true`. + +### `*Issued` (201/200) + +- `#resource` — o documento já materializado (DTO hidratado). +- `#issued?` → `true`. + +## Distinguindo o resultado + +Você pode discriminar com os predicados `pending?` / `issued?` ou com pattern +matching: + +```ruby +result = client.service_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { cityServiceCode: "2690", servicesAmount: 100.0, description: "Suporte" } +) + +case result +in Nfe::Resources::ServiceInvoicePending => pending + pending.invoice_id # reconsulte com este id +in Nfe::Resources::ServiceInvoiceIssued => issued + issued.resource # NFS-e já pronta +end +``` + +Com predicados: + +```ruby +invoice_id = result.pending? ? result.invoice_id : result.resource.id +``` + +## Loop de polling manual + +Faça polling com `retrieve` até um **estado terminal**, decidido por +`Nfe::FlowStatus.terminal?`: + +```ruby +company_id = "55df4dc6b6cd9007e4f13ee8" +invoice_id = result.pending? ? result.invoice_id : result.resource.id + +invoice = + loop do + current = client.service_invoices.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break current if Nfe::FlowStatus.terminal?(current.flow_status) + + sleep 2 + end + +# `invoice.flow_status` agora é um estado terminal. +``` + +### Estados de fluxo (`flow_status`) + +Estados **terminais** (encerram o polling): + +| Status | Significado | +| --- | --- | +| `Issued` | Emitido com sucesso. | +| `IssueFailed` | Falha na emissão. | +| `Cancelled` | Cancelado. | +| `CancelFailed` | Falha no cancelamento. | + +`Nfe::FlowStatus.terminal?` aceita `String` ou `Symbol` e retorna `true` apenas +para os quatro acima; qualquer outro valor (como `WaitingSend` ou +`PullFromCityHall`) retorna `false`. + +:::tip `get_status` em `service_invoices` +O recurso `service_invoices` oferece `get_status`, derivado do `retrieve` (sem +HTTP extra), como atalho para inspecionar o estado atual. +::: + +## Por que não existe `create_and_wait`? + +A `v1.0` **não** implementa `create_and_wait`, `create_batch` nem +`poll_until_complete`. O contrato discriminado `*Pending` / `*Issued` somado a +`Nfe::FlowStatus.terminal?` é suficiente para escrever loops de polling manuais, +e esses auxiliares ficam deliberadamente adiados para uma versão futura — sem +quebrar o contrato público. + +:::warning Não chame helpers inexistentes +Referenciar `client.poll_until_complete(...)` ou `resource.create_and_wait(...)` +na `v1.0` levanta `NoMethodError`, pois o método não está definido. +::: + +## Próximos passos + +- [Tratamento de erros](./errors.md) — trate falhas durante o polling. +- [Configuração](./configuration.md) — ajuste `timeout` e `max_retries`. +- [Primeiros passos](./getting-started.md) — a primeira emissão de ponta a ponta. diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..c499e23 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,203 @@ +--- +title: Configuração do cliente do SDK Ruby da NFE.io +sidebar_label: Configuração +sidebar_position: 2 +slug: configuracao +description: Todas as opções do Nfe::Client e do Nfe::Configuration — chaves de API, timeouts, retries, modelo de duas chaves, sandbox vs. produção, TLS e proxy. +--- + +# Configuração + +Esta página descreve como configurar o `Nfe::Client`: os argumentos aceitos +diretamente no construtor, as opções avançadas que vivem em `Nfe::Configuration`, +o fallback por variáveis de ambiente, o modelo de duas chaves e as configurações +de rede (TLS e proxy). + +## Argumentos de `Nfe::Client.new` + +O construtor aceita um conjunto enxuto de opções de conveniência: + +```ruby +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: nil, + configuration: nil, + environment: :production, + timeout: 30, + max_retries: 3, + logger: nil, + user_agent_suffix: nil +) +``` + +| Argumento | Tipo | Padrão | Descrição | +| --- | --- | --- | --- | +| `api_key` | `String`, `nil` | `nil` | Chave principal. Cai para `NFE_API_KEY` quando ausente. | +| `data_api_key` | `String`, `nil` | `nil` | Chave dos serviços de dados. Cai para `NFE_DATA_API_KEY`. | +| `configuration` | `Nfe::Configuration`, `nil` | `nil` | Quando informado, **os demais argumentos de conveniência são ignorados**. | +| `environment` | `Symbol` | `:production` | `:production` ou `:development`. Reservado para uso futuro (sem efeito hoje). | +| `timeout` | `Integer` | `30` | Timeout de leitura em segundos (deve ser positivo). | +| `max_retries` | `Integer` | `3` | Orçamento de retentativas (inteiro não negativo). | +| `logger` | objeto, `nil` | `nil` | Logger opcional (responde a `info`/`warn`/`error`). | +| `user_agent_suffix` | `String`, `nil` | `nil` | Sufixo anexado ao `User-Agent` do SDK. | + +:::note Validação na construção +As opções são validadas na criação. Valores inválidos (por exemplo, `timeout` +não positivo, `max_retries` negativo ou `environment` desconhecido) levantam +`Nfe::ConfigurationError` antes de qualquer requisição HTTP. Veja +[Tratamento de erros](./errors.md). +::: + +## Opções avançadas — somente em `Nfe::Configuration` + +Algumas opções **não** são aceitas diretamente por `Nfe::Client.new`. Elas vivem +em `Nfe::Configuration` e são injetadas via `configuration:`: + +| Opção | Tipo | Padrão | Descrição | +| --- | --- | --- | --- | +| `open_timeout` | `Integer` | `10` | Timeout de conexão em segundos (deve ser positivo). | +| `base_url_overrides` | `Hash{Symbol=>String}` | `{}` | Sobrescreve o host por família (escape hatch). | +| `ca_file` | `String`, `nil` | `nil` | Caminho de um bundle de CA a **adicionar** ao trust store. | +| `ca_path` | `String`, `nil` | `nil` | Diretório de certificados de CA a **adicionar** ao trust store. | +| `proxy` | `String`, `URI`, `nil` | `nil` | Repassado ao `Net::HTTP`. | + +Para usá-las, construa um `Nfe::Configuration` e passe-o ao cliente. Note que ao +informar `configuration:`, os argumentos de conveniência (como `api_key:` ou +`timeout:`) passados ao `Client.new` são ignorados — tudo deve estar na +configuração: + +```ruby +configuration = Nfe::Configuration.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY", nil), + timeout: 60, + open_timeout: 15, + max_retries: 5, + proxy: "http://proxy.interno:3128", + ca_file: "/etc/ssl/certs/corporate-ca.pem" +) + +client = Nfe::Client.new(configuration: configuration) +``` + +:::tip Quando preciso de `Nfe::Configuration`? +Para o caso comum, basta `Nfe::Client.new(api_key: "...")`. Use a configuração +explícita quando precisar de `open_timeout`, `proxy`, `ca_file`/`ca_path` ou +`base_url_overrides`. +::: + +## Fallback por variáveis de ambiente + +As chaves resolvem nesta ordem de precedência: **argumento explícito não vazio +vence**; caso contrário, a variável de ambiente (quando presente) é adotada. + +- `api_key` cai para `NFE_API_KEY`. +- `data_api_key` cai para `NFE_DATA_API_KEY`. + +```sh +export NFE_API_KEY="sua-chave-principal" +export NFE_DATA_API_KEY="sua-chave-de-dados" +``` + +```ruby +# Sem argumentos: ambas as chaves vêm do ambiente. +client = Nfe::Client.new +``` + +:::note Pelo menos uma chave +A validação "ao menos uma chave informada" roda **após** o fallback. Se nenhuma +chave for resolvida (nem por argumento, nem por ambiente), a construção levanta +`Nfe::ConfigurationError`. Um cliente apenas com `data_api_key` é válido — a +exigência da chave principal é adiada até que um recurso da família `main` seja +acessado. +::: + +## Modelo de duas chaves + +O SDK usa duas chaves. As famílias de **dados** — `addresses` (CEP), +`legal_entity` (CNPJ), `natural_person` (CPF) e `nfe_query` (consultas) — usam a +`data_api_key` quando presente, com **fallback** para a `api_key`. Todas as +demais famílias usam a `api_key`. + +```ruby +# Cliente com as duas chaves: +client = Nfe::Client.new( + api_key: "chave-de-emissao", + data_api_key: "chave-de-consulta" +) + +# - client.addresses → usa data_api_key (família de dados) +# - client.legal_entity_lookup → usa data_api_key +# - client.service_invoices → usa api_key (emissão) +# - client.companies → usa api_key +``` + +Quando nenhuma chave resolve para a família acessada, o SDK levanta +`Nfe::ConfigurationError` no momento da requisição. + +:::note CT-e usa a chave principal +A família `cte` (`api.nfse.io` — emissão de NF-e/NFC-e/CT-e e regras tributárias) +**não** é uma família de dados: usa a `api_key`. Emissão é capacidade central, +não consulta de dados. +::: + +## Sandbox vs. Produção + +:::warning A separação produção vs. teste fica na conta, não no SDK +A escolha entre **produção** e **teste (homologação)** é definida na configuração +da sua conta em [app.nfe.io](https://app.nfe.io) (lado servidor) — **não** pela +chave de API nem pelo SDK. Não existe "URL de sandbox": produção e desenvolvimento +apontam para os mesmos endpoints. +::: + +O argumento `environment:` do cliente (`:production` / `:development`) está +**reservado para uso futuro**: ele é validado, mas hoje **não tem efeito** sobre +endpoints, chaves ou comportamento. Suporte completo a `environment:` está +planejado para uma versão futura. + +:::note Ambiente SEFAZ é outra coisa +Os recursos de produto e consumidor (NF-e/NFC-e) aceitam um parâmetro +**separado** `environment:` do tipo `String` (`"Production"` / `"Test"`) nas +operações de listagem e emissão — esse é o ambiente da SEFAZ e é tratado nos +guias daqueles recursos, não aqui. +::: + +## TLS e proxy + +### TLS — confiança só pode ser adicionada + +`ca_file` (e, opcionalmente, `ca_path`) é o **único** override do trust store de +TLS e só pode **adicionar/substituir** o bundle de CA usado para verificar o par. +A verificação completa do certificado do servidor permanece ativa em toda +requisição. + +```ruby +configuration = Nfe::Configuration.new( + api_key: ENV.fetch("NFE_API_KEY"), + ca_file: "/etc/ssl/certs/corporate-ca.pem" +) +``` + +:::warning Não há como desabilitar a verificação +Por design, **não existe** API pública para desabilitar a verificação do par +(sem `VERIFY_NONE`, sem `insecure_ssl`). O atributo `insecureSsl` que você possa +ver na API é uma propriedade do **alvo de entrega de webhook** (lado servidor) e +não tem relação com a configuração de TLS de saída do SDK. +::: + +### Proxy + +Defina `proxy` em `Nfe::Configuration` para repassá-lo ao `Net::HTTP`: + +```ruby +configuration = Nfe::Configuration.new( + api_key: ENV.fetch("NFE_API_KEY"), + proxy: "http://usuario:senha@proxy.interno:3128" +) +``` + +## Próximos passos + +- [Emissão assíncrona e polling](./async-and-polling.md) — o contrato HTTP 202. +- [Tratamento de erros](./errors.md) — `rescue` por tipo. +- [Primeiros passos](./getting-started.md) — instalação e primeira emissão. diff --git a/docs/downloads.md b/docs/downloads.md new file mode 100644 index 0000000..6c537d7 --- /dev/null +++ b/docs/downloads.md @@ -0,0 +1,95 @@ +--- +title: Downloads de PDF e XML no SDK Ruby da NFE.io +sidebar_label: Downloads +sidebar_position: 7 +slug: downloads +description: Baixe PDF/XML das notas. A maioria dos recursos devolve bytes binários (ASCII-8BIT) para salvar com File.binwrite; product_invoices devolve um Nfe::NfeFileResource com a URI do arquivo. +--- + +# Downloads + +Os recursos de nota expõem métodos para baixar PDF e XML. Há **dois contratos de +retorno distintos** — leia esta página com atenção antes de salvar o arquivo. + +## Contrato 1: bytes binários (a maioria dos recursos) + +Os métodos de download de `service_invoices`, `consumer_invoices`, +`transportation_invoices`, `inbound_product_invoices`, além de +`product_invoice_query` e `consumer_invoice_query`, retornam uma **String +binária** (encoding `ASCII-8BIT`). Salve sempre com `File.binwrite` para não +corromper o conteúdo: + +```ruby +pdf_bytes = client.service_invoices.download_pdf( + company_id: "55df4dc6b6cd9007e4f13ee8", + invoice_id: "abc-123" +) + +File.binwrite("nota.pdf", pdf_bytes) +``` + +O mesmo vale para o XML: + +```ruby +xml_bytes = client.service_invoices.download_xml( + company_id: "55df4dc6b6cd9007e4f13ee8", + invoice_id: "abc-123" +) + +File.binwrite("nota.xml", xml_bytes) +``` + +:::tip ZIP de toda a empresa +Em `service_invoices`, omitir `invoice_id:` (ou passar `nil`) baixa o **ZIP** com +os documentos da empresa em vez de um único arquivo. O retorno continua sendo +bytes binários. +::: + +## Contrato 2: `Nfe::NfeFileResource` (product invoices) + +:::warning Exceção importante +Os métodos `download_*` de `product_invoices` e `product_invoices_rtc` **NÃO** +retornam bytes. Eles retornam um `Nfe::NfeFileResource` — um objeto de valor que +carrega a **URI** do arquivo, porque o host `api.nfse.io/v2` responde com um +envelope JSON `{ uri }`, e não com o arquivo em si. +::: + +`Nfe::NfeFileResource` expõe `#uri`, `#name`, `#content_type` e `#size`. Para +obter os bytes, faça o download da `uri` separadamente: + +```ruby +file = client.product_invoices.download_pdf( + company_id: "55df4dc6b6cd9007e4f13ee8", + invoice_id: "abc-123" +) + +file.uri # ex.: "https://.../danfe.pdf" +file.content_type # ex.: "application/pdf" + +require "open-uri" +File.binwrite("danfe.pdf", URI.open(file.uri).read) +``` + +Os demais downloads de `product_invoices` seguem o mesmo contrato e também +devolvem um `Nfe::NfeFileResource`: `download_xml`, `download_rejection_xml`, +`download_epec_xml`, `download_correction_letter_pdf` e +`download_correction_letter_xml`. + +## Resumo dos contratos + +| Recurso | Retorno do `download_*` | Como salvar | +| --- | --- | --- | +| `service_invoices` | String binária (`ASCII-8BIT`) | `File.binwrite` direto | +| `consumer_invoices` | String binária | `File.binwrite` direto | +| `transportation_invoices` | String binária | `File.binwrite` direto | +| `inbound_product_invoices` | String binária | `File.binwrite` direto | +| `product_invoice_query` | String binária | `File.binwrite` direto | +| `consumer_invoice_query` | String binária | `File.binwrite` direto | +| `product_invoices` | `Nfe::NfeFileResource` (URI) | baixe a `#uri` e então `File.binwrite` | +| `product_invoices_rtc` | `Nfe::NfeFileResource` (URI) | baixe a `#uri` e então `File.binwrite` | + +## Próximos passos + +- [Roteamento multi-host](./multi-host-routing.md) — por que os dois contratos existem (hosts diferentes). +- [Emissão RTC](./rtc-emission.md) — NF-e/NFC-e e NFS-e da Reforma Tributária. +- [Paginação](./pagination.md) — liste notas antes de baixá-las. diff --git a/docs/errors.md b/docs/errors.md new file mode 100644 index 0000000..fac33d7 --- /dev/null +++ b/docs/errors.md @@ -0,0 +1,155 @@ +--- +title: Tratamento de erros no SDK Ruby da NFE.io +sidebar_label: Tratamento de erros +sidebar_position: 4 +slug: tratamento-de-erros +description: A hierarquia Nfe::Error, a tabela de códigos HTTP por classe, padrões idiomáticos de rescue, validação client-side fail-fast, RateLimitError#retry_after e erros de rede. +--- + +# Tratamento de erros + +Todos os erros do SDK derivam de `Nfe::Error`, então você pode capturar a +família inteira com um único `rescue Nfe::Error`. Esta página descreve a +hierarquia, os códigos HTTP mapeados, padrões de `rescue` por tipo, a validação +client-side e os erros de rede. + +## A hierarquia de erros + +| Classe | Código HTTP | Quando ocorre | +| --- | --- | --- | +| `Nfe::Error` | — | Base de toda a família. | +| `Nfe::AuthenticationError` | 401 | Chave de API ausente ou inválida. | +| `Nfe::AuthorizationError` | 403 | Chave válida, mas sem permissão para o recurso. | +| `Nfe::InvalidRequestError` | 400 / 422 | Requisição malformada ou reprovada na validação. | +| `Nfe::NotFoundError` | 404 | Recurso não existe. | +| `Nfe::ConflictError` | 409 | Conflito com o estado atual do recurso. | +| `Nfe::RateLimitError` | 429 | Excesso de requisições; expõe `#retry_after`. | +| `Nfe::ServerError` | 5xx | Falha no servidor da API. | +| `Nfe::ApiConnectionError` | — | Falha de rede (DNS, conexão recusada, TLS, reset). | +| `Nfe::TimeoutError` | — | Timeout de conexão/leitura (`< ApiConnectionError`). | +| `Nfe::SignatureVerificationError` | — | Assinatura de webhook reprovada. | +| `Nfe::ConfigurationError` | — | SDK mal configurado (chave ausente, `environment` inválido). | +| `Nfe::InvoiceProcessingError` | — | Resposta 202 viola o protocolo (ex.: sem header `Location`). | + +:::note `TimeoutError` é subclasse de `ApiConnectionError` +Um `rescue Nfe::ApiConnectionError` também captura `Nfe::TimeoutError`. Trate o +timeout antes, se quiser distingui-lo. +::: + +## Contexto carregado pelos erros HTTP + +Erros derivados de uma resposta HTTP carregam contexto para diagnóstico: +`#status_code`, `#request_id`, `#error_code`, `#response_body` e +`#response_headers`. + +```ruby +begin + client.service_invoices.retrieve(company_id: "...", invoice_id: "...") +rescue Nfe::Error => e + e.status_code # ex.: 404 + e.request_id # id de correlação do servidor + e.error_code # código de erro legível por máquina +end +``` + +:::tip `#to_h` é seguro para logs +`Nfe::Error#to_h` devolve um Hash com `type`, `message`, `status_code`, +`request_id` e `error_code` — e **omite deliberadamente** o corpo e os headers +brutos, que podem conter a chave de API ou PII. Prefira-o ao logar erros. +::: + +## Padrões de `rescue` por tipo + +Capture do mais específico para o mais genérico: + +```ruby +begin + client.service_invoices.create(company_id: company_id, data: payload) +rescue Nfe::AuthenticationError + # 401 — revise a chave de API. + raise +rescue Nfe::AuthorizationError + # 403 — a chave não tem permissão para este recurso. + raise +rescue Nfe::InvalidRequestError => e + # 400/422 — corrija o payload; e.message traz o detalhe do servidor. + warn "Requisição inválida: #{e.message}" +rescue Nfe::RateLimitError => e + # 429 — respeite o retry_after antes de tentar de novo. + sleep(e.retry_after || 5) + retry +rescue Nfe::ServerError + # 5xx — falha do lado do servidor; reportar/retentar com backoff. + raise +rescue Nfe::TimeoutError + # Timeout de conexão/leitura. + raise +rescue Nfe::ApiConnectionError + # Outras falhas de rede. + raise +rescue Nfe::Error => e + # Rede de segurança para qualquer erro do SDK. + warn e.to_h.inspect + raise +end +``` + +## Validação client-side (fail-fast) + +Validações client-side (id de empresa vazio, chave de acesso com tamanho +errado, CNPJ/CPF/CEP/UF inválidos) levantam `Nfe::InvalidRequestError` com uma +mensagem em pt-BR **antes** de qualquer requisição HTTP: + +```ruby +begin + client.service_invoices.retrieve(company_id: "", invoice_id: "abc") +rescue Nfe::InvalidRequestError => e + # Levantado de forma síncrona, sem rede. e.status_code é nil aqui. + warn e.message # mensagem em português identificando o argumento inválido +end +``` + +:::note Sem `status_code` na validação local +Por não vir de uma resposta HTTP, um `InvalidRequestError` client-side tem +`status_code` igual a `nil` — diferente do mesmo erro vindo de um 400/422. +::: + +## `RateLimitError#retry_after` + +No HTTP 429, o SDK lê o header `Retry-After` (quando presente) e o expõe como um +inteiro de segundos em `#retry_after`. Pode ser `nil` se o servidor não anunciar. + +```ruby +begin + client.addresses.retrieve(postal_code: "01310100") +rescue Nfe::RateLimitError => e + wait = e.retry_after || 5 + sleep wait + retry +end +``` + +## Erros de rede + +Quando nenhuma troca HTTP se completa, o SDK levanta um erro de rede em vez de +devolver uma resposta: + +- `Nfe::ApiConnectionError` — DNS, conexão recusada, TLS, reset de conexão. +- `Nfe::TimeoutError` — timeout de conexão ou de leitura; subclasse de + `ApiConnectionError`. A exceção original fica preservada em `cause`. + +```ruby +begin + client.companies.list +rescue Nfe::TimeoutError => e + warn "Timeout: #{e.message}; causa original: #{e.cause&.class}" +rescue Nfe::ApiConnectionError => e + warn "Falha de conexão: #{e.message}" +end +``` + +## Próximos passos + +- [Emissão assíncrona e polling](./async-and-polling.md) — trate falhas no loop. +- [Configuração](./configuration.md) — `timeout`, `max_retries` e TLS. +- [Primeiros passos](./getting-started.md) — visão geral do SDK. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..e05fdd7 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,108 @@ +--- +title: Primeiros passos com o SDK Ruby da NFE.io +sidebar_label: Primeiros passos +sidebar_position: 1 +slug: primeiros-passos +description: Instale o gem nfe-io, crie um Nfe::Client, emita sua primeira NFS-e e acompanhe o processamento com polling. +--- + +# Primeiros passos + +Este guia cobre a instalação, a criação do cliente e a emissão da sua primeira +nota fiscal de serviço (NFS-e), incluindo o acompanhamento do processamento. + +## 1. Instale o gem + +```ruby +# Gemfile +gem "nfe-io", "~> 1.0" +``` + +```sh +bundle install +# ou, sem editar o Gemfile: +bundle add nfe-io +``` + +:::note Requisitos +Ruby **3.2** ou superior. O SDK não tem dependências de runtime — apenas a +biblioteca padrão do Ruby. +::: + +## 2. Crie um cliente + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) +``` + +A chave também pode vir da variável de ambiente `NFE_API_KEY` — o argumento +explícito sempre vence. Recursos de **dados** (CEP, CNPJ, CPF, consultas) usam +uma segunda chave, `data_api_key:`, com fallback para `api_key`. Todas as opções +estão em [Configuração](./configuration.md). + +## 3. Emita uma NFS-e + +```ruby +result = client.service_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + cityServiceCode: "2690", + description: "Manutenção e suporte técnico", + servicesAmount: 100.0, + borrower: { federalTaxNumber: "191", name: "Banco do Brasil SA" } + } +) +``` + +:::tip Chaves em camelCase +O corpo (`data:`) usa as chaves em camelCase, exatamente como a API espera. +::: + +## 4. Trate o retorno discriminado + +A emissão é assíncrona. `create` devolve **um de dois tipos**, que você pode +distinguir com pattern matching ou com os predicados `pending?`/`issued?`: + +```ruby +case result +in Nfe::Resources::ServiceInvoicePending => pending + pending.invoice_id # id para reconsultar enquanto processa +in Nfe::Resources::ServiceInvoiceIssued => issued + issued.resource # NFS-e já materializada (HTTP 201) +end +``` + +## 5. Acompanhe até um estado terminal (polling) + +Não existe `create_and_wait` na `v1.0` — faça polling com `retrieve` até um +estado terminal, usando `Nfe::FlowStatus.terminal?`: + +```ruby +company_id = "55df4dc6b6cd9007e4f13ee8" +invoice_id = result.pending? ? result.invoice_id : result.resource.id + +loop do + invoice = client.service_invoices.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + + sleep 2 +end +``` + +:::warning Produção vs. teste +A separação **produção vs. teste (homologação)** é definida na configuração da +sua conta em [app.nfe.io](https://app.nfe.io) — **não** pela chave de API nem +pelo SDK. O argumento `environment:` do cliente está reservado para uso futuro. +::: + +## Próximos passos + +- [Configuração](./configuration.md) — todas as opções do cliente. +- [Emissão assíncrona e polling](./async-and-polling.md) — o contrato 202 em detalhe. +- [Tratamento de erros](./errors.md) — `rescue` por tipo. +- [Webhooks](./webhooks.md) — receba a conclusão por push em vez de polling. diff --git a/docs/multi-host-routing.md b/docs/multi-host-routing.md new file mode 100644 index 0000000..e52a527 --- /dev/null +++ b/docs/multi-host-routing.md @@ -0,0 +1,83 @@ +--- +title: Roteamento multi-host no SDK Ruby da NFE.io +sidebar_label: Roteamento multi-host +sidebar_position: 8 +slug: roteamento-multi-host +description: Entenda como o SDK roteia cada recurso para o host correto (api.nfe.io, api.nfse.io e os hosts de dados), o modelo de duas chaves e o escape hatch base_url_overrides. +--- + +# Roteamento multi-host + +A plataforma NFE.io expõe várias APIs em hosts diferentes. O SDK roteia cada +recurso **automaticamente** para o host certo — nenhum recurso hard-codeia uma +URL. Cada recurso declara uma **família** (`api_family`) e obtém seu host a +partir da `Nfe::Configuration`. + +## Famílias, hosts e recursos + +| Família | Host | Recursos | +| --- | --- | --- | +| `main` | `api.nfe.io` (`/v1`) | `service_invoices`, `service_invoices_rtc`, entidades (companies, legal/natural people), `webhooks` | +| `cte` | `api.nfse.io` (`/v2`) | `product_invoices`, `product_invoices_rtc`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `tax_calculation`, `tax_codes`, `state_taxes` | +| `addresses` | `address.api.nfe.io/v2` | consulta de endereços (CEP) | +| `legal-entity` | `legalentity.api.nfe.io` | consulta de pessoa jurídica (CNPJ) | +| `natural-person` | `naturalperson.api.nfe.io` | consulta de pessoa física (CPF) | +| `nfe-query` | `nfe.api.nfe.io` | `product_invoice_query`, `consumer_invoice_query` | + +:::note O segmento de versão +Para a família `main`, o `/v1` é fornecido pelo `api_version` de cada recurso, +não pelo host. O host de `addresses` já embute o `/v2`. +::: + +## Modelo de duas chaves + +O SDK usa duas chaves de API. As **famílias de dados** preferem `data_api_key` +(com fallback para `api_key`); todas as outras famílias usam `api_key`. + +As famílias de dados são: + +- `addresses` +- `legal-entity` +- `natural-person` +- `nfe-query` + +```ruby +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") +) +``` + +Qualquer das chaves pode vir das variáveis de ambiente `NFE_API_KEY` / +`NFE_DATA_API_KEY` (o argumento explícito sempre vence). + +:::warning `:cte` NÃO é família de dados +A família `:cte` (`api.nfse.io` — emissão de NF-e/NFC-e/CT-e + regras de imposto, +tax codes e state taxes) usa a **`api_key` principal**, e não a `data_api_key`. +Neste SDK a emissão é uma capacidade central, não uma consulta de dados. Isso é +uma **divergência deliberada do SDK Node** (que roteia `api.nfse.io` pela cadeia +de fallback da chave de dados). +::: + +## Escape hatch: `base_url_overrides` + +Para apontar uma família para outro host (ambiente de testes próprio, proxy, +mock), use `base_url_overrides:` na configuração. Um override por família vence +o host padrão: + +```ruby +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + base_url_overrides: { + cte: "https://mock.local/nfse" + } +) +``` + +Uma família desconhecida cai no host `main` como padrão seguro. + +## Próximos passos + +- [Downloads](./downloads.md) — por que `product_invoices` (host `cte`) devolve uma URI em vez de bytes. +- [Emissão RTC](./rtc-emission.md) — os recursos RTC e seus hosts. +- [Paginação](./pagination.md) — formas de paginação por família. diff --git a/docs/pagination.md b/docs/pagination.md new file mode 100644 index 0000000..5402707 --- /dev/null +++ b/docs/pagination.md @@ -0,0 +1,108 @@ +--- +title: Paginação de listas no SDK Ruby da NFE.io +sidebar_label: Paginação +sidebar_position: 6 +slug: paginacao +description: Itere listas com Nfe::ListResponse (que inclui Enumerable) e leia os metadados de página em Nfe::ListPage — paginação por página ou por cursor, conforme o recurso. +--- + +# Paginação + +Os métodos `list` retornam um `Nfe::ListResponse`. Ele inclui `Enumerable`, então +você itera diretamente sobre os itens hidratados — sem precisar acessar `#data` — +e lê os metadados de paginação em `#page`. + +## `Nfe::ListResponse` + +Tem dois membros: + +- `#data` — o `Array` de DTOs hidratados. +- `#page` — um `Nfe::ListPage` com os metadados de paginação. + +Como inclui `Enumerable` (delegando `each` a `#data`), você usa `map`, `select`, +`each_with_index` e os demais métodos diretamente: + +```ruby +list = client.service_invoices.list(company_id: "55df4dc6b6cd9007e4f13ee8") + +list.each do |invoice| + puts invoice.id +end + +ids = list.map(&:id) # Enumerable direto, sem list.data +total = list.count +``` + +## `Nfe::ListPage` + +Os endpoints da NFE.io paginam em **uma de duas formas**, e cada recurso +preenche apenas a metade relevante: + +- **Por página** — `#page_index` / `#page_count` (campos de cursor ficam `nil`). +- **Por cursor** — `#starting_after` / `#ending_before` (`#page_index` fica `nil`). + +`#total` é opcional e pode aparecer em qualquer uma das formas. + +```ruby +page = list.page + +if page.page_index + puts "Página #{page.page_index} de #{page.page_count}" +else + puts "Próximo cursor: #{page.starting_after}" +end + +page.total # pode ser nil +``` + +## Qual recurso usa qual forma + +| Recurso | Forma de paginação | +| --- | --- | +| `service_invoices.list` | por página (`page_index`/`page_count`) | +| `product_invoices.list` | por cursor (`starting_after`/`ending_before`) | +| `product_invoices_rtc.list` | por cursor | +| `consumer_invoices.list` | por cursor | +| `state_taxes.list` | por cursor | + +### Por página: `service_invoices` + +```ruby +list = client.service_invoices.list( + company_id: "55df4dc6b6cd9007e4f13ee8", + page_index: 1, + page_count: 50 +) + +list.each { |inv| puts inv.id } +``` + +### Por cursor: `product_invoices` + +:::warning `environment:` é obrigatório +`product_invoices.list` e `product_invoices_rtc.list` **exigem** o argumento +`environment:` — uma String `"Production"` ou `"Test"`. Omiti-lo levanta +`Nfe::InvalidRequestError`. +::: + +```ruby +list = client.product_invoices.list( + company_id: "55df4dc6b6cd9007e4f13ee8", + environment: "Production", + limit: 50 +) + +# Avance usando o cursor da página anterior: +next_page = client.product_invoices.list( + company_id: "55df4dc6b6cd9007e4f13ee8", + environment: "Production", + starting_after: list.page.starting_after, + limit: 50 +) +``` + +## Próximos passos + +- [Downloads](./downloads.md) — baixe os arquivos das notas listadas. +- [Webhooks](./webhooks.md) — receba eventos por push em vez de listar. +- [Roteamento multi-host](./multi-host-routing.md) — entenda em qual host cada recurso vive. diff --git a/docs/recursos/_category_.json b/docs/recursos/_category_.json new file mode 100644 index 0000000..6a0316c --- /dev/null +++ b/docs/recursos/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Recursos (cookbook)", + "position": 10, + "collapsed": true, + "link": { "type": "generated-index", "slug": "recursos", "title": "Recursos (cookbook)" } +} diff --git a/docs/recursos/addresses.md b/docs/recursos/addresses.md new file mode 100644 index 0000000..7777728 --- /dev/null +++ b/docs/recursos/addresses.md @@ -0,0 +1,78 @@ +--- +title: Consulta de endereços (addresses) no SDK Ruby da NFE.io +sidebar_label: Endereços +sidebar_position: 11 +slug: enderecos +description: Consulta de endereços por CEP, por termo livre e por filtro OData no recurso addresses do SDK Ruby da NFE.io. +--- + +# Consulta de endereços (`addresses`) + +O recurso `addresses` consulta endereços por CEP, por termo livre ou por filtro +OData. Faz parte da família de **dados** `addresses`, servida por +`address.api.nfe.io/v2`. Como host já embute a versão, os caminhos são usados como +estão. + +:::note Família de dados — configure `data_api_key` +`addresses` é um serviço de **dados**: usa a `data_api_key` quando presente, com +**fallback** para a `api_key`. Configure `data_api_key:` (ou `NFE_DATA_API_KEY`) +para separar a chave de consulta da chave de emissão. Veja +[Configuração](../configuration.md). +::: + +## Métodos públicos + +```ruby +addresses.lookup_by_postal_code(postal_code) # => Nfe::AddressLookupResponse +addresses.lookup_by_term(term) # => Nfe::AddressLookupResponse +addresses.search(filter: nil) # => Nfe::AddressLookupResponse +``` + +## Exemplos + +### Consultar por CEP + +```ruby +require "nfe" + +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") +) + +resposta = client.addresses.lookup_by_postal_code("01310-100") +resposta.addresses +``` + +:::warning CEP é validado antes do HTTP +O CEP precisa ter **8 dígitos** (separadores são removidos). Um CEP inválido +levanta `Nfe::InvalidRequestError` **antes** de qualquer requisição. Veja +[Tratamento de erros](../errors.md). +::: + +### Consultar por termo livre + +```ruby +client.addresses.lookup_by_term("Avenida Paulista, São Paulo") +``` + +Um `term` vazio ou só com espaços levanta `Nfe::InvalidRequestError`. + +### Buscar com filtro OData + +```ruby +client.addresses.search(filter: "city eq 'São Paulo'") + +# Sem filtro: lista o que a API retornar por padrão. +client.addresses.search +``` + +:::note `filter` é opaco +O argumento `filter:` é repassado verbatim como `$filter` na query — o SDK não +interpreta nem valida a expressão OData. +::: + +## Veja também + +- [Configuração](../configuration.md) — modelo de duas chaves e `data_api_key`. +- [Consulta de CNPJ](./legal-entity-lookup.md) e [Consulta de CPF](./natural-person-lookup.md) — outras famílias de dados. diff --git a/docs/recursos/companies.md b/docs/recursos/companies.md new file mode 100644 index 0000000..3b6ed7a --- /dev/null +++ b/docs/recursos/companies.md @@ -0,0 +1,125 @@ +--- +title: Empresas (companies) no SDK Ruby da NFE.io +sidebar_label: Empresas +sidebar_position: 7 +slug: empresas +description: CRUD de empresas e ciclo de vida do certificado digital (upload, validação e status) no recurso companies do SDK Ruby da NFE.io. +--- + +# Empresas (`companies`) + +O recurso `companies` gerencia as empresas emissoras da sua conta — CRUD completo +mais o ciclo de vida do certificado digital (upload, substituição, validação e +status). Faz parte da família `main`, servida por `api.nfe.io` (`/v1`), e usa a +`api_key`. + +:::note Exclusão é `remove`, não `delete` +Para excluir uma empresa, chame `companies.remove(company_id)`. O nome evita +conflito de semântica com `delete` e mantém paridade com os SDKs Node e PHP. +::: + +## Métodos públicos + +```ruby +companies.create(data) # => Nfe::Company +companies.list(page_index: 0, page_count: 100) # => Nfe::ListResponse +companies.list_all # => Array +companies.list_each # => Enumerator +companies.retrieve(company_id) # => Nfe::Company +companies.update(company_id, data) # => Nfe::Company +companies.remove(company_id) # => { deleted: true, id: ... } +companies.find_by_tax_number(tax_number) # => Nfe::Company | nil +companies.find_by_name(name) # => Array + +# Certificado digital +companies.validate_certificate(file:, password:) # => Nfe::CertificateInfo (sem HTTP) +companies.upload_certificate(company_id, file:, password:, filename: nil) +companies.replace_certificate(company_id, file:, password:, filename: nil) +companies.get_certificate_status(company_id) # => Nfe::CertificateStatus +companies.check_certificate_expiration(company_id, threshold_days: 30) +companies.get_companies_with_certificates # => Array +companies.get_companies_with_expiring_certificates(threshold_days: 30) +``` + +## Exemplos + +### Criar e recuperar uma empresa + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) + +company = client.companies.create( + name: "Acme Serviços LTDA", + federalTaxNumber: "12345678000199", + email: "fiscal@acme.com.br" +) + +client.companies.retrieve(company.id) +``` + +:::tip Validação local de `federalTaxNumber` +`create` e `update` validam o formato de `federalTaxNumber` (11 dígitos para CPF +ou 14 para CNPJ) e o formato do `email` quando presente, levantando +`Nfe::InvalidRequestError` **antes** de qualquer requisição HTTP. Não há +verificação de dígito verificador. +::: + +### Paginar e localizar empresas + +```ruby +# Uma página por vez (page_index é 0-based no SDK): +page = client.companies.list(page_index: 0, page_count: 50) +page.data.each { |c| puts c.name } + +# Todas as empresas (auto-paginação) ou stream preguiçoso: +client.companies.list_all +client.companies.list_each.each { |c| puts c.id } + +# Buscas auxiliares (filtragem no cliente): +client.companies.find_by_tax_number("12.345.678/0001-99") +client.companies.find_by_name("acme") +``` + +:::warning Helpers de busca não são otimizados +`find_by_tax_number`, `find_by_name`, `list_all`, `get_companies_with_certificates` +e `get_companies_with_expiring_certificates` percorrem **todas** as páginas e +filtram no cliente. Evite em contas com muitas empresas. +::: + +### Validar e enviar o certificado digital + +```ruby +# Validação puramente local (não faz HTTP): confere senha e DER. +info = client.companies.validate_certificate( + file: "/caminho/certificado.pfx", + password: ENV.fetch("CERT_PASSWORD") +) + +# Upload: pré-valida localmente (fail-fast) e então envia multipart/form-data. +client.companies.upload_certificate( + company.id, + file: "/caminho/certificado.pfx", + password: ENV.fetch("CERT_PASSWORD"), + filename: "certificado.pfx" +) + +# Status e alerta de expiração: +status = client.companies.get_certificate_status(company.id) +status.days_until_expiration + +client.companies.check_certificate_expiration(company.id, threshold_days: 30) +``` + +:::note Apenas `.pfx` e `.p12` +Quando você informa `filename:`, o SDK rejeita extensões diferentes de `.pfx` e +`.p12` com `Nfe::InvalidRequestError`. O parâmetro `file:` aceita um caminho de +arquivo ou os bytes brutos do certificado. +::: + +## Veja também + +- [Pessoas jurídicas](./legal-people.md) e [Pessoas físicas](./natural-people.md) — tomadores vinculados à empresa. +- [Webhooks](./webhooks.md) — eventos por empresa. +- [Tratamento de erros](../errors.md). diff --git a/docs/recursos/consumer-invoice-query.md b/docs/recursos/consumer-invoice-query.md new file mode 100644 index 0000000..844610e --- /dev/null +++ b/docs/recursos/consumer-invoice-query.md @@ -0,0 +1,68 @@ +--- +title: Consulta de NFC-e (consumer_invoice_query) no SDK Ruby da NFE.io +sidebar_label: Consulta de NFC-e +sidebar_position: 18 +slug: consulta-nfce +description: Consulta de cupom fiscal NFC-e (CFe-SAT) por chave de acesso — recuperação e download de XML — no SDK Ruby da NFE.io. +--- + +# Consulta de NFC-e (`consumer_invoice_query`) + +O recurso `consumer_invoice_query` consulta cupons fiscais NFC-e (CFe-SAT) já +emitidos, pela chave de acesso. Faz parte da família de **dados** `nfe_query`, +servida por `nfe.api.nfe.io` (`/v1`, caminho `/coupon/`). + +:::warning Não confunda com a emissão de NFC-e +Este recurso é **distinto** de `consumer_invoices` (emissão de NFC-e): host e +versão de API diferentes. Aqui apenas recuperamos e baixamos um cupom **já +emitido**. +::: + +:::note Família de dados — configure `data_api_key` +Esta é uma família de **dados**: usa a `data_api_key` quando presente, com +**fallback** para a `api_key`. Configure `data_api_key:` (ou `NFE_DATA_API_KEY`). +Veja [Configuração](../configuration.md). +::: + +## Métodos públicos + +```ruby +consumer_invoice_query.retrieve(access_key) # => Nfe::TaxCoupon +consumer_invoice_query.download_xml(access_key) # => String (bytes ASCII-8BIT) +``` + +## Exemplos + +### Recuperar um cupom e baixar o XML + +```ruby +require "nfe" + +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") +) + +chave = "35200114200166000187650010000000071234567890" + +cupom = client.consumer_invoice_query.retrieve(chave) + +xml = client.consumer_invoice_query.download_xml(chave) +File.binwrite("nfce.xml", xml) +``` + +:::warning Chave de acesso é validada antes do HTTP +A chave de acesso precisa ter **44 dígitos**. Uma chave inválida levanta +`Nfe::InvalidRequestError` **antes** de qualquer requisição. +::: + +:::tip `download_xml` retorna bytes binários +O retorno são os **bytes** do XML (`ASCII-8BIT`); grave com `File.binwrite`. Veja +o guia de [Downloads](../downloads.md). +::: + +## Veja também + +- [Consulta de NF-e (product_invoice_query)](./product-invoice-query.md) — o equivalente para NF-e. +- [Downloads](../downloads.md) — manipulação de XML binário. +- [Configuração](../configuration.md) — modelo de duas chaves. diff --git a/docs/recursos/consumer-invoices.md b/docs/recursos/consumer-invoices.md new file mode 100644 index 0000000..26ae3f3 --- /dev/null +++ b/docs/recursos/consumer-invoices.md @@ -0,0 +1,116 @@ +--- +title: Notas fiscais de consumidor (NFC-e) +sidebar_label: Notas de consumidor +sidebar_position: 3 +slug: notas-fiscais-de-consumidor +description: Emita NFC-e (modelo 65) com client.consumer_invoices no host api.nfse.io /v2 — emissão discriminada, listagem por cursor, downloads em bytes e inutilização coletiva. +--- + +# Notas fiscais de consumidor (NFC-e) + +`client.consumer_invoices` cobre o ciclo de vida da NFC-e (Nota Fiscal de +Consumidor Eletrônica, modelo 65) no host `api.nfse.io`, sob `/v2`. É útil para +integrações de PDV e e-commerce. + +:::note Adição parity-plus +Este recurso vai além do SDK Node.js, que não expõe emissão de NFC-e. A API +NFE.io suporta o ciclo completo da NFC-e desde a v2. +::: + +A emissão segue o **contrato 202 discriminado**: `create` / +`create_with_state_tax` devolvem `ConsumerInvoicePending` ou +`ConsumerInvoiceIssued`. Não há `create_and_wait` nem `create_batch`. + +## Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | Emite a NFC-e. | `ConsumerInvoicePending` ou `ConsumerInvoiceIssued` | +| `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` | Emite vinculada a uma inscrição estadual. | `ConsumerInvoicePending` ou `ConsumerInvoiceIssued` | +| `list(company_id:, environment:, **options)` | Lista por cursor. `environment` (`"Production"`/`"Test"`) é **obrigatório**. | `Nfe::ListResponse` | +| `retrieve(company_id:, invoice_id:)` | Consulta por id. | `Nfe::ConsumerInvoice` | +| `cancel(company_id:, invoice_id:)` | Cancela (síncrono). | `Nfe::ConsumerInvoice` | +| `list_items(company_id:, invoice_id:)` | Lista os itens. | `Array` | +| `list_events(company_id:, invoice_id:)` | Lista os eventos. | `Array` | +| `download_pdf(company_id:, invoice_id:)` | DANFE NFC-e PDF. | `String` binária | +| `download_xml(company_id:, invoice_id:)` | XML autorizado. | `String` binária | +| `download_rejection_xml(company_id:, invoice_id:)` | XML de rejeição. | `String` binária | +| `disable_range(company_id:, data:)` | Inutilização coletiva de uma faixa. | `Hash` | + +:::warning Métodos ausentes por lei fiscal +A NFC-e não tem carta de correção, EPEC, nem inutilização individual. Logo, +`send_correction_letter`, `download_epec_xml` e `disable` **não existem** neste +recurso — chamá-los levanta `NoMethodError`. Para inutilizar, use apenas +`disable_range` (coletiva). +::: + +## Emitir uma NFC-e + +```ruby +result = client.consumer_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + items: [ + { code: "001", description: "Café 250g", quantity: 2, unitAmount: 19.9 } + ], + payment: [{ method: "Cash", amount: 39.8 }] + } +) + +case result +in Nfe::Resources::ConsumerInvoicePending => pending + pending.invoice_id +in Nfe::Resources::ConsumerInvoiceIssued => issued + issued.resource # Nfe::ConsumerInvoice +end +``` + +:::tip Idempotência +`create` e `create_with_state_tax` aceitam `idempotency_key:` (header +`Idempotency-Key`) e `request_options:`. Reutilize a mesma chave em retentativas +para evitar emissão duplicada. +::: + +## Acompanhar até um estado terminal + +```ruby +loop do + nfce = client.consumer_invoices.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break if Nfe::FlowStatus.terminal?(nfce.flow_status) + + sleep 2 +end +``` + +## Baixar PDF e XML (bytes binários) + +Ao contrário das notas de produto, aqui os downloads retornam uma `String` +binária (`ASCII-8BIT`) — grave com `File.binwrite`. + +```ruby +pdf = client.consumer_invoices.download_pdf( + company_id: company_id, + invoice_id: invoice_id +) +File.binwrite("danfe-nfce.pdf", pdf) +``` + +## Inutilização coletiva + +```ruby +client.consumer_invoices.disable_range( + company_id: company_id, + data: { + environment: "Production", serie: 1, state: "SP", + beginNumber: 50, lastNumber: 60, reason: "Falha de comunicação com a SEFAZ" + } +) +``` + +## Próximos passos + +- [Notas de produto (NF-e)](./product-invoices.md) — modelo 55 com downloads por URI. +- [Emissão RTC](./rtc.md) — layout da Reforma Tributária para produto. diff --git a/docs/recursos/inbound-product-invoices.md b/docs/recursos/inbound-product-invoices.md new file mode 100644 index 0000000..4bce351 --- /dev/null +++ b/docs/recursos/inbound-product-invoices.md @@ -0,0 +1,116 @@ +--- +title: NF-e de entrada e manifestação do destinatário +sidebar_label: NF-e de entrada +sidebar_position: 5 +slug: notas-de-entrada +description: Habilite a busca automática de NF-e de fornecedores (Distribuição DFe), leia documentos e eventos por chave de acesso e envie a manifestação do destinatário com client.inbound_product_invoices no host api.nfse.io /v2. +--- + +# NF-e de entrada e manifestação do destinatário + +`client.inbound_product_invoices` gerencia NF-e **emitidas por fornecedores** +(entrada), no host `api.nfse.io`, sob `/v2`. Ele habilita a busca automática via +SEFAZ Distribuição DFe, lê documentos e eventos por chave de acesso, envia a +Manifestação do Destinatário e reprocessa webhooks. + +:::note Recurso de entrada, não de emissão +É um recurso de consulta/configuração; não há contrato 202 `Pending` / `Issued`. +Existem duas superfícies de detalhe: o formato webhook-v1 +(`.../inbound/{chave}`) e o formato webhook-v2 recomendado +(`.../inbound/productinvoice/{chave}`, que adiciona o array de NF-e de produto). +::: + +## Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `enable_auto_fetch(company_id:, **opts)` | Habilita a busca automática de NF-e. | `Nfe::InboundSettings` | +| `disable_auto_fetch(company_id:)` | Desabilita a busca automática. | `Nfe::InboundSettings` | +| `get_settings(company_id:)` | Lê as configurações atuais. | `Nfe::InboundSettings` | +| `get_details(company_id:, access_key:)` | Detalhes (webhook-v1). | `Nfe::InboundInvoiceMetadata` | +| `get_product_invoice_details(company_id:, access_key:)` | Detalhes da NF-e (webhook-v2). | `Nfe::InboundInvoiceMetadata` | +| `get_event_details(company_id:, access_key:, event_key:)` | Detalhes de um evento (webhook-v1). | `Nfe::InboundInvoiceMetadata` | +| `get_product_invoice_event_details(company_id:, access_key:, event_key:)` | Detalhes de um evento (webhook-v2). | `Nfe::InboundInvoiceMetadata` | +| `get_xml(company_id:, access_key:)` | XML do documento. | `String` binária | +| `get_event_xml(company_id:, access_key:, event_key:)` | XML de um evento. | `String` binária | +| `get_pdf(company_id:, access_key:)` | DANFE PDF da NF-e. | `String` binária | +| `get_json(company_id:, access_key:)` | Representação JSON estruturada. | `Nfe::InboundInvoiceMetadata` | +| `manifest(company_id:, access_key:, tp_event: 210210)` | Envia a manifestação do destinatário. | `String` | +| `reprocess_webhook(company_id:, access_key_or_nsu:)` | Reprocessa o webhook por chave ou NSU. | `Nfe::InboundInvoiceMetadata` | + +As opções de `enable_auto_fetch` são `start_from_nsu`, `start_from_date`, +`environment_sefaz`, `automatic_manifesting` e `webhook_version`. + +:::tip Constantes de tipo de evento da manifestação +O módulo expõe constantes para `tp_event`: + +```ruby +Nfe::Resources::InboundProductInvoices::MANIFEST_AWARENESS # 210210 (padrão) — Ciência da Operação +Nfe::Resources::InboundProductInvoices::MANIFEST_CONFIRMATION # 210220 — Confirmação da Operação +Nfe::Resources::InboundProductInvoices::MANIFEST_NOT_PERFORMED # 210240 — Operação não Realizada +``` +::: + +## Habilitar a busca automática + +```ruby +settings = client.inbound_product_invoices.enable_auto_fetch( + company_id: "55df4dc6b6cd9007e4f13ee8", + start_from_date: "2026-01-01", + webhook_version: "2" +) +``` + +## Ler uma NF-e de fornecedor + +```ruby +access_key = "35240611111111000199550010000012341000012345" + +detalhes = client.inbound_product_invoices.get_product_invoice_details( + company_id: company_id, + access_key: access_key +) + +pdf = client.inbound_product_invoices.get_pdf( + company_id: company_id, + access_key: access_key +) +File.binwrite("nfe-entrada.pdf", pdf) # bytes binários (ASCII-8BIT) +``` + +## Manifestar o destinatário + +`tp_event` é numérico e default `210210` (Ciência da Operação). Use as +constantes para confirmar ou recusar a operação. + +```ruby +# Ciência da operação (padrão): +client.inbound_product_invoices.manifest( + company_id: company_id, + access_key: access_key +) + +# Confirmação da operação: +client.inbound_product_invoices.manifest( + company_id: company_id, + access_key: access_key, + tp_event: Nfe::Resources::InboundProductInvoices::MANIFEST_CONFIRMATION +) +``` + +## Reprocessar webhook (por chave ou NSU) + +`reprocess_webhook` aceita tanto uma chave de acesso de 44 dígitos quanto um NSU +numérico — um NSU não é rejeitado como chave inválida. + +```ruby +client.inbound_product_invoices.reprocess_webhook( + company_id: company_id, + access_key_or_nsu: "123456" +) +``` + +## Próximos passos + +- [CT-e de entrada](./transportation-invoices.md) — busca automática de CT-e. +- [Webhooks](../webhooks.md) — receba a chegada de novos documentos por push. diff --git a/docs/recursos/legal-entity-lookup.md b/docs/recursos/legal-entity-lookup.md new file mode 100644 index 0000000..bceea8e --- /dev/null +++ b/docs/recursos/legal-entity-lookup.md @@ -0,0 +1,89 @@ +--- +title: Consulta de CNPJ (legal_entity_lookup) no SDK Ruby da NFE.io +sidebar_label: Consulta de CNPJ +sidebar_position: 12 +slug: consulta-cnpj +description: Consulta cadastral de pessoa jurídica por CNPJ — dados básicos e inscrição estadual (inclusive para emissão) no SDK Ruby da NFE.io. +--- + +# Consulta de CNPJ (`legal_entity_lookup`) + +O recurso `legal_entity_lookup` consulta dados cadastrais de pessoa jurídica por +CNPJ: informações básicas e inscrição estadual (inclusive a versão adequada para +emissão). Faz parte da família de **dados** `legal_entity`, servida por +`legalentity.api.nfe.io`. O segmento de versão (`/v2`) já vem no caminho de cada +requisição. + +:::note Família de dados — configure `data_api_key` +Esta é uma família de **dados**: usa a `data_api_key` quando presente, com +**fallback** para a `api_key`. Configure `data_api_key:` (ou `NFE_DATA_API_KEY`). +Veja [Configuração](../configuration.md). +::: + +## Métodos públicos + +```ruby +legal_entity_lookup.get_basic_info(federal_tax_number, update_address: nil, update_city_code: nil) +# => Nfe::LegalEntityBasicInfoResponse + +legal_entity_lookup.get_state_tax_info(state, federal_tax_number) +# => Nfe::LegalEntityStateTaxResponse + +legal_entity_lookup.get_state_tax_for_invoice(state, federal_tax_number) +# => Nfe::LegalEntityStateTaxForInvoiceResponse + +legal_entity_lookup.get_suggested_state_tax_for_invoice(state, federal_tax_number) +# => Nfe::LegalEntityStateTaxForInvoiceResponse +``` + +## Exemplos + +### Dados básicos de um CNPJ + +```ruby +require "nfe" + +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") +) + +info = client.legal_entity_lookup.get_basic_info("00.000.000/0001-91") +info + +# Opcionalmente força atualização de endereço/código de município: +client.legal_entity_lookup.get_basic_info( + "00000000000191", + update_address: true, + update_city_code: true +) +``` + +:::warning CNPJ é validado antes do HTTP +O CNPJ precisa ter **14 dígitos** (separadores removidos). Um CNPJ inválido +levanta `Nfe::InvalidRequestError` **antes** de qualquer requisição. +::: + +### Inscrição estadual para emissão + +```ruby +# Inscrição estadual em um estado (UF): +client.legal_entity_lookup.get_state_tax_info("SP", "00000000000191") + +# Versão adequada para uso em uma nota: +client.legal_entity_lookup.get_state_tax_for_invoice("SP", "00000000000191") + +# Sugestão da inscrição estadual para a nota: +client.legal_entity_lookup.get_suggested_state_tax_for_invoice("SP", "00000000000191") +``` + +:::note UF e CNPJ validados localmente +`state` é validado como UF (case-insensitive) e o CNPJ como 14 dígitos. Qualquer +um inválido levanta `Nfe::InvalidRequestError` antes do HTTP. +::: + +## Veja também + +- [Consulta de CPF](./natural-person-lookup.md) — o equivalente para PF. +- [Inscrições estaduais (state_taxes)](./state-taxes.md) — cadastro de IE da sua empresa. +- [Configuração](../configuration.md) — modelo de duas chaves. diff --git a/docs/recursos/legal-people.md b/docs/recursos/legal-people.md new file mode 100644 index 0000000..8d88b8e --- /dev/null +++ b/docs/recursos/legal-people.md @@ -0,0 +1,80 @@ +--- +title: Pessoas jurídicas (legal_people) no SDK Ruby da NFE.io +sidebar_label: Pessoas jurídicas +sidebar_position: 8 +slug: pessoas-juridicas +description: CRUD de pessoas jurídicas (tomadores PJ) escopadas por empresa, com create_batch e find_by_tax_number, no SDK Ruby da NFE.io. +--- + +# Pessoas jurídicas (`legal_people`) + +O recurso `legal_people` gerencia pessoas jurídicas (tomadores PJ) **escopadas por +empresa**, sob `/companies/{id}/legalpeople`. Faz parte da família `main`, servida +por `api.nfe.io` (`/v1`), e usa a `api_key`. + +## Métodos públicos + +```ruby +legal_people.list(company_id) # => Nfe::ListResponse +legal_people.create(company_id, data) # => Nfe::LegalPerson +legal_people.retrieve(company_id, legal_person_id) # => Nfe::LegalPerson +legal_people.update(company_id, legal_person_id, data) # => Nfe::LegalPerson +legal_people.delete(company_id, legal_person_id) # => nil +legal_people.create_batch(company_id, list) # => Array +legal_people.find_by_tax_number(company_id, federal_tax_number) # => Nfe::LegalPerson | nil +``` + +:::note `list` não pagina +`list(company_id)` devolve todas as pessoas jurídicas da empresa em um único +`Nfe::ListResponse` (paridade com o SDK Node), sem cursores nem páginas. +::: + +## Exemplos + +### Criar e recuperar + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) +company_id = "55df4dc6b6cd9007e4f13ee8" + +person = client.legal_people.create( + company_id, + name: "Banco do Brasil SA", + federalTaxNumber: "00000000000191" +) + +client.legal_people.retrieve(company_id, person.id) +``` + +### Criar várias de uma vez + +```ruby +people = client.legal_people.create_batch(company_id, [ + { name: "Fornecedor A LTDA", federalTaxNumber: "12345678000199" }, + { name: "Fornecedor B LTDA", federalTaxNumber: "98765432000188" } +]) +``` + +:::tip `create_batch` é sequencial +Diferente do SDK Node (que usa `Promise.all`), o `create_batch` executa as +criações **em sequência** e devolve os resultados na mesma ordem da lista. +::: + +### Localizar por CNPJ + +```ruby +person = client.legal_people.find_by_tax_number(company_id, "12.345.678/0001-99") +``` + +:::note Filtragem no cliente +`find_by_tax_number` chama `list` e filtra localmente, normalizando os dígitos do +CNPJ antes de comparar. +::: + +## Veja também + +- [Pessoas físicas](./natural-people.md) — o equivalente para PF. +- [Empresas](./companies.md) — o escopo (`company_id`) destes recursos. +- [Consulta de CNPJ](./legal-entity-lookup.md) — dados cadastrais de uma PJ na Receita. diff --git a/docs/recursos/natural-people.md b/docs/recursos/natural-people.md new file mode 100644 index 0000000..c08ed8d --- /dev/null +++ b/docs/recursos/natural-people.md @@ -0,0 +1,72 @@ +--- +title: Pessoas físicas (natural_people) no SDK Ruby da NFE.io +sidebar_label: Pessoas físicas +sidebar_position: 9 +slug: pessoas-fisicas +description: CRUD de pessoas físicas (tomadores PF) escopadas por empresa, com create_batch e find_by_tax_number, no SDK Ruby da NFE.io. +--- + +# Pessoas físicas (`natural_people`) + +O recurso `natural_people` gerencia pessoas físicas (tomadores PF) **escopadas por +empresa**, sob `/companies/{id}/naturalpeople`. Faz parte da família `main`, +servida por `api.nfe.io` (`/v1`), e usa a `api_key`. + +## Métodos públicos + +```ruby +natural_people.list(company_id) # => Nfe::ListResponse +natural_people.create(company_id, data) # => Nfe::NaturalPerson +natural_people.retrieve(company_id, natural_person_id) # => Nfe::NaturalPerson +natural_people.update(company_id, natural_person_id, data) # => Nfe::NaturalPerson +natural_people.delete(company_id, natural_person_id) # => nil +natural_people.create_batch(company_id, list) # => Array +natural_people.find_by_tax_number(company_id, federal_tax_number) # => Nfe::NaturalPerson | nil +``` + +:::note `list` não pagina +`list(company_id)` devolve todas as pessoas físicas da empresa em um único +`Nfe::ListResponse` (paridade com o SDK Node), sem cursores nem páginas. +::: + +## Exemplos + +### Criar e recuperar + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) +company_id = "55df4dc6b6cd9007e4f13ee8" + +person = client.natural_people.create( + company_id, + name: "Maria da Silva", + federalTaxNumber: "39053344705" +) + +client.natural_people.retrieve(company_id, person.id) +``` + +### Criar várias e localizar por CPF + +```ruby +client.natural_people.create_batch(company_id, [ + { name: "João Souza", federalTaxNumber: "11144477735" }, + { name: "Ana Lima", federalTaxNumber: "39053344705" } +]) + +# find_by_tax_number normaliza para 11 dígitos antes de filtrar: +client.natural_people.find_by_tax_number(company_id, "390.533.447-05") +``` + +:::tip `create_batch` é sequencial +As criações são executadas **em sequência** e devolvidas na ordem da lista +informada — não em paralelo. +::: + +## Veja também + +- [Pessoas jurídicas](./legal-people.md) — o equivalente para PJ. +- [Empresas](./companies.md) — o escopo (`company_id`) destes recursos. +- [Consulta de CPF](./natural-person-lookup.md) — situação cadastral de uma PF na Receita. diff --git a/docs/recursos/natural-person-lookup.md b/docs/recursos/natural-person-lookup.md new file mode 100644 index 0000000..3d0233d --- /dev/null +++ b/docs/recursos/natural-person-lookup.md @@ -0,0 +1,62 @@ +--- +title: Consulta de CPF (natural_person_lookup) no SDK Ruby da NFE.io +sidebar_label: Consulta de CPF +sidebar_position: 13 +slug: consulta-cpf +description: Consulta da situação cadastral de uma pessoa física (CPF + data de nascimento) na Receita Federal pelo SDK Ruby da NFE.io. +--- + +# Consulta de CPF (`natural_person_lookup`) + +O recurso `natural_person_lookup` consulta a situação cadastral de uma pessoa +física na Receita Federal a partir do CPF e da data de nascimento. Faz parte da +família de **dados** `natural_person`, servida por `naturalperson.api.nfe.io`. O +segmento de versão (`/v1`) já vem no caminho da requisição. + +:::note Família de dados — configure `data_api_key` +Esta é uma família de **dados**: usa a `data_api_key` quando presente, com +**fallback** para a `api_key`. Configure `data_api_key:` (ou `NFE_DATA_API_KEY`). +Veja [Configuração](../configuration.md). +::: + +## Métodos públicos + +```ruby +natural_person_lookup.get_status(federal_tax_number, birth_date) +# => Nfe::NaturalPersonStatusResponse | nil +``` + +O `birth_date` aceita `String`, `Date`, `Time` ou `DateTime` — o SDK normaliza +para `YYYY-MM-DD` via `Nfe::DateNormalizer` antes da requisição. + +## Exemplos + +### Consultar a situação cadastral + +```ruby +require "nfe" +require "date" + +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") +) + +# Data como String: +client.natural_person_lookup.get_status("390.533.447-05", "1985-03-12") + +# Ou como objeto Date/Time/DateTime: +client.natural_person_lookup.get_status("39053344705", Date.new(1985, 3, 12)) +``` + +:::warning CPF e data validados antes do HTTP +O CPF é normalizado para **11 dígitos** e a data de nascimento é normalizada para +`YYYY-MM-DD`. Entradas inválidas levantam `Nfe::InvalidRequestError` **antes** de +qualquer requisição. Veja [Tratamento de erros](../errors.md). +::: + +## Veja também + +- [Consulta de CNPJ](./legal-entity-lookup.md) — o equivalente para PJ. +- [Pessoas físicas](./natural-people.md) — cadastro de tomadores PF na sua conta. +- [Configuração](../configuration.md) — modelo de duas chaves. diff --git a/docs/recursos/product-invoice-query.md b/docs/recursos/product-invoice-query.md new file mode 100644 index 0000000..c02e03e --- /dev/null +++ b/docs/recursos/product-invoice-query.md @@ -0,0 +1,75 @@ +--- +title: Consulta de NF-e (product_invoice_query) no SDK Ruby da NFE.io +sidebar_label: Consulta de NF-e +sidebar_position: 17 +slug: consulta-nfe +description: Consulta de NF-e por chave de acesso — detalhes, download de PDF (DANFE) e XML, e listagem de eventos — no SDK Ruby da NFE.io. +--- + +# Consulta de NF-e (`product_invoice_query`) + +O recurso `product_invoice_query` faz consultas somente-leitura de NF-e (nota +fiscal de produto) pela chave de acesso: detalhes, download de PDF (DANFE) e XML, +e listagem de eventos. Faz parte da família de **dados** `nfe_query`, servida por +`nfe.api.nfe.io`. O segmento de versão (`/v2`) já vem no caminho da requisição. + +:::note Família de dados — configure `data_api_key` +Esta é uma família de **dados**: usa a `data_api_key` quando presente, com +**fallback** para a `api_key`. Configure `data_api_key:` (ou `NFE_DATA_API_KEY`). +Veja [Configuração](../configuration.md). +::: + +## Métodos públicos + +```ruby +product_invoice_query.retrieve(access_key) # => Nfe::ProductInvoiceDetails | nil +product_invoice_query.download_pdf(access_key) # => String (bytes ASCII-8BIT) +product_invoice_query.download_xml(access_key) # => String (bytes ASCII-8BIT) +product_invoice_query.list_events(access_key) # => Nfe::ProductInvoiceEventsResponse | nil +``` + +## Exemplos + +### Consultar detalhes e eventos + +```ruby +require "nfe" + +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") +) + +chave = "35200114200166000187550010000000071234567890" + +detalhes = client.product_invoice_query.retrieve(chave) +eventos = client.product_invoice_query.list_events(chave) +``` + +:::warning Chave de acesso é validada antes do HTTP +A chave de acesso precisa ter **44 dígitos**. Uma chave inválida levanta +`Nfe::InvalidRequestError` **antes** de qualquer requisição. Veja +[Tratamento de erros](../errors.md). +::: + +### Baixar PDF (DANFE) e XML + +```ruby +pdf = client.product_invoice_query.download_pdf(chave) +File.binwrite("danfe.pdf", pdf) + +xml = client.product_invoice_query.download_xml(chave) +File.binwrite("nfe.xml", xml) +``` + +:::tip Downloads retornam bytes binários +`download_pdf` e `download_xml` devolvem os **bytes** (`ASCII-8BIT`), não um +objeto hidratado. Grave-os com `File.binwrite`. Veja o guia de +[Downloads](../downloads.md). +::: + +## Veja também + +- [Consulta de NFC-e (consumer_invoice_query)](./consumer-invoice-query.md) — o equivalente para cupons. +- [Downloads](../downloads.md) — manipulação de PDF/XML binários. +- [Configuração](../configuration.md) — modelo de duas chaves. diff --git a/docs/recursos/product-invoices.md b/docs/recursos/product-invoices.md new file mode 100644 index 0000000..3cfaf7f --- /dev/null +++ b/docs/recursos/product-invoices.md @@ -0,0 +1,158 @@ +--- +title: Notas fiscais de produto (NF-e) +sidebar_label: Notas de produto +sidebar_position: 2 +slug: notas-fiscais-de-produto +description: Emita NF-e modelo 55 com client.product_invoices no host api.nfse.io /v2 — listagem por cursor com environment obrigatório, carta de correção, inutilização e downloads por URI. +--- + +# Notas fiscais de produto (NF-e) + +`client.product_invoices` cobre o ciclo de vida completo da NF-e (modelo 55) no +host `api.nfse.io`, sob `/v2`: emissão, listagem por cursor, consulta, +cancelamento, carta de correção (CC-e), inutilização e downloads. + +A emissão segue o **contrato 202 discriminado** (assíncrona; conclusão via +webhook): `create` / `create_with_state_tax` devolvem `ProductInvoicePending` +ou `ProductInvoiceIssued`. Não há `create_and_wait` nem `create_batch`. + +:::warning Downloads retornam URI, não bytes +Diferente das demais notas, os métodos de download desta classe retornam um +`Nfe::NfeFileResource` com o atributo `uri` — **não** os bytes do arquivo. Use a +`uri` para baixar o conteúdo separadamente. +::: + +## Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | Emite a NF-e. | `ProductInvoicePending` ou `ProductInvoiceIssued` | +| `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` | Emite vinculada a uma inscrição estadual. | `ProductInvoicePending` ou `ProductInvoiceIssued` | +| `list(company_id:, environment:, **options)` | Lista por cursor; `environment` obrigatório. | `Nfe::ListResponse` | +| `retrieve(company_id:, invoice_id:)` | Consulta por id. | `Nfe::ProductInvoice` | +| `cancel(company_id:, invoice_id:, reason: nil)` | Cancela (assíncrono); `reason` vai na query. | `Hash` | +| `list_items(company_id:, invoice_id:, limit: nil, starting_after: nil)` | Lista os itens da nota. | `Nfe::ListResponse` | +| `list_events(company_id:, invoice_id:, limit: nil, starting_after: nil)` | Lista os eventos fiscais. | `Nfe::ListResponse` | +| `download_pdf(company_id:, invoice_id:, force: nil)` | DANFE PDF (URI). | `Nfe::NfeFileResource` | +| `download_xml(company_id:, invoice_id:)` | XML autorizado (URI). | `Nfe::NfeFileResource` | +| `download_rejection_xml(company_id:, invoice_id:)` | XML de rejeição (URI). | `Nfe::NfeFileResource` | +| `download_epec_xml(company_id:, invoice_id:)` | XML de contingência EPEC (URI). | `Nfe::NfeFileResource` | +| `send_correction_letter(company_id:, invoice_id:, reason:)` | Emite CC-e; `reason` de 15 a 1000 caracteres. | `Hash` | +| `download_correction_letter_pdf(company_id:, invoice_id:)` | PDF da CC-e (URI). | `Nfe::NfeFileResource` | +| `download_correction_letter_xml(company_id:, invoice_id:)` | XML da CC-e (URI). | `Nfe::NfeFileResource` | +| `disable(company_id:, invoice_id:, reason: nil)` | Inutiliza uma nota (assíncrono). | `Hash` | +| `disable_range(company_id:, data:)` | Inutiliza uma faixa de numeração. | `Hash` | + +As opções de cursor em `list`, `list_items` e `list_events` são +`starting_after`, `ending_before`, `limit` e `q`. + +## Emitir uma NF-e + +```ruby +result = client.product_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + buyer: { federalTaxNumber: 11111111111111, name: "Cliente Exemplo LTDA" }, + items: [ + { code: "001", description: "Produto X", quantity: 1, unitAmount: 99.9 } + ] + } +) + +if result.pending? + result.invoice_id # acompanhe via retrieve +else + result.resource # Nfe::ProductInvoice +end +``` + +:::tip Idempotência +Tanto `create` quanto `create_with_state_tax` aceitam `idempotency_key:` (header +`Idempotency-Key`) e `request_options:` (overrides por chamada). Em retentativas, +reutilize a **mesma** chave para evitar emissão duplicada. +::: + +## Listar com `environment` obrigatório + +A paginação é por cursor e o parâmetro `environment` (String `"Production"` ou +`"Test"`) é **obrigatório** — chamar `list` sem ele levanta +`Nfe::InvalidRequestError` sem chamada HTTP. + +```ruby +pagina = client.product_invoices.list( + company_id: company_id, + environment: "Production", + limit: 50 +) +pagina.each { |nf| puts nf.id } +``` + +:::note `environment` é o ambiente da SEFAZ +Este `environment` (String) é um parâmetro real de ambiente da SEFAZ, separado +da configuração produção/teste da conta (definida em +[app.nfe.io](https://app.nfe.io)). O `environment:` (símbolo) do `Nfe::Client` +está reservado para uso futuro. +::: + +## Acompanhar até um estado terminal + +```ruby +loop do + nf = client.product_invoices.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break if Nfe::FlowStatus.terminal?(nf.flow_status) + + sleep 2 +end +``` + +## Baixar arquivos (via URI) + +```ruby +arquivo = client.product_invoices.download_pdf( + company_id: company_id, + invoice_id: invoice_id +) +arquivo.uri # URL para baixar o DANFE PDF +``` + +## Carta de correção (CC-e) + +O `reason` precisa ter entre 15 e 1000 caracteres; fora dessa faixa o SDK +levanta `Nfe::InvalidRequestError` antes de qualquer HTTP. + +```ruby +client.product_invoices.send_correction_letter( + company_id: company_id, + invoice_id: invoice_id, + reason: "Correção do endereço de entrega do destinatário" +) +``` + +## Inutilizar (disablement) + +```ruby +# Uma nota específica: +client.product_invoices.disable( + company_id: company_id, + invoice_id: invoice_id, + reason: "Numeração não utilizada" +) + +# Uma faixa de numeração: +client.product_invoices.disable_range( + company_id: company_id, + data: { + environment: "Production", serie: 1, state: "SP", + beginNumber: 100, lastNumber: 110, reason: "Falha de impressão" + } +) +``` + +## Próximos passos + +- [Notas de consumidor (NFC-e)](./consumer-invoices.md) — downloads em bytes. +- [Emissão RTC](./rtc.md) — `product_invoices_rtc` com IBS/CBS/IS no item. +- [Paginação](../pagination.md) — cursor vs. página. diff --git a/docs/recursos/rtc.md b/docs/recursos/rtc.md new file mode 100644 index 0000000..b64fb47 --- /dev/null +++ b/docs/recursos/rtc.md @@ -0,0 +1,214 @@ +--- +title: Emissão RTC (Reforma Tributária — IBS, CBS e IS) +sidebar_label: Emissão RTC +sidebar_position: 6 +slug: rtc +description: Emita NFS-e e NF-e/NFC-e no layout da Reforma Tributária do Consumo com client.service_invoices_rtc (api.nfe.io /v1) e client.product_invoices_rtc (api.nfse.io /v2), selecionando o layout pela presença dos grupos IBS/CBS no payload. +--- + +# Emissão RTC (Reforma Tributária do Consumo) + +A Reforma Tributária do Consumo (RTC) adiciona os grupos de tributos IBS, CBS e +IS aos documentos fiscais. O SDK expõe dois recursos dedicados e **opt-in** para +emitir no layout RTC, sem alterar os recursos clássicos: + +- `client.service_invoices_rtc` — NFS-e RTC, host `api.nfe.io` sob `/v1`. +- `client.product_invoices_rtc` — NF-e (mod 55) e NFC-e (mod 65) RTC, host `api.nfse.io` sob `/v2`. + +Ambos reutilizam os **mesmos endpoints** dos recursos clássicos. Não há header +nem parâmetro de discriminação: o layout RTC é selecionado pela **presença dos +grupos de imposto no payload**. + +:::note O que seleciona o layout RTC +- Em serviço: o grupo `ibsCbs` na raiz do payload (camelCase). +- Em produto: o grupo `IBSCBS` no nível do item (`items[].tax.IBSCBS`). + +Quando esses grupos estão ausentes, a API usa o layout clássico. +::: + +:::tip `data:` é sempre um Hash em camelCase +Em ambos os recursos, `create(data:)` recebe um **Hash** com chaves camelCase, +serializado como está. As DTOs geradas (`Nfe::Generated::ServiceInvoiceRtcV1` e +`Nfe::Generated::ProductInvoiceRtcV1`) documentam a **forma** esperada do +payload, mas só desserializam respostas — não são aceitas como entrada. +::: + +Consulte o guia conceitual em [Emissão RTC](../rtc-emission.md) para o contexto +fiscal completo. + +--- + +## NFS-e RTC — `client.service_invoices_rtc` + +Host `api.nfe.io` sob `/v1`, mesmo host do `client.service_invoices` clássico. + +### Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | Emite a NFS-e RTC. | `ServiceInvoiceRtcPending` ou `ServiceInvoiceRtcIssued` | +| `retrieve(company_id:, invoice_id:)` | Consulta por id. | `Nfe::ServiceInvoice` | +| `cancel(company_id:, invoice_id:)` | Cancela (síncrono). | `Nfe::ServiceInvoice` | +| `download_cancellation_xml(company_id:, invoice_id:)` | XML do evento de cancelamento (e110001). | `String` binária | + +### Emitir uma NFS-e RTC + +O grupo `ibsCbs` (com `operationIndicator` e `classCode`) seleciona o layout. + +```ruby +result = client.service_invoices_rtc.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + borrower: { federalTaxNumber: "191", name: "Banco do Brasil SA" }, + cityServiceCode: "2690", + federalServiceCode: "01.01", + description: "Consultoria", + servicesAmount: 100.0, + nbsCode: "1.0101", + ibsCbs: { + operationIndicator: "000000", + classCode: "000001", + cbs: { rate: 0.088, amount: 8.8 }, + ibs: { state: { rate: 0.177, amount: 17.7 }, municipal: { rate: 0.0, amount: 0.0 } } + } + } +) + +if result.is_a?(Nfe::Resources::ServiceInvoiceRtcPending) + result.invoice_id # acompanhe via retrieve +else + result.resource # Nfe::ServiceInvoice +end +``` + +:::warning Cancellation XML é apenas do Ambiente Nacional +`download_cancellation_xml` só está disponível para notas do Ambiente Nacional +(ADN) e depois que a nota atinge o status `Cancelled`. Provedores +municipais/ABRASF não têm esse evento; nesse caso a API responde 404 e o SDK +levanta `Nfe::NotFoundError`. +::: + +### Acompanhar até um estado terminal + +```ruby +loop do + nf = client.service_invoices_rtc.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break if Nfe::FlowStatus.terminal?(nf.flow_status) + + sleep 2 +end +``` + +--- + +## NF-e / NFC-e RTC — `client.product_invoices_rtc` + +Host `api.nfse.io` sob `/v2`, mesmo host do `client.product_invoices` clássico. +Um único `create` emite tanto NF-e (mod 55) quanto NFC-e (mod 65) — a distinção +vem da forma do payload (`printType`, `consumerType`/`presenceType`, presença de +`buyer`). + +### Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | Emite a NF-e/NFC-e RTC. | `ProductInvoiceRtcPending` ou `ProductInvoiceRtcIssued` | +| `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` | Emite vinculada a uma inscrição estadual. | `ProductInvoiceRtcPending` ou `ProductInvoiceRtcIssued` | +| `list(company_id:, environment:, starting_after: nil, ending_before: nil, limit: nil, q: nil)` | Lista por cursor; `environment` obrigatório. | `Nfe::ListResponse` | +| `retrieve(company_id:, invoice_id:)` | Consulta por id. | `InvoiceResource` | +| `cancel(company_id:, invoice_id:, reason: nil)` | Cancela (assíncrono). | `RequestCancellationResource` | +| `list_items(company_id:, invoice_id:)` | Lista os itens. | `InvoiceItemsResource` | +| `list_events(company_id:, invoice_id:)` | Lista os eventos. | `InvoiceEventsResource` | +| `download_pdf(company_id:, invoice_id:, force: false)` | DANFE PDF (URI). | `Nfe::NfeFileResource` | +| `download_xml(company_id:, invoice_id:)` | XML autorizado (URI). | `Nfe::NfeFileResource` | +| `download_rejection_xml(company_id:, invoice_id:)` | XML de rejeição (URI). | `Nfe::NfeFileResource` | +| `download_epec_xml(company_id:, invoice_id:)` | XML de contingência EPEC (URI). | `Nfe::NfeFileResource` | +| `send_correction_letter(company_id:, invoice_id:, reason:)` | Emite CC-e; `reason` de 15 a 1000 caracteres. | `RequestCancellationResource` | +| `download_correction_letter_pdf(company_id:, invoice_id:)` | PDF da CC-e (URI). | `Nfe::NfeFileResource` | +| `download_correction_letter_xml(company_id:, invoice_id:)` | XML da CC-e (URI). | `Nfe::NfeFileResource` | +| `disable(company_id:, invoice_id:, reason: nil)` | Inutiliza uma nota. | `DisablementResource` | +| `disable_range(company_id:, data:)` | Inutiliza uma faixa de numeração. | `DisablementResource` | + +Os tipos `InvoiceResource`, `RequestCancellationResource`, `DisablementResource` +etc. pertencem a `Nfe::Generated::ProductInvoiceRtcV1`. + +:::warning Downloads retornam URI, não bytes +Como no recurso clássico de produto, os downloads retornam um +`Nfe::NfeFileResource` (atributo `uri`), e não os bytes do arquivo. +::: + +### Emitir uma NF-e RTC + +O grupo `IBSCBS` no item (`items[].tax.IBSCBS`) seleciona o layout. O grupo `IS` +(Imposto Seletivo) existe apenas no payload de produto. + +```ruby +result = client.product_invoices_rtc.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + buyer: { federalTaxNumber: 11111111111111, name: "Cliente Exemplo LTDA" }, + items: [ + { + code: "001", description: "Produto X", quantity: 1, unitAmount: 100.0, + tax: { + IBSCBS: { + state: { rate: 0.177, amount: 17.7 }, + municipal: { rate: 0.0, amount: 0.0 }, + cbs: { rate: 0.088, amount: 8.8 } + }, + IS: { + situationCode: "00", classificationCode: "000", + basis: 100.0, rate: 0.0, amount: 0.0 + } + } + } + ] + } +) + +if result.is_a?(Nfe::Resources::ProductInvoiceRtcPending) + result.invoice_id +else + result.resource # Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource +end +``` + +### Listar com `environment` obrigatório + +```ruby +pagina = client.product_invoices_rtc.list( + company_id: company_id, + environment: "Production", + limit: 50 +) +pagina.each { |nf| puts nf.flow_status } +``` + +:::note `environment` é o ambiente da SEFAZ +O `environment` (String `"Production"`/`"Test"`) é o ambiente real da SEFAZ, +separado da configuração produção/teste da conta em +[app.nfe.io](https://app.nfe.io). Omiti-lo levanta `Nfe::InvalidRequestError` +sem chamada HTTP. +::: + +### Acompanhar até um estado terminal + +```ruby +loop do + nf = client.product_invoices_rtc.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break if Nfe::FlowStatus.terminal?(nf.flow_status) + + sleep 2 +end +``` + +## Próximos passos + +- [Emissão RTC (guia conceitual)](../rtc-emission.md) — IBS/CBS/IS em detalhe. +- [Notas de serviço](./service-invoices.md) e [Notas de produto](./product-invoices.md) — os recursos clássicos. diff --git a/docs/recursos/service-invoices.md b/docs/recursos/service-invoices.md new file mode 100644 index 0000000..2b52e67 --- /dev/null +++ b/docs/recursos/service-invoices.md @@ -0,0 +1,139 @@ +--- +title: Notas fiscais de serviço (NFS-e) +sidebar_label: Notas de serviço +sidebar_position: 1 +slug: notas-fiscais-de-servico +description: Emita, liste, consulte, cancele e baixe NFS-e com client.service_invoices no host api.nfe.io /v1, tratando o retorno discriminado 202. +--- + +# Notas fiscais de serviço (NFS-e) + +`client.service_invoices` é o recurso canônico de emissão da plataforma. Ele +fala com o host `api.nfe.io` no caminho `/v1` e cobre todo o ciclo de vida da +NFS-e: emissão assíncrona, listagem paginada, consulta, cancelamento, envio por +e-mail e download de PDF/XML. + +A emissão segue o **contrato 202 discriminado**: `create` devolve um de dois +tipos, e você acompanha o processamento com `retrieve` (ou `get_status`) até um +estado terminal. Não existe `create_and_wait` nem `create_batch` na `v1.0`. + +:::note Host e versão +Todas as URLs efetivas ficam sob `https://api.nfe.io/v1/...`. Este é o único +recurso de nota que usa o host `api.nfe.io`; os demais usam `api.nfse.io`. +::: + +## Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | Emite a NFS-e. | `ServiceInvoicePending` ou `ServiceInvoiceIssued` | +| `list(company_id:, **options)` | Lista paginada (page-style) com filtros de data. | `Nfe::ListResponse` | +| `retrieve(company_id:, invoice_id:)` | Consulta uma NFS-e por id. | `Nfe::ServiceInvoice` | +| `cancel(company_id:, invoice_id:)` | Cancela (síncrono) e devolve o modelo atualizado. | `Nfe::ServiceInvoice` | +| `send_email(company_id:, invoice_id:)` | Reenvia a nota por e-mail ao tomador. | `Hash` com `sent:` e `message:` | +| `download_pdf(company_id:, invoice_id: nil)` | PDF da nota; sem `invoice_id`, baixa o ZIP da empresa. | `String` binária | +| `download_xml(company_id:, invoice_id: nil)` | XML da nota; sem `invoice_id`, baixa o ZIP da empresa. | `String` binária | +| `get_status(company_id:, invoice_id:)` | Snapshot de status derivado de `retrieve` (sem HTTP extra). | `StatusResult` | + +As opções de `list` (em snake_case) são `page_index`, `page_count`, +`issued_begin`, `issued_end`, `created_begin`, `created_end` e `has_totals`. + +:::warning Validação fail-fast +Todo método valida `company_id` e `invoice_id` via `Nfe::IdValidator` **antes** +de qualquer chamada HTTP. Ids vazios ou em branco levantam +`Nfe::InvalidRequestError` sem tráfego de rede. +::: + +## Emitir uma NFS-e e tratar o retorno discriminado + +`create` devolve `ServiceInvoicePending` (HTTP 202, enfileirada) ou +`ServiceInvoiceIssued` (HTTP 201, já materializada). Distinga por pattern +matching ou pelos predicados `pending?` / `issued?`. + +```ruby +result = client.service_invoices.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + cityServiceCode: "2690", + description: "Manutenção e suporte técnico", + servicesAmount: 100.0, + borrower: { federalTaxNumber: "191", name: "Banco do Brasil SA" } + } +) + +case result +in Nfe::Resources::ServiceInvoicePending => pending + pending.invoice_id # id para reconsultar enquanto processa + pending.location # caminho do header Location +in Nfe::Resources::ServiceInvoiceIssued => issued + issued.resource # Nfe::ServiceInvoice já emitida +end +``` + +:::tip Idempotência em retentativas +Passe `idempotency_key:` para enviar o header `Idempotency-Key`. O SDK nunca +refaz o POST sozinho; em um timeout, reinvoque `create` com a **mesma** chave +para o servidor deduplicar e não emitir documento fiscal duplicado. +::: + +## Acompanhar até um estado terminal (polling) + +Use `get_status`, que deriva o status de um único `retrieve` (sem chamada HTTP +adicional) e expõe `complete?` e `failed?`. + +```ruby +company_id = "55df4dc6b6cd9007e4f13ee8" +invoice_id = result.pending? ? result.invoice_id : result.resource.id + +loop do + status = client.service_invoices.get_status( + company_id: company_id, + invoice_id: invoice_id + ) + break if status.complete? # via Nfe::FlowStatus.terminal? + + sleep 2 +end +``` + +Como alternativa, você pode chamar `retrieve` diretamente e testar +`Nfe::FlowStatus.terminal?(invoice.flow_status)`. + +## Baixar PDF e XML (bytes binários) + +Os downloads retornam uma `String` binária (`ASCII-8BIT`) — grave com +`File.binwrite`. Omitir `invoice_id` baixa o ZIP de todas as notas da empresa. + +```ruby +pdf = client.service_invoices.download_pdf( + company_id: company_id, + invoice_id: invoice_id +) +File.binwrite("nfse.pdf", pdf) + +# ZIP de todas as notas da empresa (sem invoice_id): +zip = client.service_invoices.download_xml(company_id: company_id) +File.binwrite("notas.zip", zip) +``` + +## Cancelar e reenviar por e-mail + +```ruby +cancelada = client.service_invoices.cancel( + company_id: company_id, + invoice_id: invoice_id +) +cancelada.flow_status # "Cancelled" + +envio = client.service_invoices.send_email( + company_id: company_id, + invoice_id: invoice_id +) +envio[:sent] # true/false +``` + +## Próximos passos + +- [Primeiros passos](../getting-started.md) — instalação e primeira emissão. +- [Notas de produto (NF-e)](./product-invoices.md) — host `api.nfse.io` e downloads por URI. +- [Emissão RTC](./rtc.md) — layout da Reforma Tributária. diff --git a/docs/recursos/state-taxes.md b/docs/recursos/state-taxes.md new file mode 100644 index 0000000..0443c46 --- /dev/null +++ b/docs/recursos/state-taxes.md @@ -0,0 +1,72 @@ +--- +title: Inscrições estaduais (state_taxes) no SDK Ruby da NFE.io +sidebar_label: Inscrições estaduais +sidebar_position: 16 +slug: inscricoes-estaduais +description: CRUD das inscrições estaduais (Inscrição Estadual) de uma empresa, com paginação cursor-style, no SDK Ruby da NFE.io. +--- + +# Inscrições estaduais (`state_taxes`) + +O recurso `state_taxes` gerencia as inscrições estaduais (Inscrição Estadual) de +uma empresa. Faz parte da família `cte`, servida por +`api.nfse.io` (`/v2/companies/{companyId}/statetaxes`), e usa a `api_key`. + +## Métodos públicos + +```ruby +state_taxes.list(company_id, starting_after: nil, ending_before: nil, limit: nil) +# => Nfe::ListResponse + +state_taxes.create(company_id, data) # => Nfe::NfeStateTax +state_taxes.retrieve(company_id, state_tax_id) # => Nfe::NfeStateTax +state_taxes.update(company_id, state_tax_id, data) # => Nfe::NfeStateTax +state_taxes.delete(company_id, state_tax_id) # => nil +``` + +:::note Lista cursor-style +`list` usa paginação **cursor-style** (`starting_after`/`ending_before`/`limit`) e +devolve um `Nfe::ListResponse` — diferente das listas page-style de +[tax_codes](./tax-codes.md). Veja [Paginação](../pagination.md). +::: + +## Exemplos + +### Criar e recuperar uma inscrição + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) +company_id = "55df4dc6b6cd9007e4f13ee8" + +ie = client.state_taxes.create( + company_id, + code: "SP", + taxNumber: "1234567890" +) + +client.state_taxes.retrieve(company_id, ie.id) +``` + +:::tip O corpo é embrulhado em `stateTax` +Você passa apenas os atributos (em camelCase). O SDK embrulha o corpo como +`{ "stateTax": { ... } }` em `create`/`update` e desembrulha a resposta +automaticamente antes de hidratar `Nfe::NfeStateTax`. +::: + +### Listar com cursor e atualizar + +```ruby +pagina = client.state_taxes.list(company_id, limit: 50) +pagina.data.each { |ie| puts ie.code } + +client.state_taxes.update(company_id, ie.id, taxNumber: "0987654321") +client.state_taxes.delete(company_id, ie.id) +``` + +## Veja também + +- [Empresas](./companies.md) — o escopo (`company_id`) das inscrições. +- [Consulta de CNPJ](./legal-entity-lookup.md) — consultar a IE de terceiros para emissão. +- [Paginação](../pagination.md) — paginação cursor-style. diff --git a/docs/recursos/tax-calculation.md b/docs/recursos/tax-calculation.md new file mode 100644 index 0000000..caf4bd7 --- /dev/null +++ b/docs/recursos/tax-calculation.md @@ -0,0 +1,62 @@ +--- +title: Cálculo de impostos (tax_calculation) no SDK Ruby da NFE.io +sidebar_label: Cálculo de impostos +sidebar_position: 14 +slug: calculo-de-impostos +description: Execução do motor de regras tributárias por tenant, com retorno do detalhamento de impostos por item, no SDK Ruby da NFE.io. +--- + +# Cálculo de impostos (`tax_calculation`) + +O recurso `tax_calculation` executa o motor de regras tributárias de um tenant e +devolve o detalhamento de impostos por item. Faz parte da família `cte`, servida +por `api.nfse.io`, e usa a `api_key` (emissão é capacidade central, não consulta +de dados). + +## Métodos públicos + +```ruby +tax_calculation.calculate(tenant_id, request) +# => Nfe::Generated::CalculoImpostosV1::CalculateResponse +``` + +O `request` é um `Hash` com chaves em camelCase. Para type-safety, você pode +construí-lo a partir de `Nfe::Generated::CalculoImpostosV1::CalculateRequest#to_h`. + +## Exemplo + +### Calcular impostos de um pedido + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) + +resultado = client.tax_calculation.calculate( + "tenant-123", + { + operationType: "Sale", + items: [ + { code: "SKU-1", quantity: 2, unitAmount: 49.90, ncm: "61091000" } + ] + } +) + +resultado +``` + +:::warning Validação fail-fast (sem HTTP) +Antes de qualquer requisição, o SDK valida que `tenant_id` é não vazio e que o +`request` é um `Hash` contendo `operation_type` (ou `operationType`) e um array +`items` **não vazio**. Caso contrário, levanta `Nfe::InvalidRequestError`. +::: + +:::tip Use o request tipado quando quiser segurança de tipos +`CalculateRequest#to_h` ajuda a montar o corpo com a forma esperada (ICMS, IPI, +PIS, COFINS, II, ICMS-UF-Dest etc.) sem digitar as chaves à mão. +::: + +## Veja também + +- [Tabelas tributárias (tax_codes)](./tax-codes.md) — códigos de referência para montar o request. +- [Inscrições estaduais (state_taxes)](./state-taxes.md) — outro recurso da família `cte`. diff --git a/docs/recursos/tax-codes.md b/docs/recursos/tax-codes.md new file mode 100644 index 0000000..d9a17ac --- /dev/null +++ b/docs/recursos/tax-codes.md @@ -0,0 +1,59 @@ +--- +title: Tabelas tributárias (tax_codes) no SDK Ruby da NFE.io +sidebar_label: Tabelas tributárias +sidebar_position: 15 +slug: codigos-fiscais +description: Listas de referência do CT-e — códigos de operação, finalidades de aquisição e perfis tributários — com paginação page-style no SDK Ruby da NFE.io. +--- + +# Tabelas tributárias (`tax_codes`) + +O recurso `tax_codes` expõe as quatro listas de referência consumidas ao montar um +CT-e: códigos de operação, finalidades de aquisição e os perfis tributários do +emitente e do destinatário. Faz parte da família `cte`, servida por `api.nfse.io`, +e usa a `api_key`. + +## Métodos públicos + +```ruby +tax_codes.list_operation_codes(page_index: nil, page_count: nil) # => Nfe::TaxCodePaginatedResponse +tax_codes.list_acquisition_purposes(page_index: nil, page_count: nil) # => Nfe::TaxCodePaginatedResponse +tax_codes.list_issuer_tax_profiles(page_index: nil, page_count: nil) # => Nfe::TaxCodePaginatedResponse +tax_codes.list_recipient_tax_profiles(page_index: nil, page_count: nil) # => Nfe::TaxCodePaginatedResponse +``` + +:::note Paginação page-style (1-based) +Diferente das listas cursor-style do SDK, estes endpoints paginam por página +**1-based** (`page_index`/`page_count`) e devolvem um `Nfe::TaxCodePaginatedResponse` +(não um `Nfe::ListResponse`). Os parâmetros de paginação só são enviados quando +informados. +::: + +## Exemplos + +### Listar códigos de operação + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) + +# Sem paginação explícita: +client.tax_codes.list_operation_codes + +# Página 2, 20 itens (page_index é 1-based): +client.tax_codes.list_operation_codes(page_index: 2, page_count: 20) +``` + +### Listar perfis tributários e finalidades + +```ruby +client.tax_codes.list_acquisition_purposes +client.tax_codes.list_issuer_tax_profiles +client.tax_codes.list_recipient_tax_profiles +``` + +## Veja também + +- [Cálculo de impostos (tax_calculation)](./tax-calculation.md) — consome estes códigos. +- [Paginação](../pagination.md) — diferenças entre listas page-style e cursor-style. diff --git a/docs/recursos/transportation-invoices.md b/docs/recursos/transportation-invoices.md new file mode 100644 index 0000000..dc3fa7a --- /dev/null +++ b/docs/recursos/transportation-invoices.md @@ -0,0 +1,91 @@ +--- +title: Conhecimentos de transporte recebidos (CT-e) +sidebar_label: CT-e de entrada +sidebar_position: 4 +slug: conhecimentos-de-transporte +description: Habilite a busca automática de CT-e (Distribuição DFe) e leia documentos e eventos recebidos por chave de acesso com client.transportation_invoices no host api.nfse.io /v2. +--- + +# Conhecimentos de transporte recebidos (CT-e) + +`client.transportation_invoices` gerencia CT-e (Conhecimento de Transporte +Eletrônico) **recebidos**, no host `api.nfse.io`, sob `/v2`. Ele habilita a +busca automática via SEFAZ Distribuição DFe e lê documentos e eventos por chave +de acesso de 44 dígitos. + +:::note Recurso de entrada, não de emissão +Este é um recurso de consulta/configuração (settings + buscas por chave de +acesso). Não há contrato 202 `Pending` / `Issued` aqui — não se emite CT-e por +este recurso. +::: + +## Métodos + +| Método | Descrição | Retorno | +|---|---|---| +| `enable(company_id:, start_from_nsu: nil, start_from_date: nil)` | Habilita a busca automática de CT-e. | `Nfe::InboundSettings` | +| `disable(company_id:)` | Desabilita a busca automática. | `Nfe::InboundSettings` | +| `get_settings(company_id:)` | Lê as configurações atuais de busca. | `Nfe::InboundSettings` | +| `retrieve(company_id:, access_key:)` | Metadados do CT-e por chave de acesso. | `Nfe::InboundInvoiceMetadata` | +| `download_xml(company_id:, access_key:)` | XML do CT-e. | `String` binária | +| `get_event(company_id:, access_key:, event_key:)` | Metadados de um evento do CT-e. | `Nfe::InboundInvoiceMetadata` | +| `download_event_xml(company_id:, access_key:, event_key:)` | XML de um evento do CT-e. | `String` binária | + +:::warning Chave de acesso normalizada +A `access_key` é normalizada por `Nfe::IdValidator.access_key`: separadores +(espaços, pontos, traços) são removidos e o valor precisa ter exatamente 44 +dígitos. Caso contrário, o SDK levanta `Nfe::InvalidRequestError` antes de +qualquer chamada HTTP. +::: + +## Habilitar a busca automática + +```ruby +settings = client.transportation_invoices.enable( + company_id: "55df4dc6b6cd9007e4f13ee8", + start_from_date: "2026-01-01" +) +settings # Nfe::InboundSettings +``` + +`start_from_nsu` e `start_from_date` são opcionais; quando `nil`, são omitidos +do corpo da requisição. + +## Ler um CT-e recebido por chave de acesso + +```ruby +access_key = "35240611111111000199570010000012341000012345" + +cte = client.transportation_invoices.retrieve( + company_id: company_id, + access_key: access_key +) + +xml = client.transportation_invoices.download_xml( + company_id: company_id, + access_key: access_key +) +File.binwrite("cte.xml", xml) +``` + +## Consultar e baixar um evento + +```ruby +evento = client.transportation_invoices.get_event( + company_id: company_id, + access_key: access_key, + event_key: "35240611111111000199570010000012341000012345-110111-01" +) + +xml = client.transportation_invoices.download_event_xml( + company_id: company_id, + access_key: access_key, + event_key: evento.id +) +File.binwrite("cte-evento.xml", xml) +``` + +## Próximos passos + +- [NF-e de entrada (manifestação)](./inbound-product-invoices.md) — ingestão de NF-e de fornecedores. +- [Webhooks](../webhooks.md) — receba notificações de novos documentos. diff --git a/docs/recursos/webhooks.md b/docs/recursos/webhooks.md new file mode 100644 index 0000000..303e36b --- /dev/null +++ b/docs/recursos/webhooks.md @@ -0,0 +1,84 @@ +--- +title: Webhooks no SDK Ruby da NFE.io +sidebar_label: Webhooks +sidebar_position: 10 +slug: webhooks +description: CRUD de assinaturas de webhook por empresa, disparo de teste, lista de eventos disponíveis e verificação de assinatura no SDK Ruby da NFE.io. +--- + +# Webhooks + +O recurso `webhooks` gerencia as assinaturas de webhook **escopadas por empresa**, +sob `/companies/{id}/webhooks`. Faz parte da família `main`, servida por +`api.nfe.io` (`/v1`), e usa a `api_key`. Além do CRUD, expõe um disparo de teste, +a lista estática de eventos e a verificação de assinatura. + +## Métodos públicos + +```ruby +webhooks.list(company_id) # => Nfe::ListResponse +webhooks.create(company_id, data) # => Nfe::WebhookSubscription +webhooks.retrieve(company_id, webhook_id) # => Nfe::WebhookSubscription +webhooks.update(company_id, webhook_id, data) # => Nfe::WebhookSubscription +webhooks.delete(company_id, webhook_id) # => nil +webhooks.test(company_id, webhook_id) # => { success: bool, message: String? } +webhooks.get_available_events # => Array +webhooks.verify_signature(payload:, signature:, secret:) # => Boolean +``` + +Os eventos disponíveis (`get_available_events`) são: +`invoice.issued`, `invoice.cancelled`, `invoice.failed`, `invoice.processing`, +`company.created`, `company.updated` e `company.deleted`. + +## Exemplos + +### Criar e testar uma assinatura + +```ruby +require "nfe" + +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) +company_id = "55df4dc6b6cd9007e4f13ee8" + +hook = client.webhooks.create( + company_id, + url: "https://app.exemplo.com.br/webhooks/nfe", + events: ["invoice.issued", "invoice.failed"], + secret: ENV.fetch("NFE_WEBHOOK_SECRET"), + active: true +) + +# Dispara uma entrega sintética para validar que o endpoint responde: +result = client.webhooks.test(company_id, hook.id) +result[:success] +``` + +### Verificar a assinatura de um payload recebido + +```ruby +ok = client.webhooks.verify_signature( + payload: request.raw_post, + signature: request.get_header("HTTP_X_NFE_SIGNATURE"), + secret: ENV.fetch("NFE_WEBHOOK_SECRET") +) + +head :unauthorized unless ok +``` + +:::tip Use o módulo `Nfe::Webhook` no handler +`webhooks.verify_signature` é uma delegação fina para `Nfe::Webhook.verify_signature`, +oferecida por paridade com o SDK Node. No seu controlador HTTP, prefira chamar o +módulo diretamente — ele não exige um `Nfe::Client` e **nunca** levanta exceção, +apenas devolve `true`/`false`. Veja o guia de [Webhooks](../webhooks.md). +::: + +:::note `list` tolera vários formatos +`list(company_id)` aceita a resposta da API como array puro, embrulhada em `data` +ou em um envelope `webhooks`, sempre devolvendo um `Nfe::ListResponse`. +::: + +## Veja também + +- [Webhooks (guia)](../webhooks.md) — verificação de assinatura e recebimento por push. +- [Empresas](./companies.md) — o escopo (`company_id`) das assinaturas. +- [Emissão assíncrona e polling](../async-and-polling.md) — alternativa por polling. diff --git a/docs/rtc-emission.md b/docs/rtc-emission.md new file mode 100644 index 0000000..4417f7c --- /dev/null +++ b/docs/rtc-emission.md @@ -0,0 +1,160 @@ +--- +title: Emissão RTC (Reforma Tributária do Consumo) no SDK Ruby da NFE.io +sidebar_label: Emissão RTC +sidebar_position: 9 +slug: emissao-rtc +description: Emita NFS-e e NF-e/NFC-e sob o layout da Reforma Tributária do Consumo com service_invoices_rtc e product_invoices_rtc — o layout é selecionado pela forma do payload (ibsCbs / items[].tax.IBSCBS), sem header discriminador. +--- + +# Emissão RTC + +A **Reforma Tributária do Consumo (RTC)** introduz os novos grupos de imposto +(IBS, CBS e, para produtos, o Imposto Seletivo — IS). O SDK expõe a emissão RTC +de forma **opt-in**, por meio de dois recursos dedicados: + +- `service_invoices_rtc` — NFS-e, host `api.nfe.io` (família `main`). +- `product_invoices_rtc` — NF-e (mod 55) e NFC-e (mod 65), host `api.nfse.io` (família `cte`). + +Os recursos clássicos (`service_invoices` e `product_invoices`) permanecem +inalterados. + +## O layout RTC é selecionado pela forma do payload + +Os recursos RTC usam os **mesmos endpoints** e o mesmo fluxo dos recursos +clássicos. **Não existe header discriminador nem parâmetro de query**: a API +seleciona o layout RTC a partir da **presença** de um grupo no payload. + +- NFS-e: presença do grupo `ibsCbs` na raiz do payload. +- Produto: presença do grupo a nível de item em `items[].tax.IBSCBS`. + +Quando esses grupos estão ausentes, a API recai no layout clássico. + +:::note `create(data:)` recebe um Hash +`create` recebe um **Hash** com chaves em **camelCase** (serializado como JSON +tal como está). Os DTOs gerados (`Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest` +e `Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest`) **documentam a +forma** do payload, mas não são aceitos como entrada — eles apenas desserializam +respostas (`from_api`) e não têm caminho de re-serialização camelCase. +::: + +## NFS-e RTC: o grupo `ibsCbs` + +```ruby +result = client.service_invoices_rtc.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + cityServiceCode: "2690", + federalServiceCode: "0107", + description: "Manutenção e suporte técnico", + servicesAmount: 100.0, + nbsCode: "123456789", + borrower: { federalTaxNumber: "191", name: "Banco do Brasil SA" }, + ibsCbs: { + operationIndicator: "000000", + classCode: "000001", + cbs: { rate: 0.009, amount: 0.9 }, + ibs: { + state: { rate: 0.001, amount: 0.1 }, + municipal: { rate: 0.0, amount: 0.0 } + } + } + } +) +``` + +Dentro de `ibsCbs`, `operationIndicator` (6 dígitos, `^[0-9]{6}$`) e `classCode` +(até 6 caracteres) são obrigatórios. + +## Produto RTC: `items[].tax.IBSCBS` e `IS` + +No payload de produto, os grupos RTC ficam **a nível de item**, em `items[].tax`, +ao lado dos grupos legados. O `IBSCBS` divide o IBS em esfera estadual (`state`) +e municipal (`municipal`), com o `cbs` (federal) sem divisão. O grupo `IS` +(Imposto Seletivo) é **exclusivo do payload de produto** — não há equivalente na +NFS-e. + +```ruby +result = client.product_invoices_rtc.create( + company_id: "55df4dc6b6cd9007e4f13ee8", + data: { + printType: "Normal", + items: [ + { + code: "001", + description: "Produto exemplo", + quantity: 1, + unitAmount: 100.0, + tax: { + IBSCBS: { + state: { rate: 0.001, amount: 0.1 }, + municipal: { rate: 0.0, amount: 0.0 }, + cbs: { rate: 0.009, amount: 0.9 } + }, + IS: { + situationCode: "000", + classificationCode: "000000", + basis: 100.0, + rate: 0.0, + amount: 0.0 + } + } + } + ] + } +) +``` + +:::tip NF-e (mod 55) vs NFC-e (mod 65) +Os dois modelos são emitidos pelo mesmo `create` e pelo mesmo endpoint. A +distinção vem da **forma do payload** (`printType`, `consumerType`/`presenceType`, +presença de `buyer`, presença de `expectedDeliveryOn`) — nenhum discriminador de +`model`/`mod` é enviado na raiz da requisição. +::: + +## Retorno discriminado e polling + +Como na emissão clássica, `create` devolve **um de dois tipos**, distinguíveis +por pattern matching ou pelos predicados `pending?`/`issued?`. As classes RTC são +distintas das clássicas: + +- NFS-e: `Nfe::Resources::ServiceInvoiceRtcPending` / `ServiceInvoiceRtcIssued`. +- Produto: `Nfe::Resources::ProductInvoiceRtcPending` / `ProductInvoiceRtcIssued`. + +```ruby +case result +in Nfe::Resources::ServiceInvoiceRtcPending => pending + pending.invoice_id # reconsultar enquanto processa +in Nfe::Resources::ServiceInvoiceRtcIssued => issued + issued.resource # nota já materializada +end +``` + +Não existe `create_and_wait`/`create_batch` — faça polling com `retrieve` até um +estado terminal usando `Nfe::FlowStatus.terminal?`: + +```ruby +company_id = "55df4dc6b6cd9007e4f13ee8" +invoice_id = result.pending? ? result.invoice_id : result.resource.id + +loop do + invoice = client.service_invoices_rtc.retrieve( + company_id: company_id, + invoice_id: invoice_id + ) + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + + sleep 2 +end +``` + +:::note Downloads de produto continuam devolvendo uma URI +Os `download_*` de `product_invoices_rtc` retornam um `Nfe::NfeFileResource` +(URI), exatamente como o recurso clássico de produto. Veja [Downloads](./downloads.md). +::: + +## Próximos passos + +- [Primeiros passos](./getting-started.md) — emissão clássica e o contrato 202. +- [Downloads](./downloads.md) — bytes vs. `Nfe::NfeFileResource`. +- [Roteamento multi-host](./multi-host-routing.md) — os hosts `main` e `cte`. +- [Webhooks](./webhooks.md) — receba a conclusão por push. diff --git a/docs/webhooks.md b/docs/webhooks.md new file mode 100644 index 0000000..48d515c --- /dev/null +++ b/docs/webhooks.md @@ -0,0 +1,156 @@ +--- +title: Verificação de webhooks da NFE.io +sidebar_label: Webhooks +sidebar_position: 5 +slug: webhooks +description: Verifique a assinatura HMAC-SHA1 das entregas de webhook da NFE.io com Nfe::Webhook, leia o corpo cru antes de parsear o JSON e torne seus handlers idempotentes. +--- + +# Webhooks + +Em vez de fazer polling até um estado terminal, você pode receber a conclusão da +emissão por push. A NFE.io entrega um webhook; seu endpoint **verifica a +assinatura** e reage ao evento. Este guia cobre a verificação canônica via +`Nfe::Webhook`. + +## Como a NFE.io assina as entregas + +Cada entrega traz o cabeçalho `X-Hub-Signature` com um HMAC-SHA1 calculado sobre +os **bytes exatos** do corpo da requisição, no formato `sha1=<40 hex>`: + +```text +X-Hub-Signature: sha1=BCD17C02B9E3B40A18E745E7E04247E4AD2DD935 +``` + +:::warning Documentação antiga está errada +Apenas o esquema `X-Hub-Signature` + **HMAC-SHA1** é suportado. Material de +distribuição mais antigo que menciona `X-NFe-Signature`, **SHA-256** ou +**Base64** está incorreto — um cabeçalho `sha256=` é rejeitado. +::: + +## A API de verificação + +`Nfe::Webhook` é um módulo de funções **sem estado**: não precisa de um +`Nfe::Client`, não lê a `Nfe::Configuration` e não faz nenhuma chamada de rede. +Você fornece os três argumentos: o corpo cru, o valor do cabeçalho e o segredo. + +```ruby +require "nfe" + +ok = Nfe::Webhook.verify_signature( + payload: raw_body, + signature: signature_header, + secret: ENV.fetch("NFE_WEBHOOK_SECRET") +) +``` + +### `verify_signature` → Boolean + +Retorna `true` **somente** quando o HMAC-SHA1 confere exatamente. A comparação é +feita em tempo constante (`OpenSSL.secure_compare`) e o prefixo `sha1=` é +comparado de forma **case-insensitive** (a NFE.io envia o hex em maiúsculas). + +:::tip Nunca levanta exceção +`verify_signature` **nunca** levanta. Qualquer entrada ausente, malformada, com +algoritmo errado, comprimento errado ou conteúdo não-hexadecimal resulta em +`false`. Um segredo ou assinatura `nil`/vazia também retorna `false`. +::: + +Se o cabeçalho chegar como um array de um elemento (formato que algumas pilhas +Rack/HTTP usam para cabeçalhos repetidos), o primeiro elemento é usado. + +### `construct_event` → `Nfe::WebhookEvent` + +Quando você quer não só validar, mas também desempacotar o evento, use +`construct_event`. Ele verifica primeiro; em caso de falha de assinatura **ou** +de JSON inválido, levanta `Nfe::SignatureVerificationError`. + +```ruby +event = Nfe::Webhook.construct_event( + payload: raw_body, + signature: signature_header, + secret: ENV.fetch("NFE_WEBHOOK_SECRET") +) + +event.type # ex.: "invoice.issued" +event.data # Hash com o payload (a chave "payload" ou "data" do envelope) +event.id # id estável para deduplicação, ou nil +event.created_at # timestamp da entrega como String, ou nil +``` + +`Nfe::WebhookEvent` é um objeto de valor imutável (`Data.define`). O `type` é +desempacotado da chave `action`/`event`/`type`/`event_type` do envelope, e o +`data` da chave `payload`/`data`. + +## Leia o corpo CRU antes de parsear o JSON + +A NFE.io assina os bytes que entregou. Leia o corpo cru **antes** de qualquer +parsing de JSON e passe esses bytes ao verificador. + +:::warning Não re-serialize o payload +Nunca passe um objeto já parseado e re-serializado (por exemplo +`payload.to_json`). A ordem das chaves e os espaços em branco vão diferir dos +bytes assinados, e a verificação falhará de forma imprevisível. Sempre use o +corpo cru — `request.raw_post` ou `request.body.read`. +::: + +## Exemplo: controller Rails + +```ruby +class NfeWebhooksController < ActionController::Base + # Webhooks não têm token CSRF. + skip_before_action :verify_authenticity_token + + def create + raw = request.raw_post + signature = request.headers["X-Hub-Signature"] + secret = ENV.fetch("NFE_WEBHOOK_SECRET") + + unless Nfe::Webhook.verify_signature(payload: raw, signature: signature, secret: secret) + head :unauthorized + return + end + + event = Nfe::Webhook.construct_event(payload: raw, signature: signature, secret: secret) + process_event(event) # idempotente — veja abaixo + head :ok + rescue Nfe::SignatureVerificationError + head :unauthorized + end + + private + + def process_event(event) + # Dedupe pelo id do evento/nota antes de aplicar efeitos colaterais. + return if already_handled?(event.id) + + mark_handled(event.id) + # ... reaja a event.type / event.data ... + end +end +``` + +:::note Em Rack puro +O valor do cabeçalho está em `request.get_header("HTTP_X_HUB_SIGNATURE")` e o +corpo cru em `request.body.read` (rebobine com `request.body.rewind` se for ler +de novo depois). +::: + +## Validade não é frescor — handlers devem ser idempotentes + +A NFE.io **não** envia primitiva de anti-replay: as entregas trazem apenas o +HMAC-SHA1 sobre o corpo, sem timestamp e sem nonce. Uma assinatura válida prova +**autenticidade**, mas não **frescor** — uma entrega reproduzida (replay) carrega +uma assinatura perfeitamente válida. + +:::warning Sempre dedupe +Trate seus handlers como **idempotentes** e faça **deduplicação pelo +`event.id`** (id do evento ou da nota). Processar a mesma entrega duas vezes não +pode gerar efeitos colaterais duplicados. +::: + +## Próximos passos + +- [Primeiros passos](./getting-started.md) — emissão e polling como alternativa ao push. +- [Paginação](./pagination.md) — percorra listas de notas. +- [Downloads](./downloads.md) — baixe PDF/XML das notas. diff --git a/docs/yard-theme/default/fulldoc/html/css/nfeio.css b/docs/yard-theme/default/fulldoc/html/css/nfeio.css new file mode 100644 index 0000000..7d684a6 --- /dev/null +++ b/docs/yard-theme/default/fulldoc/html/css/nfeio.css @@ -0,0 +1,101 @@ +@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&display=swap"); + +/* ============================================================ + Tema NFE.io para a referencia da API (YARD) + Marca: Manual de Identidade Visual NFE.io (media-kit oficial) + ============================================================ */ +:root { + --nfe-azul: #5DD0F2; + --nfe-verde: #7AEA53; + --nfe-cinza-claro: #E6EBF3; + --nfe-texto: #333333; + --nfe-gradiente: linear-gradient(120deg, #5DD0F2, #7AEA53); +} + +body, #content, .docstring, p, li, dd, dt, td, th, +#content h1, #content h2, #content h3, #content h4, #content h5, #content h6 { + font-family: "Roboto", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; + color: var(--nfe-texto); +} +body { background: #ffffff; } +#content { font-weight: 300; } /* Roboto Light no corpo */ + +/* ---- Faixa de marca no topo de cada pagina (gradiente + logo branco) ---- */ +#header { position: relative; } +#header::before { + content: ""; + display: block; + height: 54px; + margin: 0 0 16px; + border-radius: 6px; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAABQCAYAAACwGF+mAAAIJklEQVR4Xu2d7bnUNhCFNRUEKgAqCFQQqCBQAaGCkAoCFUAqCFQQqACoIFBBoAOoYPKci3Yf764kz8iSLXyP/9wfV9ZKZ16PRx8jS+BFBXakgOyoL+wKFQgEmhDsSgECvStzsjMEmgzsSgECvStzsjMEmgzsSgECvStzsjMEmgzsSgECvStzsjMEmgzsSgECvStzsjMEmgzsSgECvStzsjMEmgzsSgEC3cicqvpLo6qs1XwSka/Wwtel3CzQqno7hPBnCOFhCOHGmTAfQwgvReR1D8FU9XEI4WkI4W6P+mfq/BxCeCUiz3PlVPV+1AZ/t7ig/xMRwV9eIZS3j6oqQHqXAPlcPBj+SUtFVfXvEMJvLeusrOsvEcFDdXKpKh7wfyrrbHkbvPQdeuvvkhY9tKr+6/COzaBWVYAMoEe5AAw89vFS1f9CCHh7jXA9F5FnIzRk6zZkgY7eGUB7rkci8sZzQ6qsqr4PIawdk5aajdf6q0OBGGrgzTXK9VZE8Ma49lcJ6Bov2eT1p6o6mGVOPKCqwhtiXDHK9UFEtorjR9Hgqh0loGuNlow5Pb0eEOiTN8+AQL8WkRHGGx4zdynbA2g09IGIIGyougYE+iSGHhDoP0TkZZXYO7upF9AYQN2rHXkPBvTFG2cwoDEfvcW05pCPQi+g0dnq0GMQoL/EeeiL2YNBgP4UQsBb8Fmt4xiSyIWN6gk0mgYv7Z70dwK9KLyp0c8JNKfUakSuvKc30B9F5J63bQTaqxjLHxToDTR+x+2hCDQBrVVgDaDdoQeBrjUn71sLaFfoQaAJZq0CawGN9pnnSgl0rTl535pAY1kcsx4nm3xSJiDQBLNWgRZAfwsh/GRswHsReTBXlkDPKcT/5xRoAfSHEALmmn83yjwbehBoo5IsdqFAK6CxdRFQ3zJoPBt6EGiDiiySVKAJ0Ni66MzgeCMij3I2cQKNfcqzcXnmt/AQYuulKzfPuVKI5enqjVohBOx1dq+2tuQ97o0PLdqhqkjj+/msfV8sYytLn5oBjR9TVWzu/9XywyGEbDKAE2jjz2WL4WFAW8zQOIFe2j7cX3QALX4gMzgHfEhkOGx+glbYalDrQLKMiIjEB+eWiLyt7VNroCEAOmsZJGaTAVYGGtp9FpE7VhE3ABpNc6+4WvtTeFOm9sS79l6rKra1YjLgKpMpl40UgT78HpwLHhzXmxP1NwU6NtiT6ZL0PBsAjaabNzltBLRrcWopzAX4XNkx0ZbHh9EItMse0742B7r0FGZEvgg9CHRaKXixFqBa68jANwt09Mp4671cAnRs5wvPBrdeQCMbGq8NS+hxkQxAoH9coCcZ+1deuQHQ7zwPchego5fGWRYvjN7gJBmAQCdVWz0zxeuhz2a69gV0RehxjGE3ABrTRuYzNjaKobcYFKaOk0iGHHE6DsdeHHRsCrR16rCbh45Ao3M4kMVyHUOPlYHG0v39waftZuNWi8DeMh4PnXjIWwONGZDHc7NRXYGOUHuOQ5iKYNUf5+rVzotiWggnPrmmh5weGlsDliysYHZj8eE9VjGn5ZxAQ8PpmKkH0DgLpXiYUXegI9QYIJ6vDuU0RsqW58Qm83RbjVFT9ziBXj1UaNhPU8iRWSXuBXRxHnwtoLHSZIUU8HvS8gl0K4LP6rF6aFXF9gOcFDu9egGNJfgst6sAXRF6eExEoD1qOco6gE69gbsBXTpNYDWgI9SIdS078hyy21f4PJWWyjLkOD1HLzOI7wl01omtDbQn9LDyRw9tVcpZzuGhU4dr9gQ6OzBcFejopbFZxZoMYDEBgbaoVFGGQBtEixPw1mQAQ40MOSwi1ZQZGOgxQo6DqI0PDKeHrqHVcI8D6NT0Xs+Q4+KLCofurB5yTKBOTfUYZL4oQqBrVDPc4wB6zWm7byJy/vGqY2+2BNqTDFCSf3SgYezj5ywMHGWLiAhWHVe7HECnPqDUy0Nvv7CSs4AzDzFXzehA9wQQr3p8/2V26V9VsfsR6XH4dAXGMEiuyH6yLg7gTSuFsexaS99Fe2/moSehhycPMQXHdQYaesweLl/I9SymOlk9dAT6fLtwDw+NTWTFb8mMAPTS0OO6Aw2esmedGD6Rlz2Y3gN0hHq6YtgaaHByY+5ttDnQUYglH7Ek0N+POkh+1s3wibyvInIz9eqrAHq6cNYUaGvcNgTQhXjN0g8C/f1skeSrWFXPY9uUpjdTW2i9QEc7HpKkhwPamr3dZPN5/Ka4NQ9xapTsnKTlaagpU/lR0pqfst6THfkbPHR291oN0BOoUe+rhTmFeBifej5ZV/LQ1n0Xzfb7xpG4NQ8R2rlSp6x0WMqpao+NVpafTpUpxdBzCRbecMXlwJYAXfNpwGJafExHL+27QPrSbW/GR8lqmb21w0zZTWZn8MBjWsuS2V4LquW+2eRZVc0lWMB+d3MDrYyD8R40gwfqmHVjPJfD9RtTkWbPeYhbJRF+nG/7xHFNeB3MzoFarDItE4XENFBqqymMcPicmfn4Lm8bLOVjmASDYUC2NtjQAVOesEExhSzun0E7YcdDO032O3MwWNh5OPd7Mw4rNU17tfoX9USoUs3ULNAWw7LMj6MA4F4CZKuexv08qA7e25XTWWoDgW5lIdYzhAIEeggzsBGtFCDQrZRkPUMoQKCHMAMb0UoBAt1KSdYzhAIEeggzsBGtFCDQrZRkPUMoQKCHMAMb0UoBAt1KSdYzhAIEeggzsBGtFCDQrZRkPUMoQKCHMAMb0UoBAt1KSdYzhAIEeggzsBGtFCDQrZRkPUMo8D9U/jar4bcwKwAAAABJRU5ErkJggg==") no-repeat 20px center, var(--nfe-gradiente); + background-size: auto 26px, cover; + box-shadow: 0 1px 5px rgba(51, 51, 51, 0.18); +} + +/* ---- Titulos: Roboto Medium com sublinhado em gradiente da marca ---- */ +#content h1, #content h2 { + font-weight: 500; + border-bottom: 3px solid var(--nfe-azul); + border-image: var(--nfe-gradiente) 1; + padding-bottom: 0.25em; +} +#content h3, #content h4 { font-weight: 500; } + +/* ---- Links: texto legivel (#333) com sublinhado da marca; verde no hover ---- */ +#content a, #content a:link, #content a:visited { + color: var(--nfe-texto); + text-decoration: none; + border-bottom: 1px solid var(--nfe-azul); +} +#content a:hover { border-bottom-color: var(--nfe-verde); color: #1f1f1f; } +#content a.summary_signature, #content a.summary_signature:link { border-bottom: none; } + +/* ---- Codigo: fundo cinza claro da marca, acento azul ---- */ +#content tt, #content code, #content .docstring code { + background: var(--nfe-cinza-claro); + color: var(--nfe-texto); + border-radius: 3px; + padding: 0.1em 0.35em; +} +#content pre, #content pre.code, .source_code pre { + background: var(--nfe-cinza-claro); + border-left: 3px solid var(--nfe-azul); + border-radius: 4px; +} +#content pre code, #content pre tt { background: transparent; padding: 0; } + +/* ---- Assinaturas de metodos e blocos de resumo ---- */ +.summary_signature { + background: var(--nfe-cinza-claro); + border: 1px solid #d7deea; + border-radius: 4px; +} +.summary_signature:hover { border-color: var(--nfe-azul); } +h2.summary, .docstring h1, .docstring h2 { color: var(--nfe-texto); } + +/* ---- Tabelas ---- */ +#content table th { background: var(--nfe-cinza-claro); color: var(--nfe-texto); font-weight: 500; } + +/* ---- Tags (Note/Returns/Params) com barra da marca ---- */ +.note, .docstring .note { + border-left: 4px solid var(--nfe-azul); + background: var(--nfe-cinza-claro); + border-radius: 4px; +} +.note.returns { border-left-color: var(--nfe-verde); } +.note.deprecated { border-left-color: #f2a65d; } + +/* ---- Navegacao lateral (frame) ---- */ +#full_list, #nav, .nav_wrap { font-family: "Roboto", sans-serif; } +#full_list li { color: var(--nfe-texto); } +#full_list .toggle { color: var(--nfe-azul); } +ul#full_list li.clicked, #full_list li:hover { background: var(--nfe-cinza-claro); } + +/* ---- Busca ---- */ +#search a, #search a:link { color: var(--nfe-texto); } +#search a:hover, #search a.active { color: #ffffff; background: var(--nfe-azul); } + +/* ---- Rodape ---- */ +#footer { color: #888; border-top: 1px solid var(--nfe-cinza-claro); } +#footer a { color: var(--nfe-texto); border-bottom: 1px solid var(--nfe-verde); text-decoration: none; } diff --git a/docs/yard-theme/default/fulldoc/html/setup.rb b/docs/yard-theme/default/fulldoc/html/setup.rb new file mode 100644 index 0000000..4272ca7 --- /dev/null +++ b/docs/yard-theme/default/fulldoc/html/setup.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +# NFE.io YARD theme: append the brand stylesheet to the default ones so it loads +# last (and thus overrides the defaults) on both the main pages and the nav frame. +def stylesheets + super + %w[css/nfeio.css] +end + +def stylesheets_full_list + super + %w[css/nfeio.css] +end diff --git a/docs/yard-theme/default/layout/html/headers.erb b/docs/yard-theme/default/layout/html/headers.erb new file mode 100644 index 0000000..f56b827 --- /dev/null +++ b/docs/yard-theme/default/layout/html/headers.erb @@ -0,0 +1,18 @@ + + + + + + + <%= h @page_title %> + <% if options.title && @page_title != options.title %> + — <%= h options.title %> + <% end %> + +<% stylesheets.each do |stylesheet| %> + +<% end %> +<%= erb :script_setup %> +<% javascripts.each do |javascript| %> + +<% end %> diff --git a/docs/yard-theme/default/layout/html/setup.rb b/docs/yard-theme/default/layout/html/setup.rb new file mode 100644 index 0000000..40e2d42 --- /dev/null +++ b/docs/yard-theme/default/layout/html/setup.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +# Layout-scope override so the brand stylesheet is linked on every rendered +# object page (the fulldoc-scope override only covers the nav frame + asset copy). +def stylesheets + super + %w[css/nfeio.css] +end diff --git a/lib/data/ssl-bundle.crt b/lib/data/ssl-bundle.crt deleted file mode 100644 index 9b9a3c8..0000000 --- a/lib/data/ssl-bundle.crt +++ /dev/null @@ -1,3738 +0,0 @@ -## -## ca-bundle.crt -- Bundle of CA Root Certificates -## -## Certificate data from Mozilla as of: Thu Dec 5 09:40:49 2013 -## -## This is a bundle of X.509 certificates of public Certificate Authorities -## (CA). These were automatically extracted from Mozilla's root certificates -## file (certdata.txt). This file can be found in the mozilla source tree: -## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 -## -## It contains the certificates in PEM format and therefore -## can be directly used with curl / libcurl / php_curl, or with -## an Apache+mod_ssl webserver for SSL client authentication. -## Just configure this file as the SSLCACertificateFile. -## - - -GTE CyberTrust Global Root -========================== ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg -Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG -A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz -MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL -Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 -IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u -sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql -HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID -AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW -M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF -NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- - -Thawte Server CA -================ ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs -dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE -AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j -b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV -BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u -c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG -A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 -ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl -/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 -1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR -MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J -GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ -GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- - -Thawte Premium Server CA -======================== ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs -dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE -AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl -ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT -AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU -VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 -aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ -cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 -aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh -Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ -qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm -SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf -8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t -UCemDaYj+bvLpgcUQg== ------END CERTIFICATE----- - -Equifax Secure CA -================= ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE -ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT -B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR -fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW -8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG -A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE -CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG -A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS -spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB -Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 -zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB -BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 -70+sB3c4 ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority -======================================================= ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow -XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz -IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 -f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol -hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA -TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah -WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf -Tqj/ZA1k ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority - G2 -============================================================ ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO -FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 -lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB -MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT -1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD -Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 ------END CERTIFICATE----- - -GlobalSign Root CA -================== ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx -GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds -b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV -BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD -VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa -DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc -THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb -Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP -c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX -gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF -AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj -Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG -j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH -hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC -X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- - -GlobalSign Root CA - R2 -======================= ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv -YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh -bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT -aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln -bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 -ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp -s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN -S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL -TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C -ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i -YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN -BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp -9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu -01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 -9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- - -ValiCert Class 1 VA -=================== ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp -b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh -bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy -MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 -d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg -UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 -LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi -GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm -DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG -lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX -icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP -Orf1LXLI ------END CERTIFICATE----- - -ValiCert Class 2 VA -=================== ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp -b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh -bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw -MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 -d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg -UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 -LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC -CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf -ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ -SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV -UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 -W9ViH0Pd ------END CERTIFICATE----- - -RSA Root Certificate 1 -====================== ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp -b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh -bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw -MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 -d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg -UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 -LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td -3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H -BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs -3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF -V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r -on+jjBXu ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 -EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc -cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw -EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj -055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA -ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f -j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC -/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 -xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa -t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- - -Verisign Class 4 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS -tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM -8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW -Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX -Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA -j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt -mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm -fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd -RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG -UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== ------END CERTIFICATE----- - -Entrust.net Secure Server CA -============================ ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV -BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg -cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl -ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG -A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi -eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p -dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ -aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 -gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw -ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw -CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l -dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF -bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu -dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw -NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow -HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA -BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN -Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 -n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- - -Entrust.net Premium 2048 Secure Server CA -========================================= ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u -ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp -bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV -BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx -NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 -d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl -MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u -ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL -Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr -hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW -nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi -VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ -KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy -T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT -J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e -nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= ------END CERTIFICATE----- - -Baltimore CyberTrust Root -========================= ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE -ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li -ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC -SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs -dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME -uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB -UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C -G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 -XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr -l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI -VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB -BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh -cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 -hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa -Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H -RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - -Equifax Secure Global eBusiness CA -================================== ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp -bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx -HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds -b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV -PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN -qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn -hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j -BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs -MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN -I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY -NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- - -Equifax Secure eBusiness CA 1 -============================= ------BEGIN CERTIFICATE----- -MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB -LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE -ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz -IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ -1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a -IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk -MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW -Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF -AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 -lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ -KpYrtWKmpj29f5JZzVoqgrI3eQ== ------END CERTIFICATE----- - -AddTrust Low-Value Services Root -================================ ------BEGIN CERTIFICATE----- -MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU -cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw -CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO -ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 -54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr -oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 -Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui -GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w -HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw -HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt -ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph -iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY -eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr -mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj -ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= ------END CERTIFICATE----- - -AddTrust External Root -====================== ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD -VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw -NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU -cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg -Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 -+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw -Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo -aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy -2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 -7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL -VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk -VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB -IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl -j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 -e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u -G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- - -AddTrust Public Services Root -============================= ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU -cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ -BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l -dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu -nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i -d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG -Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw -HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G -A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G -A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 -JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL -+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao -GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 -Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H -EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= ------END CERTIFICATE----- - -AddTrust Qualified Certificates Root -==================================== ------BEGIN CERTIFICATE----- -MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU -cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx -CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ -IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx -64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 -KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o -L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR -wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU -MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE -BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y -azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG -GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X -dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze -RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB -iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= ------END CERTIFICATE----- - -Entrust Root Certification Authority -==================================== ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV -BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw -b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG -A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 -MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu -MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu -Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v -dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz -A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww -Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 -j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN -rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 -MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH -hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM -Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa -v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS -W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 -tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- - -RSA Security 2048 v3 -==================== ------BEGIN CERTIFICATE----- -MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK -ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy -MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb -BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 -Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb -WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH -KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP -+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ -MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E -FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY -v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj -0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj -VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 -nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA -pKnXwiJPZ9d37CAFYd4= ------END CERTIFICATE----- - -GeoTrust Global CA -================== ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw -MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j -LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo -BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet -8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc -T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU -vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk -DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q -zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 -d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 -mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p -XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm -Mw== ------END CERTIFICATE----- - -GeoTrust Global CA 2 -==================== ------BEGIN CERTIFICATE----- -MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw -MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j -LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ -NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k -LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA -Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b -HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH -K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 -srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh -ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL -OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC -x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF -H4z1Ir+rzoPz4iIprn2DQKi6bA== ------END CERTIFICATE----- - -GeoTrust Universal CA -===================== ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 -MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu -Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t -JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e -RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs -7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d -8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V -qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga -Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB -Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu -KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 -ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 -XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB -hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 -qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL -oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK -xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF -KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 -DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK -xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU -p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI -P/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- - -GeoTrust Universal CA 2 -======================= ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN -R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 -MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg -SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 -DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 -j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q -JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a -QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 -WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP -20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn -ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC -SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG -8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 -+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E -BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ -4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ -mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq -A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg -Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP -pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d -FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp -gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm -X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- - -America Online Root Certification Authority 1 -============================================= ------BEGIN CERTIFICATE----- -MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG -A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg -T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG -v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z -DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh -sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP -8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T -AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z -o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf -GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF -VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft -3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g -Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds -sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 ------END CERTIFICATE----- - -America Online Root Certification Authority 2 -============================================= ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT -QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG -A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg -T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en -fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 -f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO -qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN -RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 -gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn -6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid -FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 -Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj -B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op -aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY -T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p -+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg -JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy -zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO -ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh -1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf -GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff -Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP -cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= ------END CERTIFICATE----- - -Visa eCommerce Root -=================== ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG -EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug -QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 -WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm -VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv -bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL -F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b -RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 -TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI -/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs -GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG -MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc -CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW -YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz -zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu -YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt -398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- - -Certum Root CA -============== ------BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK -ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla -Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u -by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x -wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL -kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ -89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K -Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P -NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ -GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg -GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ -0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS -qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE----- - -Comodo AAA Services root -======================== ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw -MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl -c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV -BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG -C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs -i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW -Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH -Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK -Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f -BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl -cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz -LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm -7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z -8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C -12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- - -Comodo Secure Services root -=========================== ------BEGIN CERTIFICATE----- -MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw -MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu -Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi -BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP -9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc -rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC -oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V -p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E -FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w -gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj -YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm -aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm -4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj -Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL -DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw -pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H -RR3B7Hzs/Sk= ------END CERTIFICATE----- - -Comodo Trusted Services root -============================ ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw -MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h -bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw -IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 -3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y -/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 -juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS -ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud -DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp -ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl -cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw -uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 -pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA -BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l -R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O -9y5Xt5hwXsjEeLBi ------END CERTIFICATE----- - -QuoVadis Root CA -================ ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE -ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz -MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp -cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD -EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk -J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL -F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL -YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen -AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w -PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y -ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 -MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj -YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs -ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW -Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu -BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw -FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 -tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo -fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul -LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x -gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi -5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi -5nrQNiOKSnQ2+Q== ------END CERTIFICATE----- - -QuoVadis Root CA 2 -================== ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT -EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx -ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 -XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk -lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB -lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy -lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt -66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn -wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh -D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy -BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie -J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud -DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU -a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv -Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 -UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm -VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK -+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW -IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 -WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X -f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II -4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 -VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - -QuoVadis Root CA 3 -================== ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT -EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx -OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC -DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg -DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij -KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K -DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv -BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp -p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 -nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX -MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM -Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz -uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT -BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj -YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB -BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD -VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 -ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE -AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV -qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s -hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z -POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 -Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp -8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC -bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu -g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p -vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr -qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- - -Security Communication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw -8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM -DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX -5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd -DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 -JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g -0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a -mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ -s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ -6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi -FL39vmwLAw== ------END CERTIFICATE----- - -Sonera Class 2 Root CA -====================== ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG -U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw -NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh -IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 -/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT -dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG -f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P -tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH -nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT -XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt -0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI -cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph -Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx -EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH -llpwrN9M ------END CERTIFICATE----- - -Staat der Nederlanden Root CA -============================= ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE -ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g -Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w -HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh -bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt -vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P -jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca -C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth -vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 -22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV -HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v -dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN -BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR -EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw -MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y -nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR -iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== ------END CERTIFICATE----- - -TDC Internet Root CA -==================== ------BEGIN CERTIFICATE----- -MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE -ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx -NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu -ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j -xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL -znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc -5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 -otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI -AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM -VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM -MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC -AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe -UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G -CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m -gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ -2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb -O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU -Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l ------END CERTIFICATE----- - -UTN DATACorp SGC Root CA -======================== ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ -BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa -MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w -HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy -dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys -raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo -wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA -9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv -33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud -DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 -BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD -LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 -DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft -Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 -I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx -EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP -DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- - -UTN USERFirst Hardware Root CA -============================== ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd -BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx -OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 -eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz -ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI -wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd -tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 -i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf -Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw -gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF -lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF -UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF -BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW -XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 -lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn -iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 -nfhmqA== ------END CERTIFICATE----- - -Camerfirma Chambers of Commerce Root -==================================== ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe -QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i -ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx -NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp -cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn -MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC -AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU -xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH -NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW -DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV -d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud -EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v -cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P -AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh -bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD -VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz -aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi -fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD -L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN -UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n -ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 -erfutGWaIZDgqtCYvDi1czyL+Nw= ------END CERTIFICATE----- - -Camerfirma Global Chambersign Root -================================== ------BEGIN CERTIFICATE----- -MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe -QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i -ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx -NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt -YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg -MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw -ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J -1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O -by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl -6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c -8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ -BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j -aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B -Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj -aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y -ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh -bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA -PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y -gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ -PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 -IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes -t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== ------END CERTIFICATE----- - -NetLock Notary (Class A) Root -============================= ------BEGIN CERTIFICATE----- -MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI -EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 -dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j -ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX -DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH -EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD -VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz -cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM -D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ -z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC -/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 -tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 -4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG -A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC -Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv -bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu -IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn -LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 -ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz -IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh -IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu -b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh -bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg -Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp -bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 -ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP -ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB -CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr -KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM -8CgHrTwXZoi1/baI ------END CERTIFICATE----- - -NetLock Business (Class B) Root -=============================== ------BEGIN CERTIFICATE----- -MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT -CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV -BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg -VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD -VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv -bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg -VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S -o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr -1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV -HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ -RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh -dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 -ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv -c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg -YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh -c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz -Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA -bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl -IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 -YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj -cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM -43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR -stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI ------END CERTIFICATE----- - -NetLock Express (Class C) Root -============================== ------BEGIN CERTIFICATE----- -MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT -CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV -BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD -KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ -BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 -dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j -ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB -jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z -W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 -euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw -DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN -RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn -YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB -IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i -aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 -ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs -ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo -dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y -emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k -IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ -UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg -YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 -xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW -gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== ------END CERTIFICATE----- - -XRamp Global CA Root -==================== ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE -BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj -dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx -HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg -U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu -IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx -foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE -zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs -AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry -xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap -oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC -AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc -/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n -nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz -8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- - -Go Daddy Class 2 CA -=================== ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY -VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG -A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g -RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD -ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv -2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 -qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j -YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY -vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O -BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o -atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu -MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim -PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt -I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI -Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b -vZ8= ------END CERTIFICATE----- - -Starfield Class 2 CA -==================== ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc -U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo -MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG -A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG -SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY -bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ -JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm -epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN -F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF -MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f -hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo -bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs -afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM -PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD -KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 -QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- - -StartCom Certification Authority -================================ ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu -ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 -NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk -LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg -U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y -o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ -Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d -eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt -2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z -6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ -osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ -untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc -UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT -37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj -YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH -AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw -Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg -U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 -LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl -cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh -cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT -dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC -AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh -3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm -vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk -fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 -fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ -EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl -1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ -lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro -g14= ------END CERTIFICATE----- - -Taiwan GRCA -=========== ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG -EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X -DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv -dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN -w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 -BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O -1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO -htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov -J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 -Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t -B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB -O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 -lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV -HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 -09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ -TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj -Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 -Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU -D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz -DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk -Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk -7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ -CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy -+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS ------END CERTIFICATE----- - -Firmaprofesional Root CA -======================== ------BEGIN CERTIFICATE----- -MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT -GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp -Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA -ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL -MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT -OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 -ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V -j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH -lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf -3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 -NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww -KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG -AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD -ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq -u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf -wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm -7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG -VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= ------END CERTIFICATE----- - -Wells Fargo Root CA -=================== ------BEGIN CERTIFICATE----- -MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV -BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN -MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl -bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv -MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX -x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 -E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 -OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j -sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj -YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF -BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD -ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv -m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R -OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx -x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 -tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= ------END CERTIFICATE----- - -Swisscom Root CA 1 -================== ------BEGIN CERTIFICATE----- -MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG -EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy -dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 -MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln -aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM -MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF -NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe -AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC -b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn -7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN -cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp -WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 -haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY -MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw -HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j -BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 -MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn -jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ -MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H -VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl -vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl -OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 -1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq -nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy -x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW -NY6E0F/6MBr1mmz0DlP5OlvRHA== ------END CERTIFICATE----- - -DigiCert Assured ID Root CA -=========================== ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw -IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx -MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL -ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO -9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy -UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW -/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy -oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf -GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF -66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq -hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc -EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn -SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i -8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - -DigiCert Global Root CA -======================= ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw -HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw -MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 -dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn -TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 -BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H -4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y -7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB -o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm -8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF -BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr -EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt -tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 -UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -DigiCert High Assurance EV Root CA -================================== ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw -KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw -MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ -MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu -Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t -Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS -OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 -MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ -NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe -h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB -Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY -JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ -V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp -myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK -mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K ------END CERTIFICATE----- - -Certplus Class 2 Primary CA -=========================== ------BEGIN CERTIFICATE----- -MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE -BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN -OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy -dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR -5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ -Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO -YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e -e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME -CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ -YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t -L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD -P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R -TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ -7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW -//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 -l7+ijrRU ------END CERTIFICATE----- - -DST Root CA X3 -============== ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK -ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X -DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 -cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT -rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 -UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy -xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d -utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ -MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug -dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE -GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw -RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS -fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- - -DST ACES CA X6 -============== ------BEGIN CERTIFICATE----- -MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG -EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT -MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha -MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE -CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI -DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa -pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow -GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy -MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu -Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy -dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU -CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 -5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t -Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq -nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs -vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 -oKfN5XozNmr6mis= ------END CERTIFICATE----- - -TURKTRUST Certificate Services Provider Root 1 -============================================== ------BEGIN CERTIFICATE----- -MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP -MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 -acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx -MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg -U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB -TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC -aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX -yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i -Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ -8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 -W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME -BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 -sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE -q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy -B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY -nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H ------END CERTIFICATE----- - -TURKTRUST Certificate Services Provider Root 2 -============================================== ------BEGIN CERTIFICATE----- -MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP -MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg -QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN -MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr -dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G -A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls -acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe -LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI -x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g -QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr -5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB -AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt -Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 -Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ -hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P -9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 -UrbnBEI= ------END CERTIFICATE----- - -SwissSign Gold CA - G2 -====================== ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw -EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN -MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp -c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq -t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C -jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg -vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF -ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR -AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend -jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO -peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR -7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi -GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 -OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm -5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr -44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf -Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m -Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp -mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk -vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf -KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br -NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj -viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- - -SwissSign Silver CA - G2 -======================== ------BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT -BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X -DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 -aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG -9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 -N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm -+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH -6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu -MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h -qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 -FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs -ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc -celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X -CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB -tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P -4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F -kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L -3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx -/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa -DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP -e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu -WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ -DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub -DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE----- - -GeoTrust Primary Certification Authority -======================================== ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx -CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ -cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN -b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 -nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge -RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt -tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI -hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K -Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN -NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa -Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG -1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- - -thawte Primary Root CA -====================== ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE -BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 -aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 -MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg -SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv -KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT -FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs -oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ -1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc -q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K -aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p -afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF -AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE -uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 -jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH -z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== ------END CERTIFICATE----- - -VeriSign Class 3 Public Primary Certification Authority - G5 -============================================================ ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO -ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk -IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln -biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh -dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz -j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD -Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ -Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r -fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv -Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG -SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ -X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE -KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC -Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE -ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- - -SecureTrust CA -============== ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG -EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy -dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe -BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX -OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t -DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH -GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b -01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH -ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj -aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ -KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu -SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf -mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ -nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -Secure Global CA -================ ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG -EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH -bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg -MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg -Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx -YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ -bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g -8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV -HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi -0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn -oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA -MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ -OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn -CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 -3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -COMODO Certification Authority -============================== ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE -BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG -A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb -MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD -T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH -+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww -xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV -4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA -1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI -rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k -b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC -AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP -OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc -IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN -+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== ------END CERTIFICATE----- - -Network Solutions Certificate Authority -======================================= ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG -EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr -IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx -MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx -jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT -aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT -crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc -/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB -AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv -bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA -A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q -4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ -GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD -ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- - -WellsSecure Public Root Certificate Authority -============================================= ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM -F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw -NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN -MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl -bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD -VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 -iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 -i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 -bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB -K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB -AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu -cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm -lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB -i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww -GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI -K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 -bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj -qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es -E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ -tylv2G0xffX8oRAHh84vWdw+WNs= ------END CERTIFICATE----- - -COMODO ECC Certification Authority -================================== ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC -R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE -ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix -GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X -4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni -wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG -FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA -U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -IGC/A -===== ------BEGIN CERTIFICATE----- -MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD -VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE -Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy -MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI -EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT -STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 -TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW -So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy -HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd -frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ -tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB -egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC -iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK -q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q -MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg -Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI -lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF -0mBWWg== ------END CERTIFICATE----- - -Security Communication EV RootCA1 -================================= ------BEGIN CERTIFICATE----- -MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc -U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh -dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE -BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl -Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO -/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX -WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z -ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 -bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK -9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG -SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm -iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG -Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW -mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW -T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 ------END CERTIFICATE----- - -OISTE WISeKey Global Root GA CA -=============================== ------BEGIN CERTIFICATE----- -MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE -BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG -A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH -bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD -VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw -IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 -IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 -Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg -Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD -d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ -/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R -LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ -KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm -MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 -+vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa -hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY -okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= ------END CERTIFICATE----- - -Microsec e-Szigno Root CA -========================= ------BEGIN CERTIFICATE----- -MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE -BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL -EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 -MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz -dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT -GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG -d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N -oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc -QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ -PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb -MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG -IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD -VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 -LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A -dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn -AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA -4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg -AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA -egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 -Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO -PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv -c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h -cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw -IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT -WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV -MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER -MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp -Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal -HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT -nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE -aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a -86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK -yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB -S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= ------END CERTIFICATE----- - -Certigna -======== ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw -EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 -MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI -Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q -XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH -GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p -ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg -DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf -Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ -tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ -BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J -SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA -hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ -ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu -PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY -1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- - -AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. -====================================== ------BEGIN CERTIFICATE----- -MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT -AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg -LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w -HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ -U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh -IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN -yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU -2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 -4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP -2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm -8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf -HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa -Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK -5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b -czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g -ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF -BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug -cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf -AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX -EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v -/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 -MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 -3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk -eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f -/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h -RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU -Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== ------END CERTIFICATE----- - -TC TrustCenter Class 2 CA II -============================ ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy -IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw -MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 -c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE -AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw -IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 -xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ -Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u -SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB -7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 -Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU -cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i -SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G -dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ -KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj -TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP -JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk -vQ== ------END CERTIFICATE----- - -TC TrustCenter Class 3 CA II -============================ ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy -IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw -MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 -c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE -AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W -yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo -6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ -uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk -2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB -7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 -Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU -cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i -SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE -O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 -yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 -IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal -092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc -5A== ------END CERTIFICATE----- - -TC TrustCenter Universal CA I -============================= ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy -IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN -MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg -VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw -JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC -qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv -xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw -ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O -gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j -BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG -1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy -vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 -ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT -ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a -7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY ------END CERTIFICATE----- - -Deutsche Telekom Root CA 2 -========================== ------BEGIN CERTIFICATE----- -MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT -RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG -A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 -MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G -A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS -b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 -bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI -KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY -AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK -Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV -jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV -HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr -E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy -zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 -rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G -dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU -Cm26OWMohpLzGITY+9HPBVZkVw== ------END CERTIFICATE----- - -ComSign Secured CA -================== ------BEGIN CERTIFICATE----- -MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE -AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w -NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD -QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs -49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH -7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB -kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 -9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw -AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t -U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA -j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC -AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a -BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp -FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP -51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz -OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== ------END CERTIFICATE----- - -Cybertrust Global Root -====================== ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li -ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 -MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD -ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -+Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW -0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL -AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin -89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT -8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 -MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G -A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO -lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi -5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 -hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T -X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW -WL1WMRJOEcgh4LMRkWXbtKaIOM5V ------END CERTIFICATE----- - -ePKI Root Certification Authority -================================= ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG -EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx -MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq -MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs -IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi -lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv -qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX -12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O -WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ -ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao -lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ -vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi -Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi -MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 -1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq -KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV -xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP -NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r -GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE -xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx -gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy -sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD -BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 -============================================================================================================================= ------BEGIN CERTIFICATE----- -MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH -DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q -aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry -b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV -BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg -S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 -MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl -IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF -n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl -IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft -dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl -cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO -Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 -xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR -6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL -hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd -BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 -N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT -y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh -LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M -dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= ------END CERTIFICATE----- - -Buypass Class 2 CA 1 -==================== ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 -MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh -c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M -cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 -0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 -0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R -uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P -AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV -1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt -7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 -fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w -wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho ------END CERTIFICATE----- - -Buypass Class 3 CA 1 -==================== ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 -MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh -c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx -ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 -n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia -AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c -1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P -AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 -pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA -EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 -htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj -el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 ------END CERTIFICATE----- - -EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 -========================================================================== ------BEGIN CERTIFICATE----- -MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg -QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe -Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p -ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt -IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by -X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b -gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr -eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ -TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy -Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn -uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI -qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm -ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 -Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW -Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t -FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm -zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k -XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT -bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU -RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK -1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt -2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ -Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 -AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT ------END CERTIFICATE----- - -certSIGN ROOT CA -================ ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD -VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa -Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE -CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I -JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH -rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 -ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD -0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 -AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B -Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB -AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 -SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 -x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt -vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz -TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD ------END CERTIFICATE----- - -CNNIC ROOT -========== ------BEGIN CERTIFICATE----- -MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE -ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw -OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD -o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz -VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT -VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or -czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK -y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC -wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S -lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 -Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM -O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 -BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 -G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m -mxE= ------END CERTIFICATE----- - -ApplicationCA - Japanese Government -=================================== ------BEGIN CERTIFICATE----- -MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT -SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw -MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl -cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 -fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN -wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE -jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu -nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU -WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV -BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD -vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs -o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g -/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD -io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW -dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL -rosot4LKGAfmt1t06SAZf7IbiVQ= ------END CERTIFICATE----- - -GeoTrust Primary Certification Authority - G3 -============================================= ------BEGIN CERTIFICATE----- -MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 -IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz -NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo -YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT -LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j -K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE -c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C -IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu -dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr -2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 -cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE -Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD -AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s -t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt ------END CERTIFICATE----- - -thawte Primary Root CA - G2 -=========================== ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC -VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu -IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg -Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV -MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG -b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt -IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS -LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 -8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU -mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN -G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K -rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- - -thawte Primary Root CA - G3 -=========================== ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE -BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 -aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w -ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD -VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG -A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At -P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC -+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY -7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW -vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ -KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK -A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu -t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC -8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm -er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= ------END CERTIFICATE----- - -GeoTrust Primary Certification Authority - G2 -============================================= ------BEGIN CERTIFICATE----- -MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 -OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg -MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl -b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG -BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc -KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD -VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ -EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m -ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 -npaqBA+K ------END CERTIFICATE----- - -VeriSign Universal Root Certification Authority -=============================================== ------BEGIN CERTIFICATE----- -MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO -ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk -IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj -1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP -MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 -9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I -AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR -tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G -CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O -a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud -DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 -Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx -Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx -P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P -wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 -mJO37M2CYfE45k+XmCpajQ== ------END CERTIFICATE----- - -VeriSign Class 3 Public Primary Certification Authority - G4 -============================================================ ------BEGIN CERTIFICATE----- -MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC -VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 -b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz -ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo -b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 -Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz -rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw -HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u -Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD -A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx -AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== ------END CERTIFICATE----- - -NetLock Arany (Class Gold) Főtanúsítvány -============================================ ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G -A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 -dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB -cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx -MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO -ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 -c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu -0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw -/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk -H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw -fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 -neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW -qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta -YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna -NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu -dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -Staat der Nederlanden Root CA - G2 -================================== ------BEGIN CERTIFICATE----- -MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE -CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g -Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC -TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l -ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ -5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn -vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj -CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil -e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR -OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI -CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 -48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi -trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 -qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB -AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC -ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA -A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz -+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj -f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN -kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk -CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF -URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb -CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h -oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV -IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm -66+KAQ== ------END CERTIFICATE----- - -CA Disig -======== ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK -QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw -MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz -bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm -GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD -Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo -hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt -ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w -gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P -AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz -aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff -ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa -BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t -WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 -mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ -CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K -ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA -4Z7CRneC9VkGjCFMhwnN5ag= ------END CERTIFICATE----- - -Juur-SK -======= ------BEGIN CERTIFICATE----- -MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA -c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw -DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG -SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy -aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf -TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC -+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw -UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa -Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF -MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD -HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh -AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA -cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr -AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw -cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE -FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G -A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo -ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL -abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 -IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh -Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 -yyqcjg== ------END CERTIFICATE----- - -Hongkong Post Root CA 1 -======================= ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT -DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx -NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n -IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 -ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr -auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh -qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY -V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV -HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i -h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio -l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei -IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps -T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT -c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== ------END CERTIFICATE----- - -SecureSign RootCA11 -=================== ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi -SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS -b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw -KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 -cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL -TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO -wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq -g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP -O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA -bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX -t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh -OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r -bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ -Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 -y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 -lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- - -ACEDICOM Root -============= ------BEGIN CERTIFICATE----- -MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD -T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 -MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG -A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk -WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD -YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew -MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb -m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk -HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT -xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 -3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 -2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq -TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz -4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU -9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv -bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg -aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP -eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk -zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 -ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI -KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq -nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE -I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp -MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o -tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== ------END CERTIFICATE----- - -Verisign Class 3 Public Primary Certification Authority -======================================================= ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow -XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz -IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 -f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol -hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky -CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX -bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ -D/xwzoiQ ------END CERTIFICATE----- - -Microsec e-Szigno Root CA 2009 -============================== ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER -MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv -c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE -BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt -U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA -fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG -0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA -pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm -1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC -AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf -QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE -FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o -lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX -I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 -yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi -LXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi -=================================================== ------BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG -EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz -ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 -MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 -cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u -aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY -8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y -jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI -JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk -9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG -SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d -F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq -D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 -Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq -fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX ------END CERTIFICATE----- - -GlobalSign Root CA - R3 -======================= ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv -YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh -bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT -aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln -bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt -iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ -0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 -rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl -OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 -xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 -lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 -EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E -bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 -YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r -kpeDMdmztcpHWD9f ------END CERTIFICATE----- - -Autoridad de Certificacion Firmaprofesional CIF A62634068 -========================================================= ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA -BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw -QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB -NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD -Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P -B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY -7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH -ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI -plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX -MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX -LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK -bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU -vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud -EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH -DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA -bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx -ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx -51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk -R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP -T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f -Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl -osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR -crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR -saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD -KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi -6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - -Izenpe.com -========== ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG -EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz -MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu -QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ -03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK -ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU -+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC -PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT -OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK -F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK -0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ -0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB -leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID -AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ -SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG -NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O -BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l -Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga -kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q -hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs -g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 -aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 -nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC -ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo -Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z -WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -Chambers of Commerce Root - 2008 -================================ ------BEGIN CERTIFICATE----- -MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD -MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv -bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu -QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy -Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl -ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF -EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl -cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA -XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj -h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ -ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk -NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g -D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 -lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ -0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj -ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 -EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI -G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ -BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh -bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh -bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC -CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH -AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 -wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH -3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU -RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 -M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 -YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF -9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK -zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG -nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg -OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ ------END CERTIFICATE----- - -Global Chambersign Root - 2008 -============================== ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD -MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv -bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu -QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx -NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg -Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ -QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf -VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf -XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 -ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB -/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA -TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M -H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe -Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF -HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB -AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT -BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE -BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm -aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm -aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp -1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 -dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG -/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 -ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s -dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg -9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH -foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du -qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr -P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq -c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- - -Go Daddy Root Certificate Authority - G2 -======================================== ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu -MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G -A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq -9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD -+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd -fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl -NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 -BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac -vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r -5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV -N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 ------END CERTIFICATE----- - -Starfield Root Certificate Authority - G2 -========================================= ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s -b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 -eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw -DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg -VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB -dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv -W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs -bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk -N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf -ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU -JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol -TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx -4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw -F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ -c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -Starfield Services Root Certificate Authority - G2 -================================================== ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s -b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl -IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV -BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT -dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 -h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa -hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP -LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB -rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG -SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP -E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy -xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza -YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 ------END CERTIFICATE----- - -AffirmTrust Commercial -====================== ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS -BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw -MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly -bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb -DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV -C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 -BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww -MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV -HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG -hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi -qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv -0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh -sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- - -AffirmTrust Networking -====================== ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS -BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw -MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly -bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE -Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI -dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 -/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb -h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV -HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu -UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 -12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 -WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 -/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- - -AffirmTrust Premium -=================== ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS -BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy -OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy -dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn -BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV -5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs -+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd -GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R -p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI -S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 -6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 -/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo -+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv -MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC -6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S -L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK -+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV -BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg -IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 -g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb -zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== ------END CERTIFICATE----- - -AffirmTrust Premium ECC -======================= ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV -BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx -MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U -cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ -N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW -BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK -BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X -57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM -eQ== ------END CERTIFICATE----- - -Certum Trusted Network CA -========================= ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK -ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy -MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU -ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC -l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J -J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 -fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 -cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB -Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw -DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj -jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 -mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj -Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -Certinomis - Autorité Racine -============================= ------BEGIN CERTIFICATE----- -MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK -Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg -LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG -A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw -JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa -wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly -Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw -2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N -jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q -c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC -lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb -xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g -530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna -4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ -KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x -WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva -R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 -nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B -CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv -JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE -qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b -WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE -wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ -vgt2Fl43N+bYdJeimUV5 ------END CERTIFICATE----- - -Root CA Generalitat Valenciana -============================== ------BEGIN CERTIFICATE----- -MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE -ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 -IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 -WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE -CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 -F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B -ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ -D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte -JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB -AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n -dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB -ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl -AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA -YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy -AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA -aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt -AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA -YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu -AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA -OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 -dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV -BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G -A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S -b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh -TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz -Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 -NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH -iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt -+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= ------END CERTIFICATE----- - -A-Trust-nQual-03 -================ ------BEGIN CERTIFICATE----- -MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE -Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy -a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R -dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw -RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 -ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 -c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA -zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n -yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE -SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 -iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V -cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV -eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 -ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr -sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd -JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS -mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 -ahq97BvIxYSazQ== ------END CERTIFICATE----- - -TWCA Root Certification Authority -================================= ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ -VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG -EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB -IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx -QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC -oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP -4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r -y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG -9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC -mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW -QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY -T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny -Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -Security Communication RootCA2 -============================== ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc -U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh -dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC -SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy -aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ -+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R -3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV -spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K -EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 -QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB -CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj -u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk -3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q -tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 -mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -EC-ACC -====== ------BEGIN CERTIFICATE----- -MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE -BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w -ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD -VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE -CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT -BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 -MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt -SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl -Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh -cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK -w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT -ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 -HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a -E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw -0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD -VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 -Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l -dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ -lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa -Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe -l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 -E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D -5EI= ------END CERTIFICATE----- - -Hellenic Academic and Research Institutions RootCA 2011 -======================================================= ------BEGIN CERTIFICATE----- -MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT -O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y -aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z -IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT -AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z -IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo -IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI -1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa -71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u -8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH -3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ -MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 -MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu -b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt -XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 -TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD -/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N -7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 ------END CERTIFICATE----- - -Actalis Authentication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM -BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE -AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky -MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz -IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ -wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa -by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 -zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f -YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 -oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l -EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 -hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 -EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 -jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY -iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI -WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 -JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx -K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ -Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC -4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo -2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz -lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem -OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 -vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -Trustis FPS Root CA -=================== ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG -EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 -IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV -BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ -RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk -H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa -cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt -o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA -AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd -BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c -GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC -yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P -8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV -l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl -iB6XzCGcKQENZetX2fNXlrtIzYE= ------END CERTIFICATE----- - -StartCom Certification Authority -================================ ------BEGIN CERTIFICATE----- -MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu -ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 -NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk -LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg -U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y -o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ -Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d -eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt -2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z -6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ -osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ -untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc -UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT -37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ -Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 -dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu -c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv -bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 -aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t -L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG -cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 -fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm -N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN -Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T -tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX -e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA -2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs -HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE -JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib -D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= ------END CERTIFICATE----- - -StartCom Certification Authority G2 -=================================== ------BEGIN CERTIFICATE----- -MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE -ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O -o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG -4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi -Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul -Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs -O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H -vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L -nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS -FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa -z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ -KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K -2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk -J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ -JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG -/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc -nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld -blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc -l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm -7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm -obp573PYtlNXLfbQ4ddI ------END CERTIFICATE----- - -Buypass Class 2 Root CA -======================= ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X -DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 -eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 -g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn -9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b -/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU -CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff -awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI -zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn -Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX -Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs -M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF -AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI -osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S -aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd -DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD -LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 -oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC -wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS -CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN -rJgWVqA= ------END CERTIFICATE----- - -Buypass Class 3 Root CA -======================= ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU -QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X -DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 -eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH -sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR -5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh -7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ -ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH -2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV -/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ -RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA -Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq -j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF -AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G -uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG -Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 -ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 -KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz -6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug -UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe -eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi -Cp/HuZc= ------END CERTIFICATE----- - -T-TeleSec GlobalRoot Class 3 -============================ ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM -IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU -cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx -MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz -dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD -ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK -9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU -NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF -iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W -0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr -AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb -fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT -ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h -P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== ------END CERTIFICATE----- - -EE Certification Centre Root CA -=============================== ------BEGIN CERTIFICATE----- -MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG -EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy -dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw -MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB -UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy -ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM -TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 -rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw -93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN -P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ -MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF -BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj -xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM -lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u -uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU -3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM -dcGWxZ0= ------END CERTIFICATE----- - -TURKTRUST Certificate Services Provider Root 2007 -================================================= ------BEGIN CERTIFICATE----- -MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF -bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP -MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg -QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X -DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl -a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN -BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp -bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N -YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv -KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya -KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT -rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC -AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s -Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I -aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO -Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb -BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK -poRq0Tl9 ------END CERTIFICATE----- - -D-TRUST Root Class 3 CA 2 2009 -============================== ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK -DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe -Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE -LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD -ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA -BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv -KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z -p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC -AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ -4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y -eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw -MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G -PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw -OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm -2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV -dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph -X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -D-TRUST Root Class 3 CA 2 EV 2009 -================================= ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK -DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw -OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK -DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw -OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS -egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh -zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T -7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 -sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 -11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv -cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v -ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El -MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp -b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh -c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ -PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX -ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA -NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv -w9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -PSCProcert -========== ------BEGIN CERTIFICATE----- -MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk -ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ -MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz -dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl -cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw -IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw -MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w -DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD -ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp -Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC -wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA -3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh -RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO -EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 -0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH -0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU -td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw -Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp -r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ -AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz -Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId -xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp -ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH -EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h -Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k -ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG -9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG -MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG -LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 -ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy -YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v -Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o -dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq -T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN -g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q -uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 -n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn -FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo -5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq -3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 -poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y -eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km ------END CERTIFICATE----- - -China Internet Network Information Center EV Certificates Root -============================================================== ------BEGIN CERTIFICATE----- -MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D -aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg -Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG -A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM -PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl -cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y -jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV -98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H -klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 -KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC -7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD -glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 -0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM -7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws -ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 -5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= ------END CERTIFICATE----- - -Swisscom Root CA 2 -================== ------BEGIN CERTIFICATE----- -MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG -EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy -dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 -MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln -aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC -IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM -LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo -ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ -wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH -Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a -SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS -NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab -mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY -Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 -qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw -HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O -BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu -MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO -v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ -82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz -o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs -a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx -OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW -mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o -+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC -rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX -5OfNeOI5wSsSnqaeG8XmDtkx2Q== ------END CERTIFICATE----- - -Swisscom Root EV CA 2 -===================== ------BEGIN CERTIFICATE----- -MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE -BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl -cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN -MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT -HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg -Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz -o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy -Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti -GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li -qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH -Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG -alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa -m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox -bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi -xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED -MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB -bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL -j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU -wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 -XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH -59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ -23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq -J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA -HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi -uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW -l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= ------END CERTIFICATE----- - -CA Disig Root R1 -================ ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw -EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp -ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx -EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp -c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy -3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 -u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 -m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk -CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa -YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 -vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL -LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX -ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is -XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ -04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR -xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B -LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM -CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb -VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 -YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS -ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix -lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N -UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ -a7+h89n07eLw4+1knj0vllJPgFOL ------END CERTIFICATE----- - -CA Disig Root R2 -================ ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw -EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp -ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx -EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp -c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC -w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia -xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 -A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S -GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV -g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa -5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE -koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A -Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i -Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u -Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV -sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je -dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 -1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx -mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 -utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 -sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg -UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV -7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- \ No newline at end of file diff --git a/lib/nfe.rb b/lib/nfe.rb index 43388fe..89d8468 100644 --- a/lib/nfe.rb +++ b/lib/nfe.rb @@ -1,43 +1,47 @@ -require "rest-client" -require "json" -require "nfe/version" -require "nfe/configuration" - -require "nfe/api_resource" -require "nfe/api_operations/create" -require "nfe/api_operations/delete" -require "nfe/api_operations/cancel" -require "nfe/api_operations/list" -require "nfe/api_operations/retrieve" -require "nfe/api_operations/update" -require "nfe/api_operations/download" - -require "nfe/nfe_object" -require "nfe/service_invoice" -require "nfe/company" -require "nfe/natural_people" -require "nfe/legal_people" - -require "nfe/util" -require "nfe/errors/nfe_error" +# frozen_string_literal: true +require "nfe/version" +# Error hierarchy + factory +require "nfe/errors" +require "nfe/error_factory" + +# Value objects & validation helpers +require "nfe/results" +require "nfe/pagination" +require "nfe/request_options" +require "nfe/flow_status" +require "nfe/id_validator" +require "nfe/date_normalizer" + +# Webhook signature verification + certificate handling +require "nfe/webhook_event" +require "nfe/webhook" +require "nfe/certificate" + +# HTTP transport layer (zero-dependency, Net::HTTP-based) +require "nfe/http/request" +require "nfe/http/response" +require "nfe/http/transport" +require "nfe/http/redactor" +require "nfe/http/user_agent" +require "nfe/http/net_http" +require "nfe/http/retry_policy" +require "nfe/http/retrying_transport" + +# Core DX layer (Client also requires Configuration, AbstractResource, and the 17 resource stubs) +require "nfe/configuration" +require "nfe/client" + +# Official NFE.io SDK for Ruby. +# +# Zero runtime dependencies — Ruby stdlib only. Issue and manage Brazilian +# electronic fiscal documents (NFS-e, NF-e, NFC-e, CT-e) through a single +# Stripe-style client: +# +# client = Nfe::Client.new(api_key: "your-api-key") +# client.service_invoices # resources are lazy snake_case accessors +# +# See https://nfe.io for API documentation. module Nfe - @@api_key = '' - - def self.api_key(api_key) - @@api_key = api_key - end - - def self.access_keys - "#{@@api_key}" - end - - def self.configuration - @configuration ||= Configuration.new - end - - def self.configure - yield(configuration) if block_given? - end end diff --git a/lib/nfe/api_operations/cancel.rb b/lib/nfe/api_operations/cancel.rb deleted file mode 100644 index ff5e637..0000000 --- a/lib/nfe/api_operations/cancel.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Nfe - module ApiOperations - module Cancel - def cancel(nfe_id) - method = :delete - response = api_request("#{url}/#{nfe_id}", method) - create_from(response) - end - - def self.included(base) - base.extend(Cancel) - end - end - end -end diff --git a/lib/nfe/api_operations/create.rb b/lib/nfe/api_operations/create.rb deleted file mode 100644 index 9e30970..0000000 --- a/lib/nfe/api_operations/create.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Nfe - module ApiOperations - module Create - def create(params) - method = :post - response = api_request(url, method, params) - create_from(response) - end - - def self.included(base) - base.extend(Create) - end - end - end -end \ No newline at end of file diff --git a/lib/nfe/api_operations/delete.rb b/lib/nfe/api_operations/delete.rb deleted file mode 100644 index 701095b..0000000 --- a/lib/nfe/api_operations/delete.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Nfe - module ApiOperations - module Delete - def delete(params) - method = :delete - response = api_request(url, method, params) - # reflesh_object(response) - response - end - - def self.included(base) - base.extend(Delete) - end - end - end -end \ No newline at end of file diff --git a/lib/nfe/api_operations/download.rb b/lib/nfe/api_operations/download.rb deleted file mode 100644 index 0be5d14..0000000 --- a/lib/nfe/api_operations/download.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Nfe - module ApiOperations - module Download - def download(nfe_id, file_format) - if file_format != :pdf && file_format != :xml - rcode = '422' - message = 'Invalid file format. Only :pdf or :xml are supported' - formatted = { error: message } - raise NfeError.new(rcode, formatted, formatted, message) - else - url = "#{self.url}/#{nfe_id}/#{file_format}" - method = :get - api_request_file(url, method) - end - end - - def self.included(base) - base.extend(Download) - end - end - end -end diff --git a/lib/nfe/api_operations/list.rb b/lib/nfe/api_operations/list.rb deleted file mode 100644 index 0ab37c4..0000000 --- a/lib/nfe/api_operations/list.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Nfe - module ApiOperations - module List - def list_all(params=nil) - method = :get - response = api_request(url, method, params) - create_from(response) - end - - def self.included(base) - base.extend(List) - end - end - end -end \ No newline at end of file diff --git a/lib/nfe/api_operations/retrieve.rb b/lib/nfe/api_operations/retrieve.rb deleted file mode 100644 index 3fa1888..0000000 --- a/lib/nfe/api_operations/retrieve.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Nfe - module ApiOperations - module Retrieve - def retrieve(obj_id) - obj_id = "?id=#{obj_id}" if obj_id.include? '@' - method = :get - response = api_request("#{url}/#{obj_id}",method) - create_from(response) - end - - def self.included(base) - base.extend(Retrieve) - end - end - end -end \ No newline at end of file diff --git a/lib/nfe/api_operations/update.rb b/lib/nfe/api_operations/update.rb deleted file mode 100644 index c41ca84..0000000 --- a/lib/nfe/api_operations/update.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Nfe - module ApiOperations - module Update - def save - params_to_update = {} - self.serialize_params.each do |key| - return if (@values[key] || @values[key.to_s]).is_a? Nfe::NfeObject - params_to_update[key] = (@values[key] || @values[key.to_s]) if @values - end - puts params_to_update - - update(params_to_update) - end - - def update(params=nil, url_sufix=nil) - method = :post - response = api_request("#{url}/#{url_sufix}",method,params) - reflesh_object(response) - end - end - end -end \ No newline at end of file diff --git a/lib/nfe/api_resource.rb b/lib/nfe/api_resource.rb deleted file mode 100644 index 6911581..0000000 --- a/lib/nfe/api_resource.rb +++ /dev/null @@ -1,84 +0,0 @@ -module Nfe - module ApiResource - SSL_BUNDLE_PATH = File.dirname(__FILE__) + '/../data/ssl-bundle.crt' - - def url_encode(key) - URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) - end - - def encode(params) - params.map { |k,v| "#{k}=#{url_encode(v)}" }.join('&') - end - - def api_request(url, method, params=nil) - url = "#{Nfe.configuration.url}#{url}" - api_key = Nfe.access_keys - - if method == :get && params - params_encoded = encode(params) - url = "#{url}?#{params_encoded}" - params = nil - end - - payload = (params != nil) ? params.to_json : '' - request = RestClient::Request.new( - method: method, - url: url, - payload: payload, - headers: { - content_type: 'application/json', - accept: 'application/json', - authorization: api_key, - user_agent: Nfe.configuration.user_agent - }) - - begin - response = request.execute - rescue RestClient::ExceptionWithResponse => e - if rcode = e.http_code and rbody = e.http_body - rbody = JSON.parse(rbody) - rbody = Util.symbolize_names(rbody) - - raise NfeError.new(rcode, rbody, rbody, rbody[:message]) - else - raise e - end - rescue RestClient::Exception => e - raise e - end - JSON.parse(response.to_s) - end - - def self.included(base) - base.extend(ApiResource) - end - - def api_request_file(url, method, params=nil) - api_key = Nfe.access_keys - url = "#{Nfe.configuration.url}#{url}?api_key=#{api_key}" - - request = RestClient::Request.new( - method: method, - url: url, - headers: { user_agent: Nfe.configuration.user_agent } - ) - - begin - response = request.execute - rescue RestClient::ExceptionWithResponse => e - if rcode = e.http_code and rbody = e.http_body - rbody = JSON.parse(rbody) - rbody = Util.symbolize_names(rbody) - - raise NfeError.new(rcode, rbody, rbody, rbody[:message]) - else - raise e - end - rescue RestClient::Exception => e - raise e - end - - response - end - end -end diff --git a/lib/nfe/certificate.rb b/lib/nfe/certificate.rb new file mode 100644 index 0000000..003686c --- /dev/null +++ b/lib/nfe/certificate.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require "openssl" +require "time" + +module Nfe + # Metadata extracted from a digital certificate (A1 PKCS#12) parsed locally. + # +not_before+ / +not_after+ are +Time+ instances; +serial_number+ is a + # decimal +String+. + class CertificateInfo < Data.define(:subject, :issuer, :not_before, :not_after, :serial_number) + end + + # Server-reported certificate status for a company, augmented with + # client-side expiry computations (+days_until_expiration+, +expiring_soon+). + class CertificateStatus < Data.define( + :has_certificate, :expires_on, :valid, :days_until_expiration, :expiring_soon, :details + ) + end + + # Local-only validation and inspection of A1 digital certificates (PKCS#12, + # +.pfx+/+.p12+). Uses only the +openssl+ stdlib — no network access, no new + # runtime dependency. + # + # The PKCS#12 bytes and password are handled in-memory only and never logged, + # persisted, or echoed into exception messages. + module CertificateValidator + # Default window (in days) within which a certificate is "expiring soon". + DEFAULT_THRESHOLD_DAYS = 30 + + # Number of seconds in a day, for day-delta math. + SECONDS_PER_DAY = 86_400 + + module_function + + # @param filename [String, nil] a certificate filename. + # @return [Boolean] +true+ for +.pfx+/+.p12+ (case-insensitive). + def supported_format?(filename) + ext = filename.to_s.downcase.split(".").last + %w[pfx p12].include?(ext) + end + + # Parse PKCS#12 bytes with the given password and extract certificate + # metadata. + # + # @param der_bytes [String] the raw +.pfx+/+.p12+ bytes. + # @param password [String] the certificate password. + # @return [Nfe::CertificateInfo] + # @raise [Nfe::InvalidRequestError] on a wrong password or malformed DER. + # The message never includes the password or the raw bytes. + def validate(der_bytes, password) + pkcs12 = OpenSSL::PKCS12.new(der_bytes, password) + cert = pkcs12.certificate + + CertificateInfo.new( + subject: cert.subject.to_s, + issuer: cert.issuer.to_s, + not_before: cert.not_before, + not_after: cert.not_after, + serial_number: cert.serial.to_s + ) + rescue OpenSSL::OpenSSLError, ArgumentError, TypeError + raise Nfe::InvalidRequestError, "Certificado ou senha inválidos" + end + + # Whole days from now until +not_after+ (negative once expired). + # + # @param not_after [Time, String] the expiry instant. + # @return [Integer] + def days_until_expiration(not_after) + expiry = coerce_time(not_after) + ((expiry - Time.now) / SECONDS_PER_DAY).floor + end + + # @param not_after [Time, String] the expiry instant. + # @param threshold_days [Integer] the "soon" window (default 30). + # @return [Boolean] +true+ when expiry is within +[0, threshold_days)+. + def expiring_soon?(not_after, threshold_days = DEFAULT_THRESHOLD_DAYS) + days = days_until_expiration(not_after) + days >= 0 && days < threshold_days + end + + # @api private + def coerce_time(value) + value.is_a?(Time) ? value : Time.parse(value.to_s) + end + end +end diff --git a/lib/nfe/client.rb b/lib/nfe/client.rb new file mode 100644 index 0000000..6e66dc1 --- /dev/null +++ b/lib/nfe/client.rb @@ -0,0 +1,210 @@ +# frozen_string_literal: true + +require "nfe/configuration" +require "nfe/http/net_http" +require "nfe/http/retrying_transport" +require "nfe/http/retry_policy" +require "nfe/http/request" +require "nfe/http/user_agent" +require "nfe/error_factory" + +require "nfe/resources/abstract_resource" +require "nfe/resources/service_invoices" +require "nfe/resources/product_invoices" +require "nfe/resources/consumer_invoices" +require "nfe/resources/transportation_invoices" +require "nfe/resources/inbound_product_invoices" +require "nfe/resources/product_invoice_query" +require "nfe/resources/consumer_invoice_query" +require "nfe/resources/companies" +require "nfe/resources/legal_people" +require "nfe/resources/natural_people" +require "nfe/resources/webhooks" +require "nfe/resources/addresses" +require "nfe/resources/legal_entity_lookup" +require "nfe/resources/natural_person_lookup" +require "nfe/resources/tax_calculation" +require "nfe/resources/tax_codes" +require "nfe/resources/state_taxes" +require "nfe/resources/service_invoices_rtc" +require "nfe/resources/product_invoices_rtc" + +module Nfe + # Primary entry point for the SDK. + # + # client = Nfe::Client.new(api_key: "...") + # client.service_invoices.create(company_id: "...", data: { ... }) + # + # Resources are exposed as lazy, memoized snake_case accessors, each guarded + # by a +Mutex+ so a single +Client+ is safe to share across threads + # (Rails/Sidekiq/Puma). The class is the public surface and is NOT designed + # for subclassing; customization is achieved by composing + # {Nfe::Configuration} and the injected transport. + class Client + # The 17 core resource accessor names mapped to their resource classes. + RESOURCES = { + service_invoices: Resources::ServiceInvoices, + product_invoices: Resources::ProductInvoices, + consumer_invoices: Resources::ConsumerInvoices, + transportation_invoices: Resources::TransportationInvoices, + inbound_product_invoices: Resources::InboundProductInvoices, + product_invoice_query: Resources::ProductInvoiceQuery, + consumer_invoice_query: Resources::ConsumerInvoiceQuery, + companies: Resources::Companies, + legal_people: Resources::LegalPeople, + natural_people: Resources::NaturalPeople, + webhooks: Resources::Webhooks, + addresses: Resources::Addresses, + legal_entity_lookup: Resources::LegalEntityLookup, + natural_person_lookup: Resources::NaturalPersonLookup, + tax_calculation: Resources::TaxCalculation, + tax_codes: Resources::TaxCodes, + state_taxes: Resources::StateTaxes, + # RTC (Reforma Tributária) emission — paridade-plus addons, not part of + # the 17 canonical resources shared with the PHP/Node SDKs. + service_invoices_rtc: Resources::ServiceInvoicesRtc, + product_invoices_rtc: Resources::ProductInvoicesRtc + }.freeze + + # @return [Nfe::Configuration] the active configuration. + attr_reader :configuration + + # @param api_key [String, nil] the main API key (overridden by +configuration+). + # @param data_api_key [String, nil] the data-services API key. + # @param configuration [Nfe::Configuration, nil] when supplied, the other + # convenience keyword arguments are ignored. + # @param environment [Symbol] :production (default) or :development. + # @param timeout [Integer] read timeout in seconds. + # @param max_retries [Integer] retries after the initial attempt. + # @param logger [#info, #warn, #error, nil] + # @param user_agent_suffix [String, nil] + def initialize(api_key: nil, data_api_key: nil, configuration: nil, + environment: :production, timeout: 30, max_retries: 3, + logger: nil, user_agent_suffix: nil) + @configuration = configuration || Configuration.new( + api_key: api_key, + data_api_key: data_api_key, + environment: environment, + timeout: timeout, + max_retries: max_retries, + logger: logger, + user_agent_suffix: user_agent_suffix + ) + @resources = {} + @transports = {} + @resource_mutex = Mutex.new + @transport_mutex = Mutex.new + end + + # Lazy, thread-safe, memoized resource accessors (each built once under a Mutex). + def service_invoices = resource(:service_invoices) + def product_invoices = resource(:product_invoices) + def consumer_invoices = resource(:consumer_invoices) + def transportation_invoices = resource(:transportation_invoices) + def inbound_product_invoices = resource(:inbound_product_invoices) + def product_invoice_query = resource(:product_invoice_query) + def consumer_invoice_query = resource(:consumer_invoice_query) + def companies = resource(:companies) + def legal_people = resource(:legal_people) + def natural_people = resource(:natural_people) + def webhooks = resource(:webhooks) + def addresses = resource(:addresses) + def legal_entity_lookup = resource(:legal_entity_lookup) + def natural_person_lookup = resource(:natural_person_lookup) + def tax_calculation = resource(:tax_calculation) + def tax_codes = resource(:tax_codes) + def state_taxes = resource(:state_taxes) + def service_invoices_rtc = resource(:service_invoices_rtc) + def product_invoices_rtc = resource(:product_invoices_rtc) + + # Issue an arbitrary request against +family+, applying the family's host + # and key plus the standard authorization and User-Agent headers. This is + # the low-level escape hatch shared by every resource. + # + # When +request_options+ is supplied, its non-nil +api_key+, +base_url+, and + # +timeout+ override the family-resolved values for this single call (enabling + # multi-tenant per-call keys); nil fields fall back to family resolution. + # + # Raises the appropriate {Nfe::Error} subclass (via {Nfe::ErrorFactory}) on a + # non-2xx response (note: 202 is a success); otherwise returns the + # {Nfe::Http::Response}. + # + # @api private + def request(method, family:, path:, query: {}, body: nil, headers: {}, + idempotency_key: nil, request_options: nil) + request = build_request(method, family: family, path: path, query: query, + body: body, headers: headers, + idempotency_key: idempotency_key, + request_options: request_options) + + response = transport_for(family).call(request) + raise Nfe::ErrorFactory.from_response(response) unless response.success? + + response + end + + private + + # Compose the {Nfe::Http::Request}, resolving host/key/timeout from the + # family (with per-call +request_options+ overrides) and applying the + # standard headers. + def build_request(method, family:, path:, query:, body:, headers:, + idempotency_key:, request_options:) + base_url = request_options&.base_url || configuration.base_url_for(family) + api_key = request_options&.api_key || configuration.api_key_for(family) + + Http::Request.new( + method: method.to_s.upcase, + base_url: base_url, + path: path, + headers: default_headers(api_key).merge(headers), + query: query, + body: body, + open_timeout: configuration.open_timeout, + read_timeout: request_options&.timeout || configuration.timeout, + idempotency_key: idempotency_key + ) + end + + # Standard headers applied to every outgoing request. + def default_headers(api_key) + { + "X-NFE-APIKEY" => api_key, + "User-Agent" => Http::UserAgent.build(configuration.user_agent_suffix), + "Accept" => "application/json" + } + end + + # Memoize (under a Mutex) the resource instance for +name+. + def resource(name) + @resource_mutex.synchronize do + @resources[name] ||= RESOURCES.fetch(name).new(self) + end + end + + # Memoize (under a Mutex) a RetryingTransport(NetHttp) per family. Families + # may differ in nothing transport-wise today, but memoizing per family keeps + # the door open for per-host tuning and matches the canonical contract. + def transport_for(family) + @transport_mutex.synchronize do + @transports[family] ||= build_transport + end + end + + def build_transport + inner = Http::NetHttp.new( + default_open_timeout: configuration.open_timeout, + default_read_timeout: configuration.timeout, + ca_file: configuration.ca_file + ) + policy = Http::RetryPolicy.new( + max_retries: configuration.max_retries, + base_delay: 1.0, + max_delay: 30.0, + jitter: 0.3 + ) + Http::RetryingTransport.new(inner: inner, policy: policy, + logger: configuration.logger) + end + end +end diff --git a/lib/nfe/company.rb b/lib/nfe/company.rb deleted file mode 100644 index c7d9348..0000000 --- a/lib/nfe/company.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Nfe - class Company < NfeObject - include ApiResource - include ApiOperations::Create - include ApiOperations::List - include ApiOperations::Retrieve - include ApiOperations::Delete - include ApiOperations::Update - - def self.url - "/v1/companies" - end - - def url - "#{self.class.url}/#{self.id}" - end - - def self.create_from(params) - obj = self.new - obj.reflesh_object(params["companies"]) - end - end -end \ No newline at end of file diff --git a/lib/nfe/configuration.rb b/lib/nfe/configuration.rb index 2c8f416..e8644a5 100644 --- a/lib/nfe/configuration.rb +++ b/lib/nfe/configuration.rb @@ -1,10 +1,209 @@ +# frozen_string_literal: true + module Nfe + # Central configuration for the SDK and the single source of truth for the + # multi-base-URL host map. No resource hard-codes a URL: resources declare an + # +api_family+ and obtain their host via {#base_url_for}. + # + # == Two-key model + # The SDK uses two API keys. The "data" families ({#api_key_for} maps + # +:addresses+, +:legal_entity+, +:natural_person+ and +:nfe_query+ to it) + # use +data_api_key+ when present, falling back to +api_key+. Every other + # family uses +api_key+. Either key may be supplied explicitly or via the + # +NFE_API_KEY+ / +NFE_DATA_API_KEY+ environment variables (explicit wins). + # + # == Environment (reserved for future use) + # +environment:+ (+:production+ / +:development+) is currently a reserved, + # no-op parameter: it is validated but does NOT change endpoints, keys, or + # behavior. Production vs. test (homologação) is determined by the account + # configuration at https://app.nfe.io (server-side) — not by the SDK or the + # API key — and there is no "sandbox URL". Full +environment:+ support is + # planned for a future release. + # + # == TLS trust + # +ca_file+ (and optionally +ca_path+) is the ONLY override of the TLS trust + # store and can only ADD/replace a CA bundle used to verify the peer. There is + # deliberately NO public API to disable peer verification (no +VERIFY_NONE+, + # no +insecure_ssl+). The upstream +insecureSsl+ attribute is a server-side + # property of a webhook delivery target, not the SDK's outbound TLS config. class Configuration - attr_accessor :url, :user_agent + # Host per NFE.io product family, keyed by the canonical (hyphenated) + # family symbol. The +/v1+ for the +:main+ family is supplied by each + # resource's +api_version+, not baked into the host. The +:addresses+ + # family is the documented exception where +/v2+ is part of the host. + HOSTS = { + main: "https://api.nfe.io", + addresses: "https://address.api.nfe.io/v2", + "nfe-query": "https://nfe.api.nfe.io", + "legal-entity": "https://legalentity.api.nfe.io", + "natural-person": "https://naturalperson.api.nfe.io", + cte: "https://api.nfse.io" + }.freeze + + # Maps family aliases (the snake_case names resources declare) to a + # canonical family key in {HOSTS}. Keys here are already hyphen-normalized. + FAMILY_ALIASES = { + companies: :main, + "service-invoices": :main, + "legal-people": :main, + "natural-people": :main, + webhooks: :main, + transportation: :cte, + "transportation-invoices": :cte, + "inbound-product": :cte, + "inbound-product-invoices": :cte, + "product-invoices": :cte, + "consumer-invoices": :cte, + "tax-calculation": :cte, + "tax-codes": :cte, + "state-taxes": :cte, + "product-invoice-query": :"nfe-query", + "consumer-invoice-query": :"nfe-query" + }.freeze + + # Canonical families whose key resolves from +data_api_key+ first. Only the + # four dedicated-host data-lookup families belong here. +:cte+ (api.nfse.io — + # NF-e/NFC-e/CT-e emission + tax-rules/tax-codes/state-taxes) intentionally + # uses the main +api_key+ and is NOT a data family: in this SDK emission is a + # core capability, not a data-lookup. This is a deliberate divergence from the + # Node SDK (which routes api.nfse.io through the data-key fallback chain) — + # do not add +:cte+ here without revisiting that contract. + DATA_FAMILIES = %i[addresses legal-entity natural-person nfe-query].freeze + + # Accepted +environment:+ values. Reserved for future use — both currently + # share the same endpoints and key resolution (see the class doc). + VALID_ENVIRONMENTS = %i[production development].freeze + + DEFAULT_TIMEOUT = 30 + DEFAULT_OPEN_TIMEOUT = 10 + DEFAULT_MAX_RETRIES = 3 + + attr_reader :api_key, :data_api_key, :environment, :timeout, :open_timeout, + :max_retries, :logger, :user_agent_suffix, :base_url_overrides, + :ca_file, :ca_path, :proxy + + # @param api_key [String, nil] main key; falls back to +NFE_API_KEY+. + # @param data_api_key [String, nil] data-services key; falls back to + # +NFE_DATA_API_KEY+. + # @param environment [Symbol] +:production+ (default) or +:development+. + # Reserved for future use — validated but currently has no effect on + # endpoints/keys (prod vs. test is set in the account at app.nfe.io). + # @param timeout [Integer] read timeout in seconds (must be positive). + # @param open_timeout [Integer] connect timeout in seconds (must be positive). + # @param max_retries [Integer] retry budget (non-negative). + # @param logger [Object, nil] optional logger. + # @param user_agent_suffix [String, nil] appended to the SDK User-Agent. + # @param base_url_overrides [Hash{Symbol=>String}] per-family escape hatch. + # @param ca_file [String, nil] path to a CA bundle to ADD to the trust store. + # @param ca_path [String, nil] directory of CA certs to ADD to the trust store. + # @param proxy [String, URI, nil] passed through to +Net::HTTP+. + # @raise [Nfe::ConfigurationError] on invalid values. + def initialize(api_key: nil, data_api_key: nil, environment: :production, + timeout: DEFAULT_TIMEOUT, open_timeout: DEFAULT_OPEN_TIMEOUT, + max_retries: DEFAULT_MAX_RETRIES, logger: nil, + user_agent_suffix: nil, base_url_overrides: {}, + ca_file: nil, ca_path: nil, proxy: nil) + @api_key = resolve_key(api_key, "NFE_API_KEY") + @data_api_key = resolve_key(data_api_key, "NFE_DATA_API_KEY") + @environment = environment + @timeout = timeout + @open_timeout = open_timeout + @max_retries = max_retries + @logger = logger + @user_agent_suffix = user_agent_suffix + @base_url_overrides = base_url_overrides || {} + @ca_file = ca_file + @ca_path = ca_path + @proxy = proxy + + validate! + end + + # Returns the base host for a product +family+. A per-family override (from + # +base_url_overrides+) wins; an unknown family falls back to the +:main+ + # host as a safe default. + # + # @param family [Symbol, String] family or alias (snake_case accepted). + # @return [String] + def base_url_for(family) + canonical = canonical_family(family) + override = @base_url_overrides[canonical] || @base_url_overrides[family.to_sym] + override || HOSTS[canonical] || HOSTS.fetch(:main) + end + + # Resolves the API key for a +family+ under the two-key model. Data families + # prefer +data_api_key+ and fall back to +api_key+; all other families use + # +api_key+. + # + # @param family [Symbol, String] family or alias (snake_case accepted). + # @return [String] the resolved key. + # @raise [Nfe::ConfigurationError] when no key resolves for the family. + def api_key_for(family) + canonical = canonical_family(family) + key = if DATA_FAMILIES.include?(canonical) + @data_api_key || @api_key + else + @api_key + end + return key unless key.nil? || key.empty? + + raise Nfe::ConfigurationError, + "Nenhuma chave de API configurada para a família \"#{canonical}\". " \ + "Informe api_key (ou data_api_key para famílias de dados)." + end + + private + + # Applies the ENV fallback: an explicit, non-empty argument always wins; + # otherwise the environment variable (when present) is adopted. + def resolve_key(explicit, env_name) + return explicit unless explicit.nil? || explicit.to_s.empty? + + env_value = ENV.fetch(env_name, nil) + return env_value unless env_value.nil? || env_value.empty? + + explicit + end + + def validate! + unless VALID_ENVIRONMENTS.include?(@environment) + raise Nfe::ConfigurationError, + "environment inválido: #{@environment.inspect}. " \ + "Use :production ou :development." + end + + if blank?(@api_key) && blank?(@data_api_key) + raise Nfe::ConfigurationError, + "É necessário informar uma api_key (ou data_api_key). " \ + "Defina o argumento ou a variável de ambiente NFE_API_KEY/NFE_DATA_API_KEY." + end + + validate_positive!(:timeout, @timeout) + validate_positive!(:open_timeout, @open_timeout) + + return unless !@max_retries.is_a?(Integer) || @max_retries.negative? + + raise Nfe::ConfigurationError, + "max_retries deve ser um inteiro não negativo, recebido #{@max_retries.inspect}." + end + + def validate_positive!(name, value) + return if value.is_a?(Numeric) && value.positive? + + raise Nfe::ConfigurationError, + "#{name} deve ser um número positivo, recebido #{value.inspect}." + end + + def blank?(value) + value.nil? || value.to_s.empty? + end + + # Normalizes a family/alias into its canonical (hyphenated) family symbol. + def canonical_family(family) + normalized = family.to_s.tr("_", "-").to_sym + return normalized if HOSTS.key?(normalized) - def initialize - @url = "https://api.nfe.io" - @user_agent = "NFe.io Ruby Client v#{Nfe::VERSION}" + FAMILY_ALIASES.fetch(normalized, normalized) end end end diff --git a/lib/nfe/date_normalizer.rb b/lib/nfe/date_normalizer.rb new file mode 100644 index 0000000..b1ce974 --- /dev/null +++ b/lib/nfe/date_normalizer.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "date" +require "time" + +module Nfe + # Normalizes date inputs to the canonical +YYYY-MM-DD+ string the lookup APIs + # expect. Accepts either an already-formatted ISO date string or a Ruby + # date/time object, and raises {Nfe::InvalidRequestError} (Portuguese-language + # message) on any malformed, out-of-range, or unsupported input. + module DateNormalizer + ISO_DATE = /\A\d{4}-\d{2}-\d{2}\z/ + + module_function + + # @param input [String, Date, Time, DateTime] + # @return [String] the date formatted as +YYYY-MM-DD+. + # @raise [Nfe::InvalidRequestError] on bad format, out-of-range, or type. + def to_iso_date(input) + case input + when String then from_string(input) + when Date, Time, DateTime then input.strftime("%Y-%m-%d") + else + raise Nfe::InvalidRequestError, "data inválida: tipo não suportado (#{input.class})" + end + end + + # @api private + def from_string(value) + raise Nfe::InvalidRequestError, "data inválida: use o formato YYYY-MM-DD" unless ISO_DATE.match?(value) + + Date.iso8601(value).strftime("%Y-%m-%d") + rescue ArgumentError + raise Nfe::InvalidRequestError, "data inválida: #{value.inspect} está fora do intervalo válido" + end + end +end diff --git a/lib/nfe/error_factory.rb b/lib/nfe/error_factory.rb new file mode 100644 index 0000000..10c8ddd --- /dev/null +++ b/lib/nfe/error_factory.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +require "json" + +module Nfe + # Translates HTTP responses and network exceptions into the typed + # {Nfe::Error} hierarchy. + # + # The transport returns 4xx/5xx as {Nfe::Http::Response} objects (never + # raising); the resource layer feeds those to {.from_response} to obtain the + # right error class. Network failures the transport raised are normalized via + # {.from_network_error}. + # + # The extracted message echoes server-controlled input, so it is capped to a + # bounded length and stripped of control characters before reaching the + # error — an attacker-controlled body must not flood logs or inject terminal + # escape sequences. + module ErrorFactory + # Maximum length of a message extracted from a response body. + MAX_MESSAGE_LENGTH = 500 + + # Body keys searched (in order) for a human-readable message. + MESSAGE_KEYS = %w[message error detail details].freeze + + # Body keys searched (in order) for a machine-readable error code. + ERROR_CODE_KEYS = %w[code errorCode error_code].freeze + + # ASCII control characters (C0 range plus DEL) scrubbed from messages. + CONTROL_CHARS = /[\x00-\x1f\x7f]/ + + module_function + + # Build the appropriate {Nfe::Error} subclass for an HTTP response. + # + # @param response [Nfe::Http::Response] status:, #header(name), body: + # @return [Nfe::Error] + def from_response(response) + status = response.status + parsed = parse_body(response.body) + + message = extract_message(parsed) || "API request failed with HTTP #{status}" + error_code = extract_error_code(parsed) + request_id = response.header("x-request-id") || response.header("x-correlation-id") + + kwargs = { + status_code: status, + request_id: request_id, + error_code: error_code, + response_body: response.body, + response_headers: response.headers + } + + klass = error_class_for(status) + if klass == RateLimitError + RateLimitError.new(message, retry_after: extract_retry_after(response), **kwargs) + else + klass.new(message, **kwargs) + end + end + + # Normalize a network exception raised by the transport. + # + # @param exception [Exception] + # @return [Nfe::ApiConnectionError] + def from_network_error(exception) + klass = timeout?(exception) ? TimeoutError : ApiConnectionError + error = klass.new(exception.message) + # Preserve the original exception as cause for debugging. + begin + raise error, error.message, cause: exception + rescue klass => e + e + end + end + + # @api private + def error_class_for(status) + case status + when 401 then AuthenticationError + when 403 then AuthorizationError + when 404 then NotFoundError + when 409 then ConflictError + when 429 then RateLimitError + when 400..499 then InvalidRequestError + when 500..599 then ServerError + else + status >= 500 ? ServerError : InvalidRequestError + end + end + + # @api private + def parse_body(body) + return nil if body.nil? || body.empty? + + JSON.parse(body) + rescue JSON::ParserError + nil + end + + # @api private + def extract_message(parsed) + return nil unless parsed.is_a?(Hash) + + raw = message_from_keys(parsed) || message_from_errors(parsed["errors"]) + sanitize_message(raw) + end + + # @api private + def message_from_keys(parsed) + MESSAGE_KEYS.each do |key| + value = parsed[key] + return value if value.is_a?(String) && !value.empty? + end + nil + end + + # @api private + def message_from_errors(errors) + case errors + when String + errors + when Array + first = errors[0] + first.is_a?(Hash) ? first["message"] : first + end + end + + # @api private + def sanitize_message(raw) + return nil if raw.nil? + + # Scrub ASCII control characters (incl. ESC) so an attacker-controlled + # body cannot inject terminal escape sequences, then cap the length. + text = raw.to_s.gsub(CONTROL_CHARS, " ").strip + return nil if text.empty? + + text.length > MAX_MESSAGE_LENGTH ? "#{text[0, MAX_MESSAGE_LENGTH]}..." : text + end + + # @api private + def extract_error_code(parsed) + return nil unless parsed.is_a?(Hash) + + ERROR_CODE_KEYS.each do |key| + value = parsed[key] + return value.to_s if value.is_a?(String) || value.is_a?(Integer) + end + nil + end + + # @api private + def extract_retry_after(response) + value = response.header("retry-after") + return nil if value.nil? + + Integer(value, 10) + rescue ArgumentError, TypeError + nil + end + + # @api private + def timeout?(exception) + timeout_class_names = %w[Net::OpenTimeout Net::ReadTimeout Timeout::Error] + ancestor_names = exception.class.ancestors.map(&:to_s) + timeout_class_names.intersect?(ancestor_names) + end + end +end diff --git a/lib/nfe/errors.rb b/lib/nfe/errors.rb new file mode 100644 index 0000000..9df3857 --- /dev/null +++ b/lib/nfe/errors.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +module Nfe + # Base class for every error the SDK raises. + # + # All SDK errors derive from {Nfe::Error}, so consumer code can catch the + # whole family with a single +rescue Nfe::Error+. Errors derived from an HTTP + # response carry the response context (+status_code+, +request_id+, + # +error_code+, +response_body+, +response_headers+) for diagnostics. + # + # {#to_h} returns a logging-safe Hash that deliberately omits the raw + # response body and headers, which may carry secrets or PII. + class Error < StandardError + # @return [Integer, nil] HTTP status code, when derived from a response. + attr_reader :status_code + # @return [String, nil] server-supplied request/correlation id. + attr_reader :request_id + # @return [String, nil] machine-readable error code from the body. + attr_reader :error_code + # @return [String, nil] raw response body, for programmatic inspection. + attr_reader :response_body + # @return [Hash] response headers (lowercase keys). + attr_reader :response_headers + + # @param message [String, nil] human-readable message. + # @param status_code [Integer, nil] + # @param request_id [String, nil] + # @param error_code [String, nil] + # @param response_body [String, nil] + # @param response_headers [Hash] + def initialize(message = nil, status_code: nil, request_id: nil, + error_code: nil, response_body: nil, response_headers: {}) + super(message) + @status_code = status_code + @request_id = request_id + @error_code = error_code + @response_body = response_body + @response_headers = response_headers || {} + end + + # Logging-safe representation. Never includes raw headers or body, which + # could leak the API key, certificate password, or PII. + # + # @return [Hash] + def to_h + { + type: self.class.name, + message: message, + status_code: status_code, + request_id: request_id, + error_code: error_code + } + end + end + + # HTTP 401 — the API key is missing or invalid. + class AuthenticationError < Error; end + + # HTTP 403 — the API key is valid but not authorized for the resource. + class AuthorizationError < Error; end + + # HTTP 400/422 — the request was malformed or failed validation. + class InvalidRequestError < Error; end + + # HTTP 404 — the requested resource does not exist. + class NotFoundError < Error; end + + # HTTP 409 — the request conflicts with the current resource state. + class ConflictError < Error; end + + # HTTP 429 — too many requests. Carries the optional +retry_after+ hint. + class RateLimitError < Error + # @return [Integer, nil] seconds to wait before retrying, when advertised. + attr_reader :retry_after + + # @param retry_after [Integer, nil] from the +Retry-After+ header. + def initialize(message = nil, retry_after: nil, **) + super(message, **) + @retry_after = retry_after + end + end + + # HTTP 5xx — the API failed to process the request. + class ServerError < Error; end + + # A network-level failure (DNS, connection refused, TLS, reset). Raised + # instead of returning a response, since no HTTP exchange completed. + class ApiConnectionError < Error; end + + # A connection that timed out. A subclass of {ApiConnectionError} so a + # +rescue Nfe::ApiConnectionError+ also catches timeouts. + class TimeoutError < ApiConnectionError; end + + # Raised when a webhook signature fails verification. + class SignatureVerificationError < Error; end + + # Raised when the SDK is misconfigured: a required API key is missing for a + # family, or an invalid +environment+ was supplied. Raised client-side, + # before any HTTP request is issued. + class ConfigurationError < Error; end + + # Raised when an asynchronous (202) invoice response violates the expected + # protocol — e.g., a 202 without a +Location+ header, or an +invoice_id+ that + # cannot be extracted from it. + class InvoiceProcessingError < Error; end +end diff --git a/lib/nfe/errors/.gitkeep b/lib/nfe/errors/.gitkeep new file mode 100644 index 0000000..5667a72 --- /dev/null +++ b/lib/nfe/errors/.gitkeep @@ -0,0 +1 @@ +# Typed error hierarchy (Nfe::Error and subclasses) — added by add-http-transport. diff --git a/lib/nfe/errors/nfe_error.rb b/lib/nfe/errors/nfe_error.rb deleted file mode 100644 index 19f8622..0000000 --- a/lib/nfe/errors/nfe_error.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Nfe - class NfeError < StandardError - attr_reader :http_status, :json_message, :http_message, :message - - def initialize(http_status=nil, json_message=nil, http_message=nil, message=nil) - @http_status = http_status - @json_message = json_message - @http_message = http_message - @message = message - end - end -end \ No newline at end of file diff --git a/lib/nfe/flow_status.rb b/lib/nfe/flow_status.rb new file mode 100644 index 0000000..4d5706d --- /dev/null +++ b/lib/nfe/flow_status.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Nfe + # Lifecycle status of an asynchronously-processed fiscal document. + # + # Terminal states stop polling; non-terminal states mean processing is still + # in flight. The discriminated 202 Pending/Issued contract (modeled in the + # resource changes) uses {FlowStatus.terminal?} to decide when a document is + # settled. + module FlowStatus + # States in which processing has finished (success or failure). + TERMINAL = %w[Issued IssueFailed Cancelled CancelFailed].freeze + + # States in which processing is still in progress. + NON_TERMINAL = %w[ + PullFromCityHall + WaitingCalculateTaxes + WaitingDefineRpsNumber + WaitingSend + WaitingSendCancel + WaitingReturn + WaitingDownload + ].freeze + + # Every known flow status. + ALL = (TERMINAL + NON_TERMINAL).freeze + + module_function + + # Returns +true+ when +status+ is a terminal flow state. + def terminal?(status) + TERMINAL.include?(status.to_s) + end + end +end diff --git a/lib/nfe/generated.rb b/lib/nfe/generated.rb new file mode 100644 index 0000000..471e5ff --- /dev/null +++ b/lib/nfe/generated.rb @@ -0,0 +1,553 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit + +require_relative "generated/generated_marker" +require_relative "generated/calculo_impostos_v1/calculate_item_request" +require_relative "generated/calculo_impostos_v1/calculate_item_response" +require_relative "generated/calculo_impostos_v1/calculate_request" +require_relative "generated/calculo_impostos_v1/calculate_request_issuer" +require_relative "generated/calculo_impostos_v1/calculate_request_recipient" +require_relative "generated/calculo_impostos_v1/calculate_response" +require_relative "generated/calculo_impostos_v1/cofins" +require_relative "generated/calculo_impostos_v1/icms" +require_relative "generated/calculo_impostos_v1/icms_uf_dest" +require_relative "generated/calculo_impostos_v1/ii" +require_relative "generated/calculo_impostos_v1/ipi" +require_relative "generated/calculo_impostos_v1/operation_type" +require_relative "generated/calculo_impostos_v1/origin" +require_relative "generated/calculo_impostos_v1/pis" +require_relative "generated/calculo_impostos_v1/problem_details" +require_relative "generated/calculo_impostos_v1/state" +require_relative "generated/calculo_impostos_v1/tax_code" +require_relative "generated/calculo_impostos_v1/tax_code_paginated_response" +require_relative "generated/calculo_impostos_v1/tax_regime" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource" +require_relative "generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/buyer_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/cte_metadata_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/error_response" +require_relative "generated/consulta_dfe_distribuicao_v2/inbound_company_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/issuer_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/message_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/metadata_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/process_webhook_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/transportation_resource" +require_relative "generated/consulta_dfe_distribuicao_v2/xml_file_resource" +require_relative "generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request" +require_relative "generated/consulta_nfe_distribuicao_v1/automatic_manifesting" +require_relative "generated/consulta_nfe_distribuicao_v1/buyer" +require_relative "generated/consulta_nfe_distribuicao_v1/company" +require_relative "generated/consulta_nfe_distribuicao_v1/issuer" +require_relative "generated/consulta_nfe_distribuicao_v1/links" +require_relative "generated/consulta_nfe_distribuicao_v1/product_invoice" +require_relative "generated/consulta_nfe_distribuicao_v1/sucessonarequisio" +require_relative "generated/consulta_nfe_distribuicao_v1/sucessonarequisio2" +require_relative "generated/consulta_nfe_distribuicao_v1/sucessonarequisio6" +require_relative "generated/consulta_nfe_distribuicao_v1/transportation" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource" +require_relative "generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_expression" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_model" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_type" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable" +require_relative "generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation" +require_relative "generated/contribuintes_v2/microsoft_odata_odata_entity_set_info" +require_relative "generated/contribuintes_v2/microsoft_odata_odata_function_import_info" +require_relative "generated/contribuintes_v2/microsoft_odata_odata_service_document" +require_relative "generated/contribuintes_v2/microsoft_odata_odata_singleton_info" +require_relative "generated/contribuintes_v2/microsoft_odata_odata_type_annotation" +require_relative "generated/nf_consumidor_v2/activity_resource" +require_relative "generated/nf_consumidor_v2/addition_resource" +require_relative "generated/nf_consumidor_v2/additional_information_resource" +require_relative "generated/nf_consumidor_v2/address_resource" +require_relative "generated/nf_consumidor_v2/advance_payment_item_resource" +require_relative "generated/nf_consumidor_v2/authorization_resource" +require_relative "generated/nf_consumidor_v2/bill_resource" +require_relative "generated/nf_consumidor_v2/billing_resource" +require_relative "generated/nf_consumidor_v2/buyer_resource" +require_relative "generated/nf_consumidor_v2/card_resource" +require_relative "generated/nf_consumidor_v2/cbstax_resource" +require_relative "generated/nf_consumidor_v2/cbstotals_resource" +require_relative "generated/nf_consumidor_v2/cideresource" +require_relative "generated/nf_consumidor_v2/city_resource" +require_relative "generated/nf_consumidor_v2/cofins_tax_resource" +require_relative "generated/nf_consumidor_v2/competence_adjustment_resource" +require_relative "generated/nf_consumidor_v2/consumer_invoice_request" +require_relative "generated/nf_consumidor_v2/consumer_invoices_resource" +require_relative "generated/nf_consumidor_v2/consumer_presence_type" +require_relative "generated/nf_consumidor_v2/consumer_type" +require_relative "generated/nf_consumidor_v2/contingency_details" +require_relative "generated/nf_consumidor_v2/credit_reversal_resource" +require_relative "generated/nf_consumidor_v2/credit_reversal_totals_resource" +require_relative "generated/nf_consumidor_v2/credit_transfer_tax_resource" +require_relative "generated/nf_consumidor_v2/credit_type" +require_relative "generated/nf_consumidor_v2/debit_type" +require_relative "generated/nf_consumidor_v2/deferment_tax_resource" +require_relative "generated/nf_consumidor_v2/delivery_information_resource" +require_relative "generated/nf_consumidor_v2/destination" +require_relative "generated/nf_consumidor_v2/disablement_resource" +require_relative "generated/nf_consumidor_v2/document_electronic_invoice_resource" +require_relative "generated/nf_consumidor_v2/document_invoice_reference_resource" +require_relative "generated/nf_consumidor_v2/duduction_indicator" +require_relative "generated/nf_consumidor_v2/duplicate_resource" +require_relative "generated/nf_consumidor_v2/economic_activity_resource" +require_relative "generated/nf_consumidor_v2/economic_activity_type" +require_relative "generated/nf_consumidor_v2/environment_type" +require_relative "generated/nf_consumidor_v2/error_resource" +require_relative "generated/nf_consumidor_v2/errors_resource" +require_relative "generated/nf_consumidor_v2/exempt_reason" +require_relative "generated/nf_consumidor_v2/export_detail_resource" +require_relative "generated/nf_consumidor_v2/export_hint_resource" +require_relative "generated/nf_consumidor_v2/export_resource" +require_relative "generated/nf_consumidor_v2/file_resource" +require_relative "generated/nf_consumidor_v2/flag_card" +require_relative "generated/nf_consumidor_v2/fuel_origin_resource" +require_relative "generated/nf_consumidor_v2/fuel_resource" +require_relative "generated/nf_consumidor_v2/government_purchase_entity_type" +require_relative "generated/nf_consumidor_v2/government_purchase_operation_type" +require_relative "generated/nf_consumidor_v2/government_purchase_resource" +require_relative "generated/nf_consumidor_v2/government_purchase_tax_resource" +require_relative "generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification" +require_relative "generated/nf_consumidor_v2/ibscbstax_resource" +require_relative "generated/nf_consumidor_v2/ibscbstotals_resource" +require_relative "generated/nf_consumidor_v2/ibsmunicipal_tax_resource" +require_relative "generated/nf_consumidor_v2/ibsmunicipal_totals_resource" +require_relative "generated/nf_consumidor_v2/ibsstate_tax_resource" +require_relative "generated/nf_consumidor_v2/ibsstate_totals_resource" +require_relative "generated/nf_consumidor_v2/ibstotals_resource" +require_relative "generated/nf_consumidor_v2/icms_tax_resource" +require_relative "generated/nf_consumidor_v2/icmstotal_resource" +require_relative "generated/nf_consumidor_v2/icmsufdestination_tax_resource" +require_relative "generated/nf_consumidor_v2/iitax_resource" +require_relative "generated/nf_consumidor_v2/import_declaration_resource" +require_relative "generated/nf_consumidor_v2/integration_payment_type" +require_relative "generated/nf_consumidor_v2/intermediate_resource" +require_relative "generated/nf_consumidor_v2/intermediation_type" +require_relative "generated/nf_consumidor_v2/international_transport_type" +require_relative "generated/nf_consumidor_v2/invoice_events_resource" +require_relative "generated/nf_consumidor_v2/invoice_events_resource_base" +require_relative "generated/nf_consumidor_v2/invoice_item_resource" +require_relative "generated/nf_consumidor_v2/invoice_item_tax_resource" +require_relative "generated/nf_consumidor_v2/invoice_items_resource" +require_relative "generated/nf_consumidor_v2/invoice_resource" +require_relative "generated/nf_consumidor_v2/invoice_status" +require_relative "generated/nf_consumidor_v2/invoice_without_events_resource" +require_relative "generated/nf_consumidor_v2/ipitax_resource" +require_relative "generated/nf_consumidor_v2/issqntotal_resource" +require_relative "generated/nf_consumidor_v2/issuer_from_request_resource" +require_relative "generated/nf_consumidor_v2/issuer_resource" +require_relative "generated/nf_consumidor_v2/istax_resource" +require_relative "generated/nf_consumidor_v2/istotals_resource" +require_relative "generated/nf_consumidor_v2/legal_nature" +require_relative "generated/nf_consumidor_v2/monophase_cbstotals_resource" +require_relative "generated/nf_consumidor_v2/monophase_deferment_tax_resource" +require_relative "generated/nf_consumidor_v2/monophase_ibscbstax_resource" +require_relative "generated/nf_consumidor_v2/monophase_ibstotals_resource" +require_relative "generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource" +require_relative "generated/nf_consumidor_v2/monophase_standard_tax_resource" +require_relative "generated/nf_consumidor_v2/monophase_totals_resource" +require_relative "generated/nf_consumidor_v2/monophase_withholding_tax_resource" +require_relative "generated/nf_consumidor_v2/operation_type" +require_relative "generated/nf_consumidor_v2/operational_presumed_credit_resource" +require_relative "generated/nf_consumidor_v2/payment_detail_resource" +require_relative "generated/nf_consumidor_v2/payment_method" +require_relative "generated/nf_consumidor_v2/payment_resource" +require_relative "generated/nf_consumidor_v2/payment_type" +require_relative "generated/nf_consumidor_v2/person_type" +require_relative "generated/nf_consumidor_v2/pistax_resource" +require_relative "generated/nf_consumidor_v2/presumed_credit_classification_code" +require_relative "generated/nf_consumidor_v2/presumed_credit_details_resource" +require_relative "generated/nf_consumidor_v2/presumed_credit_resource" +require_relative "generated/nf_consumidor_v2/print_type" +require_relative "generated/nf_consumidor_v2/pump_resource" +require_relative "generated/nf_consumidor_v2/purpose_type" +require_relative "generated/nf_consumidor_v2/reboque_resource" +require_relative "generated/nf_consumidor_v2/receiver_state_tax_indicator" +require_relative "generated/nf_consumidor_v2/reduction_tax_resource" +require_relative "generated/nf_consumidor_v2/referenced_dfe_resource" +require_relative "generated/nf_consumidor_v2/referenced_process_resource" +require_relative "generated/nf_consumidor_v2/regular_taxation_resource" +require_relative "generated/nf_consumidor_v2/request_cancellation_resource" +require_relative "generated/nf_consumidor_v2/returned_tax_resource" +require_relative "generated/nf_consumidor_v2/shipping_modality" +require_relative "generated/nf_consumidor_v2/special_tax_regime" +require_relative "generated/nf_consumidor_v2/state_code" +require_relative "generated/nf_consumidor_v2/state_tax_processing_authorizer" +require_relative "generated/nf_consumidor_v2/tax_coupon_information_resource" +require_relative "generated/nf_consumidor_v2/tax_determination_resource" +require_relative "generated/nf_consumidor_v2/tax_documents_reference_resource" +require_relative "generated/nf_consumidor_v2/tax_regime" +require_relative "generated/nf_consumidor_v2/taxpayer_comments_resource" +require_relative "generated/nf_consumidor_v2/total_resource" +require_relative "generated/nf_consumidor_v2/totals_withholdings" +require_relative "generated/nf_consumidor_v2/transport_group_resource" +require_relative "generated/nf_consumidor_v2/transport_information_resource" +require_relative "generated/nf_consumidor_v2/transport_rate_resource" +require_relative "generated/nf_consumidor_v2/transport_vehicle_resource" +require_relative "generated/nf_consumidor_v2/vehicle_detail_resource" +require_relative "generated/nf_consumidor_v2/volume_resource" +require_relative "generated/nf_consumidor_v2/withdrawal_information_resource" +require_relative "generated/nf_consumidor_v2/zfm_presumed_credit_resource" +require_relative "generated/nf_produto_v2/activity_resource" +require_relative "generated/nf_produto_v2/addition_resource" +require_relative "generated/nf_produto_v2/additional_information_resource" +require_relative "generated/nf_produto_v2/address_resource" +require_relative "generated/nf_produto_v2/authorization_resource" +require_relative "generated/nf_produto_v2/bill_resource" +require_relative "generated/nf_produto_v2/billing_resource" +require_relative "generated/nf_produto_v2/buyer_resource" +require_relative "generated/nf_produto_v2/card_resource" +require_relative "generated/nf_produto_v2/cideresource" +require_relative "generated/nf_produto_v2/city_resource" +require_relative "generated/nf_produto_v2/cofins_tax_resource" +require_relative "generated/nf_produto_v2/consumer_presence_type" +require_relative "generated/nf_produto_v2/consumer_type" +require_relative "generated/nf_produto_v2/contingency_details" +require_relative "generated/nf_produto_v2/delivery_information_resource" +require_relative "generated/nf_produto_v2/destination" +require_relative "generated/nf_produto_v2/disablement_resource" +require_relative "generated/nf_produto_v2/document_electronic_invoice_resource" +require_relative "generated/nf_produto_v2/document_invoice_reference_resource" +require_relative "generated/nf_produto_v2/duduction_indicator" +require_relative "generated/nf_produto_v2/duplicate_resource" +require_relative "generated/nf_produto_v2/economic_activity_resource" +require_relative "generated/nf_produto_v2/economic_activity_type" +require_relative "generated/nf_produto_v2/environment_type" +require_relative "generated/nf_produto_v2/error_resource" +require_relative "generated/nf_produto_v2/errors_resource" +require_relative "generated/nf_produto_v2/exempt_reason" +require_relative "generated/nf_produto_v2/export_detail_resource" +require_relative "generated/nf_produto_v2/export_hint_resource" +require_relative "generated/nf_produto_v2/export_resource" +require_relative "generated/nf_produto_v2/file_resource" +require_relative "generated/nf_produto_v2/flag_card" +require_relative "generated/nf_produto_v2/fuel_origin_resource" +require_relative "generated/nf_produto_v2/fuel_resource" +require_relative "generated/nf_produto_v2/icms_tax_resource" +require_relative "generated/nf_produto_v2/icmstotal" +require_relative "generated/nf_produto_v2/icmstotal_resource" +require_relative "generated/nf_produto_v2/icmsufdestination_tax_resource" +require_relative "generated/nf_produto_v2/iitax_resource" +require_relative "generated/nf_produto_v2/import_declaration_resource" +require_relative "generated/nf_produto_v2/integration_payment_type" +require_relative "generated/nf_produto_v2/intermediate_resource" +require_relative "generated/nf_produto_v2/intermediation_type" +require_relative "generated/nf_produto_v2/international_transport_type" +require_relative "generated/nf_produto_v2/invoice_events_resource_base" +require_relative "generated/nf_produto_v2/invoice_item_resource" +require_relative "generated/nf_produto_v2/invoice_item_tax_resource" +require_relative "generated/nf_produto_v2/invoice_items_resource" +require_relative "generated/nf_produto_v2/invoice_resource" +require_relative "generated/nf_produto_v2/invoice_status" +require_relative "generated/nf_produto_v2/invoice_without_events_resource" +require_relative "generated/nf_produto_v2/ipitax_resource" +require_relative "generated/nf_produto_v2/issqntotal" +require_relative "generated/nf_produto_v2/issqntotal_resource" +require_relative "generated/nf_produto_v2/issuer_from_request_resource" +require_relative "generated/nf_produto_v2/issuer_resource" +require_relative "generated/nf_produto_v2/legal_nature" +require_relative "generated/nf_produto_v2/operation_type" +require_relative "generated/nf_produto_v2/payment_detail_resource" +require_relative "generated/nf_produto_v2/payment_method" +require_relative "generated/nf_produto_v2/payment_resource" +require_relative "generated/nf_produto_v2/payment_type" +require_relative "generated/nf_produto_v2/person_type" +require_relative "generated/nf_produto_v2/pistax_resource" +require_relative "generated/nf_produto_v2/print_type" +require_relative "generated/nf_produto_v2/product_invoice_events_resource" +require_relative "generated/nf_produto_v2/product_invoice_queue_issue_resource" +require_relative "generated/nf_produto_v2/product_invoices_resource" +require_relative "generated/nf_produto_v2/pump_resource" +require_relative "generated/nf_produto_v2/purpose_type" +require_relative "generated/nf_produto_v2/queue_event_resource" +require_relative "generated/nf_produto_v2/reboque_resource" +require_relative "generated/nf_produto_v2/receiver_state_tax_indicator" +require_relative "generated/nf_produto_v2/referenced_process_resource" +require_relative "generated/nf_produto_v2/request_cancellation_resource" +require_relative "generated/nf_produto_v2/shipping_modality" +require_relative "generated/nf_produto_v2/special_tax_regime" +require_relative "generated/nf_produto_v2/state_code" +require_relative "generated/nf_produto_v2/state_tax_processing_authorizer" +require_relative "generated/nf_produto_v2/tax_coupon_information_resource" +require_relative "generated/nf_produto_v2/tax_determination_resource" +require_relative "generated/nf_produto_v2/tax_documents_reference_resource" +require_relative "generated/nf_produto_v2/tax_regime" +require_relative "generated/nf_produto_v2/taxpayer_comments_resource" +require_relative "generated/nf_produto_v2/total" +require_relative "generated/nf_produto_v2/total_resource" +require_relative "generated/nf_produto_v2/transport_group_resource" +require_relative "generated/nf_produto_v2/transport_information_resource" +require_relative "generated/nf_produto_v2/transport_rate_resource" +require_relative "generated/nf_produto_v2/transport_vehicle_resource" +require_relative "generated/nf_produto_v2/vehicle_detail_resource" +require_relative "generated/nf_produto_v2/volume_resource" +require_relative "generated/nf_produto_v2/withdrawal_information_resource" +require_relative "generated/nfeio/batch_process_response" +require_relative "generated/nfeio/environment" +require_relative "generated/nfeio/file_parsing_options_request" +require_relative "generated/nfeio/guid_pagination_cursor" +require_relative "generated/nfeio/input_info_request" +require_relative "generated/nfeio/inputs_response" +require_relative "generated/nfeio/out_put_link_response" +require_relative "generated/nfeio/out_put_response" +require_relative "generated/nfeio/output_type" +require_relative "generated/nfeio/parsing_type" +require_relative "generated/nfeio/problem_details" +require_relative "generated/nfeio/processing_batch_detail_response" +require_relative "generated/nfeio/processing_batch_summary_response" +require_relative "generated/nfeio/processing_batch_summary_response_page" +require_relative "generated/nfeio/processing_batches_response" +require_relative "generated/nfeio/processing_metrics_response" +require_relative "generated/nfeio/resource_info" +require_relative "generated/nfeio/resource_info_request" +require_relative "generated/nfeio/sort_direction" +require_relative "generated/nfeio/sort_order" +require_relative "generated/nfeio/start_processing_job_request" +require_relative "generated/nfeio/status_process" +require_relative "generated/nfeio/zip_request" +require_relative "generated/product_invoice_rtc_v1/activity_resource" +require_relative "generated/product_invoice_rtc_v1/addition_resource" +require_relative "generated/product_invoice_rtc_v1/additional_information_resource" +require_relative "generated/product_invoice_rtc_v1/address_resource" +require_relative "generated/product_invoice_rtc_v1/advance_payment_item_resource" +require_relative "generated/product_invoice_rtc_v1/authorization_resource" +require_relative "generated/product_invoice_rtc_v1/bill_resource" +require_relative "generated/product_invoice_rtc_v1/billing_resource" +require_relative "generated/product_invoice_rtc_v1/buyer_resource" +require_relative "generated/product_invoice_rtc_v1/card_resource" +require_relative "generated/product_invoice_rtc_v1/cbstax_resource" +require_relative "generated/product_invoice_rtc_v1/cbstotals_resource" +require_relative "generated/product_invoice_rtc_v1/cideresource" +require_relative "generated/product_invoice_rtc_v1/city_resource" +require_relative "generated/product_invoice_rtc_v1/cofins_tax_resource" +require_relative "generated/product_invoice_rtc_v1/competence_adjustment_resource" +require_relative "generated/product_invoice_rtc_v1/consumer_presence_type" +require_relative "generated/product_invoice_rtc_v1/consumer_type" +require_relative "generated/product_invoice_rtc_v1/contingency_details" +require_relative "generated/product_invoice_rtc_v1/credit_reversal_resource" +require_relative "generated/product_invoice_rtc_v1/credit_reversal_totals_resource" +require_relative "generated/product_invoice_rtc_v1/credit_transfer_tax_resource" +require_relative "generated/product_invoice_rtc_v1/credit_type" +require_relative "generated/product_invoice_rtc_v1/debit_type" +require_relative "generated/product_invoice_rtc_v1/deferment_tax_resource" +require_relative "generated/product_invoice_rtc_v1/delivery_information_resource" +require_relative "generated/product_invoice_rtc_v1/destination" +require_relative "generated/product_invoice_rtc_v1/disablement_resource" +require_relative "generated/product_invoice_rtc_v1/document_electronic_invoice_resource" +require_relative "generated/product_invoice_rtc_v1/document_invoice_reference_resource" +require_relative "generated/product_invoice_rtc_v1/duduction_indicator" +require_relative "generated/product_invoice_rtc_v1/duplicate_resource" +require_relative "generated/product_invoice_rtc_v1/economic_activity_resource" +require_relative "generated/product_invoice_rtc_v1/economic_activity_type" +require_relative "generated/product_invoice_rtc_v1/environment_type" +require_relative "generated/product_invoice_rtc_v1/error_resource" +require_relative "generated/product_invoice_rtc_v1/errors_resource" +require_relative "generated/product_invoice_rtc_v1/exempt_reason" +require_relative "generated/product_invoice_rtc_v1/export_detail_resource" +require_relative "generated/product_invoice_rtc_v1/export_hint_resource" +require_relative "generated/product_invoice_rtc_v1/export_resource" +require_relative "generated/product_invoice_rtc_v1/file_resource" +require_relative "generated/product_invoice_rtc_v1/flag_card" +require_relative "generated/product_invoice_rtc_v1/fuel_origin_resource" +require_relative "generated/product_invoice_rtc_v1/fuel_resource" +require_relative "generated/product_invoice_rtc_v1/government_purchase_entity_type" +require_relative "generated/product_invoice_rtc_v1/government_purchase_operation_type" +require_relative "generated/product_invoice_rtc_v1/government_purchase_resource" +require_relative "generated/product_invoice_rtc_v1/government_purchase_tax_resource" +require_relative "generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification" +require_relative "generated/product_invoice_rtc_v1/ibscbstax_resource" +require_relative "generated/product_invoice_rtc_v1/ibscbstotals_resource" +require_relative "generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource" +require_relative "generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource" +require_relative "generated/product_invoice_rtc_v1/ibsstate_tax_resource" +require_relative "generated/product_invoice_rtc_v1/ibsstate_totals_resource" +require_relative "generated/product_invoice_rtc_v1/ibstotals_resource" +require_relative "generated/product_invoice_rtc_v1/icms_tax_resource" +require_relative "generated/product_invoice_rtc_v1/icmstotal" +require_relative "generated/product_invoice_rtc_v1/icmstotal_resource" +require_relative "generated/product_invoice_rtc_v1/icmsufdestination_tax_resource" +require_relative "generated/product_invoice_rtc_v1/iitax_resource" +require_relative "generated/product_invoice_rtc_v1/import_declaration_resource" +require_relative "generated/product_invoice_rtc_v1/integration_payment_type" +require_relative "generated/product_invoice_rtc_v1/intermediate_resource" +require_relative "generated/product_invoice_rtc_v1/intermediation_type" +require_relative "generated/product_invoice_rtc_v1/international_transport_type" +require_relative "generated/product_invoice_rtc_v1/invoice_events_resource" +require_relative "generated/product_invoice_rtc_v1/invoice_events_resource_base" +require_relative "generated/product_invoice_rtc_v1/invoice_item_resource" +require_relative "generated/product_invoice_rtc_v1/invoice_item_tax_resource" +require_relative "generated/product_invoice_rtc_v1/invoice_items_resource" +require_relative "generated/product_invoice_rtc_v1/invoice_resource" +require_relative "generated/product_invoice_rtc_v1/invoice_status" +require_relative "generated/product_invoice_rtc_v1/invoice_without_events_resource" +require_relative "generated/product_invoice_rtc_v1/ipitax_resource" +require_relative "generated/product_invoice_rtc_v1/issqntotal" +require_relative "generated/product_invoice_rtc_v1/issqntotal_resource" +require_relative "generated/product_invoice_rtc_v1/issuer_from_request_resource" +require_relative "generated/product_invoice_rtc_v1/issuer_resource" +require_relative "generated/product_invoice_rtc_v1/istax_resource" +require_relative "generated/product_invoice_rtc_v1/istotals_resource" +require_relative "generated/product_invoice_rtc_v1/legal_nature" +require_relative "generated/product_invoice_rtc_v1/monophase_cbstotals_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_deferment_tax_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_ibscbstax_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_ibstotals_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_standard_tax_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_totals_resource" +require_relative "generated/product_invoice_rtc_v1/monophase_withholding_tax_resource" +require_relative "generated/product_invoice_rtc_v1/operation_type" +require_relative "generated/product_invoice_rtc_v1/operational_presumed_credit_resource" +require_relative "generated/product_invoice_rtc_v1/payment_detail_resource" +require_relative "generated/product_invoice_rtc_v1/payment_method" +require_relative "generated/product_invoice_rtc_v1/payment_resource" +require_relative "generated/product_invoice_rtc_v1/payment_type" +require_relative "generated/product_invoice_rtc_v1/person_type" +require_relative "generated/product_invoice_rtc_v1/pistax_resource" +require_relative "generated/product_invoice_rtc_v1/presumed_credit_classification_code" +require_relative "generated/product_invoice_rtc_v1/presumed_credit_details_resource" +require_relative "generated/product_invoice_rtc_v1/presumed_credit_resource" +require_relative "generated/product_invoice_rtc_v1/print_type" +require_relative "generated/product_invoice_rtc_v1/product_invoice_request" +require_relative "generated/product_invoice_rtc_v1/product_invoices_resource" +require_relative "generated/product_invoice_rtc_v1/pump_resource" +require_relative "generated/product_invoice_rtc_v1/purchase_information_resource" +require_relative "generated/product_invoice_rtc_v1/purpose_type" +require_relative "generated/product_invoice_rtc_v1/queue_event_resource" +require_relative "generated/product_invoice_rtc_v1/reboque_resource" +require_relative "generated/product_invoice_rtc_v1/receiver_state_tax_indicator" +require_relative "generated/product_invoice_rtc_v1/reduction_tax_resource" +require_relative "generated/product_invoice_rtc_v1/referenced_dfe_resource" +require_relative "generated/product_invoice_rtc_v1/referenced_process_resource" +require_relative "generated/product_invoice_rtc_v1/regular_taxation_resource" +require_relative "generated/product_invoice_rtc_v1/request_cancellation_resource" +require_relative "generated/product_invoice_rtc_v1/returned_tax_resource" +require_relative "generated/product_invoice_rtc_v1/shipping_modality" +require_relative "generated/product_invoice_rtc_v1/special_tax_regime" +require_relative "generated/product_invoice_rtc_v1/state_code" +require_relative "generated/product_invoice_rtc_v1/state_tax_processing_authorizer" +require_relative "generated/product_invoice_rtc_v1/tax_coupon_information_resource" +require_relative "generated/product_invoice_rtc_v1/tax_determination_resource" +require_relative "generated/product_invoice_rtc_v1/tax_documents_reference_resource" +require_relative "generated/product_invoice_rtc_v1/tax_regime" +require_relative "generated/product_invoice_rtc_v1/taxpayer_comments_resource" +require_relative "generated/product_invoice_rtc_v1/total" +require_relative "generated/product_invoice_rtc_v1/total_resource" +require_relative "generated/product_invoice_rtc_v1/totals_withholdings" +require_relative "generated/product_invoice_rtc_v1/transport_group_resource" +require_relative "generated/product_invoice_rtc_v1/transport_information_resource" +require_relative "generated/product_invoice_rtc_v1/transport_rate_resource" +require_relative "generated/product_invoice_rtc_v1/transport_vehicle_resource" +require_relative "generated/product_invoice_rtc_v1/vehicle_detail_resource" +require_relative "generated/product_invoice_rtc_v1/volume_resource" +require_relative "generated/product_invoice_rtc_v1/withdrawal_information_resource" +require_relative "generated/product_invoice_rtc_v1/zfm_presumed_credit_resource" +require_relative "generated/product_register_pt_br_v1/cofins_tax_group" +require_relative "generated/product_register_pt_br_v1/custom_tax_scenario" +require_relative "generated/product_register_pt_br_v1/icms_tax_group" +require_relative "generated/product_register_pt_br_v1/inter_state_tax_group" +require_relative "generated/product_register_pt_br_v1/intra_state_tax_group" +require_relative "generated/product_register_pt_br_v1/issuer_tax_profile_enum" +require_relative "generated/product_register_pt_br_v1/pis_tax_group" +require_relative "generated/product_register_pt_br_v1/product" +require_relative "generated/product_register_pt_br_v1/product_input" +require_relative "generated/product_register_pt_br_v1/recipient_tax_profile_enum" +require_relative "generated/product_register_pt_br_v1/tax_regime_enum" +require_relative "generated/service_invoice_rtc_v1/activity_event" +require_relative "generated/service_invoice_rtc_v1/address_definition" +require_relative "generated/service_invoice_rtc_v1/approximate_tax" +require_relative "generated/service_invoice_rtc_v1/approximate_totals" +require_relative "generated/service_invoice_rtc_v1/benefit" +require_relative "generated/service_invoice_rtc_v1/construction" +require_relative "generated/service_invoice_rtc_v1/deduction" +require_relative "generated/service_invoice_rtc_v1/deduction_document" +require_relative "generated/service_invoice_rtc_v1/foreign_trade" +require_relative "generated/service_invoice_rtc_v1/ibs_cbs" +require_relative "generated/service_invoice_rtc_v1/lease" +require_relative "generated/service_invoice_rtc_v1/nfse_request" +require_relative "generated/service_invoice_rtc_v1/party_definition" +require_relative "generated/service_invoice_rtc_v1/real_estate" +require_relative "generated/service_invoice_rtc_v1/reference_substitution" +require_relative "generated/service_invoice_rtc_v1/service_amount_definitions" +require_relative "generated/service_invoice_rtc_v1/suspension" +require_relative "generated/service_invoice_rtc_v1/third_party_reimbursement_document" diff --git a/lib/nfe/generated/.gitkeep b/lib/nfe/generated/.gitkeep new file mode 100644 index 0000000..6198a52 --- /dev/null +++ b/lib/nfe/generated/.gitkeep @@ -0,0 +1,2 @@ +# Reserved for value objects generated from the OpenAPI specs (add-openapi-pipeline). +# AUTO-GENERATED at build time — NEVER edit files here by hand. diff --git a/lib/nfe/generated/README.md b/lib/nfe/generated/README.md new file mode 100644 index 0000000..89927d5 --- /dev/null +++ b/lib/nfe/generated/README.md @@ -0,0 +1,28 @@ +# Generated value objects — DO NOT EDIT + +Every `.rb` in this directory (and every `.rbs` under `sig/nfe/generated/`) is +**auto-generated** from the OpenAPI specs in `openapi/` by `scripts/generate.rb`. +Each file carries an `# AUTO-GENERATED — do not edit` banner with its source spec +and a SHA-256 of that spec. + +## Regenerating + +```sh +rake generate # rewrite lib/nfe/generated/** and sig/nfe/generated/** +rake generate:check # CI gate: fails if the tree drifts from the specs +rake openapi:sync # refresh openapi/*.yaml from nfeio-docs (NFEIO_DOCS_PATH) +``` + +Hand edits here will be **overwritten** on the next `rake generate` and will fail +`rake generate:check` in CI. To change a type, change the spec in `openapi/` +(synced from `nfeio-docs`, the source of truth) and regenerate. See +`CONTRIBUTING.md` for the full sync → review → generate → commit flow. + +## Layout + +- One `Nfe::Generated::` module per spec (e.g. `ServiceInvoiceRtcV1`). +- One immutable `Data.define` value object per `components.schemas` entry, each + with a `from_api(payload)` class method (camelCase → snake_case, drops unknown + keys, recurses into nested refs). +- `lib/nfe/generated.rb` is the `require_relative` loader; `generated_marker.rb` + records the per-spec hashes. diff --git a/lib/nfe/generated/calculo_impostos_v1/calculate_item_request.rb b/lib/nfe/generated/calculo_impostos_v1/calculate_item_request.rb new file mode 100644 index 0000000..e93459f --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/calculate_item_request.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + CalculateItemRequest = Data.define(:acquisition_purpose, :benefit, :cest, :discount_amount, :ex_tipi, :freight_amount, :gtin, :icms, :id, :ii, :insurance_amount, :issuer_tax_profile, :ncm, :operation_code, :origin, :others_amount, :quantity, :recipient_tax_profile, :sku, :unit_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquisition_purpose: payload["acquisitionPurpose"], + benefit: payload["benefit"], + cest: payload["cest"], + discount_amount: payload["discountAmount"], + ex_tipi: payload["exTipi"], + freight_amount: payload["freightAmount"], + gtin: payload["gtin"], + icms: Icms.from_api(payload["icms"]), + id: payload["id"], + ii: Ii.from_api(payload["ii"]), + insurance_amount: payload["insuranceAmount"], + issuer_tax_profile: payload["issuerTaxProfile"], + ncm: payload["ncm"], + operation_code: payload["operationCode"], + origin: payload["origin"], + others_amount: payload["othersAmount"], + quantity: payload["quantity"], + recipient_tax_profile: payload["recipientTaxProfile"], + sku: payload["sku"], + unit_amount: payload["unitAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/calculate_item_response.rb b/lib/nfe/generated/calculo_impostos_v1/calculate_item_response.rb new file mode 100644 index 0000000..cc43b7d --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/calculate_item_response.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + CalculateItemResponse = Data.define(:additional_information, :benefit, :cest, :cfop, :cofins, :icms, :icms_uf_dest, :id, :ii, :ipi, :last_modified, :pis, :product_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + benefit: payload["benefit"], + cest: payload["cest"], + cfop: payload["cfop"], + cofins: Cofins.from_api(payload["cofins"]), + icms: Icms.from_api(payload["icms"]), + icms_uf_dest: IcmsUfDest.from_api(payload["icmsUfDest"]), + id: payload["id"], + ii: Ii.from_api(payload["ii"]), + ipi: Ipi.from_api(payload["ipi"]), + last_modified: payload["lastModified"], + pis: Pis.from_api(payload["pis"]), + product_id: payload["productId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/calculate_request.rb b/lib/nfe/generated/calculo_impostos_v1/calculate_request.rb new file mode 100644 index 0000000..ef460e4 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/calculate_request.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + CalculateRequest = Data.define(:collection_id, :is_product_registration, :issuer, :items, :operation_type, :recipient) do + def self.from_api(payload) + return nil if payload.nil? + + new( + collection_id: payload["collectionId"], + is_product_registration: payload["isProductRegistration"], + issuer: CalculateRequestIssuer.from_api(payload["issuer"]), + items: (payload["items"] || []).map { |e| CalculateItemRequest.from_api(e) }, + operation_type: payload["operationType"], + recipient: CalculateRequestRecipient.from_api(payload["recipient"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/calculate_request_issuer.rb b/lib/nfe/generated/calculo_impostos_v1/calculate_request_issuer.rb new file mode 100644 index 0000000..1a725a0 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/calculate_request_issuer.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + CalculateRequestIssuer = Data.define(:state, :tax_profile, :tax_regime) do + def self.from_api(payload) + return nil if payload.nil? + + new( + state: payload["state"], + tax_profile: payload["taxProfile"], + tax_regime: payload["taxRegime"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/calculate_request_recipient.rb b/lib/nfe/generated/calculo_impostos_v1/calculate_request_recipient.rb new file mode 100644 index 0000000..afb4532 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/calculate_request_recipient.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + CalculateRequestRecipient = Data.define(:state, :tax_profile, :tax_regime) do + def self.from_api(payload) + return nil if payload.nil? + + new( + state: payload["state"], + tax_profile: payload["taxProfile"], + tax_regime: payload["taxRegime"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/calculate_response.rb b/lib/nfe/generated/calculo_impostos_v1/calculate_response.rb new file mode 100644 index 0000000..d099c7a --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/calculate_response.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + CalculateResponse = Data.define(:items) do + def self.from_api(payload) + return nil if payload.nil? + + new( + items: (payload["items"] || []).map { |e| CalculateItemResponse.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/cofins.rb b/lib/nfe/generated/calculo_impostos_v1/cofins.rb new file mode 100644 index 0000000..03bdc12 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/cofins.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + Cofins = Data.define(:cst, :p_cofins, :q_bcprod, :v_aliq_prod, :v_bc, :v_cofins) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cst: payload["cst"], + p_cofins: payload["pCOFINS"], + q_bcprod: payload["qBCProd"], + v_aliq_prod: payload["vAliqProd"], + v_bc: payload["vBC"], + v_cofins: payload["vCOFINS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/icms.rb b/lib/nfe/generated/calculo_impostos_v1/icms.rb new file mode 100644 index 0000000..5e0f757 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/icms.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + Icms = Data.define(:c_benef_rbc, :csosn, :cst, :ind_deduz_deson, :mod_bc, :mod_bcst, :mot_des_icms, :mot_des_icmsst, :orig, :p_cred_sn, :p_dif, :p_fcp, :p_fcpdif, :p_fcpst, :p_fcpstret, :p_icms, :p_icmsefet, :p_icmsst, :p_mvast, :p_red_bc, :p_red_bcefet, :p_red_bcst, :p_st, :v_bc, :v_bcefet, :v_bcfcp, :v_bcfcpst, :v_bcfcpstret, :v_bcst, :v_bcstret, :v_cred_icmssn, :v_fcp, :v_fcpdif, :v_fcpefet, :v_fcpst, :v_fcpstret, :v_icms, :v_icmsdeson, :v_icmsdif, :v_icmsefet, :v_icmsop, :v_icmsst, :v_icmsstdeson, :v_icmsstret, :v_icmssubstituto) do + def self.from_api(payload) + return nil if payload.nil? + + new( + c_benef_rbc: payload["cBenefRBC"], + csosn: payload["csosn"], + cst: payload["cst"], + ind_deduz_deson: payload["indDeduzDeson"], + mod_bc: payload["modBC"], + mod_bcst: payload["modBCST"], + mot_des_icms: payload["motDesICMS"], + mot_des_icmsst: payload["motDesICMSST"], + orig: payload["orig"], + p_cred_sn: payload["pCredSN"], + p_dif: payload["pDif"], + p_fcp: payload["pFCP"], + p_fcpdif: payload["pFCPDif"], + p_fcpst: payload["pFCPST"], + p_fcpstret: payload["pFCPSTRet"], + p_icms: payload["pICMS"], + p_icmsefet: payload["pICMSEfet"], + p_icmsst: payload["pICMSST"], + p_mvast: payload["pMVAST"], + p_red_bc: payload["pRedBC"], + p_red_bcefet: payload["pRedBCEfet"], + p_red_bcst: payload["pRedBCST"], + p_st: payload["pST"], + v_bc: payload["vBC"], + v_bcefet: payload["vBCEfet"], + v_bcfcp: payload["vBCFCP"], + v_bcfcpst: payload["vBCFCPST"], + v_bcfcpstret: payload["vBCFCPSTRet"], + v_bcst: payload["vBCST"], + v_bcstret: payload["vBCSTRet"], + v_cred_icmssn: payload["vCredICMSSN"], + v_fcp: payload["vFCP"], + v_fcpdif: payload["vFCPDif"], + v_fcpefet: payload["vFCPEfet"], + v_fcpst: payload["vFCPST"], + v_fcpstret: payload["vFCPSTRet"], + v_icms: payload["vICMS"], + v_icmsdeson: payload["vICMSDeson"], + v_icmsdif: payload["vICMSDif"], + v_icmsefet: payload["vICMSEfet"], + v_icmsop: payload["vICMSOp"], + v_icmsst: payload["vICMSST"], + v_icmsstdeson: payload["vICMSSTDeson"], + v_icmsstret: payload["vICMSSTRet"], + v_icmssubstituto: payload["vICMSSubstituto"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/icms_uf_dest.rb b/lib/nfe/generated/calculo_impostos_v1/icms_uf_dest.rb new file mode 100644 index 0000000..e72c7ed --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/icms_uf_dest.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + IcmsUfDest = Data.define(:p_fcpufdest, :p_icmsinter, :p_icmsinter_part, :p_icmsufdest, :v_bcfcpufdest, :v_bcufdest, :v_fcpufdest, :v_icmsufdest, :v_icmsufremet) do + def self.from_api(payload) + return nil if payload.nil? + + new( + p_fcpufdest: payload["pFCPUFDest"], + p_icmsinter: payload["pICMSInter"], + p_icmsinter_part: payload["pICMSInterPart"], + p_icmsufdest: payload["pICMSUFDest"], + v_bcfcpufdest: payload["vBCFCPUFDest"], + v_bcufdest: payload["vBCUFDest"], + v_fcpufdest: payload["vFCPUFDest"], + v_icmsufdest: payload["vICMSUFDest"], + v_icmsufremet: payload["vICMSUFRemet"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/ii.rb b/lib/nfe/generated/calculo_impostos_v1/ii.rb new file mode 100644 index 0000000..5678d83 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/ii.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + Ii = Data.define(:inf_custo_aquis, :p_cred_sn, :v_bc, :v_cred_icmssn, :v_desp_adu, :v_enc_camb, :v_ii, :v_iof) do + def self.from_api(payload) + return nil if payload.nil? + + new( + inf_custo_aquis: payload["infCustoAquis"], + p_cred_sn: payload["pCredSN"], + v_bc: payload["vBC"], + v_cred_icmssn: payload["vCredICMSSN"], + v_desp_adu: payload["vDespAdu"], + v_enc_camb: payload["vEncCamb"], + v_ii: payload["vII"], + v_iof: payload["vIOF"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/ipi.rb b/lib/nfe/generated/calculo_impostos_v1/ipi.rb new file mode 100644 index 0000000..dfe7096 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/ipi.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + Ipi = Data.define(:c_enq, :cst, :p_ipi, :q_unid, :v_bc, :v_ipi, :v_unid) do + def self.from_api(payload) + return nil if payload.nil? + + new( + c_enq: payload["cEnq"], + cst: payload["cst"], + p_ipi: payload["pIPI"], + q_unid: payload["qUnid"], + v_bc: payload["vBC"], + v_ipi: payload["vIPI"], + v_unid: payload["vUnid"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/operation_type.rb b/lib/nfe/generated/calculo_impostos_v1/operation_type.rb new file mode 100644 index 0000000..8311bcf --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/operation_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module OperationType + Outgoing = "Outgoing" + Incoming = "Incoming" + ALL = [Outgoing, Incoming].freeze + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/origin.rb b/lib/nfe/generated/calculo_impostos_v1/origin.rb new file mode 100644 index 0000000..6d09141 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/origin.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module Origin + National = "National" + ForeignDirectImport = "ForeignDirectImport" + ForeignInternalMarket = "ForeignInternalMarket" + NationalWith40To70Import = "NationalWith40To70Import" + NationalPpb = "NationalPpb" + NationalWithLess40Import = "NationalWithLess40Import" + ForeignDirectImportWithoutNationalSimilar = "ForeignDirectImportWithoutNationalSimilar" + ForeignInternalMarketWithoutNationalSimilar = "ForeignInternalMarketWithoutNationalSimilar" + NationalWithGreater70Import = "NationalWithGreater70Import" + ALL = [National, ForeignDirectImport, ForeignInternalMarket, NationalWith40To70Import, NationalPpb, NationalWithLess40Import, ForeignDirectImportWithoutNationalSimilar, ForeignInternalMarketWithoutNationalSimilar, NationalWithGreater70Import].freeze + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/pis.rb b/lib/nfe/generated/calculo_impostos_v1/pis.rb new file mode 100644 index 0000000..18da7a7 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/pis.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + Pis = Data.define(:cst, :p_pis, :q_bcprod, :v_aliq_prod, :v_bc, :v_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cst: payload["cst"], + p_pis: payload["pPIS"], + q_bcprod: payload["qBCProd"], + v_aliq_prod: payload["vAliqProd"], + v_bc: payload["vBC"], + v_pis: payload["vPIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/problem_details.rb b/lib/nfe/generated/calculo_impostos_v1/problem_details.rb new file mode 100644 index 0000000..13f72b7 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/problem_details.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + ProblemDetails = Data.define(:detail, :instance, :status, :title, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + detail: payload["detail"], + instance: payload["instance"], + status: payload["status"], + title: payload["title"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/state.rb b/lib/nfe/generated/calculo_impostos_v1/state.rb new file mode 100644 index 0000000..d51b937 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/state.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module State + AC = "AC" + AL = "AL" + AP = "AP" + AM = "AM" + BA = "BA" + CE = "CE" + DF = "DF" + ES = "ES" + GO = "GO" + MA = "MA" + MT = "MT" + MS = "MS" + MG = "MG" + PA = "PA" + PB = "PB" + PR = "PR" + PE = "PE" + PI = "PI" + RJ = "RJ" + RN = "RN" + RS = "RS" + RO = "RO" + RR = "RR" + SC = "SC" + SP = "SP" + SE = "SE" + TO = "TO" + EX = "EX" + ALL = [AC, AL, AP, AM, BA, CE, DF, ES, GO, MA, MT, MS, MG, PA, PB, PR, PE, PI, RJ, RN, RS, RO, RR, SC, SP, SE, TO, EX].freeze + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/tax_code.rb b/lib/nfe/generated/calculo_impostos_v1/tax_code.rb new file mode 100644 index 0000000..c6d28f4 --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/tax_code.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + TaxCode = Data.define(:code, :description) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + description: payload["description"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/tax_code_paginated_response.rb b/lib/nfe/generated/calculo_impostos_v1/tax_code_paginated_response.rb new file mode 100644 index 0000000..b496b5d --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/tax_code_paginated_response.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + TaxCodePaginatedResponse = Data.define(:current_page, :items, :total_count, :total_pages) do + def self.from_api(payload) + return nil if payload.nil? + + new( + current_page: payload["currentPage"], + items: (payload["items"] || []).map { |e| TaxCode.from_api(e) }, + total_count: payload["totalCount"], + total_pages: payload["totalPages"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/calculo_impostos_v1/tax_regime.rb b/lib/nfe/generated/calculo_impostos_v1/tax_regime.rb new file mode 100644 index 0000000..f80587b --- /dev/null +++ b/lib/nfe/generated/calculo_impostos_v1/tax_regime.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module TaxRegime + NationalSimple = "NationalSimple" + RealProfit = "RealProfit" + PresumedProfit = "PresumedProfit" + NationalSimpleSublimitExceeded = "NationalSimpleSublimitExceeded" + IndividualMicroEnterprise = "IndividualMicroEnterprise" + Exempt = "Exempt" + ALL = [NationalSimple, RealProfit, PresumedProfit, NationalSimpleSublimitExceeded, IndividualMicroEnterprise, Exempt].freeze + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status.rb new file mode 100644 index 0000000..ee31577 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + module DFe_NetCore_Domain_Enums_EntityStatus + Value0 = 0 + Value1 = 1 + Value_1 = -1 + ALL = [Value0, Value1, Value_1].freeze + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type.rb new file mode 100644 index 0000000..67e00a0 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + module DFe_NetCore_Domain_Enums_MetadataResourceType + Value0 = 0 + Value1 = 1 + Value2 = 2 + Value3 = 3 + Value4 = 4 + Value5 = 5 + ALL = [Value0, Value1, Value2, Value3, Value4, Value5].freeze + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource.rb new file mode 100644 index 0000000..0172423 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_CompanyResource = Data.define(:federal_tax_number, :id, :state, :state_tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + state: payload["state"], + state_tax_number: payload["stateTaxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource.rb new file mode 100644 index 0000000..4b3310c --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_EnableInboundProductInvoiceResource = Data.define(:automatic_manifesting, :start_from_date, :start_from_nsu) do + def self.from_api(payload) + return nil if payload.nil? + + new( + automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource.from_api(payload["automaticManifesting"]), + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource.rb new file mode 100644 index 0000000..0b1c852 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_EnableTransportationInvoiceInboundResource = Data.define(:start_from_date, :start_from_nsu) do + def self.from_api(payload) + return nil if payload.nil? + + new( + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource.rb new file mode 100644 index 0000000..d0fb02e --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource = Data.define(:minutes_to_wait_awareness_operation) do + def self.from_api(payload) + return nil if payload.nil? + + new( + minutes_to_wait_awareness_operation: payload["minutesToWaitAwarenessOperation"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource.rb new file mode 100644 index 0000000..1c01912 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_MetadataResource = Data.define(:access_key, :company, :created_on, :description, :federal_tax_number_sender, :id, :issued_on, :name_sender, :nsu, :parent_access_key, :product_invoices, :total_invoice_amount, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + company: DFe_NetCore_Domain_Resources_CompanyResource.from_api(payload["company"]), + created_on: payload["createdOn"], + description: payload["description"], + federal_tax_number_sender: payload["federalTaxNumberSender"], + id: payload["id"], + issued_on: payload["issuedOn"], + name_sender: payload["nameSender"], + nsu: payload["nsu"], + parent_access_key: payload["parentAccessKey"], + product_invoices: (payload["productInvoices"] || []).map { |e| DFe_NetCore_Domain_Resources_ProductInvoiceResource.from_api(e) }, + total_invoice_amount: payload["totalInvoiceAmount"], + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource.rb new file mode 100644 index 0000000..20e3b65 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_ProductInvoiceInboundResource = Data.define(:automatic_manifesting, :company_id, :created_on, :modified_on, :start_from_date, :start_from_nsu, :status) do + def self.from_api(payload) + return nil if payload.nil? + + new( + automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource.from_api(payload["automaticManifesting"]), + company_id: payload["companyId"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"], + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + status: payload["status"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource.rb new file mode 100644 index 0000000..d2f1a01 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_ProductInvoiceResource = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource.rb b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource.rb new file mode 100644 index 0000000..7f5ee24 --- /dev/null +++ b/lib/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + DFe_NetCore_Domain_Resources_TransportationInvoiceInboundResource = Data.define(:company_id, :created_on, :modified_on, :start_from_date, :start_from_nsu, :status) do + def self.from_api(payload) + return nil if payload.nil? + + new( + company_id: payload["companyId"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"], + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + status: payload["status"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/buyer_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/buyer_resource.rb new file mode 100644 index 0000000..4014824 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/buyer_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + BuyerResource = Data.define(:federal_tax_number, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource.rb new file mode 100644 index 0000000..1107ada --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + CTeEventMetadataResource = Data.define(:receipt_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + receipt_on: payload["receiptOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/cte_metadata_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/cte_metadata_resource.rb new file mode 100644 index 0000000..317c23d --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/cte_metadata_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + CTeMetadataResource = Data.define(:issued_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + issued_on: payload["issuedOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource.rb new file mode 100644 index 0000000..d494a45 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + EnableInboundProductInvoiceResource = Data.define(:automatic_manifesting, :environment_sefaz, :start_from_date, :start_from_nsu) do + def self.from_api(payload) + return nil if payload.nil? + + new( + automatic_manifesting: payload["automaticManifesting"], + environment_sefaz: payload["environmentSEFAZ"], + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource.rb new file mode 100644 index 0000000..0c59fe5 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + EnableTransportationInvoiceInboundResource = Data.define(:environment_sefaz, :start_from_date, :start_from_nsu) do + def self.from_api(payload) + return nil if payload.nil? + + new( + environment_sefaz: payload["environmentSEFAZ"], + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/error_response.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/error_response.rb new file mode 100644 index 0000000..91486d9 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/error_response.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + ErrorResponse = Data.define(:errors) do + def self.from_api(payload) + return nil if payload.nil? + + new( + errors: payload["errors"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/inbound_company_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/inbound_company_resource.rb new file mode 100644 index 0000000..cc4f5d8 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/inbound_company_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + InboundCompanyResource = Data.define(:federal_tax_number, :id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/issuer_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/issuer_resource.rb new file mode 100644 index 0000000..73b5112 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/issuer_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + IssuerResource = Data.define(:federal_tax_number, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/message_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/message_resource.rb new file mode 100644 index 0000000..e285d04 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/message_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + MessageResource = Data.define(:message) do + def self.from_api(payload) + return nil if payload.nil? + + new( + message: payload["message"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/metadata_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/metadata_resource.rb new file mode 100644 index 0000000..f0783b0 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/metadata_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + MetadataResource = Data.define(:access_key, :company, :created_on, :description, :id, :nsu, :parent_access_key, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + company: InboundCompanyResource.from_api(payload["company"]), + created_on: payload["createdOn"], + description: payload["description"], + id: payload["id"], + nsu: payload["nsu"], + parent_access_key: payload["parentAccessKey"], + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource.rb new file mode 100644 index 0000000..40309c9 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + NFeEventMetadataODataResource = Data.define(:access_key, :company, :created_on, :description, :id, :nsu, :receipt_on, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + company: InboundCompanyResource.from_api(payload["company"]), + created_on: payload["createdOn"], + description: payload["description"], + id: payload["id"], + nsu: payload["nsu"], + receipt_on: payload["receiptOn"], + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource.rb new file mode 100644 index 0000000..02650c4 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + NFeMetadataODataResource = Data.define(:access_key, :company, :created_on, :federal_tax_number_sender, :issued_on, :name_sender, :nfe_number, :nfe_serial_number, :nsu, :operation_type, :total_invoice_amount, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + company: InboundCompanyResource.from_api(payload["company"]), + created_on: payload["createdOn"], + federal_tax_number_sender: payload["federalTaxNumberSender"], + issued_on: payload["issuedOn"], + name_sender: payload["nameSender"], + nfe_number: payload["nfeNumber"], + nfe_serial_number: payload["nfeSerialNumber"], + nsu: payload["nsu"], + operation_type: payload["operationType"], + total_invoice_amount: payload["totalInvoiceAmount"], + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource.rb new file mode 100644 index 0000000..988b5e4 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + NFeMetadataResource = Data.define(:access_key, :buyer, :company, :created_on, :description, :federal_tax_number_sender, :issued_on, :issuer, :name_sender, :nfe_number, :nfe_serial_number, :nsu, :nsu_parent, :operation_type, :parent_access_key, :total_invoice_amount, :transportation, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + buyer: BuyerResource.from_api(payload["buyer"]), + company: InboundCompanyResource.from_api(payload["company"]), + created_on: payload["createdOn"], + description: payload["description"], + federal_tax_number_sender: payload["federalTaxNumberSender"], + issued_on: payload["issuedOn"], + issuer: IssuerResource.from_api(payload["issuer"]), + name_sender: payload["nameSender"], + nfe_number: payload["nfeNumber"], + nfe_serial_number: payload["nfeSerialNumber"], + nsu: payload["nsu"], + nsu_parent: payload["nsuParent"], + operation_type: payload["operationType"], + parent_access_key: payload["parentAccessKey"], + total_invoice_amount: payload["totalInvoiceAmount"], + transportation: TransportationResource.from_api(payload["transportation"]), + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/process_webhook_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/process_webhook_resource.rb new file mode 100644 index 0000000..b2e6c1b --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/process_webhook_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + ProcessWebhookResource = Data.define(:date, :key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + date: payload["date"], + key: payload["key"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource.rb new file mode 100644 index 0000000..3e2fcbd --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + ProductInvoiceInboundResource = Data.define(:environment_sefaz, :start_from_date, :status) do + def self.from_api(payload) + return nil if payload.nil? + + new( + environment_sefaz: payload["environmentSEFAZ"], + start_from_date: payload["startFromDate"], + status: payload["status"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource.rb new file mode 100644 index 0000000..00b057c --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + TransportationInvoiceInboundResource = Data.define(:environment_sefaz, :start_from_date, :status) do + def self.from_api(payload) + return nil if payload.nil? + + new( + environment_sefaz: payload["environmentSEFAZ"], + start_from_date: payload["startFromDate"], + status: payload["status"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/transportation_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/transportation_resource.rb new file mode 100644 index 0000000..04c09b2 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/transportation_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + TransportationResource = Data.define(:federal_tax_number, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_dfe_distribuicao_v2/xml_file_resource.rb b/lib/nfe/generated/consulta_dfe_distribuicao_v2/xml_file_resource.rb new file mode 100644 index 0000000..4a6fe67 --- /dev/null +++ b/lib/nfe/generated/consulta_dfe_distribuicao_v2/xml_file_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + XmlFileResource = Data.define(:url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + url: payload["url"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request.rb new file mode 100644 index 0000000..8b4d8c4 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + AtivarbuscaautomticadedocumentoseEventosrelacionadosaNotaFiscalEletrnicaNF_eRequest = Data.define(:automatic_manifesting, :environment_sefaz, :start_from_date, :start_from_nsu, :webhook_version) do + def self.from_api(payload) + return nil if payload.nil? + + new( + automatic_manifesting: AutomaticManifesting.from_api(payload["automaticManifesting"]), + environment_sefaz: payload["environmentSEFAZ"], + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + webhook_version: payload["webhookVersion"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/automatic_manifesting.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/automatic_manifesting.rb new file mode 100644 index 0000000..d640088 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/automatic_manifesting.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + AutomaticManifesting = Data.define(:minutes_to_wait_awareness_operation) do + def self.from_api(payload) + return nil if payload.nil? + + new( + minutes_to_wait_awareness_operation: payload["minutesToWaitAwarenessOperation"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/buyer.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/buyer.rb new file mode 100644 index 0000000..5aa46f2 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/buyer.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Buyer = Data.define(:federal_tax_number, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/company.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/company.rb new file mode 100644 index 0000000..223444f --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/company.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Company = Data.define(:federal_tax_number, :id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/issuer.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/issuer.rb new file mode 100644 index 0000000..1f82e51 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/issuer.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Issuer = Data.define(:federal_tax_number, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/links.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/links.rb new file mode 100644 index 0000000..3a8c286 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/links.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Links = Data.define(:pdf, :xml) do + def self.from_api(payload) + return nil if payload.nil? + + new( + pdf: payload["pdf"], + xml: payload["xml"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/product_invoice.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/product_invoice.rb new file mode 100644 index 0000000..4c07e8a --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/product_invoice.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + ProductInvoice = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio.rb new file mode 100644 index 0000000..f9e75f1 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Sucessonarequisio = Data.define(:access_key, :buyer, :company, :created_on, :description, :federal_tax_number_sender, :id, :issued_on, :issuer, :links, :name_sender, :nfe_number, :nfe_serial_number, :nsu, :nsu_parent, :operation_type, :parent_access_key, :total_invoice_amount, :transportation, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + buyer: Buyer.from_api(payload["buyer"]), + company: Company.from_api(payload["company"]), + created_on: payload["createdOn"], + description: payload["description"], + federal_tax_number_sender: payload["federalTaxNumberSender"], + id: payload["id"], + issued_on: payload["issuedOn"], + issuer: Issuer.from_api(payload["issuer"]), + links: Links.from_api(payload["links"]), + name_sender: payload["nameSender"], + nfe_number: payload["nfeNumber"], + nfe_serial_number: payload["nfeSerialNumber"], + nsu: payload["nsu"], + nsu_parent: payload["nsuParent"], + operation_type: payload["operationType"], + parent_access_key: payload["parentAccessKey"], + total_invoice_amount: payload["totalInvoiceAmount"], + transportation: Transportation.from_api(payload["transportation"]), + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio2.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio2.rb new file mode 100644 index 0000000..a6faaeb --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio2.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Sucessonarequisio2 = Data.define(:automatic_manifesting, :company_id, :created_on, :environment_sefaz, :modified_on, :start_from_date, :start_from_nsu, :status, :webhook_version) do + def self.from_api(payload) + return nil if payload.nil? + + new( + automatic_manifesting: AutomaticManifesting.from_api(payload["automaticManifesting"]), + company_id: payload["companyId"], + created_on: payload["createdOn"], + environment_sefaz: payload["environmentSEFAZ"], + modified_on: payload["modifiedOn"], + start_from_date: payload["startFromDate"], + start_from_nsu: payload["startFromNsu"], + status: payload["status"], + webhook_version: payload["webhookVersion"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio6.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio6.rb new file mode 100644 index 0000000..cc02266 --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio6.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Sucessonarequisio6 = Data.define(:access_key, :buyer, :company, :created_on, :description, :federal_tax_number_sender, :id, :issued_on, :issuer, :links, :name_sender, :nfe_number, :nsu, :parent_access_key, :product_invoices, :total_invoice_amount, :transportation, :type, :xml_url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + buyer: Buyer.from_api(payload["buyer"]), + company: Company.from_api(payload["company"]), + created_on: payload["createdOn"], + description: payload["description"], + federal_tax_number_sender: payload["federalTaxNumberSender"], + id: payload["id"], + issued_on: payload["issuedOn"], + issuer: Issuer.from_api(payload["issuer"]), + links: Links.from_api(payload["links"]), + name_sender: payload["nameSender"], + nfe_number: payload["nfeNumber"], + nsu: payload["nsu"], + parent_access_key: payload["parentAccessKey"], + product_invoices: (payload["productInvoices"] || []).map { |e| ProductInvoice.from_api(e) }, + total_invoice_amount: payload["totalInvoiceAmount"], + transportation: Transportation.from_api(payload["transportation"]), + type: payload["type"], + xml_url: payload["xmlUrl"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/consulta_nfe_distribuicao_v1/transportation.rb b/lib/nfe/generated/consulta_nfe_distribuicao_v1/transportation.rb new file mode 100644 index 0000000..5f406ed --- /dev/null +++ b/lib/nfe/generated/consulta_nfe_distribuicao_v1/transportation.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + Transportation = Data.define(:federal_tax_number, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address.rb new file mode 100644 index 0000000..089f3a1 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Domain_Entities_Address = Data.define(:additional_information, :city, :country, :district, :number, :postal_code, :state, :street, :street_prefix) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + city: DFeTech_TaxPayers_Domain_Entities_CityBase.from_api(payload["city"]), + country: payload["country"], + district: payload["district"], + number: payload["number"], + postal_code: payload["postalCode"], + state: payload["state"], + street: payload["street"], + street_prefix: payload["streetPrefix"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment.rb new file mode 100644 index 0000000..35302c6 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_ApiEnvironment + Development = "Development" + Production = "Production" + Staging = "Staging" + ALL = [Development, Production, Staging].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status.rb new file mode 100644 index 0000000..5f399bc --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_CertificateStatus + None = "None" + Active = "Active" + Inactive = "Inactive" + Overdue = "Overdue" + Pending = "Pending" + ALL = [None, Active, Inactive, Overdue, Pending].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base.rb new file mode 100644 index 0000000..df73f59 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Domain_Entities_CityBase = Data.define(:code, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended.rb new file mode 100644 index 0000000..0f586f0 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Domain_Entities_CityExtended = Data.define(:code, :country, :name, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + country: payload["country"], + name: payload["name"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status.rb new file mode 100644 index 0000000..5363c2e --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_CompanyFiscalStatus + None = "None" + Active = "Active" + CityNotSupported = "CityNotSupported" + Pending = "Pending" + Inactive = "Inactive" + ALL = [None, Active, CityNotSupported, Pending, Inactive].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type.rb new file mode 100644 index 0000000..3b68ae7 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_EnvironmentType + None = "None" + Production = "Production" + Test = "Test" + ALL = [None, Production, Test].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by.rb new file mode 100644 index 0000000..28592a8 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_FederalTaxDeterminationBy + NotInformed = "NotInformed" + Default = "Default" + SimplesNacional = "SimplesNacional" + ALL = [NotInformed, Default, SimplesNacional].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature.rb new file mode 100644 index 0000000..af3623c --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_LegalNature + None = "None" + EmpresaPublica = "EmpresaPublica" + SociedadeEconomiaMista = "SociedadeEconomiaMista" + SociedadeAnonimaAberta = "SociedadeAnonimaAberta" + SociedadeAnonimaFechada = "SociedadeAnonimaFechada" + SociedadeEmpresariaLimitada = "SociedadeEmpresariaLimitada" + SociedadeEmpresariaEmNomeColetivo = "SociedadeEmpresariaEmNomeColetivo" + SociedadeEmpresariaEmComanditaSimples = "SociedadeEmpresariaEmComanditaSimples" + SociedadeEmpresariaEmComanditaporAcoes = "SociedadeEmpresariaEmComanditaporAcoes" + SociedadeemContaParticipacao = "SociedadeemContaParticipacao" + Empresario = "Empresario" + Cooperativa = "Cooperativa" + ConsorcioSociedades = "ConsorcioSociedades" + GrupoSociedades = "GrupoSociedades" + SociedadeEstrangeiraNoBrasil = "SociedadeEstrangeiraNoBrasil" + EmpresaBinacionalArgentinoBrasileira = "EmpresaBinacionalArgentinoBrasileira" + EmpresaDomiciliadaExterior = "EmpresaDomiciliadaExterior" + ClubeFundoInvestimento = "ClubeFundoInvestimento" + SociedadeSimplesPura = "SociedadeSimplesPura" + SociedadeSimplesLimitada = "SociedadeSimplesLimitada" + SociedadeSimplesEmNomeColetivo = "SociedadeSimplesEmNomeColetivo" + SociedadeSimplesEmComanditaSimples = "SociedadeSimplesEmComanditaSimples" + EmpresaBinacional = "EmpresaBinacional" + ConsorcioEmpregadores = "ConsorcioEmpregadores" + ConsorcioSimples = "ConsorcioSimples" + EireliNaturezaEmpresaria = "EireliNaturezaEmpresaria" + EireliNaturezaSimples = "EireliNaturezaSimples" + SociedadeUnipessoaldeAdvogados = "SociedadeUnipessoaldeAdvogados" + CooperativaDeConsumo = "CooperativaDeConsumo" + EmpresaSimplesDeInovacao = "EmpresaSimplesDeInovacao" + InvestidorNaoResidente = "InvestidorNaoResidente" + ServicoNotarial = "ServicoNotarial" + FundacaoPrivada = "FundacaoPrivada" + ServicoSocialAutonomo = "ServicoSocialAutonomo" + CondominioEdilicio = "CondominioEdilicio" + ComissaoConciliacaoPrevia = "ComissaoConciliacaoPrevia" + EntidadeMediacaoArbitragem = "EntidadeMediacaoArbitragem" + PartidoPolitico = "PartidoPolitico" + EntidadeSindical = "EntidadeSindical" + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras = "EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras" + FundacaoAssociacaoDomiciliadaExterior = "FundacaoAssociacaoDomiciliadaExterior" + OrganizacaoReligiosa = "OrganizacaoReligiosa" + ComunidadeIndigena = "ComunidadeIndigena" + FundoPrivado = "FundoPrivado" + OrgaoDirecaoNacionalPartidoPolitico = "OrgaoDirecaoNacionalPartidoPolitico" + OrgaoDirecaoRegionalPartidoPolitico = "OrgaoDirecaoRegionalPartidoPolitico" + OrgaoDirecaoLocalPartidoPolitico = "OrgaoDirecaoLocalPartidoPolitico" + ComiteFinanceiroDePartidoPolitico = "ComiteFinanceiroDePartidoPolitico" + FrentePlebiscitariaOuReferendaria = "FrentePlebiscitariaOuReferendaria" + OrganizacaoSocial = "OrganizacaoSocial" + DemaisCondominios = "DemaisCondominios" + PlanoBeneficiosPrevidenciaComplementarFechada = "PlanoBeneficiosPrevidenciaComplementarFechada" + AssociacaoPrivada = "AssociacaoPrivada" + EmpresaIndividualImobiliaria = "EmpresaIndividualImobiliaria" + SeguradoEspecial = "SeguradoEspecial" + ContribuinteIndividual = "ContribuinteIndividual" + CandidatoCargoPoliticoEletivo = "CandidatoCargoPoliticoEletivo" + Leiloeiro = "Leiloeiro" + ProdutorRural = "ProdutorRural" + OrganizacaoInternacional = "OrganizacaoInternacional" + RepresentacaoDiplomaticaEstrangeira = "RepresentacaoDiplomaticaEstrangeira" + OutrasInstituicoesExtraterritoriais = "OutrasInstituicoesExtraterritoriais" + ALL = [None, EmpresaPublica, SociedadeEconomiaMista, SociedadeAnonimaAberta, SociedadeAnonimaFechada, SociedadeEmpresariaLimitada, SociedadeEmpresariaEmNomeColetivo, SociedadeEmpresariaEmComanditaSimples, SociedadeEmpresariaEmComanditaporAcoes, SociedadeemContaParticipacao, Empresario, Cooperativa, ConsorcioSociedades, GrupoSociedades, SociedadeEstrangeiraNoBrasil, EmpresaBinacionalArgentinoBrasileira, EmpresaDomiciliadaExterior, ClubeFundoInvestimento, SociedadeSimplesPura, SociedadeSimplesLimitada, SociedadeSimplesEmNomeColetivo, SociedadeSimplesEmComanditaSimples, EmpresaBinacional, ConsorcioEmpregadores, ConsorcioSimples, EireliNaturezaEmpresaria, EireliNaturezaSimples, SociedadeUnipessoaldeAdvogados, CooperativaDeConsumo, EmpresaSimplesDeInovacao, InvestidorNaoResidente, ServicoNotarial, FundacaoPrivada, ServicoSocialAutonomo, CondominioEdilicio, ComissaoConciliacaoPrevia, EntidadeMediacaoArbitragem, PartidoPolitico, EntidadeSindical, EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras, FundacaoAssociacaoDomiciliadaExterior, OrganizacaoReligiosa, ComunidadeIndigena, FundoPrivado, OrgaoDirecaoNacionalPartidoPolitico, OrgaoDirecaoRegionalPartidoPolitico, OrgaoDirecaoLocalPartidoPolitico, ComiteFinanceiroDePartidoPolitico, FrentePlebiscitariaOuReferendaria, OrganizacaoSocial, DemaisCondominios, PlanoBeneficiosPrevidenciaComplementarFechada, AssociacaoPrivada, EmpresaIndividualImobiliaria, SeguradoEspecial, ContribuinteIndividual, CandidatoCargoPoliticoEletivo, Leiloeiro, ProdutorRural, OrganizacaoInternacional, RepresentacaoDiplomaticaEstrangeira, OutrasInstituicoesExtraterritoriais].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by.rb new file mode 100644 index 0000000..d594111 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_MunicipalTaxDeterminationBy + NotInformed = "NotInformed" + Default = "Default" + SimplesNacional = "SimplesNacional" + ALL = [NotInformed, Default, SimplesNacional].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status.rb new file mode 100644 index 0000000..ace4667 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_MunicipalTaxFiscalStatus + None = "None" + Active = "Active" + CityNotSupported = "CityNotSupported" + Pending = "Pending" + Inactive = "Inactive" + ALL = [None, Active, CityNotSupported, Pending, Inactive].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential.rb new file mode 100644 index 0000000..b8e2f2b --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Domain_Entities_SecurityCredential = Data.define(:code, :id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + id: payload["id"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime.rb new file mode 100644 index 0000000..6990cad --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_SpecialTaxRegime + Nenhum = "Nenhum" + MicroempresaMunicipal = "MicroempresaMunicipal" + Estimativa = "Estimativa" + SociedadeDeProfissionais = "SociedadeDeProfissionais" + Cooperativa = "Cooperativa" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + MicroempresarioEmpresaPequenoPorte = "MicroempresarioEmpresaPequenoPorte" + Automatico = "Automatico" + ALL = [Nenhum, MicroempresaMunicipal, Estimativa, SociedadeDeProfissionais, Cooperativa, MicroempreendedorIndividual, MicroempresarioEmpresaPequenoPorte, Automatico].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code.rb new file mode 100644 index 0000000..0fa71eb --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_StateCode + NA = "NA" + RO = "RO" + AC = "AC" + AM = "AM" + RR = "RR" + PA = "PA" + AP = "AP" + TO = "TO" + MA = "MA" + PI = "PI" + CE = "CE" + RN = "RN" + PB = "PB" + PE = "PE" + AL = "AL" + SE = "SE" + BA = "BA" + MG = "MG" + ES = "ES" + RJ = "RJ" + SP = "SP" + PR = "PR" + SC = "SC" + RS = "RS" + MS = "MS" + MT = "MT" + GO = "GO" + DF = "DF" + EX = "EX" + ALL = [NA, RO, AC, AM, RR, PA, AP, TO, MA, PI, CE, RN, PB, PE, AL, SE, BA, MG, ES, RJ, SP, PR, SC, RS, MS, MT, GO, DF, EX].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer.rb new file mode 100644 index 0000000..cbd2f18 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_StateTaxProcessingAuthorizer + Normal = "Normal" + EPEC = "EPEC" + ALL = [Normal, EPEC].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type.rb new file mode 100644 index 0000000..9695195 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_StateTaxType + Default = "Default" + NFe = "NFe" + NFCe = "NFCe" + ALL = [Default, NFe, NFCe].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status.rb new file mode 100644 index 0000000..b6cc5f9 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_Status + None = "None" + Active = "Active" + Inactive = "Inactive" + ALL = [None, Active, Inactive].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime.rb new file mode 100644 index 0000000..601c596 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_TaxRegime + None = "None" + LucroReal = "LucroReal" + LucroPresumido = "LucroPresumido" + SimplesNacional = "SimplesNacional" + SimplesNacionalExcessoSublimite = "SimplesNacionalExcessoSublimite" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + Isento = "Isento" + ALL = [None, LucroReal, LucroPresumido, SimplesNacional, SimplesNacionalExcessoSublimite, MicroempreendedorIndividual, Isento].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource.rb new file mode 100644 index 0000000..7a0a803 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_AddressResource = Data.define(:additional_information, :city, :country, :district, :number, :postal_code, :state, :street) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + city: DFeTech_TaxPayers_Resources_CityBaseResource.from_api(payload["city"]), + country: payload["country"], + district: payload["district"], + number: payload["number"], + postal_code: payload["postalCode"], + state: payload["state"], + street: payload["street"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource.rb new file mode 100644 index 0000000..3addde8 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CertificateMetadataResource = Data.define(:certificate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + certificate: DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem.from_api(payload["certificate"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item.rb new file mode 100644 index 0000000..dbbfe6a --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem = Data.define(:modified_on, :status, :subject, :tax_id, :tax_payer_id, :thumbprint, :valid_until) do + def self.from_api(payload) + return nil if payload.nil? + + new( + modified_on: payload["modifiedOn"], + status: payload["status"], + subject: payload["subject"], + tax_id: payload["taxId"], + tax_payer_id: payload["taxPayerId"], + thumbprint: payload["thumbprint"], + valid_until: payload["validUntil"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource.rb new file mode 100644 index 0000000..717a78f --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CertificatesMetadataResource = Data.define(:certificates) do + def self.from_api(payload) + return nil if payload.nil? + + new( + certificates: (payload["certificates"] || []).map { |e| DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource.rb new file mode 100644 index 0000000..37d11f6 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CityBaseResource = Data.define(:code, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource.rb new file mode 100644 index 0000000..9aa0ea1 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompaniesResource = Data.define(:companies) do + def self.from_api(payload) + return nil if payload.nil? + + new( + companies: (payload["companies"] || []).map { |e| DFeTech_TaxPayers_Resources_CompanyResourceItem.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1.rb new file mode 100644 index 0000000..23a8d64 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompanyCertificateV1 = Data.define(:expires_on, :modified_on, :status, :thumbprint) do + def self.from_api(payload) + return nil if payload.nil? + + new( + expires_on: payload["expiresOn"], + modified_on: payload["modifiedOn"], + status: payload["status"], + thumbprint: payload["thumbprint"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1.rb new file mode 100644 index 0000000..577b2fb --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompanyCollectionResourceV1 = Data.define(:companies, :page, :total_pages, :total_results) do + def self.from_api(payload) + return nil if payload.nil? + + new( + companies: (payload["companies"] || []).map { |e| DFeTech_TaxPayers_Resources_CompanyResourceV1.from_api(e) }, + page: payload["page"], + total_pages: payload["totalPages"], + total_results: payload["totalResults"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource.rb new file mode 100644 index 0000000..09fe9cb --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompanyResource = Data.define(:company) do + def self.from_api(payload) + return nil if payload.nil? + + new( + company: DFeTech_TaxPayers_Resources_CompanyResourceItem.from_api(payload["company"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item.rb new file mode 100644 index 0000000..47ba664 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompanyResourceItem = Data.define(:account_id, :address, :created_on, :federal_tax_number, :id, :modified_on, :municipal_tax_number, :municipal_taxes, :name, :state_taxes, :status, :tax_regime, :trade_name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: DFeTech_TaxPayers_Resources_AddressResource.from_api(payload["address"]), + created_on: payload["createdOn"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + modified_on: payload["modifiedOn"], + municipal_tax_number: payload["municipalTaxNumber"], + municipal_taxes: payload["municipalTaxes"], + name: payload["name"], + state_taxes: payload["stateTaxes"], + status: payload["status"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1.rb new file mode 100644 index 0000000..cdafb65 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompanyResourceV1 = Data.define(:address, :auth_issue_value, :certificate, :company_registry_number, :created_on, :email, :environment, :federal_tax_determination, :federal_tax_number, :fiscal_status, :id, :iss_rate, :last_rps_sent, :legal_nature, :login_name, :login_password, :modified_on, :municipal_tax_determination, :municipal_tax_number, :name, :openning_date, :regional_tax_number, :rps_number, :rps_serial_number, :special_tax_regime, :status, :tax_regime, :trade_name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + address: DFeTech_TaxPayers_Domain_Entities_Address.from_api(payload["address"]), + auth_issue_value: payload["authIssueValue"], + certificate: DFeTech_TaxPayers_Resources_CompanyCertificateV1.from_api(payload["certificate"]), + company_registry_number: payload["companyRegistryNumber"], + created_on: payload["createdOn"], + email: payload["email"], + environment: payload["environment"], + federal_tax_determination: payload["federalTaxDetermination"], + federal_tax_number: payload["federalTaxNumber"], + fiscal_status: payload["fiscalStatus"], + id: payload["id"], + iss_rate: payload["issRate"], + last_rps_sent: payload["lastRpsSent"], + legal_nature: payload["legalNature"], + login_name: payload["loginName"], + login_password: payload["loginPassword"], + modified_on: payload["modifiedOn"], + municipal_tax_determination: payload["municipalTaxDetermination"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + openning_date: payload["openningDate"], + regional_tax_number: payload["regionalTaxNumber"], + rps_number: payload["rpsNumber"], + rps_serial_number: payload["rpsSerialNumber"], + special_tax_regime: payload["specialTaxRegime"], + status: payload["status"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1.rb new file mode 100644 index 0000000..05829f0 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CompanySingleResourceV1 = Data.define(:companies) do + def self.from_api(payload) + return nil if payload.nil? + + new( + companies: DFeTech_TaxPayers_Resources_CompanyResourceV1.from_api(payload["companies"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource.rb new file mode 100644 index 0000000..60ee466 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateCompanyResource = Data.define(:company) do + def self.from_api(payload) + return nil if payload.nil? + + new( + company: DFeTech_TaxPayers_Resources_CreateCompanyResourceItem.from_api(payload["company"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item.rb new file mode 100644 index 0000000..3cef604 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateCompanyResourceItem = Data.define(:account_id, :address, :federal_tax_number, :municipal_tax_number, :name, :tax_regime, :trade_name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: DFeTech_TaxPayers_Resources_AddressResource.from_api(payload["address"]), + federal_tax_number: payload["federalTaxNumber"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource.rb new file mode 100644 index 0000000..50a7580 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateMunicipalTaxResource = Data.define(:municipal_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + municipal_tax: DFeTech_TaxPayers_Resources_CreateMunicipalTaxResourceItem.from_api(payload["municipalTax"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item.rb new file mode 100644 index 0000000..ec38538 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateMunicipalTaxResourceItem = Data.define(:auth_issue_value, :city, :company_registry_number, :email, :environment, :federal_tax_determination, :iss_rate, :last_rps_sent, :legal_nature, :login_name, :login_password, :municipal_tax_determination, :regional_tax_number, :rps_number, :rps_serial_number, :special_tax_regime, :tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + auth_issue_value: payload["authIssueValue"], + city: DFeTech_TaxPayers_Domain_Entities_CityExtended.from_api(payload["city"]), + company_registry_number: payload["companyRegistryNumber"], + email: payload["email"], + environment: payload["environment"], + federal_tax_determination: payload["federalTaxDetermination"], + iss_rate: payload["issRate"], + last_rps_sent: payload["lastRpsSent"], + legal_nature: payload["legalNature"], + login_name: payload["loginName"], + login_password: payload["loginPassword"], + municipal_tax_determination: payload["municipalTaxDetermination"], + regional_tax_number: payload["regionalTaxNumber"], + rps_number: payload["rpsNumber"], + rps_serial_number: payload["rpsSerialNumber"], + special_tax_regime: payload["specialTaxRegime"], + tax_number: payload["taxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource.rb new file mode 100644 index 0000000..46c4370 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource = Data.define(:switch_authorizer_strategy) do + def self.from_api(payload) + return nil if payload.nil? + + new( + switch_authorizer_strategy: payload["switchAuthorizerStrategy"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource.rb new file mode 100644 index 0000000..82002bc --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateStateTaxResource = Data.define(:state_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + state_tax: DFeTech_TaxPayers_Resources_CreateStateTaxResourceItem.from_api(payload["stateTax"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item.rb new file mode 100644 index 0000000..db6b32a --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_CreateStateTaxResourceItem = Data.define(:code, :environment_type, :number, :processing_details, :security_credential, :serie, :special_tax_regime, :tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + environment_type: payload["environmentType"], + number: payload["number"], + processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource.from_api(payload["processingDetails"]), + security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential.from_api(payload["securityCredential"]), + serie: payload["serie"], + special_tax_regime: payload["specialTaxRegime"], + tax_number: payload["taxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource.rb new file mode 100644 index 0000000..aedd9f8 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_ErrorResource = Data.define(:code, :message) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + message: payload["message"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource.rb new file mode 100644 index 0000000..125bbbe --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_ErrorsResource = Data.define(:errors) do + def self.from_api(payload) + return nil if payload.nil? + + new( + errors: (payload["errors"] || []).map { |e| DFeTech_TaxPayers_Resources_ErrorResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource.rb new file mode 100644 index 0000000..7940748 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_MunicipalTaxResource = Data.define(:municipal_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + municipal_tax: DFeTech_TaxPayers_Resources_MunicipalTaxResourceItem.from_api(payload["municipalTax"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item.rb new file mode 100644 index 0000000..dec2c57 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_MunicipalTaxResourceItem = Data.define(:account_id, :auth_issue_value, :city, :company_id, :company_registry_number, :email, :environment, :federal_tax_determination, :fiscal_status, :id, :iss_rate, :last_rps_sent, :legal_nature, :login_name, :login_password, :municipal_tax_determination, :regional_tax_number, :rps_number, :rps_serial_number, :rps_serial_numbers, :special_tax_regime, :status, :tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + auth_issue_value: payload["authIssueValue"], + city: DFeTech_TaxPayers_Domain_Entities_CityExtended.from_api(payload["city"]), + company_id: payload["companyId"], + company_registry_number: payload["companyRegistryNumber"], + email: payload["email"], + environment: payload["environment"], + federal_tax_determination: payload["federalTaxDetermination"], + fiscal_status: payload["fiscalStatus"], + id: payload["id"], + iss_rate: payload["issRate"], + last_rps_sent: payload["lastRpsSent"], + legal_nature: payload["legalNature"], + login_name: payload["loginName"], + login_password: payload["loginPassword"], + municipal_tax_determination: payload["municipalTaxDetermination"], + regional_tax_number: payload["regionalTaxNumber"], + rps_number: payload["rpsNumber"], + rps_serial_number: payload["rpsSerialNumber"], + rps_serial_numbers: payload["rpsSerialNumbers"], + special_tax_regime: payload["specialTaxRegime"], + status: payload["status"], + tax_number: payload["taxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource.rb new file mode 100644 index 0000000..801895c --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_SerieResource = Data.define(:serie) do + def self.from_api(payload) + return nil if payload.nil? + + new( + serie: DFeTech_TaxPayers_Resources_SerieResourceItem.from_api(payload["serie"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item.rb new file mode 100644 index 0000000..6925a04 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_SerieResourceItem = Data.define(:last_rps_sent, :rps_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + last_rps_sent: payload["lastRpsSent"], + rps_number: payload["rpsNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource.rb new file mode 100644 index 0000000..65d868a --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Resources_StateTaxProcessingAuthorizerResource + Normal = "Normal" + EPEC = "EPEC" + ALL = [Normal, EPEC].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource.rb new file mode 100644 index 0000000..c59e601 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Resources_StateTaxProcessingSwitchAuthorizerStrategyResource + Manual = "Manual" + StateTaxAuthorityStatusUnavailable = "StateTaxAuthorityStatusUnavailable" + ALL = [Manual, StateTaxAuthorityStatusUnavailable].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource.rb new file mode 100644 index 0000000..19de5a1 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_StateTaxResource = Data.define(:state_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + state_tax: DFeTech_TaxPayers_Resources_StateTaxResourceItem.from_api(payload["stateTax"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item.rb new file mode 100644 index 0000000..7b8af1c --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_StateTaxResourceItem = Data.define(:account_id, :code, :company_id, :created_on, :environment_type, :id, :modified_on, :number, :processing_details, :security_credential, :serie, :series, :special_tax_regime, :status, :tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + code: payload["code"], + company_id: payload["companyId"], + created_on: payload["createdOn"], + environment_type: payload["environmentType"], + id: payload["id"], + modified_on: payload["modifiedOn"], + number: payload["number"], + processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource.from_api(payload["processingDetails"]), + security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential.from_api(payload["securityCredential"]), + serie: payload["serie"], + series: payload["series"], + special_tax_regime: payload["specialTaxRegime"], + status: payload["status"], + tax_number: payload["taxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request.rb new file mode 100644 index 0000000..f801482 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_StateTaxSwitchAuthorizerRequest = Data.define(:authorizer, :reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorizer: payload["authorizer"], + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response.rb new file mode 100644 index 0000000..919627d --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_StateTaxSwitchAuthorizerResponse = Data.define(:from_authorizer, :modified_on, :reason, :to_authorizer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + from_authorizer: payload["fromAuthorizer"], + modified_on: payload["modifiedOn"], + reason: payload["reason"], + to_authorizer: payload["toAuthorizer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource.rb new file mode 100644 index 0000000..2b824d6 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_StateTaxesResource = Data.define(:state_taxes) do + def self.from_api(payload) + return nil if payload.nil? + + new( + state_taxes: (payload["stateTaxes"] || []).map { |e| DFeTech_TaxPayers_Resources_StateTaxResourceItem.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource.rb new file mode 100644 index 0000000..f8fdabe --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_UpdateCompanyResource = Data.define(:company) do + def self.from_api(payload) + return nil if payload.nil? + + new( + company: DFeTech_TaxPayers_Resources_UpdateCompanyResourceItem.from_api(payload["company"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item.rb new file mode 100644 index 0000000..bf05bec --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_UpdateCompanyResourceItem = Data.define(:account_id, :address, :federal_tax_number, :id, :municipal_tax_number, :name, :tax_regime, :trade_name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: DFeTech_TaxPayers_Resources_AddressResource.from_api(payload["address"]), + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource.rb new file mode 100644 index 0000000..aa1370c --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResource = Data.define(:municipal_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + municipal_tax: DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResourceItem.from_api(payload["municipalTax"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item.rb new file mode 100644 index 0000000..6492062 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResourceItem = Data.define(:auth_issue_value, :city, :company_registry_number, :email, :environment, :federal_tax_determination, :iss_rate, :last_rps_sent, :legal_nature, :login_name, :login_password, :municipal_tax_determination, :regional_tax_number, :rps_number, :rps_serial_number, :special_tax_regime, :tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + auth_issue_value: payload["authIssueValue"], + city: DFeTech_TaxPayers_Domain_Entities_CityExtended.from_api(payload["city"]), + company_registry_number: payload["companyRegistryNumber"], + email: payload["email"], + environment: payload["environment"], + federal_tax_determination: payload["federalTaxDetermination"], + iss_rate: payload["issRate"], + last_rps_sent: payload["lastRpsSent"], + legal_nature: payload["legalNature"], + login_name: payload["loginName"], + login_password: payload["loginPassword"], + municipal_tax_determination: payload["municipalTaxDetermination"], + regional_tax_number: payload["regionalTaxNumber"], + rps_number: payload["rpsNumber"], + rps_serial_number: payload["rpsSerialNumber"], + special_tax_regime: payload["specialTaxRegime"], + tax_number: payload["taxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource.rb new file mode 100644 index 0000000..2b95ebd --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_UpdateStateTaxResource = Data.define(:state_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + state_tax: DFeTech_TaxPayers_Resources_UpdateStateTaxResourceItem.from_api(payload["stateTax"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item.rb b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item.rb new file mode 100644 index 0000000..642db0a --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + DFeTech_TaxPayers_Resources_UpdateStateTaxResourceItem = Data.define(:code, :environment_type, :number, :processing_details, :security_credential, :serie, :special_tax_regime, :tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + environment_type: payload["environmentType"], + number: payload["number"], + processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource.from_api(payload["processingDetails"]), + security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential.from_api(payload["securityCredential"]), + serie: payload["serie"], + special_tax_regime: payload["specialTaxRegime"], + tax_number: payload["taxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind.rb new file mode 100644 index 0000000..3afc05e --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmContainerElementKind + None = "None" + EntitySet = "EntitySet" + ActionImport = "ActionImport" + FunctionImport = "FunctionImport" + Singleton = "Singleton" + ALL = [None, EntitySet, ActionImport, FunctionImport, Singleton].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind.rb new file mode 100644 index 0000000..f0b60d1 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmExpressionKind + None = "None" + BinaryConstant = "BinaryConstant" + BooleanConstant = "BooleanConstant" + DateTimeOffsetConstant = "DateTimeOffsetConstant" + DecimalConstant = "DecimalConstant" + FloatingConstant = "FloatingConstant" + GuidConstant = "GuidConstant" + IntegerConstant = "IntegerConstant" + StringConstant = "StringConstant" + DurationConstant = "DurationConstant" + Null = "Null" + Record = "Record" + Collection = "Collection" + Path = "Path" + If = "If" + Cast = "Cast" + IsOf = "IsOf" + FunctionApplication = "FunctionApplication" + LabeledExpressionReference = "LabeledExpressionReference" + Labeled = "Labeled" + PropertyPath = "PropertyPath" + NavigationPropertyPath = "NavigationPropertyPath" + DateConstant = "DateConstant" + TimeOfDayConstant = "TimeOfDayConstant" + EnumMember = "EnumMember" + AnnotationPath = "AnnotationPath" + ALL = [None, BinaryConstant, BooleanConstant, DateTimeOffsetConstant, DecimalConstant, FloatingConstant, GuidConstant, IntegerConstant, StringConstant, DurationConstant, Null, Record, Collection, Path, If, Cast, IsOf, FunctionApplication, LabeledExpressionReference, Labeled, PropertyPath, NavigationPropertyPath, DateConstant, TimeOfDayConstant, EnumMember, AnnotationPath].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind.rb new file mode 100644 index 0000000..e57852e --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmSchemaElementKind + None = "None" + TypeDefinition = "TypeDefinition" + Term = "Term" + Action = "Action" + EntityContainer = "EntityContainer" + Function = "Function" + ALL = [None, TypeDefinition, Term, Action, EntityContainer, Function].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind.rb new file mode 100644 index 0000000..bb1a8bd --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmTypeKind + None = "None" + Primitive = "Primitive" + Entity = "Entity" + Complex = "Complex" + Collection = "Collection" + EntityReference = "EntityReference" + Enum = "Enum" + TypeDefinition = "TypeDefinition" + Untyped = "Untyped" + Path = "Path" + ALL = [None, Primitive, Entity, Complex, Collection, EntityReference, Enum, TypeDefinition, Untyped, Path].freeze + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container.rb new file mode 100644 index 0000000..32ca8fb --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmEntityContainer = Data.define(:elements, :name, :namespace, :schema_element_kind) do + def self.from_api(payload) + return nil if payload.nil? + + new( + elements: (payload["elements"] || []).map { |e| Microsoft_OData_Edm_IEdmEntityContainerElement.from_api(e) }, + name: payload["name"], + namespace: payload["namespace"], + schema_element_kind: payload["schemaElementKind"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element.rb new file mode 100644 index 0000000..e0118e7 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmEntityContainerElement = Data.define(:container, :container_element_kind, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + container: Microsoft_OData_Edm_IEdmEntityContainer.from_api(payload["container"]), + container_element_kind: payload["containerElementKind"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_expression.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_expression.rb new file mode 100644 index 0000000..0b726b7 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_expression.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmExpression = Data.define(:expression_kind) do + def self.from_api(payload) + return nil if payload.nil? + + new( + expression_kind: payload["expressionKind"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_model.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_model.rb new file mode 100644 index 0000000..fa44e9f --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_model.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmModel = Data.define(:declared_namespaces, :direct_value_annotations_manager, :entity_container, :referenced_models, :schema_elements, :vocabulary_annotations) do + def self.from_api(payload) + return nil if payload.nil? + + new( + declared_namespaces: payload["declaredNamespaces"], + direct_value_annotations_manager: payload["directValueAnnotationsManager"], + entity_container: Microsoft_OData_Edm_IEdmEntityContainer.from_api(payload["entityContainer"]), + referenced_models: (payload["referencedModels"] || []).map { |e| Microsoft_OData_Edm_IEdmModel.from_api(e) }, + schema_elements: (payload["schemaElements"] || []).map { |e| Microsoft_OData_Edm_IEdmSchemaElement.from_api(e) }, + vocabulary_annotations: (payload["vocabularyAnnotations"] || []).map { |e| Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotation.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element.rb new file mode 100644 index 0000000..29c56ea --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmSchemaElement = Data.define(:name, :namespace, :schema_element_kind) do + def self.from_api(payload) + return nil if payload.nil? + + new( + name: payload["name"], + namespace: payload["namespace"], + schema_element_kind: payload["schemaElementKind"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type.rb new file mode 100644 index 0000000..f33b7a0 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmType = Data.define(:type_kind) do + def self.from_api(payload) + return nil if payload.nil? + + new( + type_kind: payload["typeKind"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference.rb new file mode 100644 index 0000000..d4e5234 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_IEdmTypeReference = Data.define(:definition, :is_nullable) do + def self.from_api(payload) + return nil if payload.nil? + + new( + definition: Microsoft_OData_Edm_IEdmType.from_api(payload["definition"]), + is_nullable: payload["isNullable"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager.rb new file mode 100644 index 0000000..e33d38f --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + # free-form object: Hash[String, untyped] + Microsoft_OData_Edm_Vocabularies_IEdmDirectValueAnnotationsManager = Hash + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term.rb new file mode 100644 index 0000000..3fda233 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_Vocabularies_IEdmTerm = Data.define(:applies_to, :default_value, :name, :namespace, :schema_element_kind, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + applies_to: payload["appliesTo"], + default_value: payload["defaultValue"], + name: payload["name"], + namespace: payload["namespace"], + schema_element_kind: payload["schemaElementKind"], + type: Microsoft_OData_Edm_IEdmTypeReference.from_api(payload["type"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable.rb new file mode 100644 index 0000000..f17dc36 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + # free-form object: Hash[String, untyped] + Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotatable = Hash + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation.rb new file mode 100644 index 0000000..9c0f7fe --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotation = Data.define(:qualifier, :target, :term, :uses_default, :value) do + def self.from_api(payload) + return nil if payload.nil? + + new( + qualifier: payload["qualifier"], + target: payload["target"], + term: Microsoft_OData_Edm_Vocabularies_IEdmTerm.from_api(payload["term"]), + uses_default: payload["usesDefault"], + value: Microsoft_OData_Edm_IEdmExpression.from_api(payload["value"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_entity_set_info.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_entity_set_info.rb new file mode 100644 index 0000000..92cc8c9 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_entity_set_info.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_ODataEntitySetInfo = Data.define(:name, :title, :type_annotation, :url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + name: payload["name"], + title: payload["title"], + type_annotation: Microsoft_OData_ODataTypeAnnotation.from_api(payload["typeAnnotation"]), + url: payload["url"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_function_import_info.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_function_import_info.rb new file mode 100644 index 0000000..6fb1d69 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_function_import_info.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_ODataFunctionImportInfo = Data.define(:name, :title, :type_annotation, :url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + name: payload["name"], + title: payload["title"], + type_annotation: Microsoft_OData_ODataTypeAnnotation.from_api(payload["typeAnnotation"]), + url: payload["url"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_service_document.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_service_document.rb new file mode 100644 index 0000000..80c27e2 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_service_document.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_ODataServiceDocument = Data.define(:entity_sets, :function_imports, :singletons, :type_annotation) do + def self.from_api(payload) + return nil if payload.nil? + + new( + entity_sets: (payload["entitySets"] || []).map { |e| Microsoft_OData_ODataEntitySetInfo.from_api(e) }, + function_imports: (payload["functionImports"] || []).map { |e| Microsoft_OData_ODataFunctionImportInfo.from_api(e) }, + singletons: (payload["singletons"] || []).map { |e| Microsoft_OData_ODataSingletonInfo.from_api(e) }, + type_annotation: Microsoft_OData_ODataTypeAnnotation.from_api(payload["typeAnnotation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_singleton_info.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_singleton_info.rb new file mode 100644 index 0000000..fceec13 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_singleton_info.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_ODataSingletonInfo = Data.define(:name, :title, :type_annotation, :url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + name: payload["name"], + title: payload["title"], + type_annotation: Microsoft_OData_ODataTypeAnnotation.from_api(payload["typeAnnotation"]), + url: payload["url"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_type_annotation.rb b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_type_annotation.rb new file mode 100644 index 0000000..02d1ad7 --- /dev/null +++ b/lib/nfe/generated/contribuintes_v2/microsoft_odata_odata_type_annotation.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_ODataTypeAnnotation = Data.define(:type_name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + type_name: payload["typeName"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/generated_marker.rb b/lib/nfe/generated/generated_marker.rb new file mode 100644 index 0000000..af57212 --- /dev/null +++ b/lib/nfe/generated/generated_marker.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit + +module Nfe + module Generated + MARKER = { + generated_at: nil, + specs: { + "calculo-impostos-v1.yaml" => "sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99", + "consulta-cte-v2.yaml" => "sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9", + "consulta-dfe-distribuicao-v2.yaml" => "sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd", + "consulta-nfe-distribuicao-v1.yaml" => "sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7", + "contribuintes-v2.json" => "sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102", + "nf-consumidor-v2.yaml" => "sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5", + "nf-produto-v2.yaml" => "sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2", + "nfeio.yaml" => "sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3", + "product-invoice-rtc-v1.yaml" => "sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a", + "product-register-pt-br-v1.yaml" => "sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64", + "service-invoice-rtc-v1.yaml" => "sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b" + } + }.freeze + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/activity_resource.rb b/lib/nfe/generated/nf_consumidor_v2/activity_resource.rb new file mode 100644 index 0000000..13355ad --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/activity_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ActivityResource = Data.define(:data, :sequence, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + data: payload["data"], + sequence: payload["sequence"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/addition_resource.rb b/lib/nfe/generated/nf_consumidor_v2/addition_resource.rb new file mode 100644 index 0000000..d919cc5 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/addition_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + AdditionResource = Data.define(:amount, :code, :drawback, :manufacturer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + code: payload["code"], + drawback: payload["drawback"], + manufacturer: payload["manufacturer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/additional_information_resource.rb b/lib/nfe/generated/nf_consumidor_v2/additional_information_resource.rb new file mode 100644 index 0000000..eb81cc3 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/additional_information_resource.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + AdditionalInformationResource = Data.define(:advance_payment, :contract, :effort, :fisco, :order, :referenced_process, :tax_documents_reference, :taxpayer, :taxpayer_comments, :xml_authorized) do + def self.from_api(payload) + return nil if payload.nil? + + new( + advance_payment: (payload["advancePayment"] || []).map { |e| AdvancePaymentItemResource.from_api(e) }, + contract: payload["contract"], + effort: payload["effort"], + fisco: payload["fisco"], + order: payload["order"], + referenced_process: (payload["referencedProcess"] || []).map { |e| ReferencedProcessResource.from_api(e) }, + tax_documents_reference: (payload["taxDocumentsReference"] || []).map { |e| TaxDocumentsReferenceResource.from_api(e) }, + taxpayer: payload["taxpayer"], + taxpayer_comments: (payload["taxpayerComments"] || []).map { |e| TaxpayerCommentsResource.from_api(e) }, + xml_authorized: payload["xmlAuthorized"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/address_resource.rb b/lib/nfe/generated/nf_consumidor_v2/address_resource.rb new file mode 100644 index 0000000..d84509b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/address_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + AddressResource = Data.define(:additional_information, :city, :country, :district, :number, :phone, :postal_code, :state, :street) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + city: CityResource.from_api(payload["city"]), + country: payload["country"], + district: payload["district"], + number: payload["number"], + phone: payload["phone"], + postal_code: payload["postalCode"], + state: payload["state"], + street: payload["street"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/advance_payment_item_resource.rb b/lib/nfe/generated/nf_consumidor_v2/advance_payment_item_resource.rb new file mode 100644 index 0000000..a411f51 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/advance_payment_item_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + AdvancePaymentItemResource = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/authorization_resource.rb b/lib/nfe/generated/nf_consumidor_v2/authorization_resource.rb new file mode 100644 index 0000000..0c76d20 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/authorization_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + AuthorizationResource = Data.define(:access_key, :message, :receipt_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + message: payload["message"], + receipt_on: payload["receiptOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/bill_resource.rb b/lib/nfe/generated/nf_consumidor_v2/bill_resource.rb new file mode 100644 index 0000000..6009640 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/bill_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + BillResource = Data.define(:discount_amount, :net_amount, :number, :original_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + discount_amount: payload["discountAmount"], + net_amount: payload["netAmount"], + number: payload["number"], + original_amount: payload["originalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/billing_resource.rb b/lib/nfe/generated/nf_consumidor_v2/billing_resource.rb new file mode 100644 index 0000000..1c31d60 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/billing_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + BillingResource = Data.define(:bill, :duplicates) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bill: BillResource.from_api(payload["bill"]), + duplicates: (payload["duplicates"] || []).map { |e| DuplicateResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/buyer_resource.rb b/lib/nfe/generated/nf_consumidor_v2/buyer_resource.rb new file mode 100644 index 0000000..e6cd5ee --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/buyer_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + BuyerResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :state_tax_number_indicator, :tax_regime, :trade_name, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + state_tax_number_indicator: payload["stateTaxNumberIndicator"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/card_resource.rb b/lib/nfe/generated/nf_consumidor_v2/card_resource.rb new file mode 100644 index 0000000..3a8e00c --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/card_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CardResource = Data.define(:authorization, :federal_tax_number, :federal_tax_number_recipient, :flag, :id_payment_terminal, :integration_payment_type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorization: payload["authorization"], + federal_tax_number: payload["federalTaxNumber"], + federal_tax_number_recipient: payload["federalTaxNumberRecipient"], + flag: payload["flag"], + id_payment_terminal: payload["idPaymentTerminal"], + integration_payment_type: payload["integrationPaymentType"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/cbstax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/cbstax_resource.rb new file mode 100644 index 0000000..9e6198b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/cbstax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CBSTaxResource = Data.define(:amount, :deferment, :rate, :reduction, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment: DefermentTaxResource.from_api(payload["deferment"]), + rate: payload["rate"], + reduction: ReductionTaxResource.from_api(payload["reduction"]), + returned_amount: ReturnedTaxResource.from_api(payload["returnedAmount"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/cbstotals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/cbstotals_resource.rb new file mode 100644 index 0000000..d8deec0 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/cbstotals_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CBSTotalsResource = Data.define(:amount, :deferment_amount, :presumed_credit_amount, :presumed_credit_conditional_amount, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment_amount: payload["defermentAmount"], + presumed_credit_amount: payload["presumedCreditAmount"], + presumed_credit_conditional_amount: payload["presumedCreditConditionalAmount"], + returned_amount: payload["returnedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/cideresource.rb b/lib/nfe/generated/nf_consumidor_v2/cideresource.rb new file mode 100644 index 0000000..be20533 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/cideresource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CIDEResource = Data.define(:bc, :cide_amount, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bc: payload["bc"], + cide_amount: payload["cideAmount"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/city_resource.rb b/lib/nfe/generated/nf_consumidor_v2/city_resource.rb new file mode 100644 index 0000000..f5f52b8 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/city_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CityResource = Data.define(:code, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/cofins_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/cofins_tax_resource.rb new file mode 100644 index 0000000..243022d --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/cofins_tax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CofinsTaxResource = Data.define(:amount, :base_tax, :base_tax_product_quantity, :cst, :product_rate, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + base_tax_product_quantity: payload["baseTaxProductQuantity"], + cst: payload["cst"], + product_rate: payload["productRate"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/competence_adjustment_resource.rb b/lib/nfe/generated/nf_consumidor_v2/competence_adjustment_resource.rb new file mode 100644 index 0000000..6d86432 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/competence_adjustment_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CompetenceAdjustmentResource = Data.define(:assessment_period, :cbs_amount, :ibs_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + assessment_period: payload["assessmentPeriod"], + cbs_amount: payload["cbsAmount"], + ibs_amount: payload["ibsAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/consumer_invoice_request.rb b/lib/nfe/generated/nf_consumidor_v2/consumer_invoice_request.rb new file mode 100644 index 0000000..8a5f7dd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/consumer_invoice_request.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ConsumerInvoiceRequest = Data.define(:additional_information, :billing, :buyer, :consumer_type, :consumption_city_code, :contingency_justification, :contingency_on, :credit_type, :debit_type, :destination, :government_purchase, :ibs_consumption_city_code, :id, :issuer, :items, :number, :operation_nature, :operation_on, :operation_type, :payment, :presence_type, :print_type, :purpose_type, :serie, :totals, :transaction_intermediate, :transport) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + consumer_type: payload["consumerType"], + consumption_city_code: payload["consumptionCityCode"], + contingency_justification: payload["contingencyJustification"], + contingency_on: payload["contingencyOn"], + credit_type: payload["creditType"], + debit_type: payload["debitType"], + destination: payload["destination"], + government_purchase: GovernmentPurchaseResource.from_api(payload["governmentPurchase"]), + ibs_consumption_city_code: payload["ibsConsumptionCityCode"], + id: payload["id"], + issuer: IssuerFromRequestResource.from_api(payload["issuer"]), + items: (payload["items"] || []).map { |e| InvoiceItemResource.from_api(e) }, + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + presence_type: payload["presenceType"], + print_type: payload["printType"], + purpose_type: payload["purposeType"], + serie: payload["serie"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/consumer_invoices_resource.rb b/lib/nfe/generated/nf_consumidor_v2/consumer_invoices_resource.rb new file mode 100644 index 0000000..1a0301d --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/consumer_invoices_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ConsumerInvoicesResource = Data.define(:consumer_invoices, :has_more) do + def self.from_api(payload) + return nil if payload.nil? + + new( + consumer_invoices: (payload["consumerInvoices"] || []).map { |e| InvoiceWithoutEventsResource.from_api(e) }, + has_more: payload["hasMore"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/consumer_presence_type.rb b/lib/nfe/generated/nf_consumidor_v2/consumer_presence_type.rb new file mode 100644 index 0000000..0ff73e6 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/consumer_presence_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ConsumerPresenceType + None = "None" + Presence = "Presence" + Internet = "Internet" + Telephone = "Telephone" + Delivery = "Delivery" + OthersNonPresenceOperation = "OthersNonPresenceOperation" + ALL = [None, Presence, Internet, Telephone, Delivery, OthersNonPresenceOperation].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/consumer_type.rb b/lib/nfe/generated/nf_consumidor_v2/consumer_type.rb new file mode 100644 index 0000000..a2e8353 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/consumer_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ConsumerType + FinalConsumer = "FinalConsumer" + Normal = "Normal" + ALL = [FinalConsumer, Normal].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/contingency_details.rb b/lib/nfe/generated/nf_consumidor_v2/contingency_details.rb new file mode 100644 index 0000000..bc3f853 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/contingency_details.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ContingencyDetails = Data.define(:authorizer, :reason, :started_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorizer: payload["authorizer"], + reason: payload["reason"], + started_on: payload["startedOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/credit_reversal_resource.rb b/lib/nfe/generated/nf_consumidor_v2/credit_reversal_resource.rb new file mode 100644 index 0000000..8b61592 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/credit_reversal_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CreditReversalResource = Data.define(:cbs_reversal_amount, :ibs_reversal_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_reversal_amount: payload["cbsReversalAmount"], + ibs_reversal_amount: payload["ibsReversalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/credit_reversal_totals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/credit_reversal_totals_resource.rb new file mode 100644 index 0000000..d19687a --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/credit_reversal_totals_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CreditReversalTotalsResource = Data.define(:cbs_reversal_amount, :ibs_reversal_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_reversal_amount: payload["cbsReversalAmount"], + ibs_reversal_amount: payload["ibsReversalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/credit_transfer_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/credit_transfer_tax_resource.rb new file mode 100644 index 0000000..7ebce76 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/credit_transfer_tax_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + CreditTransferTaxResource = Data.define(:cbs_amount, :ibs_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + ibs_amount: payload["ibsAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/credit_type.rb b/lib/nfe/generated/nf_consumidor_v2/credit_type.rb new file mode 100644 index 0000000..d61d53e --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/credit_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module CreditType + FinesAndInterest = "FinesAndInterest" + IbsPresumedCreditAppropriationZfm = "IbsPresumedCreditAppropriationZfm" + ReturnDeliveryRefusedOrNotFound = "ReturnDeliveryRefusedOrNotFound" + ValueReduction = "ValueReduction" + TransferCreditSuccession = "TransferCreditSuccession" + ALL = [FinesAndInterest, IbsPresumedCreditAppropriationZfm, ReturnDeliveryRefusedOrNotFound, ValueReduction, TransferCreditSuccession].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/debit_type.rb b/lib/nfe/generated/nf_consumidor_v2/debit_type.rb new file mode 100644 index 0000000..3f2d824 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/debit_type.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module DebitType + TransferCreditsToCooperatives = "TransferCreditsToCooperatives" + CancelCreditsExemptImmuneSales = "CancelCreditsExemptImmuneSales" + UnprocessedInvoicesDebits = "UnprocessedInvoicesDebits" + FinesAndInterest = "FinesAndInterest" + TransferInheritanceCredit = "TransferInheritanceCredit" + AdvancePayment = "AdvancePayment" + InventoryLoss = "InventoryLoss" + SnDisqualification = "SnDisqualification" + ALL = [TransferCreditsToCooperatives, CancelCreditsExemptImmuneSales, UnprocessedInvoicesDebits, FinesAndInterest, TransferInheritanceCredit, AdvancePayment, InventoryLoss, SnDisqualification].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/deferment_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/deferment_tax_resource.rb new file mode 100644 index 0000000..03c4fb7 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/deferment_tax_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + DefermentTaxResource = Data.define(:amount, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/delivery_information_resource.rb b/lib/nfe/generated/nf_consumidor_v2/delivery_information_resource.rb new file mode 100644 index 0000000..129f03b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/delivery_information_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + DeliveryInformationResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/destination.rb b/lib/nfe/generated/nf_consumidor_v2/destination.rb new file mode 100644 index 0000000..3ae9845 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/destination.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module Destination + None = "None" + InternalOperation = "Internal_Operation" + InterstateOperation = "Interstate_Operation" + InternationalOperation = "International_Operation" + ALL = [None, InternalOperation, InterstateOperation, InternationalOperation].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/disablement_resource.rb b/lib/nfe/generated/nf_consumidor_v2/disablement_resource.rb new file mode 100644 index 0000000..1584982 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/disablement_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + DisablementResource = Data.define(:begin_number, :environment, :last_number, :reason, :serie, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + begin_number: payload["beginNumber"], + environment: payload["environment"], + last_number: payload["lastNumber"], + reason: payload["reason"], + serie: payload["serie"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/document_electronic_invoice_resource.rb b/lib/nfe/generated/nf_consumidor_v2/document_electronic_invoice_resource.rb new file mode 100644 index 0000000..8a67589 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/document_electronic_invoice_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + DocumentElectronicInvoiceResource = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/document_invoice_reference_resource.rb b/lib/nfe/generated/nf_consumidor_v2/document_invoice_reference_resource.rb new file mode 100644 index 0000000..94ba47f --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/document_invoice_reference_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + DocumentInvoiceReferenceResource = Data.define(:federal_tax_number, :model, :number, :series, :state, :year_month) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + model: payload["model"], + number: payload["number"], + series: payload["series"], + state: payload["state"], + year_month: payload["yearMonth"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/duduction_indicator.rb b/lib/nfe/generated/nf_consumidor_v2/duduction_indicator.rb new file mode 100644 index 0000000..6fc0eb6 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/duduction_indicator.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module DuductionIndicator + NotDeduct = "NotDeduct" + Deduce = "Deduce" + ALL = [NotDeduct, Deduce].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/duplicate_resource.rb b/lib/nfe/generated/nf_consumidor_v2/duplicate_resource.rb new file mode 100644 index 0000000..b8907a5 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/duplicate_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + DuplicateResource = Data.define(:amount, :expiration_on, :number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + expiration_on: payload["expirationOn"], + number: payload["number"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/economic_activity_resource.rb b/lib/nfe/generated/nf_consumidor_v2/economic_activity_resource.rb new file mode 100644 index 0000000..a15c815 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/economic_activity_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + EconomicActivityResource = Data.define(:code, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/economic_activity_type.rb b/lib/nfe/generated/nf_consumidor_v2/economic_activity_type.rb new file mode 100644 index 0000000..cbe778a --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/economic_activity_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module EconomicActivityType + Main = "Main" + Secondary = "Secondary" + ALL = [Main, Secondary].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/environment_type.rb b/lib/nfe/generated/nf_consumidor_v2/environment_type.rb new file mode 100644 index 0000000..0307cd2 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/environment_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module EnvironmentType + None = "None" + Production = "Production" + Test = "Test" + ALL = [None, Production, Test].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/error_resource.rb b/lib/nfe/generated/nf_consumidor_v2/error_resource.rb new file mode 100644 index 0000000..a002851 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/error_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ErrorResource = Data.define(:code, :message) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + message: payload["message"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/errors_resource.rb b/lib/nfe/generated/nf_consumidor_v2/errors_resource.rb new file mode 100644 index 0000000..e4ab762 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/errors_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ErrorsResource = Data.define(:errors) do + def self.from_api(payload) + return nil if payload.nil? + + new( + errors: (payload["errors"] || []).map { |e| ErrorResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/exempt_reason.rb b/lib/nfe/generated/nf_consumidor_v2/exempt_reason.rb new file mode 100644 index 0000000..9b7cb7f --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/exempt_reason.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ExemptReason + Agriculture = "Agriculture" + Others = "Others" + DevelopmentEntities = "DevelopmentEntities" + ALL = [Agriculture, Others, DevelopmentEntities].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/export_detail_resource.rb b/lib/nfe/generated/nf_consumidor_v2/export_detail_resource.rb new file mode 100644 index 0000000..62108f7 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/export_detail_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ExportDetailResource = Data.define(:drawback, :hint_information) do + def self.from_api(payload) + return nil if payload.nil? + + new( + drawback: payload["drawback"], + hint_information: ExportHintResource.from_api(payload["hintInformation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/export_hint_resource.rb b/lib/nfe/generated/nf_consumidor_v2/export_hint_resource.rb new file mode 100644 index 0000000..9356923 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/export_hint_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ExportHintResource = Data.define(:access_key, :quantity, :registry_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + quantity: payload["quantity"], + registry_id: payload["registryId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/export_resource.rb b/lib/nfe/generated/nf_consumidor_v2/export_resource.rb new file mode 100644 index 0000000..e644eb4 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/export_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ExportResource = Data.define(:local, :office, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + local: payload["local"], + office: payload["office"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/file_resource.rb b/lib/nfe/generated/nf_consumidor_v2/file_resource.rb new file mode 100644 index 0000000..5054bc1 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/file_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + FileResource = Data.define(:uri) do + def self.from_api(payload) + return nil if payload.nil? + + new( + uri: payload["uri"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/flag_card.rb b/lib/nfe/generated/nf_consumidor_v2/flag_card.rb new file mode 100644 index 0000000..1a604b7 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/flag_card.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module FlagCard + None = "None" + Visa = "Visa" + Mastercard = "Mastercard" + AmericanExpress = "AmericanExpress" + Sorocred = "Sorocred" + DinersClub = "DinersClub" + Elo = "Elo" + Hipercard = "Hipercard" + Aura = "Aura" + Cabal = "Cabal" + Alelo = "Alelo" + BanesCard = "BanesCard" + CalCard = "CalCard" + Credz = "Credz" + Discover = "Discover" + GoodCard = "GoodCard" + GreenCard = "GreenCard" + Hiper = "Hiper" + JCB = "JCB" + Mais = "Mais" + MaxVan = "MaxVan" + Policard = "Policard" + RedeCompras = "RedeCompras" + Sodexo = "Sodexo" + ValeCard = "ValeCard" + Verocheque = "Verocheque" + VR = "VR" + Ticket = "Ticket" + Other = "Other" + ALL = [None, Visa, Mastercard, AmericanExpress, Sorocred, DinersClub, Elo, Hipercard, Aura, Cabal, Alelo, BanesCard, CalCard, Credz, Discover, GoodCard, GreenCard, Hiper, JCB, Mais, MaxVan, Policard, RedeCompras, Sodexo, ValeCard, Verocheque, VR, Ticket, Other].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/fuel_origin_resource.rb b/lib/nfe/generated/nf_consumidor_v2/fuel_origin_resource.rb new file mode 100644 index 0000000..23319be --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/fuel_origin_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + FuelOriginResource = Data.define(:c_uforig, :ind_import, :p_orig) do + def self.from_api(payload) + return nil if payload.nil? + + new( + c_uforig: payload["cUFOrig"], + ind_import: payload["indImport"], + p_orig: payload["pOrig"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/fuel_resource.rb b/lib/nfe/generated/nf_consumidor_v2/fuel_resource.rb new file mode 100644 index 0000000..a664a57 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/fuel_resource.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + FuelResource = Data.define(:amount_temp, :cide, :code_anp, :codif, :description_anp, :fuel_origin, :percentage_glp, :percentage_gni, :percentage_ng, :percentage_ngn, :pump, :starting_amount, :state_buyer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount_temp: payload["amountTemp"], + cide: CIDEResource.from_api(payload["cide"]), + code_anp: payload["codeANP"], + codif: payload["codif"], + description_anp: payload["descriptionANP"], + fuel_origin: FuelOriginResource.from_api(payload["fuelOrigin"]), + percentage_glp: payload["percentageGLP"], + percentage_gni: payload["percentageGNi"], + percentage_ng: payload["percentageNG"], + percentage_ngn: payload["percentageNGn"], + pump: PumpResource.from_api(payload["pump"]), + starting_amount: payload["startingAmount"], + state_buyer: payload["stateBuyer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/government_purchase_entity_type.rb b/lib/nfe/generated/nf_consumidor_v2/government_purchase_entity_type.rb new file mode 100644 index 0000000..084d113 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/government_purchase_entity_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module GovernmentPurchaseEntityType + Union = "Union" + State = "State" + FederalDistrict = "FederalDistrict" + Municipality = "Municipality" + ALL = [Union, State, FederalDistrict, Municipality].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/government_purchase_operation_type.rb b/lib/nfe/generated/nf_consumidor_v2/government_purchase_operation_type.rb new file mode 100644 index 0000000..ba8079a --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/government_purchase_operation_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module GovernmentPurchaseOperationType + Supply = "Supply" + Payment = "Payment" + SupplyThenPay = "SupplyThenPay" + PayForPastSupply = "PayForPastSupply" + SupplyAfterPay = "SupplyAfterPay" + PayNowSupplyLater = "PayNowSupplyLater" + SupplyAndPayNow = "SupplyAndPayNow" + ALL = [Supply, Payment, SupplyThenPay, PayForPastSupply, SupplyAfterPay, PayNowSupplyLater, SupplyAndPayNow].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/government_purchase_resource.rb b/lib/nfe/generated/nf_consumidor_v2/government_purchase_resource.rb new file mode 100644 index 0000000..1d07231 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/government_purchase_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + GovernmentPurchaseResource = Data.define(:entity_type, :operation_type, :rate_reduction) do + def self.from_api(payload) + return nil if payload.nil? + + new( + entity_type: payload["entityType"], + operation_type: payload["operationType"], + rate_reduction: payload["rateReduction"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/government_purchase_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/government_purchase_tax_resource.rb new file mode 100644 index 0000000..a0f1366 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/government_purchase_tax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + GovernmentPurchaseTaxResource = Data.define(:cbs_amount, :cbs_rate, :municipal_amount, :municipal_rate, :state_amount, :state_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + cbs_rate: payload["cbsRate"], + municipal_amount: payload["municipalAmount"], + municipal_rate: payload["municipalRate"], + state_amount: payload["stateAmount"], + state_rate: payload["stateRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification.rb b/lib/nfe/generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification.rb new file mode 100644 index 0000000..da559db --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module IbsZfmPresumedCreditClassification + NoPresumedCredit = "NoPresumedCredit" + FinalConsumptionGoods = "FinalConsumptionGoods" + CapitalGoods = "CapitalGoods" + IntermediateGoods = "IntermediateGoods" + ItAndOtherGoods = "ItAndOtherGoods" + ALL = [NoPresumedCredit, FinalConsumptionGoods, CapitalGoods, IntermediateGoods, ItAndOtherGoods].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibscbstax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibscbstax_resource.rb new file mode 100644 index 0000000..ccdde49 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibscbstax_resource.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSCBSTaxResource = Data.define(:basis, :calculation_mode, :cbs, :class_code, :credit_reversal, :credit_transfer, :donation_indicator, :government_purchase, :ibs_total_amount, :monophase, :municipal, :operational_presumed_credit, :regular_taxation, :situation_code, :state, :zfm_presumed_credit) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + calculation_mode: payload["calculationMode"], + cbs: CBSTaxResource.from_api(payload["cbs"]), + class_code: payload["classCode"], + credit_reversal: CreditReversalResource.from_api(payload["creditReversal"]), + credit_transfer: CreditTransferTaxResource.from_api(payload["creditTransfer"]), + donation_indicator: payload["donationIndicator"], + government_purchase: GovernmentPurchaseTaxResource.from_api(payload["governmentPurchase"]), + ibs_total_amount: payload["ibsTotalAmount"], + monophase: MonophaseIBSCBSTaxResource.from_api(payload["monophase"]), + municipal: IBSMunicipalTaxResource.from_api(payload["municipal"]), + operational_presumed_credit: OperationalPresumedCreditResource.from_api(payload["operationalPresumedCredit"]), + regular_taxation: RegularTaxationResource.from_api(payload["regularTaxation"]), + situation_code: payload["situationCode"], + state: IBSStateTaxResource.from_api(payload["state"]), + zfm_presumed_credit: ZfmPresumedCreditResource.from_api(payload["zfmPresumedCredit"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibscbstotals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibscbstotals_resource.rb new file mode 100644 index 0000000..2db443d --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibscbstotals_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSCBSTotalsResource = Data.define(:basis, :cbs, :credit_reversal, :ibs, :monophase) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + cbs: CBSTotalsResource.from_api(payload["cbs"]), + credit_reversal: CreditReversalTotalsResource.from_api(payload["creditReversal"]), + ibs: IBSTotalsResource.from_api(payload["ibs"]), + monophase: MonophaseTotalsResource.from_api(payload["monophase"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibsmunicipal_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibsmunicipal_tax_resource.rb new file mode 100644 index 0000000..5abaabd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibsmunicipal_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSMunicipalTaxResource = Data.define(:amount, :deferment, :rate, :reduction, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment: DefermentTaxResource.from_api(payload["deferment"]), + rate: payload["rate"], + reduction: ReductionTaxResource.from_api(payload["reduction"]), + returned_amount: ReturnedTaxResource.from_api(payload["returnedAmount"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibsmunicipal_totals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibsmunicipal_totals_resource.rb new file mode 100644 index 0000000..14e2f21 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibsmunicipal_totals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSMunicipalTotalsResource = Data.define(:amount, :deferment_amount, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment_amount: payload["defermentAmount"], + returned_amount: payload["returnedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibsstate_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibsstate_tax_resource.rb new file mode 100644 index 0000000..ac22185 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibsstate_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSStateTaxResource = Data.define(:amount, :deferment, :rate, :reduction, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment: DefermentTaxResource.from_api(payload["deferment"]), + rate: payload["rate"], + reduction: ReductionTaxResource.from_api(payload["reduction"]), + returned_amount: ReturnedTaxResource.from_api(payload["returnedAmount"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibsstate_totals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibsstate_totals_resource.rb new file mode 100644 index 0000000..783f9dc --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibsstate_totals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSStateTotalsResource = Data.define(:amount, :deferment_amount, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment_amount: payload["defermentAmount"], + returned_amount: payload["returnedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ibstotals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ibstotals_resource.rb new file mode 100644 index 0000000..8c00f44 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ibstotals_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IBSTotalsResource = Data.define(:municipal, :presumed_credit_amount, :presumed_credit_conditional_amount, :state, :total_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + municipal: IBSMunicipalTotalsResource.from_api(payload["municipal"]), + presumed_credit_amount: payload["presumedCreditAmount"], + presumed_credit_conditional_amount: payload["presumedCreditConditionalAmount"], + state: IBSStateTotalsResource.from_api(payload["state"]), + total_amount: payload["totalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/icms_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/icms_tax_resource.rb new file mode 100644 index 0000000..3985e3c --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/icms_tax_resource.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IcmsTaxResource = Data.define(:amount, :amount_operation, :amount_streason, :base_deferred, :base_snretention_amount, :base_stretention_amount, :base_tax, :base_tax_fcpstamount, :base_tax_modality, :base_tax_operation_percentual, :base_tax_reduction, :base_tax_st, :base_tax_stmodality, :base_tax_streduction, :basis_benefit_code, :csosn, :cst, :deduction_indicator, :effective_amount, :effective_base_tax_amount, :effective_base_tax_reduction_rate, :effective_rate, :exempt_amount, :exempt_amount_st, :exempt_reason, :exempt_reason_st, :fcp_amount, :fcp_rate, :fcpst_amount, :fcpst_rate, :fcpst_ret_amount, :fcpst_ret_rate, :origin, :percentual, :percentual_deferment, :rate, :sn_credit_amount, :sn_credit_rate, :sn_retention_amount, :st_amount, :st_final_consumer_rate, :st_margin_added_amount, :st_margin_amount, :st_rate, :st_retention_amount, :substitute_amount, :ufst) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + amount_operation: payload["amountOperation"], + amount_streason: payload["amountSTReason"], + base_deferred: payload["baseDeferred"], + base_snretention_amount: payload["baseSNRetentionAmount"], + base_stretention_amount: payload["baseSTRetentionAmount"], + base_tax: payload["baseTax"], + base_tax_fcpstamount: payload["baseTaxFCPSTAmount"], + base_tax_modality: payload["baseTaxModality"], + base_tax_operation_percentual: payload["baseTaxOperationPercentual"], + base_tax_reduction: payload["baseTaxReduction"], + base_tax_st: payload["baseTaxST"], + base_tax_stmodality: payload["baseTaxSTModality"], + base_tax_streduction: payload["baseTaxSTReduction"], + basis_benefit_code: payload["basisBenefitCode"], + csosn: payload["csosn"], + cst: payload["cst"], + deduction_indicator: payload["deductionIndicator"], + effective_amount: payload["effectiveAmount"], + effective_base_tax_amount: payload["effectiveBaseTaxAmount"], + effective_base_tax_reduction_rate: payload["effectiveBaseTaxReductionRate"], + effective_rate: payload["effectiveRate"], + exempt_amount: payload["exemptAmount"], + exempt_amount_st: payload["exemptAmountST"], + exempt_reason: payload["exemptReason"], + exempt_reason_st: payload["exemptReasonST"], + fcp_amount: payload["fcpAmount"], + fcp_rate: payload["fcpRate"], + fcpst_amount: payload["fcpstAmount"], + fcpst_rate: payload["fcpstRate"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpst_ret_rate: payload["fcpstRetRate"], + origin: payload["origin"], + percentual: payload["percentual"], + percentual_deferment: payload["percentualDeferment"], + rate: payload["rate"], + sn_credit_amount: payload["snCreditAmount"], + sn_credit_rate: payload["snCreditRate"], + sn_retention_amount: payload["snRetentionAmount"], + st_amount: payload["stAmount"], + st_final_consumer_rate: payload["stFinalConsumerRate"], + st_margin_added_amount: payload["stMarginAddedAmount"], + st_margin_amount: payload["stMarginAmount"], + st_rate: payload["stRate"], + st_retention_amount: payload["stRetentionAmount"], + substitute_amount: payload["substituteAmount"], + ufst: payload["ufst"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/icmstotal_resource.rb b/lib/nfe/generated/nf_consumidor_v2/icmstotal_resource.rb new file mode 100644 index 0000000..bd5a41a --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/icmstotal_resource.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ICMSTotalResource = Data.define(:base_tax, :cofins_amount, :discount_amount, :fcp_amount, :fcpst_amount, :fcpst_ret_amount, :fcpuf_destination_amount, :federal_taxes_amount, :freight_amount, :icms_amount, :icms_exempt_amount, :icmsuf_destination_amount, :icmsuf_sender_amount, :ii_amount, :insurance_amount, :invoice_amount, :ipi_amount, :ipi_devol_amount, :others_amount, :pis_amount, :product_amount, :q_bcmono, :q_bcmono_ret, :q_bcmono_reten, :st_amount, :st_calculation_basis_amount, :v_icmsmono, :v_icmsmono_ret, :v_icmsmono_reten) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_tax: payload["baseTax"], + cofins_amount: payload["cofinsAmount"], + discount_amount: payload["discountAmount"], + fcp_amount: payload["fcpAmount"], + fcpst_amount: payload["fcpstAmount"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpuf_destination_amount: payload["fcpufDestinationAmount"], + federal_taxes_amount: payload["federalTaxesAmount"], + freight_amount: payload["freightAmount"], + icms_amount: payload["icmsAmount"], + icms_exempt_amount: payload["icmsExemptAmount"], + icmsuf_destination_amount: payload["icmsufDestinationAmount"], + icmsuf_sender_amount: payload["icmsufSenderAmount"], + ii_amount: payload["iiAmount"], + insurance_amount: payload["insuranceAmount"], + invoice_amount: payload["invoiceAmount"], + ipi_amount: payload["ipiAmount"], + ipi_devol_amount: payload["ipiDevolAmount"], + others_amount: payload["othersAmount"], + pis_amount: payload["pisAmount"], + product_amount: payload["productAmount"], + q_bcmono: payload["qBCMono"], + q_bcmono_ret: payload["qBCMonoRet"], + q_bcmono_reten: payload["qBCMonoReten"], + st_amount: payload["stAmount"], + st_calculation_basis_amount: payload["stCalculationBasisAmount"], + v_icmsmono: payload["vICMSMono"], + v_icmsmono_ret: payload["vICMSMonoRet"], + v_icmsmono_reten: payload["vICMSMonoReten"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/icmsufdestination_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/icmsufdestination_tax_resource.rb new file mode 100644 index 0000000..3af2edd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/icmsufdestination_tax_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ICMSUFDestinationTaxResource = Data.define(:p_fcpufdest, :p_icmsinter, :p_icmsinter_part, :p_icmsufdest, :v_bcfcpufdest, :v_bcufdest, :v_fcpufdest, :v_icmsufdest, :v_icmsufremet) do + def self.from_api(payload) + return nil if payload.nil? + + new( + p_fcpufdest: payload["pFCPUFDest"], + p_icmsinter: payload["pICMSInter"], + p_icmsinter_part: payload["pICMSInterPart"], + p_icmsufdest: payload["pICMSUFDest"], + v_bcfcpufdest: payload["vBCFCPUFDest"], + v_bcufdest: payload["vBCUFDest"], + v_fcpufdest: payload["vFCPUFDest"], + v_icmsufdest: payload["vICMSUFDest"], + v_icmsufremet: payload["vICMSUFRemet"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/iitax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/iitax_resource.rb new file mode 100644 index 0000000..962203a --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/iitax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IITaxResource = Data.define(:amount, :base_tax, :customs_expenditure_amount, :iof_amount, :v_enq_camb) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + customs_expenditure_amount: payload["customsExpenditureAmount"], + iof_amount: payload["iofAmount"], + v_enq_camb: payload["vEnqCamb"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/import_declaration_resource.rb b/lib/nfe/generated/nf_consumidor_v2/import_declaration_resource.rb new file mode 100644 index 0000000..f0652e9 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/import_declaration_resource.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ImportDeclarationResource = Data.define(:acquirer_federal_tax_number, :additions, :afrmm_amount, :code, :customs_clearance_name, :customs_clearance_state, :customs_clearanced_on, :exporter, :intermediation, :international_transport, :registered_on, :state_third) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquirer_federal_tax_number: payload["acquirerFederalTaxNumber"], + additions: (payload["additions"] || []).map { |e| AdditionResource.from_api(e) }, + afrmm_amount: payload["afrmmAmount"], + code: payload["code"], + customs_clearance_name: payload["customsClearanceName"], + customs_clearance_state: payload["customsClearanceState"], + customs_clearanced_on: payload["customsClearancedOn"], + exporter: payload["exporter"], + intermediation: payload["intermediation"], + international_transport: payload["internationalTransport"], + registered_on: payload["registeredOn"], + state_third: payload["stateThird"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/integration_payment_type.rb b/lib/nfe/generated/nf_consumidor_v2/integration_payment_type.rb new file mode 100644 index 0000000..4d0cde6 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/integration_payment_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module IntegrationPaymentType + Integrated = "Integrated" + NotIntegrated = "NotIntegrated" + ALL = [Integrated, NotIntegrated].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/intermediate_resource.rb b/lib/nfe/generated/nf_consumidor_v2/intermediate_resource.rb new file mode 100644 index 0000000..fc278e3 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/intermediate_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IntermediateResource = Data.define(:federal_tax_number, :identifier) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + identifier: payload["identifier"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/intermediation_type.rb b/lib/nfe/generated/nf_consumidor_v2/intermediation_type.rb new file mode 100644 index 0000000..fef00f9 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/intermediation_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module IntermediationType + None = "None" + ByOwn = "ByOwn" + ImportOnBehalf = "ImportOnBehalf" + ByOrder = "ByOrder" + ALL = [None, ByOwn, ImportOnBehalf, ByOrder].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/international_transport_type.rb b/lib/nfe/generated/nf_consumidor_v2/international_transport_type.rb new file mode 100644 index 0000000..25dd0bc --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/international_transport_type.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module InternationalTransportType + None = "None" + Maritime = "Maritime" + River = "River" + Lake = "Lake" + Airline = "Airline" + Postal = "Postal" + Railway = "Railway" + Highway = "Highway" + Network = "Network" + Own = "Own" + Ficta = "Ficta" + Courier = "Courier" + Handcarry = "Handcarry" + ALL = [None, Maritime, River, Lake, Airline, Postal, Railway, Highway, Network, Own, Ficta, Courier, Handcarry].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_events_resource.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_events_resource.rb new file mode 100644 index 0000000..0c7c567 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_events_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceEventsResource = Data.define(:account_id, :company_id, :events, :has_more, :id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + events: (payload["events"] || []).map { |e| ActivityResource.from_api(e) }, + has_more: payload["hasMore"], + id: payload["id"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_events_resource_base.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_events_resource_base.rb new file mode 100644 index 0000000..77e2699 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_events_resource_base.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceEventsResourceBase = Data.define(:events, :has_more) do + def self.from_api(payload) + return nil if payload.nil? + + new( + events: (payload["events"] || []).map { |e| ActivityResource.from_api(e) }, + has_more: payload["hasMore"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_item_resource.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_item_resource.rb new file mode 100644 index 0000000..c45f8bd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_item_resource.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceItemResource = Data.define(:additional_information, :benefit, :cest, :cfop, :code, :code_gtin, :code_tax_gtin, :description, :discount_amount, :export_details, :extipi, :freight_amount, :fuel_detail, :ibs_zfm_presumed_credit_classification, :import_control_sheet_number, :import_declarations, :insurance_amount, :item_amount, :item_number_order_buy, :ncm, :number_order_buy, :nve, :others_amount, :presumed_credit, :quantity, :quantity_tax, :referenced_dfe, :tax, :tax_determination, :tax_unit_amount, :total_amount, :total_indicator, :unit, :unit_amount, :unit_tax, :used_movable_asset_indicator, :vehicle_detail) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + benefit: payload["benefit"], + cest: payload["cest"], + cfop: payload["cfop"], + code: payload["code"], + code_gtin: payload["codeGTIN"], + code_tax_gtin: payload["codeTaxGTIN"], + description: payload["description"], + discount_amount: payload["discountAmount"], + export_details: (payload["exportDetails"] || []).map { |e| ExportDetailResource.from_api(e) }, + extipi: payload["extipi"], + freight_amount: payload["freightAmount"], + fuel_detail: FuelResource.from_api(payload["fuelDetail"]), + ibs_zfm_presumed_credit_classification: payload["ibsZfmPresumedCreditClassification"], + import_control_sheet_number: payload["importControlSheetNumber"], + import_declarations: (payload["importDeclarations"] || []).map { |e| ImportDeclarationResource.from_api(e) }, + insurance_amount: payload["insuranceAmount"], + item_amount: payload["itemAmount"], + item_number_order_buy: payload["itemNumberOrderBuy"], + ncm: payload["ncm"], + number_order_buy: payload["numberOrderBuy"], + nve: payload["nve"], + others_amount: payload["othersAmount"], + presumed_credit: PresumedCreditResource.from_api(payload["presumedCredit"]), + quantity: payload["quantity"], + quantity_tax: payload["quantityTax"], + referenced_dfe: ReferencedDFeResource.from_api(payload["referencedDFe"]), + tax: InvoiceItemTaxResource.from_api(payload["tax"]), + tax_determination: TaxDeterminationResource.from_api(payload["taxDetermination"]), + tax_unit_amount: payload["taxUnitAmount"], + total_amount: payload["totalAmount"], + total_indicator: payload["totalIndicator"], + unit: payload["unit"], + unit_amount: payload["unitAmount"], + unit_tax: payload["unitTax"], + used_movable_asset_indicator: payload["usedMovableAssetIndicator"], + vehicle_detail: VehicleDetailResource.from_api(payload["vehicleDetail"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_item_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_item_tax_resource.rb new file mode 100644 index 0000000..212c3d1 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_item_tax_resource.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceItemTaxResource = Data.define(:ibscbs, :is, :cofins, :competence_adjustment, :icms, :icms_destination, :ii, :ipi, :pis, :total_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ibscbs: IBSCBSTaxResource.from_api(payload["IBSCBS"]), + is: ISTaxResource.from_api(payload["IS"]), + cofins: CofinsTaxResource.from_api(payload["cofins"]), + competence_adjustment: CompetenceAdjustmentResource.from_api(payload["competenceAdjustment"]), + icms: IcmsTaxResource.from_api(payload["icms"]), + icms_destination: ICMSUFDestinationTaxResource.from_api(payload["icmsDestination"]), + ii: IITaxResource.from_api(payload["ii"]), + ipi: IPITaxResource.from_api(payload["ipi"]), + pis: PISTaxResource.from_api(payload["pis"]), + total_tax: payload["totalTax"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_items_resource.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_items_resource.rb new file mode 100644 index 0000000..37006f3 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_items_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceItemsResource = Data.define(:account_id, :company_id, :has_more, :id, :items) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + has_more: payload["hasMore"], + id: payload["id"], + items: (payload["items"] || []).map { |e| InvoiceItemResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_resource.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_resource.rb new file mode 100644 index 0000000..84ed261 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_resource.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceResource = Data.define(:additional_information, :authorization, :billing, :buyer, :contingency_details, :created_on, :delivery, :environment_type, :export, :id, :issuer, :last_events, :modified_on, :number, :operation_nature, :operation_on, :operation_type, :payment, :purpose_type, :serie, :status, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + authorization: AuthorizationResource.from_api(payload["authorization"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + contingency_details: ContingencyDetails.from_api(payload["contingencyDetails"]), + created_on: payload["createdOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + environment_type: payload["environmentType"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerResource.from_api(payload["issuer"]), + last_events: InvoiceEventsResourceBase.from_api(payload["lastEvents"]), + modified_on: payload["modifiedOn"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + purpose_type: payload["purposeType"], + serie: payload["serie"], + status: payload["status"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_status.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_status.rb new file mode 100644 index 0000000..838a71a --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_status.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module InvoiceStatus + None = "None" + Created = "Created" + Processing = "Processing" + Issued = "Issued" + IssuedContingency = "IssuedContingency" + Cancelled = "Cancelled" + Disabled = "Disabled" + IssueDenied = "IssueDenied" + Error = "Error" + ALL = [None, Created, Processing, Issued, IssuedContingency, Cancelled, Disabled, IssueDenied, Error].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/invoice_without_events_resource.rb b/lib/nfe/generated/nf_consumidor_v2/invoice_without_events_resource.rb new file mode 100644 index 0000000..d7bc2d2 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/invoice_without_events_resource.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + InvoiceWithoutEventsResource = Data.define(:additional_information, :authorization, :billing, :buyer, :contingency_details, :created_on, :delivery, :environment_type, :export, :id, :issuer, :modified_on, :number, :operation_nature, :operation_on, :operation_type, :payment, :purpose_type, :serie, :status, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + authorization: AuthorizationResource.from_api(payload["authorization"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + contingency_details: ContingencyDetails.from_api(payload["contingencyDetails"]), + created_on: payload["createdOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + environment_type: payload["environmentType"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerResource.from_api(payload["issuer"]), + modified_on: payload["modifiedOn"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + purpose_type: payload["purposeType"], + serie: payload["serie"], + status: payload["status"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/ipitax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/ipitax_resource.rb new file mode 100644 index 0000000..e1c2c68 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/ipitax_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IPITaxResource = Data.define(:amount, :base, :classification, :classification_code, :cst, :producer_cnpj, :rate, :stamp_code, :stamp_quantity, :unit_amount, :unit_quantity) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base: payload["base"], + classification: payload["classification"], + classification_code: payload["classificationCode"], + cst: payload["cst"], + producer_cnpj: payload["producerCNPJ"], + rate: payload["rate"], + stamp_code: payload["stampCode"], + stamp_quantity: payload["stampQuantity"], + unit_amount: payload["unitAmount"], + unit_quantity: payload["unitQuantity"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/issqntotal_resource.rb b/lib/nfe/generated/nf_consumidor_v2/issqntotal_resource.rb new file mode 100644 index 0000000..0b05e8c --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/issqntotal_resource.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ISSQNTotalResource = Data.define(:base_rate_iss, :code_tax_regime, :deduction_reduction_bc, :discount_conditioning, :discount_unconditional, :provision_service, :total_iss, :total_retention_iss, :total_service_not_taxed_icms, :value_other_retention, :value_service_cofins, :value_service_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_rate_iss: payload["baseRateISS"], + code_tax_regime: payload["codeTaxRegime"], + deduction_reduction_bc: payload["deductionReductionBC"], + discount_conditioning: payload["discountConditioning"], + discount_unconditional: payload["discountUnconditional"], + provision_service: payload["provisionService"], + total_iss: payload["totalISS"], + total_retention_iss: payload["totalRetentionISS"], + total_service_not_taxed_icms: payload["totalServiceNotTaxedICMS"], + value_other_retention: payload["valueOtherRetention"], + value_service_cofins: payload["valueServiceCOFINS"], + value_service_pis: payload["valueServicePIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/issuer_from_request_resource.rb b/lib/nfe/generated/nf_consumidor_v2/issuer_from_request_resource.rb new file mode 100644 index 0000000..cb53748 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/issuer_from_request_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IssuerFromRequestResource = Data.define(:st_state_tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + st_state_tax_number: payload["stStateTaxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/issuer_resource.rb b/lib/nfe/generated/nf_consumidor_v2/issuer_resource.rb new file mode 100644 index 0000000..b5b032b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/issuer_resource.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + IssuerResource = Data.define(:account_id, :address, :company_registry_number, :economic_activities, :email, :federal_tax_number, :id, :legal_nature, :municipal_tax_number, :name, :openning_date, :regional_sttax_number, :regional_tax_number, :special_tax_regime, :st_state_tax_number, :tax_regime, :trade_name, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + company_registry_number: payload["companyRegistryNumber"], + economic_activities: (payload["economicActivities"] || []).map { |e| EconomicActivityResource.from_api(e) }, + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + legal_nature: payload["legalNature"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + openning_date: payload["openningDate"], + regional_sttax_number: payload["regionalSTTaxNumber"], + regional_tax_number: payload["regionalTaxNumber"], + special_tax_regime: payload["specialTaxRegime"], + st_state_tax_number: payload["stStateTaxNumber"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/istax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/istax_resource.rb new file mode 100644 index 0000000..924ea53 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/istax_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ISTaxResource = Data.define(:amount, :basis, :classification_code, :quantity, :rate, :situation_code, :unit, :unit_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + basis: payload["basis"], + classification_code: payload["classificationCode"], + quantity: payload["quantity"], + rate: payload["rate"], + situation_code: payload["situationCode"], + unit: payload["unit"], + unit_rate: payload["unitRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/istotals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/istotals_resource.rb new file mode 100644 index 0000000..1f637d5 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/istotals_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ISTotalsResource = Data.define(:amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/legal_nature.rb b/lib/nfe/generated/nf_consumidor_v2/legal_nature.rb new file mode 100644 index 0000000..d52b19d --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/legal_nature.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module LegalNature + EmpresaPublica = "EmpresaPublica" + SociedadeEconomiaMista = "SociedadeEconomiaMista" + SociedadeAnonimaAberta = "SociedadeAnonimaAberta" + SociedadeAnonimaFechada = "SociedadeAnonimaFechada" + SociedadeEmpresariaLimitada = "SociedadeEmpresariaLimitada" + SociedadeEmpresariaEmNomeColetivo = "SociedadeEmpresariaEmNomeColetivo" + SociedadeEmpresariaEmComanditaSimples = "SociedadeEmpresariaEmComanditaSimples" + SociedadeEmpresariaEmComanditaporAcoes = "SociedadeEmpresariaEmComanditaporAcoes" + SociedadeemContaParticipacao = "SociedadeemContaParticipacao" + Empresario = "Empresario" + Cooperativa = "Cooperativa" + ConsorcioSociedades = "ConsorcioSociedades" + GrupoSociedades = "GrupoSociedades" + EmpresaDomiciliadaExterior = "EmpresaDomiciliadaExterior" + ClubeFundoInvestimento = "ClubeFundoInvestimento" + SociedadeSimplesPura = "SociedadeSimplesPura" + SociedadeSimplesLimitada = "SociedadeSimplesLimitada" + SociedadeSimplesEmNomeColetivo = "SociedadeSimplesEmNomeColetivo" + SociedadeSimplesEmComanditaSimples = "SociedadeSimplesEmComanditaSimples" + EmpresaBinacional = "EmpresaBinacional" + ConsorcioEmpregadores = "ConsorcioEmpregadores" + ConsorcioSimples = "ConsorcioSimples" + EireliNaturezaEmpresaria = "EireliNaturezaEmpresaria" + EireliNaturezaSimples = "EireliNaturezaSimples" + ServicoNotarial = "ServicoNotarial" + FundacaoPrivada = "FundacaoPrivada" + ServicoSocialAutonomo = "ServicoSocialAutonomo" + CondominioEdilicio = "CondominioEdilicio" + ComissaoConciliacaoPrevia = "ComissaoConciliacaoPrevia" + EntidadeMediacaoArbitragem = "EntidadeMediacaoArbitragem" + PartidoPolitico = "PartidoPolitico" + EntidadeSindical = "EntidadeSindical" + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras = "EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras" + FundacaoAssociacaoDomiciliadaExterior = "FundacaoAssociacaoDomiciliadaExterior" + OrganizacaoReligiosa = "OrganizacaoReligiosa" + ComunidadeIndigena = "ComunidadeIndigena" + FundoPrivado = "FundoPrivado" + AssociacaoPrivada = "AssociacaoPrivada" + ALL = [EmpresaPublica, SociedadeEconomiaMista, SociedadeAnonimaAberta, SociedadeAnonimaFechada, SociedadeEmpresariaLimitada, SociedadeEmpresariaEmNomeColetivo, SociedadeEmpresariaEmComanditaSimples, SociedadeEmpresariaEmComanditaporAcoes, SociedadeemContaParticipacao, Empresario, Cooperativa, ConsorcioSociedades, GrupoSociedades, EmpresaDomiciliadaExterior, ClubeFundoInvestimento, SociedadeSimplesPura, SociedadeSimplesLimitada, SociedadeSimplesEmNomeColetivo, SociedadeSimplesEmComanditaSimples, EmpresaBinacional, ConsorcioEmpregadores, ConsorcioSimples, EireliNaturezaEmpresaria, EireliNaturezaSimples, ServicoNotarial, FundacaoPrivada, ServicoSocialAutonomo, CondominioEdilicio, ComissaoConciliacaoPrevia, EntidadeMediacaoArbitragem, PartidoPolitico, EntidadeSindical, EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras, FundacaoAssociacaoDomiciliadaExterior, OrganizacaoReligiosa, ComunidadeIndigena, FundoPrivado, AssociacaoPrivada].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_cbstotals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_cbstotals_resource.rb new file mode 100644 index 0000000..cc1bf6b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_cbstotals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseCBSTotalsResource = Data.define(:amount, :previously_withheld_amount, :withheld_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + previously_withheld_amount: payload["previouslyWithheldAmount"], + withheld_amount: payload["withheldAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_deferment_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_deferment_tax_resource.rb new file mode 100644 index 0000000..3e613e8 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_deferment_tax_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseDefermentTaxResource = Data.define(:cbs_amount, :cbs_rate, :ibs_amount, :ibs_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + cbs_rate: payload["cbsRate"], + ibs_amount: payload["ibsAmount"], + ibs_rate: payload["ibsRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_ibscbstax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_ibscbstax_resource.rb new file mode 100644 index 0000000..84e6942 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_ibscbstax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseIBSCBSTaxResource = Data.define(:cbs_amount, :deferment, :ibs_amount, :previously_withheld, :standart, :withholding) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + deferment: MonophaseDefermentTaxResource.from_api(payload["deferment"]), + ibs_amount: payload["ibsAmount"], + previously_withheld: MonophasePreviouslyWithheldTaxResource.from_api(payload["previouslyWithheld"]), + standart: MonophaseStandardTaxResource.from_api(payload["standart"]), + withholding: MonophaseWithholdingTaxResource.from_api(payload["withholding"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_ibstotals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_ibstotals_resource.rb new file mode 100644 index 0000000..84230e9 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_ibstotals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseIBSTotalsResource = Data.define(:amount, :previously_withheld_amount, :withheld_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + previously_withheld_amount: payload["previouslyWithheldAmount"], + withheld_amount: payload["withheldAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource.rb new file mode 100644 index 0000000..e26c4ea --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophasePreviouslyWithheldTaxResource = Data.define(:cbs_ad_rem_rate, :cbs_amount, :ibs_ad_rem_rate, :ibs_amount, :quantity_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_ad_rem_rate: payload["cbsAdRemRate"], + cbs_amount: payload["cbsAmount"], + ibs_ad_rem_rate: payload["ibsAdRemRate"], + ibs_amount: payload["ibsAmount"], + quantity_basis: payload["quantityBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_standard_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_standard_tax_resource.rb new file mode 100644 index 0000000..a6551af --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_standard_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseStandardTaxResource = Data.define(:cbs_ad_rem_rate, :cbs_amount, :ibs_ad_rem_rate, :ibs_amount, :quantity_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_ad_rem_rate: payload["cbsAdRemRate"], + cbs_amount: payload["cbsAmount"], + ibs_ad_rem_rate: payload["ibsAdRemRate"], + ibs_amount: payload["ibsAmount"], + quantity_basis: payload["quantityBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_totals_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_totals_resource.rb new file mode 100644 index 0000000..bbbbc6b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_totals_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseTotalsResource = Data.define(:cbs, :ibs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs: MonophaseCBSTotalsResource.from_api(payload["cbs"]), + ibs: MonophaseIBSTotalsResource.from_api(payload["ibs"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/monophase_withholding_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/monophase_withholding_tax_resource.rb new file mode 100644 index 0000000..1762e81 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/monophase_withholding_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + MonophaseWithholdingTaxResource = Data.define(:cbs_ad_rem_rate, :cbs_amount, :ibs_ad_rem_rate, :ibs_amount, :quantity_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_ad_rem_rate: payload["cbsAdRemRate"], + cbs_amount: payload["cbsAmount"], + ibs_ad_rem_rate: payload["ibsAdRemRate"], + ibs_amount: payload["ibsAmount"], + quantity_basis: payload["quantityBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/operation_type.rb b/lib/nfe/generated/nf_consumidor_v2/operation_type.rb new file mode 100644 index 0000000..a4ebd41 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/operation_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module OperationType + Outgoing = "Outgoing" + Incoming = "Incoming" + ALL = [Outgoing, Incoming].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/operational_presumed_credit_resource.rb b/lib/nfe/generated/nf_consumidor_v2/operational_presumed_credit_resource.rb new file mode 100644 index 0000000..3b842ab --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/operational_presumed_credit_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + OperationalPresumedCreditResource = Data.define(:basis, :cbs, :classification_code, :ibs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + cbs: PresumedCreditDetailsResource.from_api(payload["cbs"]), + classification_code: payload["classificationCode"], + ibs: PresumedCreditDetailsResource.from_api(payload["ibs"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/payment_detail_resource.rb b/lib/nfe/generated/nf_consumidor_v2/payment_detail_resource.rb new file mode 100644 index 0000000..749f939 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/payment_detail_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + PaymentDetailResource = Data.define(:amount, :card, :federal_tax_number_pag, :method, :method_description, :payment_date, :payment_type, :state_pag) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + card: CardResource.from_api(payload["card"]), + federal_tax_number_pag: payload["federalTaxNumberPag"], + method: payload["method"], + method_description: payload["methodDescription"], + payment_date: payload["paymentDate"], + payment_type: payload["paymentType"], + state_pag: payload["statePag"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/payment_method.rb b/lib/nfe/generated/nf_consumidor_v2/payment_method.rb new file mode 100644 index 0000000..f875db6 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/payment_method.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PaymentMethod + Cash = "Cash" + Cheque = "Cheque" + CreditCard = "CreditCard" + DebitCard = "DebitCard" + StoreCredict = "StoreCredict" + FoodVouchers = "FoodVouchers" + MealVouchers = "MealVouchers" + GiftVouchers = "GiftVouchers" + FuelVouchers = "FuelVouchers" + BankBill = "BankBill" + BankDeposit = "BankDeposit" + InstantPayment = "InstantPayment" + WireTransfer = "WireTransfer" + Cashback = "Cashback" + StaticInstantPayment = "StaticInstantPayment" + StoreCredit = "StoreCredit" + ElectronicPaymentNotInformed = "ElectronicPaymentNotInformed" + WithoutPayment = "WithoutPayment" + Others = "Others" + ALL = [Cash, Cheque, CreditCard, DebitCard, StoreCredict, FoodVouchers, MealVouchers, GiftVouchers, FuelVouchers, BankBill, BankDeposit, InstantPayment, WireTransfer, Cashback, StaticInstantPayment, StoreCredit, ElectronicPaymentNotInformed, WithoutPayment, Others].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/payment_resource.rb b/lib/nfe/generated/nf_consumidor_v2/payment_resource.rb new file mode 100644 index 0000000..3c52550 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/payment_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + PaymentResource = Data.define(:pay_back, :payment_detail) do + def self.from_api(payload) + return nil if payload.nil? + + new( + pay_back: payload["payBack"], + payment_detail: (payload["paymentDetail"] || []).map { |e| PaymentDetailResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/payment_type.rb b/lib/nfe/generated/nf_consumidor_v2/payment_type.rb new file mode 100644 index 0000000..1977626 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/payment_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PaymentType + InCash = "InCash" + Term = "Term" + ALL = [InCash, Term].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/person_type.rb b/lib/nfe/generated/nf_consumidor_v2/person_type.rb new file mode 100644 index 0000000..8e7cdfd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/person_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PersonType + Undefined = "Undefined" + NaturalPerson = "NaturalPerson" + LegalEntity = "LegalEntity" + Company = "Company" + Customer = "Customer" + ALL = [Undefined, NaturalPerson, LegalEntity, Company, Customer].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/pistax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/pistax_resource.rb new file mode 100644 index 0000000..3030cc5 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/pistax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + PISTaxResource = Data.define(:amount, :base_tax, :base_tax_product_quantity, :cst, :product_rate, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + base_tax_product_quantity: payload["baseTaxProductQuantity"], + cst: payload["cst"], + product_rate: payload["productRate"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/presumed_credit_classification_code.rb b/lib/nfe/generated/nf_consumidor_v2/presumed_credit_classification_code.rb new file mode 100644 index 0000000..774e0d7 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/presumed_credit_classification_code.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PresumedCreditClassificationCode + RuralProducerNonTaxpayer = "RuralProducerNonTaxpayer" + TacPfTransportServiceNonTaxpayer = "TacPfTransportServiceNonTaxpayer" + RecyclingFromIndividual = "RecyclingFromIndividual" + UsedMovableGoodsFromIndividualForResale = "UsedMovableGoodsFromIndividualForResale" + OptionalRegimeForCooperative = "OptionalRegimeForCooperative" + ALL = [RuralProducerNonTaxpayer, TacPfTransportServiceNonTaxpayer, RecyclingFromIndividual, UsedMovableGoodsFromIndividualForResale, OptionalRegimeForCooperative].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/presumed_credit_details_resource.rb b/lib/nfe/generated/nf_consumidor_v2/presumed_credit_details_resource.rb new file mode 100644 index 0000000..2540877 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/presumed_credit_details_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + PresumedCreditDetailsResource = Data.define(:amount, :rate, :suspensive_condition_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + rate: payload["rate"], + suspensive_condition_amount: payload["suspensiveConditionAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/presumed_credit_resource.rb b/lib/nfe/generated/nf_consumidor_v2/presumed_credit_resource.rb new file mode 100644 index 0000000..17d15d0 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/presumed_credit_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + PresumedCreditResource = Data.define(:amount, :code, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + code: payload["code"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/print_type.rb b/lib/nfe/generated/nf_consumidor_v2/print_type.rb new file mode 100644 index 0000000..eec2b39 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/print_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PrintType + None = "None" + NFeNormalPortrait = "NFeNormalPortrait" + NFeNormalLandscape = "NFeNormalLandscape" + NFeSimplified = "NFeSimplified" + DANFENFCE = "DANFE_NFC_E" + DANFENFCEMSGELETRONICA = "DANFE_NFC_E_MSG_ELETRONICA" + ALL = [None, NFeNormalPortrait, NFeNormalLandscape, NFeSimplified, DANFENFCE, DANFENFCEMSGELETRONICA].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/pump_resource.rb b/lib/nfe/generated/nf_consumidor_v2/pump_resource.rb new file mode 100644 index 0000000..184f945 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/pump_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + PumpResource = Data.define(:beginning_amount, :end_amount, :number, :percentage_bio, :spout_number, :tank_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + beginning_amount: payload["beginningAmount"], + end_amount: payload["endAmount"], + number: payload["number"], + percentage_bio: payload["percentageBio"], + spout_number: payload["spoutNumber"], + tank_number: payload["tankNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/purpose_type.rb b/lib/nfe/generated/nf_consumidor_v2/purpose_type.rb new file mode 100644 index 0000000..2f07207 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/purpose_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PurposeType + None = "None" + Normal = "Normal" + Complement = "Complement" + Adjustment = "Adjustment" + Devolution = "Devolution" + ALL = [None, Normal, Complement, Adjustment, Devolution].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/reboque_resource.rb b/lib/nfe/generated/nf_consumidor_v2/reboque_resource.rb new file mode 100644 index 0000000..570f7ea --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/reboque_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ReboqueResource = Data.define(:ferry, :plate, :rntc, :uf, :wagon) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ferry: payload["ferry"], + plate: payload["plate"], + rntc: payload["rntc"], + uf: payload["uf"], + wagon: payload["wagon"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/receiver_state_tax_indicator.rb b/lib/nfe/generated/nf_consumidor_v2/receiver_state_tax_indicator.rb new file mode 100644 index 0000000..832f7a7 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/receiver_state_tax_indicator.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ReceiverStateTaxIndicator + None = "None" + TaxPayer = "TaxPayer" + Exempt = "Exempt" + NonTaxPayer = "NonTaxPayer" + ALL = [None, TaxPayer, Exempt, NonTaxPayer].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/reduction_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/reduction_tax_resource.rb new file mode 100644 index 0000000..80328be --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/reduction_tax_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ReductionTaxResource = Data.define(:effective_rate, :rate_reduction) do + def self.from_api(payload) + return nil if payload.nil? + + new( + effective_rate: payload["effectiveRate"], + rate_reduction: payload["rateReduction"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/referenced_dfe_resource.rb b/lib/nfe/generated/nf_consumidor_v2/referenced_dfe_resource.rb new file mode 100644 index 0000000..1b3dcdf --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/referenced_dfe_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ReferencedDFeResource = Data.define(:access_key, :item_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + item_number: payload["itemNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/referenced_process_resource.rb b/lib/nfe/generated/nf_consumidor_v2/referenced_process_resource.rb new file mode 100644 index 0000000..f4a1577 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/referenced_process_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ReferencedProcessResource = Data.define(:concession_act_type, :identifier_concessory, :identifier_origin) do + def self.from_api(payload) + return nil if payload.nil? + + new( + concession_act_type: payload["concessionActType"], + identifier_concessory: payload["identifierConcessory"], + identifier_origin: payload["identifierOrigin"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/regular_taxation_resource.rb b/lib/nfe/generated/nf_consumidor_v2/regular_taxation_resource.rb new file mode 100644 index 0000000..24f062c --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/regular_taxation_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + RegularTaxationResource = Data.define(:amount, :cbs_amount, :cbs_effective_rate, :class_code, :municipal_amount, :municipal_effective_rate, :situation_code, :state_effective_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + cbs_amount: payload["cbsAmount"], + cbs_effective_rate: payload["cbsEffectiveRate"], + class_code: payload["classCode"], + municipal_amount: payload["municipalAmount"], + municipal_effective_rate: payload["municipalEffectiveRate"], + situation_code: payload["situationCode"], + state_effective_rate: payload["stateEffectiveRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/request_cancellation_resource.rb b/lib/nfe/generated/nf_consumidor_v2/request_cancellation_resource.rb new file mode 100644 index 0000000..db7c3db --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/request_cancellation_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + RequestCancellationResource = Data.define(:account_id, :company_id, :product_invoice_id, :reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + product_invoice_id: payload["productInvoiceId"], + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/returned_tax_resource.rb b/lib/nfe/generated/nf_consumidor_v2/returned_tax_resource.rb new file mode 100644 index 0000000..c47a296 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/returned_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ReturnedTaxResource = Data.define(:amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/shipping_modality.rb b/lib/nfe/generated/nf_consumidor_v2/shipping_modality.rb new file mode 100644 index 0000000..1d176fd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/shipping_modality.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ShippingModality + ByIssuer = "ByIssuer" + ByReceiver = "ByReceiver" + ByThirdParties = "ByThirdParties" + OwnBySender = "OwnBySender" + OwnByBuyer = "OwnByBuyer" + Free = "Free" + ALL = [ByIssuer, ByReceiver, ByThirdParties, OwnBySender, OwnByBuyer, Free].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/special_tax_regime.rb b/lib/nfe/generated/nf_consumidor_v2/special_tax_regime.rb new file mode 100644 index 0000000..b26a698 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/special_tax_regime.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module SpecialTaxRegime + Nenhum = "Nenhum" + MicroempresaMunicipal = "MicroempresaMunicipal" + Estimativa = "Estimativa" + SociedadeDeProfissionais = "SociedadeDeProfissionais" + Cooperativa = "Cooperativa" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + MicroempresarioEmpresaPequenoPorte = "MicroempresarioEmpresaPequenoPorte" + Automatico = "Automatico" + ALL = [Nenhum, MicroempresaMunicipal, Estimativa, SociedadeDeProfissionais, Cooperativa, MicroempreendedorIndividual, MicroempresarioEmpresaPequenoPorte, Automatico].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/state_code.rb b/lib/nfe/generated/nf_consumidor_v2/state_code.rb new file mode 100644 index 0000000..585be5b --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/state_code.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module StateCode + NA = "NA" + RO = "RO" + AC = "AC" + AM = "AM" + RR = "RR" + PA = "PA" + AP = "AP" + TO = "TO" + MA = "MA" + PI = "PI" + CE = "CE" + RN = "RN" + PB = "PB" + PE = "PE" + AL = "AL" + SE = "SE" + BA = "BA" + MG = "MG" + ES = "ES" + RJ = "RJ" + SP = "SP" + PR = "PR" + SC = "SC" + RS = "RS" + MS = "MS" + MT = "MT" + GO = "GO" + DF = "DF" + EX = "EX" + ALL = [NA, RO, AC, AM, RR, PA, AP, TO, MA, PI, CE, RN, PB, PE, AL, SE, BA, MG, ES, RJ, SP, PR, SC, RS, MS, MT, GO, DF, EX].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/state_tax_processing_authorizer.rb b/lib/nfe/generated/nf_consumidor_v2/state_tax_processing_authorizer.rb new file mode 100644 index 0000000..7f76dcc --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/state_tax_processing_authorizer.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module StateTaxProcessingAuthorizer + Normal = "Normal" + EPEC = "EPEC" + ALL = [Normal, EPEC].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/tax_coupon_information_resource.rb b/lib/nfe/generated/nf_consumidor_v2/tax_coupon_information_resource.rb new file mode 100644 index 0000000..4a45047 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/tax_coupon_information_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TaxCouponInformationResource = Data.define(:model_document_fiscal, :order_count_operation, :order_ecf) do + def self.from_api(payload) + return nil if payload.nil? + + new( + model_document_fiscal: payload["modelDocumentFiscal"], + order_count_operation: payload["orderCountOperation"], + order_ecf: payload["orderECF"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/tax_determination_resource.rb b/lib/nfe/generated/nf_consumidor_v2/tax_determination_resource.rb new file mode 100644 index 0000000..f9df058 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/tax_determination_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TaxDeterminationResource = Data.define(:acquisition_purpose, :buyer_tax_profile, :issuer_tax_profile, :operation_code, :origin) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquisition_purpose: payload["acquisitionPurpose"], + buyer_tax_profile: payload["buyerTaxProfile"], + issuer_tax_profile: payload["issuerTaxProfile"], + operation_code: payload["operationCode"], + origin: payload["origin"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/tax_documents_reference_resource.rb b/lib/nfe/generated/nf_consumidor_v2/tax_documents_reference_resource.rb new file mode 100644 index 0000000..a30df8f --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/tax_documents_reference_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TaxDocumentsReferenceResource = Data.define(:document_electronic_invoice, :document_invoice_reference, :tax_coupon_information) do + def self.from_api(payload) + return nil if payload.nil? + + new( + document_electronic_invoice: DocumentElectronicInvoiceResource.from_api(payload["documentElectronicInvoice"]), + document_invoice_reference: DocumentInvoiceReferenceResource.from_api(payload["documentInvoiceReference"]), + tax_coupon_information: TaxCouponInformationResource.from_api(payload["taxCouponInformation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/tax_regime.rb b/lib/nfe/generated/nf_consumidor_v2/tax_regime.rb new file mode 100644 index 0000000..6f7922c --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/tax_regime.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module TaxRegime + None = "None" + LucroReal = "LucroReal" + LucroPresumido = "LucroPresumido" + SimplesNacional = "SimplesNacional" + SimplesNacionalExcessoSublimite = "SimplesNacionalExcessoSublimite" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + Isento = "Isento" + ALL = [None, LucroReal, LucroPresumido, SimplesNacional, SimplesNacionalExcessoSublimite, MicroempreendedorIndividual, Isento].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/taxpayer_comments_resource.rb b/lib/nfe/generated/nf_consumidor_v2/taxpayer_comments_resource.rb new file mode 100644 index 0000000..3a917c2 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/taxpayer_comments_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TaxpayerCommentsResource = Data.define(:field, :text) do + def self.from_api(payload) + return nil if payload.nil? + + new( + field: payload["field"], + text: payload["text"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/total_resource.rb b/lib/nfe/generated/nf_consumidor_v2/total_resource.rb new file mode 100644 index 0000000..daf10ab --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/total_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TotalResource = Data.define(:ibs_cbs_totals, :icms, :is_totals, :issqn, :total_invoice_amount, :withheld_taxes) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ibs_cbs_totals: IBSCBSTotalsResource.from_api(payload["ibsCbsTotals"]), + icms: ICMSTotalResource.from_api(payload["icms"]), + is_totals: ISTotalsResource.from_api(payload["isTotals"]), + issqn: ISSQNTotalResource.from_api(payload["issqn"]), + total_invoice_amount: payload["totalInvoiceAmount"], + withheld_taxes: TotalsWithholdings.from_api(payload["withheldTaxes"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/totals_withholdings.rb b/lib/nfe/generated/nf_consumidor_v2/totals_withholdings.rb new file mode 100644 index 0000000..9c286a9 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/totals_withholdings.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TotalsWithholdings = Data.define(:cofins_amount, :csll_amount, :irrf_amount, :irrf_basis, :pis_amount, :social_secutiry_amount, :social_secutiry_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cofins_amount: payload["cofinsAmount"], + csll_amount: payload["csllAmount"], + irrf_amount: payload["irrfAmount"], + irrf_basis: payload["irrfBasis"], + pis_amount: payload["pisAmount"], + social_secutiry_amount: payload["socialSecutiryAmount"], + social_secutiry_basis: payload["socialSecutiryBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/transport_group_resource.rb b/lib/nfe/generated/nf_consumidor_v2/transport_group_resource.rb new file mode 100644 index 0000000..c963b10 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/transport_group_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TransportGroupResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :transport_retention, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + transport_retention: payload["transportRetention"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/transport_information_resource.rb b/lib/nfe/generated/nf_consumidor_v2/transport_information_resource.rb new file mode 100644 index 0000000..acdb66f --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/transport_information_resource.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TransportInformationResource = Data.define(:freight_modality, :reboque, :seal_number, :transp_rate, :transport_group, :transport_vehicle, :volume) do + def self.from_api(payload) + return nil if payload.nil? + + new( + freight_modality: payload["freightModality"], + reboque: ReboqueResource.from_api(payload["reboque"]), + seal_number: payload["sealNumber"], + transp_rate: TransportRateResource.from_api(payload["transpRate"]), + transport_group: TransportGroupResource.from_api(payload["transportGroup"]), + transport_vehicle: TransportVehicleResource.from_api(payload["transportVehicle"]), + volume: VolumeResource.from_api(payload["volume"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/transport_rate_resource.rb b/lib/nfe/generated/nf_consumidor_v2/transport_rate_resource.rb new file mode 100644 index 0000000..c0906dd --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/transport_rate_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TransportRateResource = Data.define(:bc_retention_amount, :cfop, :city_generator_fact_code, :icms_retention_amount, :icms_retention_rate, :service_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bc_retention_amount: payload["bcRetentionAmount"], + cfop: payload["cfop"], + city_generator_fact_code: payload["cityGeneratorFactCode"], + icms_retention_amount: payload["icmsRetentionAmount"], + icms_retention_rate: payload["icmsRetentionRate"], + service_amount: payload["serviceAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/transport_vehicle_resource.rb b/lib/nfe/generated/nf_consumidor_v2/transport_vehicle_resource.rb new file mode 100644 index 0000000..d388130 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/transport_vehicle_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + TransportVehicleResource = Data.define(:plate, :rntc, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + plate: payload["plate"], + rntc: payload["rntc"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/vehicle_detail_resource.rb b/lib/nfe/generated/nf_consumidor_v2/vehicle_detail_resource.rb new file mode 100644 index 0000000..e38b672 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/vehicle_detail_resource.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + VehicleDetailResource = Data.define(:brand_model_code, :chassis, :color_code, :color_description, :denatran_color_code, :engine_displacement, :engine_number, :engine_power, :fuel_type, :gross_weight, :manufacture_year, :maximum_traction_capacity, :model_year, :net_weight, :operation_type, :paint_type, :restriction_type, :seating_capacity, :serial_number, :vehicle_condition, :vehicle_species, :vehicle_type, :vin_condition, :wheel_base) do + def self.from_api(payload) + return nil if payload.nil? + + new( + brand_model_code: payload["brandModelCode"], + chassis: payload["chassis"], + color_code: payload["colorCode"], + color_description: payload["colorDescription"], + denatran_color_code: payload["denatranColorCode"], + engine_displacement: payload["engineDisplacement"], + engine_number: payload["engineNumber"], + engine_power: payload["enginePower"], + fuel_type: payload["fuelType"], + gross_weight: payload["grossWeight"], + manufacture_year: payload["manufactureYear"], + maximum_traction_capacity: payload["maximumTractionCapacity"], + model_year: payload["modelYear"], + net_weight: payload["netWeight"], + operation_type: payload["operationType"], + paint_type: payload["paintType"], + restriction_type: payload["restrictionType"], + seating_capacity: payload["seatingCapacity"], + serial_number: payload["serialNumber"], + vehicle_condition: payload["vehicleCondition"], + vehicle_species: payload["vehicleSpecies"], + vehicle_type: payload["vehicleType"], + vin_condition: payload["vinCondition"], + wheel_base: payload["wheelBase"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/volume_resource.rb b/lib/nfe/generated/nf_consumidor_v2/volume_resource.rb new file mode 100644 index 0000000..9eb1217 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/volume_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + VolumeResource = Data.define(:brand, :gross_weight, :net_weight, :species, :volume_numeration, :volume_quantity) do + def self.from_api(payload) + return nil if payload.nil? + + new( + brand: payload["brand"], + gross_weight: payload["grossWeight"], + net_weight: payload["netWeight"], + species: payload["species"], + volume_numeration: payload["volumeNumeration"], + volume_quantity: payload["volumeQuantity"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/withdrawal_information_resource.rb b/lib/nfe/generated/nf_consumidor_v2/withdrawal_information_resource.rb new file mode 100644 index 0000000..81df7a1 --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/withdrawal_information_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + WithdrawalInformationResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_consumidor_v2/zfm_presumed_credit_resource.rb b/lib/nfe/generated/nf_consumidor_v2/zfm_presumed_credit_resource.rb new file mode 100644 index 0000000..7a88faf --- /dev/null +++ b/lib/nfe/generated/nf_consumidor_v2/zfm_presumed_credit_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + ZfmPresumedCreditResource = Data.define(:amount, :classification_code) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + classification_code: payload["classificationCode"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/activity_resource.rb b/lib/nfe/generated/nf_produto_v2/activity_resource.rb new file mode 100644 index 0000000..ba97148 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/activity_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ActivityResource = Data.define(:data, :sequence, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + data: payload["data"], + sequence: payload["sequence"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/addition_resource.rb b/lib/nfe/generated/nf_produto_v2/addition_resource.rb new file mode 100644 index 0000000..93b4ebf --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/addition_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + AdditionResource = Data.define(:amount, :code, :drawback, :manufacturer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + code: payload["code"], + drawback: payload["drawback"], + manufacturer: payload["manufacturer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/additional_information_resource.rb b/lib/nfe/generated/nf_produto_v2/additional_information_resource.rb new file mode 100644 index 0000000..2acaa8b --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/additional_information_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + AdditionalInformationResource = Data.define(:contract, :effort, :fisco, :order, :referenced_process, :tax_documents_reference, :taxpayer, :taxpayer_comments, :xml_authorized) do + def self.from_api(payload) + return nil if payload.nil? + + new( + contract: payload["contract"], + effort: payload["effort"], + fisco: payload["fisco"], + order: payload["order"], + referenced_process: (payload["referencedProcess"] || []).map { |e| ReferencedProcessResource.from_api(e) }, + tax_documents_reference: (payload["taxDocumentsReference"] || []).map { |e| TaxDocumentsReferenceResource.from_api(e) }, + taxpayer: payload["taxpayer"], + taxpayer_comments: (payload["taxpayerComments"] || []).map { |e| TaxpayerCommentsResource.from_api(e) }, + xml_authorized: payload["xmlAuthorized"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/address_resource.rb b/lib/nfe/generated/nf_produto_v2/address_resource.rb new file mode 100644 index 0000000..63e8070 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/address_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + AddressResource = Data.define(:additional_information, :city, :country, :district, :number, :phone, :postal_code, :state, :street) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + city: CityResource.from_api(payload["city"]), + country: payload["country"], + district: payload["district"], + number: payload["number"], + phone: payload["phone"], + postal_code: payload["postalCode"], + state: payload["state"], + street: payload["street"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/authorization_resource.rb b/lib/nfe/generated/nf_produto_v2/authorization_resource.rb new file mode 100644 index 0000000..ab7cbba --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/authorization_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + AuthorizationResource = Data.define(:access_key, :message, :receipt_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + message: payload["message"], + receipt_on: payload["receiptOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/bill_resource.rb b/lib/nfe/generated/nf_produto_v2/bill_resource.rb new file mode 100644 index 0000000..391bec8 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/bill_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + BillResource = Data.define(:discount_amount, :net_amount, :number, :original_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + discount_amount: payload["discountAmount"], + net_amount: payload["netAmount"], + number: payload["number"], + original_amount: payload["originalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/billing_resource.rb b/lib/nfe/generated/nf_produto_v2/billing_resource.rb new file mode 100644 index 0000000..ce5bdbf --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/billing_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + BillingResource = Data.define(:bill, :duplicates) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bill: BillResource.from_api(payload["bill"]), + duplicates: (payload["duplicates"] || []).map { |e| DuplicateResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/buyer_resource.rb b/lib/nfe/generated/nf_produto_v2/buyer_resource.rb new file mode 100644 index 0000000..6e3d51c --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/buyer_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + BuyerResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :state_tax_number_indicator, :tax_regime, :trade_name, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + state_tax_number_indicator: payload["stateTaxNumberIndicator"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/card_resource.rb b/lib/nfe/generated/nf_produto_v2/card_resource.rb new file mode 100644 index 0000000..f35bd41 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/card_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + CardResource = Data.define(:authorization, :federal_tax_number, :federal_tax_number_recipient, :flag, :id_payment_terminal, :integration_payment_type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorization: payload["authorization"], + federal_tax_number: payload["federalTaxNumber"], + federal_tax_number_recipient: payload["federalTaxNumberRecipient"], + flag: payload["flag"], + id_payment_terminal: payload["idPaymentTerminal"], + integration_payment_type: payload["integrationPaymentType"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/cideresource.rb b/lib/nfe/generated/nf_produto_v2/cideresource.rb new file mode 100644 index 0000000..67bcee8 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/cideresource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + CIDEResource = Data.define(:bc, :cide_amount, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bc: payload["bc"], + cide_amount: payload["cideAmount"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/city_resource.rb b/lib/nfe/generated/nf_produto_v2/city_resource.rb new file mode 100644 index 0000000..1c71ee0 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/city_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + CityResource = Data.define(:code, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/cofins_tax_resource.rb b/lib/nfe/generated/nf_produto_v2/cofins_tax_resource.rb new file mode 100644 index 0000000..9b95cbb --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/cofins_tax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + CofinsTaxResource = Data.define(:amount, :base_tax, :base_tax_product_quantity, :cst, :product_rate, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + base_tax_product_quantity: payload["baseTaxProductQuantity"], + cst: payload["cst"], + product_rate: payload["productRate"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/consumer_presence_type.rb b/lib/nfe/generated/nf_produto_v2/consumer_presence_type.rb new file mode 100644 index 0000000..6a6189e --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/consumer_presence_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ConsumerPresenceType + None = "None" + Presence = "Presence" + Internet = "Internet" + Telephone = "Telephone" + Delivery = "Delivery" + OthersNonPresenceOperation = "OthersNonPresenceOperation" + ALL = [None, Presence, Internet, Telephone, Delivery, OthersNonPresenceOperation].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/consumer_type.rb b/lib/nfe/generated/nf_produto_v2/consumer_type.rb new file mode 100644 index 0000000..1a071d9 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/consumer_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ConsumerType + FinalConsumer = "FinalConsumer" + Normal = "Normal" + ALL = [FinalConsumer, Normal].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/contingency_details.rb b/lib/nfe/generated/nf_produto_v2/contingency_details.rb new file mode 100644 index 0000000..07a8318 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/contingency_details.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ContingencyDetails = Data.define(:authorizer, :reason, :started_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorizer: payload["authorizer"], + reason: payload["reason"], + started_on: payload["startedOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/delivery_information_resource.rb b/lib/nfe/generated/nf_produto_v2/delivery_information_resource.rb new file mode 100644 index 0000000..2dd7c1c --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/delivery_information_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + DeliveryInformationResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/destination.rb b/lib/nfe/generated/nf_produto_v2/destination.rb new file mode 100644 index 0000000..69eafb1 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/destination.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module Destination + None = "None" + InternalOperation = "Internal_Operation" + InterstateOperation = "Interstate_Operation" + InternationalOperation = "International_Operation" + ALL = [None, InternalOperation, InterstateOperation, InternationalOperation].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/disablement_resource.rb b/lib/nfe/generated/nf_produto_v2/disablement_resource.rb new file mode 100644 index 0000000..d9ae5fc --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/disablement_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + DisablementResource = Data.define(:begin_number, :environment, :last_number, :reason, :serie, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + begin_number: payload["beginNumber"], + environment: payload["environment"], + last_number: payload["lastNumber"], + reason: payload["reason"], + serie: payload["serie"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/document_electronic_invoice_resource.rb b/lib/nfe/generated/nf_produto_v2/document_electronic_invoice_resource.rb new file mode 100644 index 0000000..414e41d --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/document_electronic_invoice_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + DocumentElectronicInvoiceResource = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/document_invoice_reference_resource.rb b/lib/nfe/generated/nf_produto_v2/document_invoice_reference_resource.rb new file mode 100644 index 0000000..69b1c58 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/document_invoice_reference_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + DocumentInvoiceReferenceResource = Data.define(:federal_tax_number, :model, :number, :series, :state, :year_month) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + model: payload["model"], + number: payload["number"], + series: payload["series"], + state: payload["state"], + year_month: payload["yearMonth"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/duduction_indicator.rb b/lib/nfe/generated/nf_produto_v2/duduction_indicator.rb new file mode 100644 index 0000000..c9a176e --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/duduction_indicator.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module DuductionIndicator + NotDeduct = "NotDeduct" + Deduce = "Deduce" + ALL = [NotDeduct, Deduce].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/duplicate_resource.rb b/lib/nfe/generated/nf_produto_v2/duplicate_resource.rb new file mode 100644 index 0000000..7390b23 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/duplicate_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + DuplicateResource = Data.define(:amount, :expiration_on, :number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + expiration_on: payload["expirationOn"], + number: payload["number"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/economic_activity_resource.rb b/lib/nfe/generated/nf_produto_v2/economic_activity_resource.rb new file mode 100644 index 0000000..d369fb9 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/economic_activity_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + EconomicActivityResource = Data.define(:code, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/economic_activity_type.rb b/lib/nfe/generated/nf_produto_v2/economic_activity_type.rb new file mode 100644 index 0000000..55926f9 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/economic_activity_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module EconomicActivityType + Main = "Main" + Secondary = "Secondary" + ALL = [Main, Secondary].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/environment_type.rb b/lib/nfe/generated/nf_produto_v2/environment_type.rb new file mode 100644 index 0000000..fa899f7 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/environment_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module EnvironmentType + None = "None" + Production = "Production" + Test = "Test" + ALL = [None, Production, Test].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/error_resource.rb b/lib/nfe/generated/nf_produto_v2/error_resource.rb new file mode 100644 index 0000000..5f614af --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/error_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ErrorResource = Data.define(:code, :message) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + message: payload["message"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/errors_resource.rb b/lib/nfe/generated/nf_produto_v2/errors_resource.rb new file mode 100644 index 0000000..e2f9949 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/errors_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ErrorsResource = Data.define(:errors) do + def self.from_api(payload) + return nil if payload.nil? + + new( + errors: (payload["errors"] || []).map { |e| ErrorResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/exempt_reason.rb b/lib/nfe/generated/nf_produto_v2/exempt_reason.rb new file mode 100644 index 0000000..51770bc --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/exempt_reason.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ExemptReason + Agriculture = "Agriculture" + Others = "Others" + DevelopmentEntities = "DevelopmentEntities" + ALL = [Agriculture, Others, DevelopmentEntities].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/export_detail_resource.rb b/lib/nfe/generated/nf_produto_v2/export_detail_resource.rb new file mode 100644 index 0000000..24f9841 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/export_detail_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ExportDetailResource = Data.define(:drawback, :hint_information) do + def self.from_api(payload) + return nil if payload.nil? + + new( + drawback: payload["drawback"], + hint_information: ExportHintResource.from_api(payload["hintInformation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/export_hint_resource.rb b/lib/nfe/generated/nf_produto_v2/export_hint_resource.rb new file mode 100644 index 0000000..df31e37 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/export_hint_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ExportHintResource = Data.define(:access_key, :quantity, :registry_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + quantity: payload["quantity"], + registry_id: payload["registryId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/export_resource.rb b/lib/nfe/generated/nf_produto_v2/export_resource.rb new file mode 100644 index 0000000..70b9e5d --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/export_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ExportResource = Data.define(:local, :office, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + local: payload["local"], + office: payload["office"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/file_resource.rb b/lib/nfe/generated/nf_produto_v2/file_resource.rb new file mode 100644 index 0000000..a7fe6a4 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/file_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + FileResource = Data.define(:uri) do + def self.from_api(payload) + return nil if payload.nil? + + new( + uri: payload["uri"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/flag_card.rb b/lib/nfe/generated/nf_produto_v2/flag_card.rb new file mode 100644 index 0000000..d6663f1 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/flag_card.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module FlagCard + None = "None" + Visa = "Visa" + Mastercard = "Mastercard" + AmericanExpress = "AmericanExpress" + Sorocred = "Sorocred" + DinersClub = "DinersClub" + Elo = "Elo" + Hipercard = "Hipercard" + Aura = "Aura" + Cabal = "Cabal" + Alelo = "Alelo" + BanesCard = "BanesCard" + CalCard = "CalCard" + Credz = "Credz" + Discover = "Discover" + GoodCard = "GoodCard" + GreenCard = "GreenCard" + Hiper = "Hiper" + JCB = "JCB" + Mais = "Mais" + MaxVan = "MaxVan" + Policard = "Policard" + RedeCompras = "RedeCompras" + Sodexo = "Sodexo" + ValeCard = "ValeCard" + Verocheque = "Verocheque" + VR = "VR" + Ticket = "Ticket" + Other = "Other" + ALL = [None, Visa, Mastercard, AmericanExpress, Sorocred, DinersClub, Elo, Hipercard, Aura, Cabal, Alelo, BanesCard, CalCard, Credz, Discover, GoodCard, GreenCard, Hiper, JCB, Mais, MaxVan, Policard, RedeCompras, Sodexo, ValeCard, Verocheque, VR, Ticket, Other].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/fuel_origin_resource.rb b/lib/nfe/generated/nf_produto_v2/fuel_origin_resource.rb new file mode 100644 index 0000000..4d2e6bb --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/fuel_origin_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + FuelOriginResource = Data.define(:c_uforig, :ind_import, :p_orig) do + def self.from_api(payload) + return nil if payload.nil? + + new( + c_uforig: payload["cUFOrig"], + ind_import: payload["indImport"], + p_orig: payload["pOrig"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/fuel_resource.rb b/lib/nfe/generated/nf_produto_v2/fuel_resource.rb new file mode 100644 index 0000000..077e8c8 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/fuel_resource.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + FuelResource = Data.define(:amount_temp, :cide, :code_anp, :codif, :description_anp, :fuel_origin, :percentage_glp, :percentage_gni, :percentage_ng, :percentage_ngn, :pump, :starting_amount, :state_buyer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount_temp: payload["amountTemp"], + cide: CIDEResource.from_api(payload["cide"]), + code_anp: payload["codeANP"], + codif: payload["codif"], + description_anp: payload["descriptionANP"], + fuel_origin: FuelOriginResource.from_api(payload["fuelOrigin"]), + percentage_glp: payload["percentageGLP"], + percentage_gni: payload["percentageGNi"], + percentage_ng: payload["percentageNG"], + percentage_ngn: payload["percentageNGn"], + pump: PumpResource.from_api(payload["pump"]), + starting_amount: payload["startingAmount"], + state_buyer: payload["stateBuyer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/icms_tax_resource.rb b/lib/nfe/generated/nf_produto_v2/icms_tax_resource.rb new file mode 100644 index 0000000..e250417 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/icms_tax_resource.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + IcmsTaxResource = Data.define(:amount, :amount_operation, :amount_streason, :base_deferred, :base_snretention_amount, :base_stretention_amount, :base_tax, :base_tax_fcpstamount, :base_tax_modality, :base_tax_operation_percentual, :base_tax_reduction, :base_tax_st, :base_tax_stmodality, :base_tax_streduction, :csosn, :cst, :deduction_indicator, :effective_amount, :effective_base_tax_amount, :effective_base_tax_reduction_rate, :effective_rate, :exempt_amount, :exempt_amount_st, :exempt_reason, :exempt_reason_st, :fcp_amount, :fcp_rate, :fcpst_amount, :fcpst_rate, :fcpst_ret_amount, :fcpst_ret_rate, :origin, :percentual, :percentual_deferment, :rate, :sn_credit_amount, :sn_credit_rate, :sn_retention_amount, :st_amount, :st_final_consumer_rate, :st_margin_added_amount, :st_margin_amount, :st_rate, :st_retention_amount, :substitute_amount, :ufst) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + amount_operation: payload["amountOperation"], + amount_streason: payload["amountSTReason"], + base_deferred: payload["baseDeferred"], + base_snretention_amount: payload["baseSNRetentionAmount"], + base_stretention_amount: payload["baseSTRetentionAmount"], + base_tax: payload["baseTax"], + base_tax_fcpstamount: payload["baseTaxFCPSTAmount"], + base_tax_modality: payload["baseTaxModality"], + base_tax_operation_percentual: payload["baseTaxOperationPercentual"], + base_tax_reduction: payload["baseTaxReduction"], + base_tax_st: payload["baseTaxST"], + base_tax_stmodality: payload["baseTaxSTModality"], + base_tax_streduction: payload["baseTaxSTReduction"], + csosn: payload["csosn"], + cst: payload["cst"], + deduction_indicator: payload["deductionIndicator"], + effective_amount: payload["effectiveAmount"], + effective_base_tax_amount: payload["effectiveBaseTaxAmount"], + effective_base_tax_reduction_rate: payload["effectiveBaseTaxReductionRate"], + effective_rate: payload["effectiveRate"], + exempt_amount: payload["exemptAmount"], + exempt_amount_st: payload["exemptAmountST"], + exempt_reason: payload["exemptReason"], + exempt_reason_st: payload["exemptReasonST"], + fcp_amount: payload["fcpAmount"], + fcp_rate: payload["fcpRate"], + fcpst_amount: payload["fcpstAmount"], + fcpst_rate: payload["fcpstRate"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpst_ret_rate: payload["fcpstRetRate"], + origin: payload["origin"], + percentual: payload["percentual"], + percentual_deferment: payload["percentualDeferment"], + rate: payload["rate"], + sn_credit_amount: payload["snCreditAmount"], + sn_credit_rate: payload["snCreditRate"], + sn_retention_amount: payload["snRetentionAmount"], + st_amount: payload["stAmount"], + st_final_consumer_rate: payload["stFinalConsumerRate"], + st_margin_added_amount: payload["stMarginAddedAmount"], + st_margin_amount: payload["stMarginAmount"], + st_rate: payload["stRate"], + st_retention_amount: payload["stRetentionAmount"], + substitute_amount: payload["substituteAmount"], + ufst: payload["ufst"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/icmstotal.rb b/lib/nfe/generated/nf_produto_v2/icmstotal.rb new file mode 100644 index 0000000..29c1602 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/icmstotal.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ICMSTotal = Data.define(:base_tax, :cofins_amount, :discount_amount, :fcp_amount, :fcpst_amount, :fcpst_ret_amount, :fcpuf_destination_amount, :federal_taxes_amount, :freight_amount, :icms_amount, :icms_exempt_amount, :icmsuf_destination_amount, :icmsuf_sender_amount, :ii_amount, :insurance_amount, :invoice_amount, :ipi_amount, :ipi_devol_amount, :others_amount, :pis_amount, :product_amount, :q_bcmono, :q_bcmono_ret, :q_bcmono_reten, :st_amount, :st_calculation_basis_amount, :v_icmsmono, :v_icmsmono_ret, :v_icmsmono_reten) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_tax: payload["baseTax"], + cofins_amount: payload["cofinsAmount"], + discount_amount: payload["discountAmount"], + fcp_amount: payload["fcpAmount"], + fcpst_amount: payload["fcpstAmount"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpuf_destination_amount: payload["fcpufDestinationAmount"], + federal_taxes_amount: payload["federalTaxesAmount"], + freight_amount: payload["freightAmount"], + icms_amount: payload["icmsAmount"], + icms_exempt_amount: payload["icmsExemptAmount"], + icmsuf_destination_amount: payload["icmsufDestinationAmount"], + icmsuf_sender_amount: payload["icmsufSenderAmount"], + ii_amount: payload["iiAmount"], + insurance_amount: payload["insuranceAmount"], + invoice_amount: payload["invoiceAmount"], + ipi_amount: payload["ipiAmount"], + ipi_devol_amount: payload["ipiDevolAmount"], + others_amount: payload["othersAmount"], + pis_amount: payload["pisAmount"], + product_amount: payload["productAmount"], + q_bcmono: payload["qBCMono"], + q_bcmono_ret: payload["qBCMonoRet"], + q_bcmono_reten: payload["qBCMonoReten"], + st_amount: payload["stAmount"], + st_calculation_basis_amount: payload["stCalculationBasisAmount"], + v_icmsmono: payload["vICMSMono"], + v_icmsmono_ret: payload["vICMSMonoRet"], + v_icmsmono_reten: payload["vICMSMonoReten"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/icmstotal_resource.rb b/lib/nfe/generated/nf_produto_v2/icmstotal_resource.rb new file mode 100644 index 0000000..d9e635f --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/icmstotal_resource.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ICMSTotalResource = Data.define(:base_tax, :cofins_amount, :discount_amount, :fcp_amount, :fcpst_amount, :fcpst_ret_amount, :fcpuf_destination_amount, :federal_taxes_amount, :freight_amount, :icms_amount, :icms_exempt_amount, :icmsuf_destination_amount, :icmsuf_sender_amount, :ii_amount, :insurance_amount, :invoice_amount, :ipi_amount, :ipi_devol_amount, :others_amount, :pis_amount, :product_amount, :q_bcmono, :q_bcmono_ret, :q_bcmono_reten, :st_amount, :st_calculation_basis_amount, :v_icmsmono, :v_icmsmono_ret, :v_icmsmono_reten) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_tax: payload["baseTax"], + cofins_amount: payload["cofinsAmount"], + discount_amount: payload["discountAmount"], + fcp_amount: payload["fcpAmount"], + fcpst_amount: payload["fcpstAmount"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpuf_destination_amount: payload["fcpufDestinationAmount"], + federal_taxes_amount: payload["federalTaxesAmount"], + freight_amount: payload["freightAmount"], + icms_amount: payload["icmsAmount"], + icms_exempt_amount: payload["icmsExemptAmount"], + icmsuf_destination_amount: payload["icmsufDestinationAmount"], + icmsuf_sender_amount: payload["icmsufSenderAmount"], + ii_amount: payload["iiAmount"], + insurance_amount: payload["insuranceAmount"], + invoice_amount: payload["invoiceAmount"], + ipi_amount: payload["ipiAmount"], + ipi_devol_amount: payload["ipiDevolAmount"], + others_amount: payload["othersAmount"], + pis_amount: payload["pisAmount"], + product_amount: payload["productAmount"], + q_bcmono: payload["qBCMono"], + q_bcmono_ret: payload["qBCMonoRet"], + q_bcmono_reten: payload["qBCMonoReten"], + st_amount: payload["stAmount"], + st_calculation_basis_amount: payload["stCalculationBasisAmount"], + v_icmsmono: payload["vICMSMono"], + v_icmsmono_ret: payload["vICMSMonoRet"], + v_icmsmono_reten: payload["vICMSMonoReten"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/icmsufdestination_tax_resource.rb b/lib/nfe/generated/nf_produto_v2/icmsufdestination_tax_resource.rb new file mode 100644 index 0000000..ef00b29 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/icmsufdestination_tax_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ICMSUFDestinationTaxResource = Data.define(:p_fcpufdest, :p_icmsinter, :p_icmsinter_part, :p_icmsufdest, :v_bcfcpufdest, :v_bcufdest, :v_fcpufdest, :v_icmsufdest, :v_icmsufremet) do + def self.from_api(payload) + return nil if payload.nil? + + new( + p_fcpufdest: payload["pFCPUFDest"], + p_icmsinter: payload["pICMSInter"], + p_icmsinter_part: payload["pICMSInterPart"], + p_icmsufdest: payload["pICMSUFDest"], + v_bcfcpufdest: payload["vBCFCPUFDest"], + v_bcufdest: payload["vBCUFDest"], + v_fcpufdest: payload["vFCPUFDest"], + v_icmsufdest: payload["vICMSUFDest"], + v_icmsufremet: payload["vICMSUFRemet"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/iitax_resource.rb b/lib/nfe/generated/nf_produto_v2/iitax_resource.rb new file mode 100644 index 0000000..e003ca6 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/iitax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + IITaxResource = Data.define(:amount, :base_tax, :customs_expenditure_amount, :iof_amount, :v_enq_camb) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + customs_expenditure_amount: payload["customsExpenditureAmount"], + iof_amount: payload["iofAmount"], + v_enq_camb: payload["vEnqCamb"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/import_declaration_resource.rb b/lib/nfe/generated/nf_produto_v2/import_declaration_resource.rb new file mode 100644 index 0000000..e6744f9 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/import_declaration_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ImportDeclarationResource = Data.define(:acquirer_federal_tax_number, :additions, :code, :customs_clearance_name, :customs_clearance_state, :customs_clearanced_on, :exporter, :intermediation, :international_transport, :registered_on, :state_third) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquirer_federal_tax_number: payload["acquirerFederalTaxNumber"], + additions: (payload["additions"] || []).map { |e| AdditionResource.from_api(e) }, + code: payload["code"], + customs_clearance_name: payload["customsClearanceName"], + customs_clearance_state: payload["customsClearanceState"], + customs_clearanced_on: payload["customsClearancedOn"], + exporter: payload["exporter"], + intermediation: payload["intermediation"], + international_transport: payload["internationalTransport"], + registered_on: payload["registeredOn"], + state_third: payload["stateThird"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/integration_payment_type.rb b/lib/nfe/generated/nf_produto_v2/integration_payment_type.rb new file mode 100644 index 0000000..9dbf061 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/integration_payment_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module IntegrationPaymentType + Integrated = "Integrated" + NotIntegrated = "NotIntegrated" + ALL = [Integrated, NotIntegrated].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/intermediate_resource.rb b/lib/nfe/generated/nf_produto_v2/intermediate_resource.rb new file mode 100644 index 0000000..adf809f --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/intermediate_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + IntermediateResource = Data.define(:federal_tax_number, :identifier) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + identifier: payload["identifier"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/intermediation_type.rb b/lib/nfe/generated/nf_produto_v2/intermediation_type.rb new file mode 100644 index 0000000..70bcf04 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/intermediation_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module IntermediationType + None = "None" + ByOwn = "ByOwn" + ImportOnBehalf = "ImportOnBehalf" + ByOrder = "ByOrder" + ALL = [None, ByOwn, ImportOnBehalf, ByOrder].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/international_transport_type.rb b/lib/nfe/generated/nf_produto_v2/international_transport_type.rb new file mode 100644 index 0000000..44ef430 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/international_transport_type.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module InternationalTransportType + None = "None" + Maritime = "Maritime" + River = "River" + Lake = "Lake" + Airline = "Airline" + Postal = "Postal" + Railway = "Railway" + Highway = "Highway" + Network = "Network" + Own = "Own" + Ficta = "Ficta" + Courier = "Courier" + Handcarry = "Handcarry" + ALL = [None, Maritime, River, Lake, Airline, Postal, Railway, Highway, Network, Own, Ficta, Courier, Handcarry].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_events_resource_base.rb b/lib/nfe/generated/nf_produto_v2/invoice_events_resource_base.rb new file mode 100644 index 0000000..f73174e --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_events_resource_base.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + InvoiceEventsResourceBase = Data.define(:events, :has_more) do + def self.from_api(payload) + return nil if payload.nil? + + new( + events: (payload["events"] || []).map { |e| ActivityResource.from_api(e) }, + has_more: payload["hasMore"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_item_resource.rb b/lib/nfe/generated/nf_produto_v2/invoice_item_resource.rb new file mode 100644 index 0000000..d446cac --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_item_resource.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + InvoiceItemResource = Data.define(:additional_information, :benefit, :cest, :cfop, :code, :code_gtin, :code_tax_gtin, :description, :discount_amount, :export_details, :extipi, :freight_amount, :fuel_detail, :import_control_sheet_number, :import_declarations, :insurance_amount, :item_number_order_buy, :ncm, :number_order_buy, :nve, :others_amount, :quantity, :quantity_tax, :tax, :tax_determination, :tax_unit_amount, :total_amount, :total_indicator, :unit, :unit_amount, :unit_tax, :vehicle_detail) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + benefit: payload["benefit"], + cest: payload["cest"], + cfop: payload["cfop"], + code: payload["code"], + code_gtin: payload["codeGTIN"], + code_tax_gtin: payload["codeTaxGTIN"], + description: payload["description"], + discount_amount: payload["discountAmount"], + export_details: (payload["exportDetails"] || []).map { |e| ExportDetailResource.from_api(e) }, + extipi: payload["extipi"], + freight_amount: payload["freightAmount"], + fuel_detail: FuelResource.from_api(payload["fuelDetail"]), + import_control_sheet_number: payload["importControlSheetNumber"], + import_declarations: (payload["importDeclarations"] || []).map { |e| ImportDeclarationResource.from_api(e) }, + insurance_amount: payload["insuranceAmount"], + item_number_order_buy: payload["itemNumberOrderBuy"], + ncm: payload["ncm"], + number_order_buy: payload["numberOrderBuy"], + nve: payload["nve"], + others_amount: payload["othersAmount"], + quantity: payload["quantity"], + quantity_tax: payload["quantityTax"], + tax: InvoiceItemTaxResource.from_api(payload["tax"]), + tax_determination: TaxDeterminationResource.from_api(payload["taxDetermination"]), + tax_unit_amount: payload["taxUnitAmount"], + total_amount: payload["totalAmount"], + total_indicator: payload["totalIndicator"], + unit: payload["unit"], + unit_amount: payload["unitAmount"], + unit_tax: payload["unitTax"], + vehicle_detail: VehicleDetailResource.from_api(payload["vehicleDetail"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_item_tax_resource.rb b/lib/nfe/generated/nf_produto_v2/invoice_item_tax_resource.rb new file mode 100644 index 0000000..6ccc957 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_item_tax_resource.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + InvoiceItemTaxResource = Data.define(:cofins, :icms, :icms_destination, :ii, :ipi, :pis, :total_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cofins: CofinsTaxResource.from_api(payload["cofins"]), + icms: IcmsTaxResource.from_api(payload["icms"]), + icms_destination: ICMSUFDestinationTaxResource.from_api(payload["icmsDestination"]), + ii: IITaxResource.from_api(payload["ii"]), + ipi: IPITaxResource.from_api(payload["ipi"]), + pis: PISTaxResource.from_api(payload["pis"]), + total_tax: payload["totalTax"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_items_resource.rb b/lib/nfe/generated/nf_produto_v2/invoice_items_resource.rb new file mode 100644 index 0000000..bacf39f --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_items_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + InvoiceItemsResource = Data.define(:account_id, :company_id, :has_more, :id, :items) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + has_more: payload["hasMore"], + id: payload["id"], + items: (payload["items"] || []).map { |e| InvoiceItemResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_resource.rb b/lib/nfe/generated/nf_produto_v2/invoice_resource.rb new file mode 100644 index 0000000..949fcd4 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_resource.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + InvoiceResource = Data.define(:additional_information, :authorization, :billing, :buyer, :contingency_details, :created_on, :delivery, :environment_type, :export, :id, :issuer, :last_events, :modified_on, :number, :operation_nature, :operation_on, :operation_type, :payment, :purpose_type, :serie, :status, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + authorization: AuthorizationResource.from_api(payload["authorization"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + contingency_details: ContingencyDetails.from_api(payload["contingencyDetails"]), + created_on: payload["createdOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + environment_type: payload["environmentType"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerResource.from_api(payload["issuer"]), + last_events: InvoiceEventsResourceBase.from_api(payload["lastEvents"]), + modified_on: payload["modifiedOn"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + purpose_type: payload["purposeType"], + serie: payload["serie"], + status: payload["status"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_status.rb b/lib/nfe/generated/nf_produto_v2/invoice_status.rb new file mode 100644 index 0000000..0f75fa4 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_status.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module InvoiceStatus + None = "None" + Created = "Created" + Processing = "Processing" + Issued = "Issued" + IssuedContingency = "IssuedContingency" + Cancelled = "Cancelled" + Disabled = "Disabled" + IssueDenied = "IssueDenied" + Error = "Error" + ALL = [None, Created, Processing, Issued, IssuedContingency, Cancelled, Disabled, IssueDenied, Error].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/invoice_without_events_resource.rb b/lib/nfe/generated/nf_produto_v2/invoice_without_events_resource.rb new file mode 100644 index 0000000..0846cb6 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/invoice_without_events_resource.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + InvoiceWithoutEventsResource = Data.define(:additional_information, :authorization, :billing, :buyer, :contingency_details, :created_on, :delivery, :environment_type, :export, :id, :issuer, :modified_on, :number, :operation_nature, :operation_on, :operation_type, :payment, :purpose_type, :serie, :status, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + authorization: AuthorizationResource.from_api(payload["authorization"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + contingency_details: ContingencyDetails.from_api(payload["contingencyDetails"]), + created_on: payload["createdOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + environment_type: payload["environmentType"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerResource.from_api(payload["issuer"]), + modified_on: payload["modifiedOn"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + purpose_type: payload["purposeType"], + serie: payload["serie"], + status: payload["status"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/ipitax_resource.rb b/lib/nfe/generated/nf_produto_v2/ipitax_resource.rb new file mode 100644 index 0000000..1e7839c --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/ipitax_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + IPITaxResource = Data.define(:amount, :base, :classification, :classification_code, :cst, :producer_cnpj, :rate, :stamp_code, :stamp_quantity, :unit_amount, :unit_quantity) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base: payload["base"], + classification: payload["classification"], + classification_code: payload["classificationCode"], + cst: payload["cst"], + producer_cnpj: payload["producerCNPJ"], + rate: payload["rate"], + stamp_code: payload["stampCode"], + stamp_quantity: payload["stampQuantity"], + unit_amount: payload["unitAmount"], + unit_quantity: payload["unitQuantity"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/issqntotal.rb b/lib/nfe/generated/nf_produto_v2/issqntotal.rb new file mode 100644 index 0000000..e9a5010 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/issqntotal.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ISSQNTotal = Data.define(:base_rate_iss, :code_tax_regime, :deduction_reduction_bc, :discount_conditioning, :discount_unconditional, :provision_service, :total_iss, :total_retention_iss, :total_service_not_taxed_icms, :value_other_retention, :value_service_cofins, :value_service_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_rate_iss: payload["baseRateISS"], + code_tax_regime: payload["codeTaxRegime"], + deduction_reduction_bc: payload["deductionReductionBC"], + discount_conditioning: payload["discountConditioning"], + discount_unconditional: payload["discountUnconditional"], + provision_service: payload["provisionService"], + total_iss: payload["totalISS"], + total_retention_iss: payload["totalRetentionISS"], + total_service_not_taxed_icms: payload["totalServiceNotTaxedICMS"], + value_other_retention: payload["valueOtherRetention"], + value_service_cofins: payload["valueServiceCOFINS"], + value_service_pis: payload["valueServicePIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/issqntotal_resource.rb b/lib/nfe/generated/nf_produto_v2/issqntotal_resource.rb new file mode 100644 index 0000000..b34172a --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/issqntotal_resource.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ISSQNTotalResource = Data.define(:base_rate_iss, :code_tax_regime, :deduction_reduction_bc, :discount_conditioning, :discount_unconditional, :provision_service, :total_iss, :total_retention_iss, :total_service_not_taxed_icms, :value_other_retention, :value_service_cofins, :value_service_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_rate_iss: payload["baseRateISS"], + code_tax_regime: payload["codeTaxRegime"], + deduction_reduction_bc: payload["deductionReductionBC"], + discount_conditioning: payload["discountConditioning"], + discount_unconditional: payload["discountUnconditional"], + provision_service: payload["provisionService"], + total_iss: payload["totalISS"], + total_retention_iss: payload["totalRetentionISS"], + total_service_not_taxed_icms: payload["totalServiceNotTaxedICMS"], + value_other_retention: payload["valueOtherRetention"], + value_service_cofins: payload["valueServiceCOFINS"], + value_service_pis: payload["valueServicePIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/issuer_from_request_resource.rb b/lib/nfe/generated/nf_produto_v2/issuer_from_request_resource.rb new file mode 100644 index 0000000..0ee02ee --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/issuer_from_request_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + IssuerFromRequestResource = Data.define(:st_state_tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + st_state_tax_number: payload["stStateTaxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/issuer_resource.rb b/lib/nfe/generated/nf_produto_v2/issuer_resource.rb new file mode 100644 index 0000000..5a469af --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/issuer_resource.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + IssuerResource = Data.define(:account_id, :address, :company_registry_number, :economic_activities, :email, :federal_tax_number, :id, :legal_nature, :municipal_tax_number, :name, :openning_date, :regional_sttax_number, :regional_tax_number, :special_tax_regime, :st_state_tax_number, :tax_regime, :trade_name, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + company_registry_number: payload["companyRegistryNumber"], + economic_activities: (payload["economicActivities"] || []).map { |e| EconomicActivityResource.from_api(e) }, + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + legal_nature: payload["legalNature"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + openning_date: payload["openningDate"], + regional_sttax_number: payload["regionalSTTaxNumber"], + regional_tax_number: payload["regionalTaxNumber"], + special_tax_regime: payload["specialTaxRegime"], + st_state_tax_number: payload["stStateTaxNumber"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/legal_nature.rb b/lib/nfe/generated/nf_produto_v2/legal_nature.rb new file mode 100644 index 0000000..fc4376f --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/legal_nature.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module LegalNature + EmpresaPublica = "EmpresaPublica" + SociedadeEconomiaMista = "SociedadeEconomiaMista" + SociedadeAnonimaAberta = "SociedadeAnonimaAberta" + SociedadeAnonimaFechada = "SociedadeAnonimaFechada" + SociedadeEmpresariaLimitada = "SociedadeEmpresariaLimitada" + SociedadeEmpresariaEmNomeColetivo = "SociedadeEmpresariaEmNomeColetivo" + SociedadeEmpresariaEmComanditaSimples = "SociedadeEmpresariaEmComanditaSimples" + SociedadeEmpresariaEmComanditaporAcoes = "SociedadeEmpresariaEmComanditaporAcoes" + SociedadeemContaParticipacao = "SociedadeemContaParticipacao" + Empresario = "Empresario" + Cooperativa = "Cooperativa" + ConsorcioSociedades = "ConsorcioSociedades" + GrupoSociedades = "GrupoSociedades" + EmpresaDomiciliadaExterior = "EmpresaDomiciliadaExterior" + ClubeFundoInvestimento = "ClubeFundoInvestimento" + SociedadeSimplesPura = "SociedadeSimplesPura" + SociedadeSimplesLimitada = "SociedadeSimplesLimitada" + SociedadeSimplesEmNomeColetivo = "SociedadeSimplesEmNomeColetivo" + SociedadeSimplesEmComanditaSimples = "SociedadeSimplesEmComanditaSimples" + EmpresaBinacional = "EmpresaBinacional" + ConsorcioEmpregadores = "ConsorcioEmpregadores" + ConsorcioSimples = "ConsorcioSimples" + EireliNaturezaEmpresaria = "EireliNaturezaEmpresaria" + EireliNaturezaSimples = "EireliNaturezaSimples" + ServicoNotarial = "ServicoNotarial" + FundacaoPrivada = "FundacaoPrivada" + ServicoSocialAutonomo = "ServicoSocialAutonomo" + CondominioEdilicio = "CondominioEdilicio" + ComissaoConciliacaoPrevia = "ComissaoConciliacaoPrevia" + EntidadeMediacaoArbitragem = "EntidadeMediacaoArbitragem" + PartidoPolitico = "PartidoPolitico" + EntidadeSindical = "EntidadeSindical" + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras = "EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras" + FundacaoAssociacaoDomiciliadaExterior = "FundacaoAssociacaoDomiciliadaExterior" + OrganizacaoReligiosa = "OrganizacaoReligiosa" + ComunidadeIndigena = "ComunidadeIndigena" + FundoPrivado = "FundoPrivado" + AssociacaoPrivada = "AssociacaoPrivada" + ALL = [EmpresaPublica, SociedadeEconomiaMista, SociedadeAnonimaAberta, SociedadeAnonimaFechada, SociedadeEmpresariaLimitada, SociedadeEmpresariaEmNomeColetivo, SociedadeEmpresariaEmComanditaSimples, SociedadeEmpresariaEmComanditaporAcoes, SociedadeemContaParticipacao, Empresario, Cooperativa, ConsorcioSociedades, GrupoSociedades, EmpresaDomiciliadaExterior, ClubeFundoInvestimento, SociedadeSimplesPura, SociedadeSimplesLimitada, SociedadeSimplesEmNomeColetivo, SociedadeSimplesEmComanditaSimples, EmpresaBinacional, ConsorcioEmpregadores, ConsorcioSimples, EireliNaturezaEmpresaria, EireliNaturezaSimples, ServicoNotarial, FundacaoPrivada, ServicoSocialAutonomo, CondominioEdilicio, ComissaoConciliacaoPrevia, EntidadeMediacaoArbitragem, PartidoPolitico, EntidadeSindical, EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras, FundacaoAssociacaoDomiciliadaExterior, OrganizacaoReligiosa, ComunidadeIndigena, FundoPrivado, AssociacaoPrivada].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/operation_type.rb b/lib/nfe/generated/nf_produto_v2/operation_type.rb new file mode 100644 index 0000000..791a0eb --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/operation_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module OperationType + Outgoing = "Outgoing" + Incoming = "Incoming" + ALL = [Outgoing, Incoming].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/payment_detail_resource.rb b/lib/nfe/generated/nf_produto_v2/payment_detail_resource.rb new file mode 100644 index 0000000..d9789fd --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/payment_detail_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + PaymentDetailResource = Data.define(:amount, :card, :federal_tax_number_pag, :method, :method_description, :payment_date, :payment_type, :state_pag) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + card: CardResource.from_api(payload["card"]), + federal_tax_number_pag: payload["federalTaxNumberPag"], + method: payload["method"], + method_description: payload["methodDescription"], + payment_date: payload["paymentDate"], + payment_type: payload["paymentType"], + state_pag: payload["statePag"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/payment_method.rb b/lib/nfe/generated/nf_produto_v2/payment_method.rb new file mode 100644 index 0000000..ce25f84 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/payment_method.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PaymentMethod + Cash = "Cash" + Cheque = "Cheque" + CreditCard = "CreditCard" + DebitCard = "DebitCard" + StoreCredict = "StoreCredict" + FoodVouchers = "FoodVouchers" + MealVouchers = "MealVouchers" + GiftVouchers = "GiftVouchers" + FuelVouchers = "FuelVouchers" + BankBill = "BankBill" + BankDeposit = "BankDeposit" + InstantPayment = "InstantPayment" + WireTransfer = "WireTransfer" + Cashback = "Cashback" + WithoutPayment = "WithoutPayment" + Others = "Others" + ALL = [Cash, Cheque, CreditCard, DebitCard, StoreCredict, FoodVouchers, MealVouchers, GiftVouchers, FuelVouchers, BankBill, BankDeposit, InstantPayment, WireTransfer, Cashback, WithoutPayment, Others].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/payment_resource.rb b/lib/nfe/generated/nf_produto_v2/payment_resource.rb new file mode 100644 index 0000000..f6432c2 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/payment_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + PaymentResource = Data.define(:pay_back, :payment_detail) do + def self.from_api(payload) + return nil if payload.nil? + + new( + pay_back: payload["payBack"], + payment_detail: (payload["paymentDetail"] || []).map { |e| PaymentDetailResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/payment_type.rb b/lib/nfe/generated/nf_produto_v2/payment_type.rb new file mode 100644 index 0000000..b7ad9da --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/payment_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PaymentType + InCash = "InCash" + Term = "Term" + ALL = [InCash, Term].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/person_type.rb b/lib/nfe/generated/nf_produto_v2/person_type.rb new file mode 100644 index 0000000..c24a5c1 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/person_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PersonType + Undefined = "Undefined" + NaturalPerson = "NaturalPerson" + LegalEntity = "LegalEntity" + Company = "Company" + Customer = "Customer" + ALL = [Undefined, NaturalPerson, LegalEntity, Company, Customer].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/pistax_resource.rb b/lib/nfe/generated/nf_produto_v2/pistax_resource.rb new file mode 100644 index 0000000..74cb75d --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/pistax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + PISTaxResource = Data.define(:amount, :base_tax, :base_tax_product_quantity, :cst, :product_rate, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + base_tax_product_quantity: payload["baseTaxProductQuantity"], + cst: payload["cst"], + product_rate: payload["productRate"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/print_type.rb b/lib/nfe/generated/nf_produto_v2/print_type.rb new file mode 100644 index 0000000..d7c40ac --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/print_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PrintType + None = "None" + NFeNormalPortrait = "NFeNormalPortrait" + NFeNormalLandscape = "NFeNormalLandscape" + NFeSimplified = "NFeSimplified" + DANFENFCE = "DANFE_NFC_E" + DANFENFCEMSGELETRONICA = "DANFE_NFC_E_MSG_ELETRONICA" + ALL = [None, NFeNormalPortrait, NFeNormalLandscape, NFeSimplified, DANFENFCE, DANFENFCEMSGELETRONICA].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/product_invoice_events_resource.rb b/lib/nfe/generated/nf_produto_v2/product_invoice_events_resource.rb new file mode 100644 index 0000000..7b032a6 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/product_invoice_events_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ProductInvoiceEventsResource = Data.define(:account_id, :company_id, :events, :has_more, :id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + events: (payload["events"] || []).map { |e| ActivityResource.from_api(e) }, + has_more: payload["hasMore"], + id: payload["id"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/product_invoice_queue_issue_resource.rb b/lib/nfe/generated/nf_produto_v2/product_invoice_queue_issue_resource.rb new file mode 100644 index 0000000..095afe9 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/product_invoice_queue_issue_resource.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ProductInvoiceQueueIssueResource = Data.define(:additional_information, :billing, :buyer, :consumer_type, :contingency_justification, :contingency_on, :delivery, :destination, :export, :id, :issuer, :items, :number, :operation_nature, :operation_on, :operation_type, :payment, :presence_type, :print_type, :purpose_type, :serie, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + consumer_type: payload["consumerType"], + contingency_justification: payload["contingencyJustification"], + contingency_on: payload["contingencyOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + destination: payload["destination"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerFromRequestResource.from_api(payload["issuer"]), + items: (payload["items"] || []).map { |e| InvoiceItemResource.from_api(e) }, + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + presence_type: payload["presenceType"], + print_type: payload["printType"], + purpose_type: payload["purposeType"], + serie: payload["serie"], + totals: Total.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/product_invoices_resource.rb b/lib/nfe/generated/nf_produto_v2/product_invoices_resource.rb new file mode 100644 index 0000000..6e306f3 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/product_invoices_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ProductInvoicesResource = Data.define(:has_more, :product_invoices) do + def self.from_api(payload) + return nil if payload.nil? + + new( + has_more: payload["hasMore"], + product_invoices: (payload["productInvoices"] || []).map { |e| InvoiceWithoutEventsResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/pump_resource.rb b/lib/nfe/generated/nf_produto_v2/pump_resource.rb new file mode 100644 index 0000000..5d022b7 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/pump_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + PumpResource = Data.define(:beginning_amount, :end_amount, :number, :percentage_bio, :spout_number, :tank_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + beginning_amount: payload["beginningAmount"], + end_amount: payload["endAmount"], + number: payload["number"], + percentage_bio: payload["percentageBio"], + spout_number: payload["spoutNumber"], + tank_number: payload["tankNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/purpose_type.rb b/lib/nfe/generated/nf_produto_v2/purpose_type.rb new file mode 100644 index 0000000..5da3c1e --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/purpose_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PurposeType + None = "None" + Normal = "Normal" + Complement = "Complement" + Adjustment = "Adjustment" + Devolution = "Devolution" + ALL = [None, Normal, Complement, Adjustment, Devolution].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/queue_event_resource.rb b/lib/nfe/generated/nf_produto_v2/queue_event_resource.rb new file mode 100644 index 0000000..34996da --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/queue_event_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + QueueEventResource = Data.define(:reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/reboque_resource.rb b/lib/nfe/generated/nf_produto_v2/reboque_resource.rb new file mode 100644 index 0000000..5eb0acc --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/reboque_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ReboqueResource = Data.define(:ferry, :plate, :rntc, :uf, :wagon) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ferry: payload["ferry"], + plate: payload["plate"], + rntc: payload["rntc"], + uf: payload["uf"], + wagon: payload["wagon"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/receiver_state_tax_indicator.rb b/lib/nfe/generated/nf_produto_v2/receiver_state_tax_indicator.rb new file mode 100644 index 0000000..f7f5bd5 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/receiver_state_tax_indicator.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ReceiverStateTaxIndicator + None = "None" + TaxPayer = "TaxPayer" + Exempt = "Exempt" + NonTaxPayer = "NonTaxPayer" + ALL = [None, TaxPayer, Exempt, NonTaxPayer].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/referenced_process_resource.rb b/lib/nfe/generated/nf_produto_v2/referenced_process_resource.rb new file mode 100644 index 0000000..11cb76c --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/referenced_process_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + ReferencedProcessResource = Data.define(:concession_act_type, :identifier_concessory, :identifier_origin) do + def self.from_api(payload) + return nil if payload.nil? + + new( + concession_act_type: payload["concessionActType"], + identifier_concessory: payload["identifierConcessory"], + identifier_origin: payload["identifierOrigin"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/request_cancellation_resource.rb b/lib/nfe/generated/nf_produto_v2/request_cancellation_resource.rb new file mode 100644 index 0000000..c18310f --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/request_cancellation_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + RequestCancellationResource = Data.define(:account_id, :company_id, :product_invoice_id, :reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + product_invoice_id: payload["productInvoiceId"], + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/shipping_modality.rb b/lib/nfe/generated/nf_produto_v2/shipping_modality.rb new file mode 100644 index 0000000..4d1e021 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/shipping_modality.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ShippingModality + ByIssuer = "ByIssuer" + ByReceiver = "ByReceiver" + ByThirdParties = "ByThirdParties" + OwnBySender = "OwnBySender" + OwnByBuyer = "OwnByBuyer" + Free = "Free" + ALL = [ByIssuer, ByReceiver, ByThirdParties, OwnBySender, OwnByBuyer, Free].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/special_tax_regime.rb b/lib/nfe/generated/nf_produto_v2/special_tax_regime.rb new file mode 100644 index 0000000..df95cd2 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/special_tax_regime.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module SpecialTaxRegime + Nenhum = "Nenhum" + MicroempresaMunicipal = "MicroempresaMunicipal" + Estimativa = "Estimativa" + SociedadeDeProfissionais = "SociedadeDeProfissionais" + Cooperativa = "Cooperativa" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + MicroempresarioEmpresaPequenoPorte = "MicroempresarioEmpresaPequenoPorte" + Automatico = "Automatico" + ALL = [Nenhum, MicroempresaMunicipal, Estimativa, SociedadeDeProfissionais, Cooperativa, MicroempreendedorIndividual, MicroempresarioEmpresaPequenoPorte, Automatico].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/state_code.rb b/lib/nfe/generated/nf_produto_v2/state_code.rb new file mode 100644 index 0000000..f1edda6 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/state_code.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module StateCode + NA = "NA" + RO = "RO" + AC = "AC" + AM = "AM" + RR = "RR" + PA = "PA" + AP = "AP" + TO = "TO" + MA = "MA" + PI = "PI" + CE = "CE" + RN = "RN" + PB = "PB" + PE = "PE" + AL = "AL" + SE = "SE" + BA = "BA" + MG = "MG" + ES = "ES" + RJ = "RJ" + SP = "SP" + PR = "PR" + SC = "SC" + RS = "RS" + MS = "MS" + MT = "MT" + GO = "GO" + DF = "DF" + EX = "EX" + ALL = [NA, RO, AC, AM, RR, PA, AP, TO, MA, PI, CE, RN, PB, PE, AL, SE, BA, MG, ES, RJ, SP, PR, SC, RS, MS, MT, GO, DF, EX].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/state_tax_processing_authorizer.rb b/lib/nfe/generated/nf_produto_v2/state_tax_processing_authorizer.rb new file mode 100644 index 0000000..faf2891 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/state_tax_processing_authorizer.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module StateTaxProcessingAuthorizer + Normal = "Normal" + EPEC = "EPEC" + ALL = [Normal, EPEC].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/tax_coupon_information_resource.rb b/lib/nfe/generated/nf_produto_v2/tax_coupon_information_resource.rb new file mode 100644 index 0000000..263fa0d --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/tax_coupon_information_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TaxCouponInformationResource = Data.define(:model_document_fiscal, :order_count_operation, :order_ecf) do + def self.from_api(payload) + return nil if payload.nil? + + new( + model_document_fiscal: payload["modelDocumentFiscal"], + order_count_operation: payload["orderCountOperation"], + order_ecf: payload["orderECF"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/tax_determination_resource.rb b/lib/nfe/generated/nf_produto_v2/tax_determination_resource.rb new file mode 100644 index 0000000..c080949 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/tax_determination_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TaxDeterminationResource = Data.define(:acquisition_purpose, :buyer_tax_profile, :issuer_tax_profile, :operation_code, :origin) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquisition_purpose: payload["acquisitionPurpose"], + buyer_tax_profile: payload["buyerTaxProfile"], + issuer_tax_profile: payload["issuerTaxProfile"], + operation_code: payload["operationCode"], + origin: payload["origin"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/tax_documents_reference_resource.rb b/lib/nfe/generated/nf_produto_v2/tax_documents_reference_resource.rb new file mode 100644 index 0000000..b734c05 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/tax_documents_reference_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TaxDocumentsReferenceResource = Data.define(:document_electronic_invoice, :document_invoice_reference, :tax_coupon_information) do + def self.from_api(payload) + return nil if payload.nil? + + new( + document_electronic_invoice: DocumentElectronicInvoiceResource.from_api(payload["documentElectronicInvoice"]), + document_invoice_reference: DocumentInvoiceReferenceResource.from_api(payload["documentInvoiceReference"]), + tax_coupon_information: TaxCouponInformationResource.from_api(payload["taxCouponInformation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/tax_regime.rb b/lib/nfe/generated/nf_produto_v2/tax_regime.rb new file mode 100644 index 0000000..7da28c7 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/tax_regime.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module TaxRegime + None = "None" + LucroReal = "LucroReal" + LucroPresumido = "LucroPresumido" + SimplesNacional = "SimplesNacional" + SimplesNacionalExcessoSublimite = "SimplesNacionalExcessoSublimite" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + Isento = "Isento" + ALL = [None, LucroReal, LucroPresumido, SimplesNacional, SimplesNacionalExcessoSublimite, MicroempreendedorIndividual, Isento].freeze + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/taxpayer_comments_resource.rb b/lib/nfe/generated/nf_produto_v2/taxpayer_comments_resource.rb new file mode 100644 index 0000000..3059b46 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/taxpayer_comments_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TaxpayerCommentsResource = Data.define(:field, :text) do + def self.from_api(payload) + return nil if payload.nil? + + new( + field: payload["field"], + text: payload["text"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/total.rb b/lib/nfe/generated/nf_produto_v2/total.rb new file mode 100644 index 0000000..a1edcee --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/total.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + Total = Data.define(:icms, :issqn) do + def self.from_api(payload) + return nil if payload.nil? + + new( + icms: ICMSTotal.from_api(payload["icms"]), + issqn: ISSQNTotal.from_api(payload["issqn"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/total_resource.rb b/lib/nfe/generated/nf_produto_v2/total_resource.rb new file mode 100644 index 0000000..e73e332 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/total_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TotalResource = Data.define(:icms, :issqn) do + def self.from_api(payload) + return nil if payload.nil? + + new( + icms: ICMSTotalResource.from_api(payload["icms"]), + issqn: ISSQNTotalResource.from_api(payload["issqn"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/transport_group_resource.rb b/lib/nfe/generated/nf_produto_v2/transport_group_resource.rb new file mode 100644 index 0000000..df93fa9 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/transport_group_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TransportGroupResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :transport_retention, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + transport_retention: payload["transportRetention"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/transport_information_resource.rb b/lib/nfe/generated/nf_produto_v2/transport_information_resource.rb new file mode 100644 index 0000000..97f97da --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/transport_information_resource.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TransportInformationResource = Data.define(:freight_modality, :reboque, :seal_number, :transp_rate, :transport_group, :transport_vehicle, :volume) do + def self.from_api(payload) + return nil if payload.nil? + + new( + freight_modality: payload["freightModality"], + reboque: ReboqueResource.from_api(payload["reboque"]), + seal_number: payload["sealNumber"], + transp_rate: TransportRateResource.from_api(payload["transpRate"]), + transport_group: TransportGroupResource.from_api(payload["transportGroup"]), + transport_vehicle: TransportVehicleResource.from_api(payload["transportVehicle"]), + volume: VolumeResource.from_api(payload["volume"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/transport_rate_resource.rb b/lib/nfe/generated/nf_produto_v2/transport_rate_resource.rb new file mode 100644 index 0000000..f0c68fb --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/transport_rate_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TransportRateResource = Data.define(:bc_retention_amount, :cfop, :city_generator_fact_code, :icms_retention_amount, :icms_retention_rate, :service_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bc_retention_amount: payload["bcRetentionAmount"], + cfop: payload["cfop"], + city_generator_fact_code: payload["cityGeneratorFactCode"], + icms_retention_amount: payload["icmsRetentionAmount"], + icms_retention_rate: payload["icmsRetentionRate"], + service_amount: payload["serviceAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/transport_vehicle_resource.rb b/lib/nfe/generated/nf_produto_v2/transport_vehicle_resource.rb new file mode 100644 index 0000000..01325ba --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/transport_vehicle_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + TransportVehicleResource = Data.define(:plate, :rntc, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + plate: payload["plate"], + rntc: payload["rntc"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/vehicle_detail_resource.rb b/lib/nfe/generated/nf_produto_v2/vehicle_detail_resource.rb new file mode 100644 index 0000000..b94d509 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/vehicle_detail_resource.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + VehicleDetailResource = Data.define(:brand_model_code, :chassis, :color_code, :color_description, :denatran_color_code, :engine_displacement, :engine_number, :engine_power, :fuel_type, :gross_weight, :manufacture_year, :maximum_traction_capacity, :model_year, :net_weight, :operation_type, :paint_type, :restriction_type, :seating_capacity, :serial_number, :vehicle_condition, :vehicle_species, :vehicle_type, :vin_condition, :wheel_base) do + def self.from_api(payload) + return nil if payload.nil? + + new( + brand_model_code: payload["brandModelCode"], + chassis: payload["chassis"], + color_code: payload["colorCode"], + color_description: payload["colorDescription"], + denatran_color_code: payload["denatranColorCode"], + engine_displacement: payload["engineDisplacement"], + engine_number: payload["engineNumber"], + engine_power: payload["enginePower"], + fuel_type: payload["fuelType"], + gross_weight: payload["grossWeight"], + manufacture_year: payload["manufactureYear"], + maximum_traction_capacity: payload["maximumTractionCapacity"], + model_year: payload["modelYear"], + net_weight: payload["netWeight"], + operation_type: payload["operationType"], + paint_type: payload["paintType"], + restriction_type: payload["restrictionType"], + seating_capacity: payload["seatingCapacity"], + serial_number: payload["serialNumber"], + vehicle_condition: payload["vehicleCondition"], + vehicle_species: payload["vehicleSpecies"], + vehicle_type: payload["vehicleType"], + vin_condition: payload["vinCondition"], + wheel_base: payload["wheelBase"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/volume_resource.rb b/lib/nfe/generated/nf_produto_v2/volume_resource.rb new file mode 100644 index 0000000..90788c6 --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/volume_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + VolumeResource = Data.define(:brand, :gross_weight, :net_weight, :species, :volume_numeration, :volume_quantity) do + def self.from_api(payload) + return nil if payload.nil? + + new( + brand: payload["brand"], + gross_weight: payload["grossWeight"], + net_weight: payload["netWeight"], + species: payload["species"], + volume_numeration: payload["volumeNumeration"], + volume_quantity: payload["volumeQuantity"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nf_produto_v2/withdrawal_information_resource.rb b/lib/nfe/generated/nf_produto_v2/withdrawal_information_resource.rb new file mode 100644 index 0000000..1eadcdb --- /dev/null +++ b/lib/nfe/generated/nf_produto_v2/withdrawal_information_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + WithdrawalInformationResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/batch_process_response.rb b/lib/nfe/generated/nfeio/batch_process_response.rb new file mode 100644 index 0000000..753e7d0 --- /dev/null +++ b/lib/nfe/generated/nfeio/batch_process_response.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + BatchProcessResponse = Data.define(:created_at, :input, :out_puts, :status, :status_reason, :updated_at) do + def self.from_api(payload) + return nil if payload.nil? + + new( + created_at: payload["createdAt"], + input: payload["input"], + out_puts: (payload["outPuts"] || []).map { |e| OutPutResponse.from_api(e) }, + status: payload["status"], + status_reason: payload["statusReason"], + updated_at: payload["updatedAt"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/environment.rb b/lib/nfe/generated/nfeio/environment.rb new file mode 100644 index 0000000..34f7979 --- /dev/null +++ b/lib/nfe/generated/nfeio/environment.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module Environment + Test = "Test" + Production = "Production" + ALL = [Test, Production].freeze + end + end + end +end diff --git a/lib/nfe/generated/nfeio/file_parsing_options_request.rb b/lib/nfe/generated/nfeio/file_parsing_options_request.rb new file mode 100644 index 0000000..748632c --- /dev/null +++ b/lib/nfe/generated/nfeio/file_parsing_options_request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + FileParsingOptionsRequest = Data.define(:column_to_parse, :parsing_type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + column_to_parse: payload["columnToParse"], + parsing_type: payload["parsingType"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/guid_pagination_cursor.rb b/lib/nfe/generated/nfeio/guid_pagination_cursor.rb new file mode 100644 index 0000000..2d68443 --- /dev/null +++ b/lib/nfe/generated/nfeio/guid_pagination_cursor.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + GuidPaginationCursor = Data.define(:value) do + def self.from_api(payload) + return nil if payload.nil? + + new( + value: payload["value"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/input_info_request.rb b/lib/nfe/generated/nfeio/input_info_request.rb new file mode 100644 index 0000000..5ad09fa --- /dev/null +++ b/lib/nfe/generated/nfeio/input_info_request.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + InputInfoRequest = Data.define(:parsing_options, :url, :use_cache) do + def self.from_api(payload) + return nil if payload.nil? + + new( + parsing_options: FileParsingOptionsRequest.from_api(payload["parsingOptions"]), + url: payload["url"], + use_cache: payload["useCache"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/inputs_response.rb b/lib/nfe/generated/nfeio/inputs_response.rb new file mode 100644 index 0000000..98b43d8 --- /dev/null +++ b/lib/nfe/generated/nfeio/inputs_response.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + InputsResponse = Data.define(:outputs, :total_inputs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + outputs: payload["outputs"], + total_inputs: payload["totalInputs"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/out_put_link_response.rb b/lib/nfe/generated/nfeio/out_put_link_response.rb new file mode 100644 index 0000000..63993c4 --- /dev/null +++ b/lib/nfe/generated/nfeio/out_put_link_response.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + OutPutLinkResponse = Data.define(:file_name, :url) do + def self.from_api(payload) + return nil if payload.nil? + + new( + file_name: payload["fileName"], + url: payload["url"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/out_put_response.rb b/lib/nfe/generated/nfeio/out_put_response.rb new file mode 100644 index 0000000..0747965 --- /dev/null +++ b/lib/nfe/generated/nfeio/out_put_response.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + OutPutResponse = Data.define(:out_put_link, :status, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + out_put_link: OutPutLinkResponse.from_api(payload["outPutLink"]), + status: payload["status"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/output_type.rb b/lib/nfe/generated/nfeio/output_type.rb new file mode 100644 index 0000000..9e7ba4d --- /dev/null +++ b/lib/nfe/generated/nfeio/output_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module OutputType + PDF = "PDF" + XML = "XML" + Csv = "Csv" + ALL = [PDF, XML, Csv].freeze + end + end + end +end diff --git a/lib/nfe/generated/nfeio/parsing_type.rb b/lib/nfe/generated/nfeio/parsing_type.rb new file mode 100644 index 0000000..eab254b --- /dev/null +++ b/lib/nfe/generated/nfeio/parsing_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module ParsingType + Csv = "Csv" + Xls = "Xls" + ALL = [Csv, Xls].freeze + end + end + end +end diff --git a/lib/nfe/generated/nfeio/problem_details.rb b/lib/nfe/generated/nfeio/problem_details.rb new file mode 100644 index 0000000..eec69b3 --- /dev/null +++ b/lib/nfe/generated/nfeio/problem_details.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ProblemDetails = Data.define(:detail, :instance, :status, :title, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + detail: payload["detail"], + instance: payload["instance"], + status: payload["status"], + title: payload["title"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/processing_batch_detail_response.rb b/lib/nfe/generated/nfeio/processing_batch_detail_response.rb new file mode 100644 index 0000000..355eaa3 --- /dev/null +++ b/lib/nfe/generated/nfeio/processing_batch_detail_response.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ProcessingBatchDetailResponse = Data.define(:batch_processes, :created_at, :created_by, :id, :inputs, :metrics, :name, :resource_name, :stage, :status, :updated_at) do + def self.from_api(payload) + return nil if payload.nil? + + new( + batch_processes: (payload["batchProcesses"] || []).map { |e| BatchProcessResponse.from_api(e) }, + created_at: payload["createdAt"], + created_by: payload["createdBy"], + id: payload["id"], + inputs: InputsResponse.from_api(payload["inputs"]), + metrics: ProcessingMetricsResponse.from_api(payload["metrics"]), + name: payload["name"], + resource_name: payload["resourceName"], + stage: payload["stage"], + status: payload["status"], + updated_at: payload["updatedAt"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/processing_batch_summary_response.rb b/lib/nfe/generated/nfeio/processing_batch_summary_response.rb new file mode 100644 index 0000000..03e0a05 --- /dev/null +++ b/lib/nfe/generated/nfeio/processing_batch_summary_response.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ProcessingBatchSummaryResponse = Data.define(:auto_generated, :created_at, :created_by, :id, :inputs, :metrics, :name, :out_puts, :parent_id, :resource_name, :stage, :status, :updated_at) do + def self.from_api(payload) + return nil if payload.nil? + + new( + auto_generated: payload["autoGenerated"], + created_at: payload["createdAt"], + created_by: payload["createdBy"], + id: payload["id"], + inputs: InputsResponse.from_api(payload["inputs"]), + metrics: ProcessingMetricsResponse.from_api(payload["metrics"]), + name: payload["name"], + out_puts: (payload["outPuts"] || []).map { |e| OutPutResponse.from_api(e) }, + parent_id: payload["parentId"], + resource_name: payload["resourceName"], + stage: payload["stage"], + status: payload["status"], + updated_at: payload["updatedAt"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/processing_batch_summary_response_page.rb b/lib/nfe/generated/nfeio/processing_batch_summary_response_page.rb new file mode 100644 index 0000000..2d4091a --- /dev/null +++ b/lib/nfe/generated/nfeio/processing_batch_summary_response_page.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ProcessingBatchSummaryResponsePage = Data.define(:has_next, :has_previous, :items, :next_cursor, :previous_cursor) do + def self.from_api(payload) + return nil if payload.nil? + + new( + has_next: payload["hasNext"], + has_previous: payload["hasPrevious"], + items: (payload["items"] || []).map { |e| ProcessingBatchSummaryResponse.from_api(e) }, + next_cursor: GuidPaginationCursor.from_api(payload["nextCursor"]), + previous_cursor: GuidPaginationCursor.from_api(payload["previousCursor"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/processing_batches_response.rb b/lib/nfe/generated/nfeio/processing_batches_response.rb new file mode 100644 index 0000000..d8ad8c5 --- /dev/null +++ b/lib/nfe/generated/nfeio/processing_batches_response.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ProcessingBatchesResponse = Data.define(:created_at, :id, :status, :updated_at) do + def self.from_api(payload) + return nil if payload.nil? + + new( + created_at: payload["createdAt"], + id: payload["id"], + status: payload["status"], + updated_at: payload["updatedAt"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/processing_metrics_response.rb b/lib/nfe/generated/nfeio/processing_metrics_response.rb new file mode 100644 index 0000000..cb7b2a4 --- /dev/null +++ b/lib/nfe/generated/nfeio/processing_metrics_response.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ProcessingMetricsResponse = Data.define(:total, :total_error, :total_success) do + def self.from_api(payload) + return nil if payload.nil? + + new( + total: payload["total"], + total_error: payload["totalError"], + total_success: payload["totalSuccess"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/resource_info.rb b/lib/nfe/generated/nfeio/resource_info.rb new file mode 100644 index 0000000..b5ffbbe --- /dev/null +++ b/lib/nfe/generated/nfeio/resource_info.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ResourceInfo = Data.define(:id, :name, :outputs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + name: payload["name"], + outputs: payload["outputs"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/resource_info_request.rb b/lib/nfe/generated/nfeio/resource_info_request.rb new file mode 100644 index 0000000..c0a3791 --- /dev/null +++ b/lib/nfe/generated/nfeio/resource_info_request.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ResourceInfoRequest = Data.define(:id, :name, :outputs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + name: payload["name"], + outputs: payload["outputs"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/sort_direction.rb b/lib/nfe/generated/nfeio/sort_direction.rb new file mode 100644 index 0000000..a791d21 --- /dev/null +++ b/lib/nfe/generated/nfeio/sort_direction.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module SortDirection + Forward = "Forward" + Backward = "Backward" + ALL = [Forward, Backward].freeze + end + end + end +end diff --git a/lib/nfe/generated/nfeio/sort_order.rb b/lib/nfe/generated/nfeio/sort_order.rb new file mode 100644 index 0000000..a95518a --- /dev/null +++ b/lib/nfe/generated/nfeio/sort_order.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module SortOrder + Asc = "Asc" + Desc = "Desc" + ALL = [Asc, Desc].freeze + end + end + end +end diff --git a/lib/nfe/generated/nfeio/start_processing_job_request.rb b/lib/nfe/generated/nfeio/start_processing_job_request.rb new file mode 100644 index 0000000..431ad0f --- /dev/null +++ b/lib/nfe/generated/nfeio/start_processing_job_request.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + StartProcessingJobRequest = Data.define(:created_by, :environment, :input, :name, :resource) do + def self.from_api(payload) + return nil if payload.nil? + + new( + created_by: payload["createdBy"], + environment: payload["environment"], + input: InputInfoRequest.from_api(payload["input"]), + name: payload["name"], + resource: ResourceInfoRequest.from_api(payload["resource"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/nfeio/status_process.rb b/lib/nfe/generated/nfeio/status_process.rb new file mode 100644 index 0000000..d10424e --- /dev/null +++ b/lib/nfe/generated/nfeio/status_process.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module StatusProcess + Pending = "Pending" + Running = "Running" + Completed = "Completed" + Duplicated = "Duplicated" + Error = "Error" + PartialSuccess = "PartialSuccess" + Succeed = "Succeed" + ALL = [Pending, Running, Completed, Duplicated, Error, PartialSuccess, Succeed].freeze + end + end + end +end diff --git a/lib/nfe/generated/nfeio/zip_request.rb b/lib/nfe/generated/nfeio/zip_request.rb new file mode 100644 index 0000000..ec2aeb7 --- /dev/null +++ b/lib/nfe/generated/nfeio/zip_request.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + ZipRequest = Data.define(:blob_name, :id, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + blob_name: payload["blobName"], + id: payload["id"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/activity_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/activity_resource.rb new file mode 100644 index 0000000..66679a7 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/activity_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ActivityResource = Data.define(:data, :sequence, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + data: payload["data"], + sequence: payload["sequence"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/addition_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/addition_resource.rb new file mode 100644 index 0000000..af4df0e --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/addition_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + AdditionResource = Data.define(:amount, :code, :drawback, :manufacturer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + code: payload["code"], + drawback: payload["drawback"], + manufacturer: payload["manufacturer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/additional_information_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/additional_information_resource.rb new file mode 100644 index 0000000..0c23c63 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/additional_information_resource.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + AdditionalInformationResource = Data.define(:advance_payment, :contract, :effort, :fisco, :order, :referenced_process, :tax_documents_reference, :taxpayer, :taxpayer_comments, :xml_authorized) do + def self.from_api(payload) + return nil if payload.nil? + + new( + advance_payment: (payload["advancePayment"] || []).map { |e| AdvancePaymentItemResource.from_api(e) }, + contract: payload["contract"], + effort: payload["effort"], + fisco: payload["fisco"], + order: payload["order"], + referenced_process: (payload["referencedProcess"] || []).map { |e| ReferencedProcessResource.from_api(e) }, + tax_documents_reference: (payload["taxDocumentsReference"] || []).map { |e| TaxDocumentsReferenceResource.from_api(e) }, + taxpayer: payload["taxpayer"], + taxpayer_comments: (payload["taxpayerComments"] || []).map { |e| TaxpayerCommentsResource.from_api(e) }, + xml_authorized: payload["xmlAuthorized"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/address_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/address_resource.rb new file mode 100644 index 0000000..9c82431 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/address_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + AddressResource = Data.define(:additional_information, :city, :country, :district, :number, :phone, :postal_code, :state, :street) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + city: CityResource.from_api(payload["city"]), + country: payload["country"], + district: payload["district"], + number: payload["number"], + phone: payload["phone"], + postal_code: payload["postalCode"], + state: payload["state"], + street: payload["street"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/advance_payment_item_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/advance_payment_item_resource.rb new file mode 100644 index 0000000..5894f88 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/advance_payment_item_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + AdvancePaymentItemResource = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/authorization_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/authorization_resource.rb new file mode 100644 index 0000000..11da3ca --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/authorization_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + AuthorizationResource = Data.define(:access_key, :description, :message, :receipt_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + description: payload["description"], + message: payload["message"], + receipt_on: payload["receiptOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/bill_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/bill_resource.rb new file mode 100644 index 0000000..86ca074 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/bill_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + BillResource = Data.define(:discount_amount, :net_amount, :number, :original_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + discount_amount: payload["discountAmount"], + net_amount: payload["netAmount"], + number: payload["number"], + original_amount: payload["originalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/billing_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/billing_resource.rb new file mode 100644 index 0000000..4594976 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/billing_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + BillingResource = Data.define(:bill, :duplicates) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bill: BillResource.from_api(payload["bill"]), + duplicates: (payload["duplicates"] || []).map { |e| DuplicateResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/buyer_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/buyer_resource.rb new file mode 100644 index 0000000..d35cfe0 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/buyer_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + BuyerResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :state_tax_number_indicator, :tax_regime, :trade_name, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + state_tax_number_indicator: payload["stateTaxNumberIndicator"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/card_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/card_resource.rb new file mode 100644 index 0000000..ee6daff --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/card_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CardResource = Data.define(:authorization, :federal_tax_number, :federal_tax_number_recipient, :flag, :id_payment_terminal, :integration_payment_type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorization: payload["authorization"], + federal_tax_number: payload["federalTaxNumber"], + federal_tax_number_recipient: payload["federalTaxNumberRecipient"], + flag: payload["flag"], + id_payment_terminal: payload["idPaymentTerminal"], + integration_payment_type: payload["integrationPaymentType"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/cbstax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/cbstax_resource.rb new file mode 100644 index 0000000..728c5b4 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/cbstax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CBSTaxResource = Data.define(:amount, :deferment, :rate, :reduction, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment: DefermentTaxResource.from_api(payload["deferment"]), + rate: payload["rate"], + reduction: ReductionTaxResource.from_api(payload["reduction"]), + returned_amount: ReturnedTaxResource.from_api(payload["returnedAmount"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/cbstotals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/cbstotals_resource.rb new file mode 100644 index 0000000..b6bde2c --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/cbstotals_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CBSTotalsResource = Data.define(:amount, :deferment_amount, :presumed_credit_amount, :presumed_credit_conditional_amount, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment_amount: payload["defermentAmount"], + presumed_credit_amount: payload["presumedCreditAmount"], + presumed_credit_conditional_amount: payload["presumedCreditConditionalAmount"], + returned_amount: payload["returnedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/cideresource.rb b/lib/nfe/generated/product_invoice_rtc_v1/cideresource.rb new file mode 100644 index 0000000..e666809 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/cideresource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CIDEResource = Data.define(:bc, :cide_amount, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bc: payload["bc"], + cide_amount: payload["cideAmount"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/city_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/city_resource.rb new file mode 100644 index 0000000..bdfd562 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/city_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CityResource = Data.define(:code, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/cofins_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/cofins_tax_resource.rb new file mode 100644 index 0000000..6e9b844 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/cofins_tax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CofinsTaxResource = Data.define(:amount, :base_tax, :base_tax_product_quantity, :cst, :product_rate, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + base_tax_product_quantity: payload["baseTaxProductQuantity"], + cst: payload["cst"], + product_rate: payload["productRate"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/competence_adjustment_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/competence_adjustment_resource.rb new file mode 100644 index 0000000..6acc8f3 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/competence_adjustment_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CompetenceAdjustmentResource = Data.define(:assessment_period, :cbs_amount, :ibs_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + assessment_period: payload["assessmentPeriod"], + cbs_amount: payload["cbsAmount"], + ibs_amount: payload["ibsAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/consumer_presence_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/consumer_presence_type.rb new file mode 100644 index 0000000..cb49d9d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/consumer_presence_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ConsumerPresenceType + None = "None" + Presence = "Presence" + Internet = "Internet" + Telephone = "Telephone" + Delivery = "Delivery" + OthersNonPresenceOperation = "OthersNonPresenceOperation" + ALL = [None, Presence, Internet, Telephone, Delivery, OthersNonPresenceOperation].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/consumer_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/consumer_type.rb new file mode 100644 index 0000000..450347c --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/consumer_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ConsumerType + FinalConsumer = "FinalConsumer" + Normal = "Normal" + ALL = [FinalConsumer, Normal].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/contingency_details.rb b/lib/nfe/generated/product_invoice_rtc_v1/contingency_details.rb new file mode 100644 index 0000000..c03d9aa --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/contingency_details.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ContingencyDetails = Data.define(:authorizer, :reason, :started_on) do + def self.from_api(payload) + return nil if payload.nil? + + new( + authorizer: payload["authorizer"], + reason: payload["reason"], + started_on: payload["startedOn"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/credit_reversal_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/credit_reversal_resource.rb new file mode 100644 index 0000000..6d83ad8 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/credit_reversal_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CreditReversalResource = Data.define(:cbs_reversal_amount, :ibs_reversal_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_reversal_amount: payload["cbsReversalAmount"], + ibs_reversal_amount: payload["ibsReversalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/credit_reversal_totals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/credit_reversal_totals_resource.rb new file mode 100644 index 0000000..3b56e1d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/credit_reversal_totals_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CreditReversalTotalsResource = Data.define(:cbs_reversal_amount, :ibs_reversal_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_reversal_amount: payload["cbsReversalAmount"], + ibs_reversal_amount: payload["ibsReversalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/credit_transfer_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/credit_transfer_tax_resource.rb new file mode 100644 index 0000000..a8d6873 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/credit_transfer_tax_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + CreditTransferTaxResource = Data.define(:cbs_amount, :ibs_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + ibs_amount: payload["ibsAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/credit_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/credit_type.rb new file mode 100644 index 0000000..229ed23 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/credit_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module CreditType + FinesAndInterest = "FinesAndInterest" + IbsPresumedCreditAppropriationZfm = "IbsPresumedCreditAppropriationZfm" + ReturnDeliveryRefusedOrNotFound = "ReturnDeliveryRefusedOrNotFound" + ValueReduction = "ValueReduction" + TransferCreditSuccession = "TransferCreditSuccession" + ALL = [FinesAndInterest, IbsPresumedCreditAppropriationZfm, ReturnDeliveryRefusedOrNotFound, ValueReduction, TransferCreditSuccession].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/debit_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/debit_type.rb new file mode 100644 index 0000000..763306a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/debit_type.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module DebitType + TransferCreditsToCooperatives = "TransferCreditsToCooperatives" + CancelCreditsExemptImmuneSales = "CancelCreditsExemptImmuneSales" + UnprocessedInvoicesDebits = "UnprocessedInvoicesDebits" + FinesAndInterest = "FinesAndInterest" + TransferInheritanceCredit = "TransferInheritanceCredit" + AdvancePayment = "AdvancePayment" + InventoryLoss = "InventoryLoss" + SnDisqualification = "SnDisqualification" + ALL = [TransferCreditsToCooperatives, CancelCreditsExemptImmuneSales, UnprocessedInvoicesDebits, FinesAndInterest, TransferInheritanceCredit, AdvancePayment, InventoryLoss, SnDisqualification].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/deferment_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/deferment_tax_resource.rb new file mode 100644 index 0000000..0044cb1 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/deferment_tax_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + DefermentTaxResource = Data.define(:amount, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/delivery_information_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/delivery_information_resource.rb new file mode 100644 index 0000000..29b389f --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/delivery_information_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + DeliveryInformationResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/destination.rb b/lib/nfe/generated/product_invoice_rtc_v1/destination.rb new file mode 100644 index 0000000..69fb46e --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/destination.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module Destination + None = "None" + InternalOperation = "InternalOperation" + InterstateOperation = "InterstateOperation" + InternationalOperation = "InternationalOperation" + ALL = [None, InternalOperation, InterstateOperation, InternationalOperation].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/disablement_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/disablement_resource.rb new file mode 100644 index 0000000..2ae7277 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/disablement_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + DisablementResource = Data.define(:begin_number, :environment, :last_number, :reason, :serie, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + begin_number: payload["beginNumber"], + environment: payload["environment"], + last_number: payload["lastNumber"], + reason: payload["reason"], + serie: payload["serie"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/document_electronic_invoice_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/document_electronic_invoice_resource.rb new file mode 100644 index 0000000..8fd914a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/document_electronic_invoice_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + DocumentElectronicInvoiceResource = Data.define(:access_key) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/document_invoice_reference_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/document_invoice_reference_resource.rb new file mode 100644 index 0000000..df16257 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/document_invoice_reference_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + DocumentInvoiceReferenceResource = Data.define(:federal_tax_number, :model, :number, :series, :state, :year_month) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + model: payload["model"], + number: payload["number"], + series: payload["series"], + state: payload["state"], + year_month: payload["yearMonth"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/duduction_indicator.rb b/lib/nfe/generated/product_invoice_rtc_v1/duduction_indicator.rb new file mode 100644 index 0000000..2e73afb --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/duduction_indicator.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module DuductionIndicator + NotDeduct = "NotDeduct" + Deduce = "Deduce" + ALL = [NotDeduct, Deduce].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/duplicate_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/duplicate_resource.rb new file mode 100644 index 0000000..d32f094 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/duplicate_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + DuplicateResource = Data.define(:amount, :expiration_on, :number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + expiration_on: payload["expirationOn"], + number: payload["number"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/economic_activity_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/economic_activity_resource.rb new file mode 100644 index 0000000..3723d1d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/economic_activity_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + EconomicActivityResource = Data.define(:code, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/economic_activity_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/economic_activity_type.rb new file mode 100644 index 0000000..2d7fcb3 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/economic_activity_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module EconomicActivityType + Main = "Main" + Secondary = "Secondary" + ALL = [Main, Secondary].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/environment_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/environment_type.rb new file mode 100644 index 0000000..4979505 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/environment_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module EnvironmentType + None = "None" + Production = "Production" + Test = "Test" + ALL = [None, Production, Test].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/error_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/error_resource.rb new file mode 100644 index 0000000..9a21d2b --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/error_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ErrorResource = Data.define(:code, :message) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + message: payload["message"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/errors_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/errors_resource.rb new file mode 100644 index 0000000..ccfab6d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/errors_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ErrorsResource = Data.define(:errors) do + def self.from_api(payload) + return nil if payload.nil? + + new( + errors: (payload["errors"] || []).map { |e| ErrorResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/exempt_reason.rb b/lib/nfe/generated/product_invoice_rtc_v1/exempt_reason.rb new file mode 100644 index 0000000..eb9bd41 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/exempt_reason.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ExemptReason + Agriculture = "Agriculture" + Others = "Others" + DevelopmentEntities = "DevelopmentEntities" + ALL = [Agriculture, Others, DevelopmentEntities].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/export_detail_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/export_detail_resource.rb new file mode 100644 index 0000000..240ba7e --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/export_detail_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ExportDetailResource = Data.define(:drawback, :hint_information) do + def self.from_api(payload) + return nil if payload.nil? + + new( + drawback: payload["drawback"], + hint_information: ExportHintResource.from_api(payload["hintInformation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/export_hint_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/export_hint_resource.rb new file mode 100644 index 0000000..29908d8 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/export_hint_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ExportHintResource = Data.define(:access_key, :quantity, :registry_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + quantity: payload["quantity"], + registry_id: payload["registryId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/export_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/export_resource.rb new file mode 100644 index 0000000..42d1940 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/export_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ExportResource = Data.define(:local, :office, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + local: payload["local"], + office: payload["office"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/file_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/file_resource.rb new file mode 100644 index 0000000..4943b21 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/file_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + FileResource = Data.define(:uri) do + def self.from_api(payload) + return nil if payload.nil? + + new( + uri: payload["uri"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/flag_card.rb b/lib/nfe/generated/product_invoice_rtc_v1/flag_card.rb new file mode 100644 index 0000000..56c69a5 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/flag_card.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module FlagCard + None = "None" + Visa = "Visa" + Mastercard = "Mastercard" + AmericanExpress = "AmericanExpress" + Sorocred = "Sorocred" + DinersClub = "DinersClub" + Elo = "Elo" + Hipercard = "Hipercard" + Aura = "Aura" + Cabal = "Cabal" + Alelo = "Alelo" + BanesCard = "BanesCard" + CalCard = "CalCard" + Credz = "Credz" + Discover = "Discover" + GoodCard = "GoodCard" + GreenCard = "GreenCard" + Hiper = "Hiper" + JCB = "JCB" + Mais = "Mais" + MaxVan = "MaxVan" + Policard = "Policard" + RedeCompras = "RedeCompras" + Sodexo = "Sodexo" + ValeCard = "ValeCard" + Verocheque = "Verocheque" + VR = "VR" + Ticket = "Ticket" + Other = "Other" + ALL = [None, Visa, Mastercard, AmericanExpress, Sorocred, DinersClub, Elo, Hipercard, Aura, Cabal, Alelo, BanesCard, CalCard, Credz, Discover, GoodCard, GreenCard, Hiper, JCB, Mais, MaxVan, Policard, RedeCompras, Sodexo, ValeCard, Verocheque, VR, Ticket, Other].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/fuel_origin_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/fuel_origin_resource.rb new file mode 100644 index 0000000..ae141a5 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/fuel_origin_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + FuelOriginResource = Data.define(:c_uforig, :ind_import, :p_orig) do + def self.from_api(payload) + return nil if payload.nil? + + new( + c_uforig: payload["cUFOrig"], + ind_import: payload["indImport"], + p_orig: payload["pOrig"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/fuel_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/fuel_resource.rb new file mode 100644 index 0000000..78ae641 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/fuel_resource.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + FuelResource = Data.define(:amount_temp, :cide, :code_anp, :codif, :description_anp, :fuel_origin, :percentage_glp, :percentage_gni, :percentage_ng, :percentage_ngn, :pump, :starting_amount, :state_buyer) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount_temp: payload["amountTemp"], + cide: CIDEResource.from_api(payload["cide"]), + code_anp: payload["codeANP"], + codif: payload["codif"], + description_anp: payload["descriptionANP"], + fuel_origin: FuelOriginResource.from_api(payload["fuelOrigin"]), + percentage_glp: payload["percentageGLP"], + percentage_gni: payload["percentageGNi"], + percentage_ng: payload["percentageNG"], + percentage_ngn: payload["percentageNGn"], + pump: PumpResource.from_api(payload["pump"]), + starting_amount: payload["startingAmount"], + state_buyer: payload["stateBuyer"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_entity_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_entity_type.rb new file mode 100644 index 0000000..e2c4531 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_entity_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module GovernmentPurchaseEntityType + Union = "Union" + State = "State" + FederalDistrict = "FederalDistrict" + Municipality = "Municipality" + ALL = [Union, State, FederalDistrict, Municipality].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_operation_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_operation_type.rb new file mode 100644 index 0000000..0f01979 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_operation_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module GovernmentPurchaseOperationType + Supply = "Supply" + Payment = "Payment" + SupplyThenPay = "SupplyThenPay" + PayForPastSupply = "PayForPastSupply" + SupplyAfterPay = "SupplyAfterPay" + PayNowSupplyLater = "PayNowSupplyLater" + SupplyAndPayNow = "SupplyAndPayNow" + ALL = [Supply, Payment, SupplyThenPay, PayForPastSupply, SupplyAfterPay, PayNowSupplyLater, SupplyAndPayNow].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_resource.rb new file mode 100644 index 0000000..3b1c472 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + GovernmentPurchaseResource = Data.define(:entity_type, :operation_type, :rate_reduction) do + def self.from_api(payload) + return nil if payload.nil? + + new( + entity_type: payload["entityType"], + operation_type: payload["operationType"], + rate_reduction: payload["rateReduction"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_tax_resource.rb new file mode 100644 index 0000000..7ec473e --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/government_purchase_tax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + GovernmentPurchaseTaxResource = Data.define(:cbs_amount, :cbs_rate, :municipal_amount, :municipal_rate, :state_amount, :state_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + cbs_rate: payload["cbsRate"], + municipal_amount: payload["municipalAmount"], + municipal_rate: payload["municipalRate"], + state_amount: payload["stateAmount"], + state_rate: payload["stateRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification.rb new file mode 100644 index 0000000..d4d1961 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module IbsZfmPresumedCreditClassification + NoPresumedCredit = "NoPresumedCredit" + FinalConsumptionGoods = "FinalConsumptionGoods" + CapitalGoods = "CapitalGoods" + IntermediateGoods = "IntermediateGoods" + ItAndOtherGoods = "ItAndOtherGoods" + ALL = [NoPresumedCredit, FinalConsumptionGoods, CapitalGoods, IntermediateGoods, ItAndOtherGoods].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibscbstax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibscbstax_resource.rb new file mode 100644 index 0000000..613df1d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibscbstax_resource.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSCBSTaxResource = Data.define(:basis, :calculation_mode, :cbs, :class_code, :credit_reversal, :credit_transfer, :donation_indicator, :government_purchase, :ibs_total_amount, :monophase, :municipal, :operational_presumed_credit, :regular_taxation, :situation_code, :state, :zfm_presumed_credit) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + calculation_mode: payload["calculationMode"], + cbs: CBSTaxResource.from_api(payload["cbs"]), + class_code: payload["classCode"], + credit_reversal: CreditReversalResource.from_api(payload["creditReversal"]), + credit_transfer: CreditTransferTaxResource.from_api(payload["creditTransfer"]), + donation_indicator: payload["donationIndicator"], + government_purchase: GovernmentPurchaseTaxResource.from_api(payload["governmentPurchase"]), + ibs_total_amount: payload["ibsTotalAmount"], + monophase: MonophaseIBSCBSTaxResource.from_api(payload["monophase"]), + municipal: IBSMunicipalTaxResource.from_api(payload["municipal"]), + operational_presumed_credit: OperationalPresumedCreditResource.from_api(payload["operationalPresumedCredit"]), + regular_taxation: RegularTaxationResource.from_api(payload["regularTaxation"]), + situation_code: payload["situationCode"], + state: IBSStateTaxResource.from_api(payload["state"]), + zfm_presumed_credit: ZfmPresumedCreditResource.from_api(payload["zfmPresumedCredit"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibscbstotals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibscbstotals_resource.rb new file mode 100644 index 0000000..973f4a4 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibscbstotals_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSCBSTotalsResource = Data.define(:basis, :cbs, :credit_reversal, :ibs, :monophase) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + cbs: CBSTotalsResource.from_api(payload["cbs"]), + credit_reversal: CreditReversalTotalsResource.from_api(payload["creditReversal"]), + ibs: IBSTotalsResource.from_api(payload["ibs"]), + monophase: MonophaseTotalsResource.from_api(payload["monophase"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource.rb new file mode 100644 index 0000000..eb328b6 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSMunicipalTaxResource = Data.define(:amount, :deferment, :rate, :reduction, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment: DefermentTaxResource.from_api(payload["deferment"]), + rate: payload["rate"], + reduction: ReductionTaxResource.from_api(payload["reduction"]), + returned_amount: ReturnedTaxResource.from_api(payload["returnedAmount"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource.rb new file mode 100644 index 0000000..1588edc --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSMunicipalTotalsResource = Data.define(:amount, :deferment_amount, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment_amount: payload["defermentAmount"], + returned_amount: payload["returnedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibsstate_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibsstate_tax_resource.rb new file mode 100644 index 0000000..a39b416 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibsstate_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSStateTaxResource = Data.define(:amount, :deferment, :rate, :reduction, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment: DefermentTaxResource.from_api(payload["deferment"]), + rate: payload["rate"], + reduction: ReductionTaxResource.from_api(payload["reduction"]), + returned_amount: ReturnedTaxResource.from_api(payload["returnedAmount"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibsstate_totals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibsstate_totals_resource.rb new file mode 100644 index 0000000..c135ae3 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibsstate_totals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSStateTotalsResource = Data.define(:amount, :deferment_amount, :returned_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + deferment_amount: payload["defermentAmount"], + returned_amount: payload["returnedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ibstotals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ibstotals_resource.rb new file mode 100644 index 0000000..d3aab93 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ibstotals_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IBSTotalsResource = Data.define(:municipal, :presumed_credit_amount, :presumed_credit_conditional_amount, :state, :total_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + municipal: IBSMunicipalTotalsResource.from_api(payload["municipal"]), + presumed_credit_amount: payload["presumedCreditAmount"], + presumed_credit_conditional_amount: payload["presumedCreditConditionalAmount"], + state: IBSStateTotalsResource.from_api(payload["state"]), + total_amount: payload["totalAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/icms_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/icms_tax_resource.rb new file mode 100644 index 0000000..121676b --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/icms_tax_resource.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IcmsTaxResource = Data.define(:amount, :amount_operation, :amount_streason, :base_deferred, :base_snretention_amount, :base_stretention_amount, :base_tax, :base_tax_fcpstamount, :base_tax_modality, :base_tax_operation_percentual, :base_tax_reduction, :base_tax_st, :base_tax_stmodality, :base_tax_streduction, :basis_benefit_code, :csosn, :cst, :deduction_indicator, :effective_amount, :effective_base_tax_amount, :effective_base_tax_reduction_rate, :effective_rate, :exempt_amount, :exempt_amount_st, :exempt_reason, :exempt_reason_st, :fcp_amount, :fcp_rate, :fcpst_amount, :fcpst_rate, :fcpst_ret_amount, :fcpst_ret_rate, :origin, :percentual, :percentual_deferment, :rate, :sn_credit_amount, :sn_credit_rate, :sn_retention_amount, :st_amount, :st_final_consumer_rate, :st_margin_added_amount, :st_margin_amount, :st_rate, :st_retention_amount, :substitute_amount, :ufst) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + amount_operation: payload["amountOperation"], + amount_streason: payload["amountSTReason"], + base_deferred: payload["baseDeferred"], + base_snretention_amount: payload["baseSNRetentionAmount"], + base_stretention_amount: payload["baseSTRetentionAmount"], + base_tax: payload["baseTax"], + base_tax_fcpstamount: payload["baseTaxFCPSTAmount"], + base_tax_modality: payload["baseTaxModality"], + base_tax_operation_percentual: payload["baseTaxOperationPercentual"], + base_tax_reduction: payload["baseTaxReduction"], + base_tax_st: payload["baseTaxST"], + base_tax_stmodality: payload["baseTaxSTModality"], + base_tax_streduction: payload["baseTaxSTReduction"], + basis_benefit_code: payload["basisBenefitCode"], + csosn: payload["csosn"], + cst: payload["cst"], + deduction_indicator: payload["deductionIndicator"], + effective_amount: payload["effectiveAmount"], + effective_base_tax_amount: payload["effectiveBaseTaxAmount"], + effective_base_tax_reduction_rate: payload["effectiveBaseTaxReductionRate"], + effective_rate: payload["effectiveRate"], + exempt_amount: payload["exemptAmount"], + exempt_amount_st: payload["exemptAmountST"], + exempt_reason: payload["exemptReason"], + exempt_reason_st: payload["exemptReasonST"], + fcp_amount: payload["fcpAmount"], + fcp_rate: payload["fcpRate"], + fcpst_amount: payload["fcpstAmount"], + fcpst_rate: payload["fcpstRate"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpst_ret_rate: payload["fcpstRetRate"], + origin: payload["origin"], + percentual: payload["percentual"], + percentual_deferment: payload["percentualDeferment"], + rate: payload["rate"], + sn_credit_amount: payload["snCreditAmount"], + sn_credit_rate: payload["snCreditRate"], + sn_retention_amount: payload["snRetentionAmount"], + st_amount: payload["stAmount"], + st_final_consumer_rate: payload["stFinalConsumerRate"], + st_margin_added_amount: payload["stMarginAddedAmount"], + st_margin_amount: payload["stMarginAmount"], + st_rate: payload["stRate"], + st_retention_amount: payload["stRetentionAmount"], + substitute_amount: payload["substituteAmount"], + ufst: payload["ufst"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/icmstotal.rb b/lib/nfe/generated/product_invoice_rtc_v1/icmstotal.rb new file mode 100644 index 0000000..59fabcc --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/icmstotal.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ICMSTotal = Data.define(:base_tax, :cofins_amount, :discount_amount, :fcp_amount, :fcpst_amount, :fcpst_ret_amount, :fcpuf_destination_amount, :federal_taxes_amount, :freight_amount, :icms_amount, :icms_exempt_amount, :icmsuf_destination_amount, :icmsuf_sender_amount, :ii_amount, :insurance_amount, :invoice_amount, :ipi_amount, :ipi_devol_amount, :others_amount, :pis_amount, :product_amount, :q_bcmono, :q_bcmono_ret, :q_bcmono_reten, :st_amount, :st_calculation_basis_amount, :v_icmsmono, :v_icmsmono_ret, :v_icmsmono_reten) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_tax: payload["baseTax"], + cofins_amount: payload["cofinsAmount"], + discount_amount: payload["discountAmount"], + fcp_amount: payload["fcpAmount"], + fcpst_amount: payload["fcpstAmount"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpuf_destination_amount: payload["fcpufDestinationAmount"], + federal_taxes_amount: payload["federalTaxesAmount"], + freight_amount: payload["freightAmount"], + icms_amount: payload["icmsAmount"], + icms_exempt_amount: payload["icmsExemptAmount"], + icmsuf_destination_amount: payload["icmsufDestinationAmount"], + icmsuf_sender_amount: payload["icmsufSenderAmount"], + ii_amount: payload["iiAmount"], + insurance_amount: payload["insuranceAmount"], + invoice_amount: payload["invoiceAmount"], + ipi_amount: payload["ipiAmount"], + ipi_devol_amount: payload["ipiDevolAmount"], + others_amount: payload["othersAmount"], + pis_amount: payload["pisAmount"], + product_amount: payload["productAmount"], + q_bcmono: payload["qBCMono"], + q_bcmono_ret: payload["qBCMonoRet"], + q_bcmono_reten: payload["qBCMonoReten"], + st_amount: payload["stAmount"], + st_calculation_basis_amount: payload["stCalculationBasisAmount"], + v_icmsmono: payload["vICMSMono"], + v_icmsmono_ret: payload["vICMSMonoRet"], + v_icmsmono_reten: payload["vICMSMonoReten"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/icmstotal_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/icmstotal_resource.rb new file mode 100644 index 0000000..1cc9cbd --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/icmstotal_resource.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ICMSTotalResource = Data.define(:base_tax, :cofins_amount, :discount_amount, :fcp_amount, :fcpst_amount, :fcpst_ret_amount, :fcpuf_destination_amount, :federal_taxes_amount, :freight_amount, :icms_amount, :icms_exempt_amount, :icmsuf_destination_amount, :icmsuf_sender_amount, :ii_amount, :insurance_amount, :invoice_amount, :ipi_amount, :ipi_devol_amount, :others_amount, :pis_amount, :product_amount, :q_bcmono, :q_bcmono_ret, :q_bcmono_reten, :st_amount, :st_calculation_basis_amount, :v_icmsmono, :v_icmsmono_ret, :v_icmsmono_reten) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_tax: payload["baseTax"], + cofins_amount: payload["cofinsAmount"], + discount_amount: payload["discountAmount"], + fcp_amount: payload["fcpAmount"], + fcpst_amount: payload["fcpstAmount"], + fcpst_ret_amount: payload["fcpstRetAmount"], + fcpuf_destination_amount: payload["fcpufDestinationAmount"], + federal_taxes_amount: payload["federalTaxesAmount"], + freight_amount: payload["freightAmount"], + icms_amount: payload["icmsAmount"], + icms_exempt_amount: payload["icmsExemptAmount"], + icmsuf_destination_amount: payload["icmsufDestinationAmount"], + icmsuf_sender_amount: payload["icmsufSenderAmount"], + ii_amount: payload["iiAmount"], + insurance_amount: payload["insuranceAmount"], + invoice_amount: payload["invoiceAmount"], + ipi_amount: payload["ipiAmount"], + ipi_devol_amount: payload["ipiDevolAmount"], + others_amount: payload["othersAmount"], + pis_amount: payload["pisAmount"], + product_amount: payload["productAmount"], + q_bcmono: payload["qBCMono"], + q_bcmono_ret: payload["qBCMonoRet"], + q_bcmono_reten: payload["qBCMonoReten"], + st_amount: payload["stAmount"], + st_calculation_basis_amount: payload["stCalculationBasisAmount"], + v_icmsmono: payload["vICMSMono"], + v_icmsmono_ret: payload["vICMSMonoRet"], + v_icmsmono_reten: payload["vICMSMonoReten"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/icmsufdestination_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/icmsufdestination_tax_resource.rb new file mode 100644 index 0000000..0a6cd80 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/icmsufdestination_tax_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ICMSUFDestinationTaxResource = Data.define(:p_fcpufdest, :p_icmsinter, :p_icmsinter_part, :p_icmsufdest, :v_bcfcpufdest, :v_bcufdest, :v_fcpufdest, :v_icmsufdest, :v_icmsufremet) do + def self.from_api(payload) + return nil if payload.nil? + + new( + p_fcpufdest: payload["pFCPUFDest"], + p_icmsinter: payload["pICMSInter"], + p_icmsinter_part: payload["pICMSInterPart"], + p_icmsufdest: payload["pICMSUFDest"], + v_bcfcpufdest: payload["vBCFCPUFDest"], + v_bcufdest: payload["vBCUFDest"], + v_fcpufdest: payload["vFCPUFDest"], + v_icmsufdest: payload["vICMSUFDest"], + v_icmsufremet: payload["vICMSUFRemet"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/iitax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/iitax_resource.rb new file mode 100644 index 0000000..5977eb6 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/iitax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IITaxResource = Data.define(:amount, :base_tax, :customs_expenditure_amount, :iof_amount, :v_enq_camb) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + customs_expenditure_amount: payload["customsExpenditureAmount"], + iof_amount: payload["iofAmount"], + v_enq_camb: payload["vEnqCamb"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/import_declaration_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/import_declaration_resource.rb new file mode 100644 index 0000000..c4d94ad --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/import_declaration_resource.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ImportDeclarationResource = Data.define(:acquirer_federal_tax_number, :additions, :afrmm_amount, :code, :customs_clearance_name, :customs_clearance_state, :customs_clearanced_on, :exporter, :intermediation, :international_transport, :registered_on, :state_third) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquirer_federal_tax_number: payload["acquirerFederalTaxNumber"], + additions: (payload["additions"] || []).map { |e| AdditionResource.from_api(e) }, + afrmm_amount: payload["afrmmAmount"], + code: payload["code"], + customs_clearance_name: payload["customsClearanceName"], + customs_clearance_state: payload["customsClearanceState"], + customs_clearanced_on: payload["customsClearancedOn"], + exporter: payload["exporter"], + intermediation: payload["intermediation"], + international_transport: payload["internationalTransport"], + registered_on: payload["registeredOn"], + state_third: payload["stateThird"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/integration_payment_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/integration_payment_type.rb new file mode 100644 index 0000000..552d8da --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/integration_payment_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module IntegrationPaymentType + Integrated = "Integrated" + NotIntegrated = "NotIntegrated" + ALL = [Integrated, NotIntegrated].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/intermediate_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/intermediate_resource.rb new file mode 100644 index 0000000..e6e5428 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/intermediate_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IntermediateResource = Data.define(:federal_tax_number, :identifier) do + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"], + identifier: payload["identifier"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/intermediation_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/intermediation_type.rb new file mode 100644 index 0000000..d29172c --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/intermediation_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module IntermediationType + None = "None" + ByOwn = "ByOwn" + ImportOnBehalf = "ImportOnBehalf" + ByOrder = "ByOrder" + ALL = [None, ByOwn, ImportOnBehalf, ByOrder].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/international_transport_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/international_transport_type.rb new file mode 100644 index 0000000..df155ca --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/international_transport_type.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module InternationalTransportType + None = "None" + Maritime = "Maritime" + River = "River" + Lake = "Lake" + Airline = "Airline" + Postal = "Postal" + Railway = "Railway" + Highway = "Highway" + Network = "Network" + Own = "Own" + Ficta = "Ficta" + Courier = "Courier" + Handcarry = "Handcarry" + ALL = [None, Maritime, River, Lake, Airline, Postal, Railway, Highway, Network, Own, Ficta, Courier, Handcarry].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_events_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_events_resource.rb new file mode 100644 index 0000000..5869cd7 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_events_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceEventsResource = Data.define(:account_id, :company_id, :events, :has_more, :id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + events: (payload["events"] || []).map { |e| ActivityResource.from_api(e) }, + has_more: payload["hasMore"], + id: payload["id"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_events_resource_base.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_events_resource_base.rb new file mode 100644 index 0000000..3eb38fa --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_events_resource_base.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceEventsResourceBase = Data.define(:events, :has_more) do + def self.from_api(payload) + return nil if payload.nil? + + new( + events: (payload["events"] || []).map { |e| ActivityResource.from_api(e) }, + has_more: payload["hasMore"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_item_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_item_resource.rb new file mode 100644 index 0000000..26be688 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_item_resource.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceItemResource = Data.define(:additional_information, :benefit, :cest, :cfop, :code, :code_gtin, :code_tax_gtin, :description, :discount_amount, :export_details, :extipi, :freight_amount, :fuel_detail, :ibs_zfm_presumed_credit_classification, :import_control_sheet_number, :import_declarations, :insurance_amount, :item_amount, :item_number_order_buy, :ncm, :number_order_buy, :nve, :others_amount, :presumed_credit, :quantity, :quantity_tax, :referenced_dfe, :tax, :tax_determination, :tax_unit_amount, :total_amount, :total_indicator, :unit, :unit_amount, :unit_tax, :used_movable_asset_indicator, :vehicle_detail) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + benefit: payload["benefit"], + cest: payload["cest"], + cfop: payload["cfop"], + code: payload["code"], + code_gtin: payload["codeGTIN"], + code_tax_gtin: payload["codeTaxGTIN"], + description: payload["description"], + discount_amount: payload["discountAmount"], + export_details: (payload["exportDetails"] || []).map { |e| ExportDetailResource.from_api(e) }, + extipi: payload["extipi"], + freight_amount: payload["freightAmount"], + fuel_detail: FuelResource.from_api(payload["fuelDetail"]), + ibs_zfm_presumed_credit_classification: payload["ibsZfmPresumedCreditClassification"], + import_control_sheet_number: payload["importControlSheetNumber"], + import_declarations: (payload["importDeclarations"] || []).map { |e| ImportDeclarationResource.from_api(e) }, + insurance_amount: payload["insuranceAmount"], + item_amount: payload["itemAmount"], + item_number_order_buy: payload["itemNumberOrderBuy"], + ncm: payload["ncm"], + number_order_buy: payload["numberOrderBuy"], + nve: payload["nve"], + others_amount: payload["othersAmount"], + presumed_credit: PresumedCreditResource.from_api(payload["presumedCredit"]), + quantity: payload["quantity"], + quantity_tax: payload["quantityTax"], + referenced_dfe: ReferencedDFeResource.from_api(payload["referencedDFe"]), + tax: InvoiceItemTaxResource.from_api(payload["tax"]), + tax_determination: TaxDeterminationResource.from_api(payload["taxDetermination"]), + tax_unit_amount: payload["taxUnitAmount"], + total_amount: payload["totalAmount"], + total_indicator: payload["totalIndicator"], + unit: payload["unit"], + unit_amount: payload["unitAmount"], + unit_tax: payload["unitTax"], + used_movable_asset_indicator: payload["usedMovableAssetIndicator"], + vehicle_detail: VehicleDetailResource.from_api(payload["vehicleDetail"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_item_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_item_tax_resource.rb new file mode 100644 index 0000000..e17b6ea --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_item_tax_resource.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceItemTaxResource = Data.define(:ibscbs, :is, :cofins, :competence_adjustment, :icms, :icms_destination, :ii, :ipi, :pis, :total_tax) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ibscbs: IBSCBSTaxResource.from_api(payload["IBSCBS"]), + is: ISTaxResource.from_api(payload["IS"]), + cofins: CofinsTaxResource.from_api(payload["cofins"]), + competence_adjustment: CompetenceAdjustmentResource.from_api(payload["competenceAdjustment"]), + icms: IcmsTaxResource.from_api(payload["icms"]), + icms_destination: ICMSUFDestinationTaxResource.from_api(payload["icmsDestination"]), + ii: IITaxResource.from_api(payload["ii"]), + ipi: IPITaxResource.from_api(payload["ipi"]), + pis: PISTaxResource.from_api(payload["pis"]), + total_tax: payload["totalTax"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_items_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_items_resource.rb new file mode 100644 index 0000000..10aa499 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_items_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceItemsResource = Data.define(:account_id, :company_id, :has_more, :id, :items) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + has_more: payload["hasMore"], + id: payload["id"], + items: (payload["items"] || []).map { |e| InvoiceItemResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_resource.rb new file mode 100644 index 0000000..7447529 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_resource.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceResource = Data.define(:additional_information, :authorization, :billing, :buyer, :contingency_details, :created_on, :delivery, :environment_type, :export, :id, :issuer, :last_events, :modified_on, :number, :operation_nature, :operation_on, :operation_type, :payment, :purpose_type, :serie, :status, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + authorization: AuthorizationResource.from_api(payload["authorization"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + contingency_details: ContingencyDetails.from_api(payload["contingencyDetails"]), + created_on: payload["createdOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + environment_type: payload["environmentType"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerResource.from_api(payload["issuer"]), + last_events: InvoiceEventsResourceBase.from_api(payload["lastEvents"]), + modified_on: payload["modifiedOn"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + purpose_type: payload["purposeType"], + serie: payload["serie"], + status: payload["status"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_status.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_status.rb new file mode 100644 index 0000000..645a8cf --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_status.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module InvoiceStatus + None = "None" + Created = "Created" + Processing = "Processing" + Issued = "Issued" + IssuedContingency = "IssuedContingency" + Cancelled = "Cancelled" + Disabled = "Disabled" + IssueDenied = "IssueDenied" + Error = "Error" + ALL = [None, Created, Processing, Issued, IssuedContingency, Cancelled, Disabled, IssueDenied, Error].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/invoice_without_events_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/invoice_without_events_resource.rb new file mode 100644 index 0000000..01f9436 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/invoice_without_events_resource.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + InvoiceWithoutEventsResource = Data.define(:additional_information, :authorization, :billing, :buyer, :contingency_details, :created_on, :delivery, :environment_type, :export, :id, :issuer, :modified_on, :number, :operation_nature, :operation_on, :operation_type, :payment, :purpose_type, :serie, :status, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + authorization: AuthorizationResource.from_api(payload["authorization"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + contingency_details: ContingencyDetails.from_api(payload["contingencyDetails"]), + created_on: payload["createdOn"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + environment_type: payload["environmentType"], + export: ExportResource.from_api(payload["export"]), + id: payload["id"], + issuer: IssuerResource.from_api(payload["issuer"]), + modified_on: payload["modifiedOn"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + purpose_type: payload["purposeType"], + serie: payload["serie"], + status: payload["status"], + totals: TotalResource.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/ipitax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/ipitax_resource.rb new file mode 100644 index 0000000..1cdaee2 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/ipitax_resource.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IPITaxResource = Data.define(:amount, :base, :classification, :classification_code, :cst, :producer_cnpj, :rate, :stamp_code, :stamp_quantity, :unit_amount, :unit_quantity) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base: payload["base"], + classification: payload["classification"], + classification_code: payload["classificationCode"], + cst: payload["cst"], + producer_cnpj: payload["producerCNPJ"], + rate: payload["rate"], + stamp_code: payload["stampCode"], + stamp_quantity: payload["stampQuantity"], + unit_amount: payload["unitAmount"], + unit_quantity: payload["unitQuantity"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/issqntotal.rb b/lib/nfe/generated/product_invoice_rtc_v1/issqntotal.rb new file mode 100644 index 0000000..15009e2 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/issqntotal.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ISSQNTotal = Data.define(:base_rate_iss, :code_tax_regime, :deduction_reduction_bc, :discount_conditioning, :discount_unconditional, :provision_service, :total_iss, :total_retention_iss, :total_service_not_taxed_icms, :value_other_retention, :value_service_cofins, :value_service_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_rate_iss: payload["baseRateISS"], + code_tax_regime: payload["codeTaxRegime"], + deduction_reduction_bc: payload["deductionReductionBC"], + discount_conditioning: payload["discountConditioning"], + discount_unconditional: payload["discountUnconditional"], + provision_service: payload["provisionService"], + total_iss: payload["totalISS"], + total_retention_iss: payload["totalRetentionISS"], + total_service_not_taxed_icms: payload["totalServiceNotTaxedICMS"], + value_other_retention: payload["valueOtherRetention"], + value_service_cofins: payload["valueServiceCOFINS"], + value_service_pis: payload["valueServicePIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/issqntotal_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/issqntotal_resource.rb new file mode 100644 index 0000000..2d3ffdf --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/issqntotal_resource.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ISSQNTotalResource = Data.define(:base_rate_iss, :code_tax_regime, :deduction_reduction_bc, :discount_conditioning, :discount_unconditional, :provision_service, :total_iss, :total_retention_iss, :total_service_not_taxed_icms, :value_other_retention, :value_service_cofins, :value_service_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + base_rate_iss: payload["baseRateISS"], + code_tax_regime: payload["codeTaxRegime"], + deduction_reduction_bc: payload["deductionReductionBC"], + discount_conditioning: payload["discountConditioning"], + discount_unconditional: payload["discountUnconditional"], + provision_service: payload["provisionService"], + total_iss: payload["totalISS"], + total_retention_iss: payload["totalRetentionISS"], + total_service_not_taxed_icms: payload["totalServiceNotTaxedICMS"], + value_other_retention: payload["valueOtherRetention"], + value_service_cofins: payload["valueServiceCOFINS"], + value_service_pis: payload["valueServicePIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/issuer_from_request_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/issuer_from_request_resource.rb new file mode 100644 index 0000000..c79104e --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/issuer_from_request_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IssuerFromRequestResource = Data.define(:st_state_tax_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + st_state_tax_number: payload["stStateTaxNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/issuer_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/issuer_resource.rb new file mode 100644 index 0000000..ccf3f1a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/issuer_resource.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + IssuerResource = Data.define(:account_id, :address, :company_registry_number, :economic_activities, :email, :federal_tax_number, :id, :legal_nature, :municipal_tax_number, :name, :openning_date, :regional_sttax_number, :regional_tax_number, :special_tax_regime, :st_state_tax_number, :tax_regime, :trade_name, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + company_registry_number: payload["companyRegistryNumber"], + economic_activities: (payload["economicActivities"] || []).map { |e| EconomicActivityResource.from_api(e) }, + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + legal_nature: payload["legalNature"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + openning_date: payload["openningDate"], + regional_sttax_number: payload["regionalSTTaxNumber"], + regional_tax_number: payload["regionalTaxNumber"], + special_tax_regime: payload["specialTaxRegime"], + st_state_tax_number: payload["stStateTaxNumber"], + tax_regime: payload["taxRegime"], + trade_name: payload["tradeName"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/istax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/istax_resource.rb new file mode 100644 index 0000000..df6421b --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/istax_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ISTaxResource = Data.define(:amount, :basis, :classification_code, :quantity, :rate, :situation_code, :unit, :unit_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + basis: payload["basis"], + classification_code: payload["classificationCode"], + quantity: payload["quantity"], + rate: payload["rate"], + situation_code: payload["situationCode"], + unit: payload["unit"], + unit_rate: payload["unitRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/istotals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/istotals_resource.rb new file mode 100644 index 0000000..40ef088 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/istotals_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ISTotalsResource = Data.define(:amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/legal_nature.rb b/lib/nfe/generated/product_invoice_rtc_v1/legal_nature.rb new file mode 100644 index 0000000..ccd6efa --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/legal_nature.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module LegalNature + EmpresaPublica = "EmpresaPublica" + SociedadeEconomiaMista = "SociedadeEconomiaMista" + SociedadeAnonimaAberta = "SociedadeAnonimaAberta" + SociedadeAnonimaFechada = "SociedadeAnonimaFechada" + SociedadeEmpresariaLimitada = "SociedadeEmpresariaLimitada" + SociedadeEmpresariaEmNomeColetivo = "SociedadeEmpresariaEmNomeColetivo" + SociedadeEmpresariaEmComanditaSimples = "SociedadeEmpresariaEmComanditaSimples" + SociedadeEmpresariaEmComanditaporAcoes = "SociedadeEmpresariaEmComanditaporAcoes" + SociedadeemContaParticipacao = "SociedadeemContaParticipacao" + Empresario = "Empresario" + Cooperativa = "Cooperativa" + ConsorcioSociedades = "ConsorcioSociedades" + GrupoSociedades = "GrupoSociedades" + EmpresaDomiciliadaExterior = "EmpresaDomiciliadaExterior" + ClubeFundoInvestimento = "ClubeFundoInvestimento" + SociedadeSimplesPura = "SociedadeSimplesPura" + SociedadeSimplesLimitada = "SociedadeSimplesLimitada" + SociedadeSimplesEmNomeColetivo = "SociedadeSimplesEmNomeColetivo" + SociedadeSimplesEmComanditaSimples = "SociedadeSimplesEmComanditaSimples" + EmpresaBinacional = "EmpresaBinacional" + ConsorcioEmpregadores = "ConsorcioEmpregadores" + ConsorcioSimples = "ConsorcioSimples" + EireliNaturezaEmpresaria = "EireliNaturezaEmpresaria" + EireliNaturezaSimples = "EireliNaturezaSimples" + ServicoNotarial = "ServicoNotarial" + FundacaoPrivada = "FundacaoPrivada" + ServicoSocialAutonomo = "ServicoSocialAutonomo" + CondominioEdilicio = "CondominioEdilicio" + ComissaoConciliacaoPrevia = "ComissaoConciliacaoPrevia" + EntidadeMediacaoArbitragem = "EntidadeMediacaoArbitragem" + PartidoPolitico = "PartidoPolitico" + EntidadeSindical = "EntidadeSindical" + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras = "EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras" + FundacaoAssociacaoDomiciliadaExterior = "FundacaoAssociacaoDomiciliadaExterior" + OrganizacaoReligiosa = "OrganizacaoReligiosa" + ComunidadeIndigena = "ComunidadeIndigena" + FundoPrivado = "FundoPrivado" + AssociacaoPrivada = "AssociacaoPrivada" + ALL = [EmpresaPublica, SociedadeEconomiaMista, SociedadeAnonimaAberta, SociedadeAnonimaFechada, SociedadeEmpresariaLimitada, SociedadeEmpresariaEmNomeColetivo, SociedadeEmpresariaEmComanditaSimples, SociedadeEmpresariaEmComanditaporAcoes, SociedadeemContaParticipacao, Empresario, Cooperativa, ConsorcioSociedades, GrupoSociedades, EmpresaDomiciliadaExterior, ClubeFundoInvestimento, SociedadeSimplesPura, SociedadeSimplesLimitada, SociedadeSimplesEmNomeColetivo, SociedadeSimplesEmComanditaSimples, EmpresaBinacional, ConsorcioEmpregadores, ConsorcioSimples, EireliNaturezaEmpresaria, EireliNaturezaSimples, ServicoNotarial, FundacaoPrivada, ServicoSocialAutonomo, CondominioEdilicio, ComissaoConciliacaoPrevia, EntidadeMediacaoArbitragem, PartidoPolitico, EntidadeSindical, EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras, FundacaoAssociacaoDomiciliadaExterior, OrganizacaoReligiosa, ComunidadeIndigena, FundoPrivado, AssociacaoPrivada].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_cbstotals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_cbstotals_resource.rb new file mode 100644 index 0000000..5ac30a3 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_cbstotals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseCBSTotalsResource = Data.define(:amount, :previously_withheld_amount, :withheld_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + previously_withheld_amount: payload["previouslyWithheldAmount"], + withheld_amount: payload["withheldAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_deferment_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_deferment_tax_resource.rb new file mode 100644 index 0000000..432fa4e --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_deferment_tax_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseDefermentTaxResource = Data.define(:cbs_amount, :cbs_rate, :ibs_amount, :ibs_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + cbs_rate: payload["cbsRate"], + ibs_amount: payload["ibsAmount"], + ibs_rate: payload["ibsRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_ibscbstax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_ibscbstax_resource.rb new file mode 100644 index 0000000..4471b46 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_ibscbstax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseIBSCBSTaxResource = Data.define(:cbs_amount, :deferment, :ibs_amount, :previously_withheld, :standart, :withholding) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_amount: payload["cbsAmount"], + deferment: MonophaseDefermentTaxResource.from_api(payload["deferment"]), + ibs_amount: payload["ibsAmount"], + previously_withheld: MonophasePreviouslyWithheldTaxResource.from_api(payload["previouslyWithheld"]), + standart: MonophaseStandardTaxResource.from_api(payload["standart"]), + withholding: MonophaseWithholdingTaxResource.from_api(payload["withholding"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_ibstotals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_ibstotals_resource.rb new file mode 100644 index 0000000..1229251 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_ibstotals_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseIBSTotalsResource = Data.define(:amount, :previously_withheld_amount, :withheld_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + previously_withheld_amount: payload["previouslyWithheldAmount"], + withheld_amount: payload["withheldAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource.rb new file mode 100644 index 0000000..396769f --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophasePreviouslyWithheldTaxResource = Data.define(:cbs_ad_rem_rate, :cbs_amount, :ibs_ad_rem_rate, :ibs_amount, :quantity_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_ad_rem_rate: payload["cbsAdRemRate"], + cbs_amount: payload["cbsAmount"], + ibs_ad_rem_rate: payload["ibsAdRemRate"], + ibs_amount: payload["ibsAmount"], + quantity_basis: payload["quantityBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_standard_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_standard_tax_resource.rb new file mode 100644 index 0000000..c04c118 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_standard_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseStandardTaxResource = Data.define(:cbs_ad_rem_rate, :cbs_amount, :ibs_ad_rem_rate, :ibs_amount, :quantity_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_ad_rem_rate: payload["cbsAdRemRate"], + cbs_amount: payload["cbsAmount"], + ibs_ad_rem_rate: payload["ibsAdRemRate"], + ibs_amount: payload["ibsAmount"], + quantity_basis: payload["quantityBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_totals_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_totals_resource.rb new file mode 100644 index 0000000..5150494 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_totals_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseTotalsResource = Data.define(:cbs, :ibs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs: MonophaseCBSTotalsResource.from_api(payload["cbs"]), + ibs: MonophaseIBSTotalsResource.from_api(payload["ibs"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/monophase_withholding_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/monophase_withholding_tax_resource.rb new file mode 100644 index 0000000..1084404 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/monophase_withholding_tax_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + MonophaseWithholdingTaxResource = Data.define(:cbs_ad_rem_rate, :cbs_amount, :ibs_ad_rem_rate, :ibs_amount, :quantity_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cbs_ad_rem_rate: payload["cbsAdRemRate"], + cbs_amount: payload["cbsAmount"], + ibs_ad_rem_rate: payload["ibsAdRemRate"], + ibs_amount: payload["ibsAmount"], + quantity_basis: payload["quantityBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/operation_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/operation_type.rb new file mode 100644 index 0000000..1c31db2 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/operation_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module OperationType + Outgoing = "Outgoing" + Incoming = "Incoming" + ALL = [Outgoing, Incoming].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/operational_presumed_credit_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/operational_presumed_credit_resource.rb new file mode 100644 index 0000000..f0f806c --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/operational_presumed_credit_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + OperationalPresumedCreditResource = Data.define(:basis, :cbs, :classification_code, :ibs) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + cbs: PresumedCreditDetailsResource.from_api(payload["cbs"]), + classification_code: payload["classificationCode"], + ibs: PresumedCreditDetailsResource.from_api(payload["ibs"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/payment_detail_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/payment_detail_resource.rb new file mode 100644 index 0000000..35b80c5 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/payment_detail_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PaymentDetailResource = Data.define(:amount, :card, :federal_tax_number_pag, :method, :method_description, :payment_date, :payment_type, :state_pag) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + card: CardResource.from_api(payload["card"]), + federal_tax_number_pag: payload["federalTaxNumberPag"], + method: payload["method"], + method_description: payload["methodDescription"], + payment_date: payload["paymentDate"], + payment_type: payload["paymentType"], + state_pag: payload["statePag"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/payment_method.rb b/lib/nfe/generated/product_invoice_rtc_v1/payment_method.rb new file mode 100644 index 0000000..49fd31a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/payment_method.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PaymentMethod + Cash = "Cash" + Cheque = "Cheque" + CreditCard = "CreditCard" + DebitCard = "DebitCard" + StoreCredict = "StoreCredict" + FoodVouchers = "FoodVouchers" + MealVouchers = "MealVouchers" + GiftVouchers = "GiftVouchers" + FuelVouchers = "FuelVouchers" + MercantileDuplicate = "MercantileDuplicate" + BankBill = "BankBill" + BankDeposit = "BankDeposit" + InstantPayment = "InstantPayment" + WireTransfer = "WireTransfer" + Cashback = "Cashback" + StaticInstantPayment = "StaticInstantPayment" + StoreCredit = "StoreCredit" + ElectronicPaymentNotInformed = "ElectronicPaymentNotInformed" + WithoutPayment = "WithoutPayment" + Others = "Others" + ALL = [Cash, Cheque, CreditCard, DebitCard, StoreCredict, FoodVouchers, MealVouchers, GiftVouchers, FuelVouchers, MercantileDuplicate, BankBill, BankDeposit, InstantPayment, WireTransfer, Cashback, StaticInstantPayment, StoreCredit, ElectronicPaymentNotInformed, WithoutPayment, Others].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/payment_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/payment_resource.rb new file mode 100644 index 0000000..943c0c7 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/payment_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PaymentResource = Data.define(:pay_back, :payment_detail) do + def self.from_api(payload) + return nil if payload.nil? + + new( + pay_back: payload["payBack"], + payment_detail: (payload["paymentDetail"] || []).map { |e| PaymentDetailResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/payment_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/payment_type.rb new file mode 100644 index 0000000..00200c4 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/payment_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PaymentType + InCash = "InCash" + Term = "Term" + ALL = [InCash, Term].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/person_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/person_type.rb new file mode 100644 index 0000000..837dd6d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/person_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PersonType + Undefined = "Undefined" + NaturalPerson = "NaturalPerson" + LegalEntity = "LegalEntity" + Company = "Company" + Customer = "Customer" + ALL = [Undefined, NaturalPerson, LegalEntity, Company, Customer].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/pistax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/pistax_resource.rb new file mode 100644 index 0000000..9654ce5 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/pistax_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PISTaxResource = Data.define(:amount, :base_tax, :base_tax_product_quantity, :cst, :product_rate, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + base_tax: payload["baseTax"], + base_tax_product_quantity: payload["baseTaxProductQuantity"], + cst: payload["cst"], + product_rate: payload["productRate"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_classification_code.rb b/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_classification_code.rb new file mode 100644 index 0000000..b298db9 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_classification_code.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PresumedCreditClassificationCode + RuralProducerNonTaxpayer = "RuralProducerNonTaxpayer" + TacPfTransportServiceNonTaxpayer = "TacPfTransportServiceNonTaxpayer" + RecyclingFromIndividual = "RecyclingFromIndividual" + UsedMovableGoodsFromIndividualForResale = "UsedMovableGoodsFromIndividualForResale" + OptionalRegimeForCooperative = "OptionalRegimeForCooperative" + ALL = [RuralProducerNonTaxpayer, TacPfTransportServiceNonTaxpayer, RecyclingFromIndividual, UsedMovableGoodsFromIndividualForResale, OptionalRegimeForCooperative].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_details_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_details_resource.rb new file mode 100644 index 0000000..30d67ef --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_details_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PresumedCreditDetailsResource = Data.define(:amount, :rate, :suspensive_condition_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + rate: payload["rate"], + suspensive_condition_amount: payload["suspensiveConditionAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_resource.rb new file mode 100644 index 0000000..858a4da --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/presumed_credit_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PresumedCreditResource = Data.define(:amount, :code, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + code: payload["code"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/print_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/print_type.rb new file mode 100644 index 0000000..aff57cf --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/print_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PrintType + None = "None" + NFeNormalPortrait = "NFeNormalPortrait" + NFeNormalLandscape = "NFeNormalLandscape" + NFeSimplified = "NFeSimplified" + DANFENFCE = "DANFE_NFC_E" + DANFENFCEMSGELETRONICA = "DANFE_NFC_E_MSG_ELETRONICA" + ALL = [None, NFeNormalPortrait, NFeNormalLandscape, NFeSimplified, DANFENFCE, DANFENFCEMSGELETRONICA].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/product_invoice_request.rb b/lib/nfe/generated/product_invoice_rtc_v1/product_invoice_request.rb new file mode 100644 index 0000000..6f0847d --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/product_invoice_request.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ProductInvoiceRequest = Data.define(:additional_information, :billing, :buyer, :consumer_type, :consumption_city_code, :contingency_justification, :contingency_on, :credit_type, :debit_type, :delivery, :destination, :expected_delivery_on, :export, :government_purchase, :ibs_consumption_city_code, :id, :issuer_tax_substitute, :items, :number, :operation_nature, :operation_on, :operation_type, :payment, :presence_type, :print_type, :purchase_information, :purpose_type, :serie, :totals, :transaction_intermediate, :transport, :withdrawal) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: AdditionalInformationResource.from_api(payload["additionalInformation"]), + billing: BillingResource.from_api(payload["billing"]), + buyer: BuyerResource.from_api(payload["buyer"]), + consumer_type: payload["consumerType"], + consumption_city_code: payload["consumptionCityCode"], + contingency_justification: payload["contingencyJustification"], + contingency_on: payload["contingencyOn"], + credit_type: payload["creditType"], + debit_type: payload["debitType"], + delivery: DeliveryInformationResource.from_api(payload["delivery"]), + destination: payload["destination"], + expected_delivery_on: payload["expectedDeliveryOn"], + export: ExportResource.from_api(payload["export"]), + government_purchase: GovernmentPurchaseResource.from_api(payload["governmentPurchase"]), + ibs_consumption_city_code: payload["ibsConsumptionCityCode"], + id: payload["id"], + issuer_tax_substitute: IssuerFromRequestResource.from_api(payload["issuerTaxSubstitute"]), + items: (payload["items"] || []).map { |e| InvoiceItemResource.from_api(e) }, + number: payload["number"], + operation_nature: payload["operationNature"], + operation_on: payload["operationOn"], + operation_type: payload["operationType"], + payment: (payload["payment"] || []).map { |e| PaymentResource.from_api(e) }, + presence_type: payload["presenceType"], + print_type: payload["printType"], + purchase_information: PurchaseInformationResource.from_api(payload["purchaseInformation"]), + purpose_type: payload["purposeType"], + serie: payload["serie"], + totals: Total.from_api(payload["totals"]), + transaction_intermediate: IntermediateResource.from_api(payload["transactionIntermediate"]), + transport: TransportInformationResource.from_api(payload["transport"]), + withdrawal: WithdrawalInformationResource.from_api(payload["withdrawal"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/product_invoices_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/product_invoices_resource.rb new file mode 100644 index 0000000..4e24496 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/product_invoices_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ProductInvoicesResource = Data.define(:has_more, :product_invoices) do + def self.from_api(payload) + return nil if payload.nil? + + new( + has_more: payload["hasMore"], + product_invoices: (payload["productInvoices"] || []).map { |e| InvoiceWithoutEventsResource.from_api(e) }, + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/pump_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/pump_resource.rb new file mode 100644 index 0000000..d25a2b6 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/pump_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PumpResource = Data.define(:beginning_amount, :end_amount, :number, :percentage_bio, :spout_number, :tank_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + beginning_amount: payload["beginningAmount"], + end_amount: payload["endAmount"], + number: payload["number"], + percentage_bio: payload["percentageBio"], + spout_number: payload["spoutNumber"], + tank_number: payload["tankNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/purchase_information_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/purchase_information_resource.rb new file mode 100644 index 0000000..f5365d1 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/purchase_information_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + PurchaseInformationResource = Data.define(:commitment_note, :contract_number, :purchase_order) do + def self.from_api(payload) + return nil if payload.nil? + + new( + commitment_note: payload["commitmentNote"], + contract_number: payload["contractNumber"], + purchase_order: payload["purchaseOrder"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/purpose_type.rb b/lib/nfe/generated/product_invoice_rtc_v1/purpose_type.rb new file mode 100644 index 0000000..cf49812 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/purpose_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PurposeType + None = "None" + Normal = "Normal" + Complement = "Complement" + Adjustment = "Adjustment" + Devolution = "Devolution" + ALL = [None, Normal, Complement, Adjustment, Devolution].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/queue_event_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/queue_event_resource.rb new file mode 100644 index 0000000..b9bbda4 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/queue_event_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + QueueEventResource = Data.define(:reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/reboque_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/reboque_resource.rb new file mode 100644 index 0000000..e49c3a2 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/reboque_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ReboqueResource = Data.define(:ferry, :plate, :rntc, :uf, :wagon) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ferry: payload["ferry"], + plate: payload["plate"], + rntc: payload["rntc"], + uf: payload["uf"], + wagon: payload["wagon"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/receiver_state_tax_indicator.rb b/lib/nfe/generated/product_invoice_rtc_v1/receiver_state_tax_indicator.rb new file mode 100644 index 0000000..820eb37 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/receiver_state_tax_indicator.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ReceiverStateTaxIndicator + None = "None" + TaxPayer = "TaxPayer" + Exempt = "Exempt" + NonTaxPayer = "NonTaxPayer" + ALL = [None, TaxPayer, Exempt, NonTaxPayer].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/reduction_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/reduction_tax_resource.rb new file mode 100644 index 0000000..e2ae95a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/reduction_tax_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ReductionTaxResource = Data.define(:effective_rate, :rate_reduction) do + def self.from_api(payload) + return nil if payload.nil? + + new( + effective_rate: payload["effectiveRate"], + rate_reduction: payload["rateReduction"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/referenced_dfe_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/referenced_dfe_resource.rb new file mode 100644 index 0000000..6e35b77 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/referenced_dfe_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ReferencedDFeResource = Data.define(:access_key, :item_number) do + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"], + item_number: payload["itemNumber"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/referenced_process_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/referenced_process_resource.rb new file mode 100644 index 0000000..c85db0a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/referenced_process_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ReferencedProcessResource = Data.define(:concession_act_type, :identifier_concessory, :identifier_origin) do + def self.from_api(payload) + return nil if payload.nil? + + new( + concession_act_type: payload["concessionActType"], + identifier_concessory: payload["identifierConcessory"], + identifier_origin: payload["identifierOrigin"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/regular_taxation_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/regular_taxation_resource.rb new file mode 100644 index 0000000..284dfd2 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/regular_taxation_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + RegularTaxationResource = Data.define(:amount, :cbs_amount, :cbs_effective_rate, :class_code, :municipal_amount, :municipal_effective_rate, :situation_code, :state_effective_rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + cbs_amount: payload["cbsAmount"], + cbs_effective_rate: payload["cbsEffectiveRate"], + class_code: payload["classCode"], + municipal_amount: payload["municipalAmount"], + municipal_effective_rate: payload["municipalEffectiveRate"], + situation_code: payload["situationCode"], + state_effective_rate: payload["stateEffectiveRate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/request_cancellation_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/request_cancellation_resource.rb new file mode 100644 index 0000000..b99448a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/request_cancellation_resource.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + RequestCancellationResource = Data.define(:account_id, :company_id, :product_invoice_id, :reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + company_id: payload["companyId"], + product_invoice_id: payload["productInvoiceId"], + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/returned_tax_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/returned_tax_resource.rb new file mode 100644 index 0000000..5005b46 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/returned_tax_resource.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ReturnedTaxResource = Data.define(:amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/shipping_modality.rb b/lib/nfe/generated/product_invoice_rtc_v1/shipping_modality.rb new file mode 100644 index 0000000..9a702b0 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/shipping_modality.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ShippingModality + ByIssuer = "ByIssuer" + ByReceiver = "ByReceiver" + ByThirdParties = "ByThirdParties" + OwnBySender = "OwnBySender" + OwnByBuyer = "OwnByBuyer" + Free = "Free" + ALL = [ByIssuer, ByReceiver, ByThirdParties, OwnBySender, OwnByBuyer, Free].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/special_tax_regime.rb b/lib/nfe/generated/product_invoice_rtc_v1/special_tax_regime.rb new file mode 100644 index 0000000..d33d431 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/special_tax_regime.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module SpecialTaxRegime + Nenhum = "Nenhum" + MicroempresaMunicipal = "MicroempresaMunicipal" + Estimativa = "Estimativa" + SociedadeDeProfissionais = "SociedadeDeProfissionais" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + MicroempresarioEmpresaPequenoPorte = "MicroempresarioEmpresaPequenoPorte" + Automatico = "Automatico" + ALL = [Nenhum, MicroempresaMunicipal, Estimativa, SociedadeDeProfissionais, MicroempreendedorIndividual, MicroempresarioEmpresaPequenoPorte, Automatico].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/state_code.rb b/lib/nfe/generated/product_invoice_rtc_v1/state_code.rb new file mode 100644 index 0000000..b9a0d4a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/state_code.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module StateCode + NA = "NA" + RO = "RO" + AC = "AC" + AM = "AM" + RR = "RR" + PA = "PA" + AP = "AP" + TO = "TO" + MA = "MA" + PI = "PI" + CE = "CE" + RN = "RN" + PB = "PB" + PE = "PE" + AL = "AL" + SE = "SE" + BA = "BA" + MG = "MG" + ES = "ES" + RJ = "RJ" + SP = "SP" + PR = "PR" + SC = "SC" + RS = "RS" + MS = "MS" + MT = "MT" + GO = "GO" + DF = "DF" + EX = "EX" + ALL = [NA, RO, AC, AM, RR, PA, AP, TO, MA, PI, CE, RN, PB, PE, AL, SE, BA, MG, ES, RJ, SP, PR, SC, RS, MS, MT, GO, DF, EX].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/state_tax_processing_authorizer.rb b/lib/nfe/generated/product_invoice_rtc_v1/state_tax_processing_authorizer.rb new file mode 100644 index 0000000..9b25421 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/state_tax_processing_authorizer.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module StateTaxProcessingAuthorizer + Normal = "Normal" + EPEC = "EPEC" + ALL = [Normal, EPEC].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/tax_coupon_information_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/tax_coupon_information_resource.rb new file mode 100644 index 0000000..59571d6 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/tax_coupon_information_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TaxCouponInformationResource = Data.define(:model_document_fiscal, :order_count_operation, :order_ecf) do + def self.from_api(payload) + return nil if payload.nil? + + new( + model_document_fiscal: payload["modelDocumentFiscal"], + order_count_operation: payload["orderCountOperation"], + order_ecf: payload["orderECF"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/tax_determination_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/tax_determination_resource.rb new file mode 100644 index 0000000..87b8473 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/tax_determination_resource.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TaxDeterminationResource = Data.define(:acquisition_purpose, :buyer_tax_profile, :issuer_tax_profile, :operation_code, :origin) do + def self.from_api(payload) + return nil if payload.nil? + + new( + acquisition_purpose: payload["acquisitionPurpose"], + buyer_tax_profile: payload["buyerTaxProfile"], + issuer_tax_profile: payload["issuerTaxProfile"], + operation_code: payload["operationCode"], + origin: payload["origin"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/tax_documents_reference_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/tax_documents_reference_resource.rb new file mode 100644 index 0000000..a8592eb --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/tax_documents_reference_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TaxDocumentsReferenceResource = Data.define(:document_electronic_invoice, :document_invoice_reference, :tax_coupon_information) do + def self.from_api(payload) + return nil if payload.nil? + + new( + document_electronic_invoice: DocumentElectronicInvoiceResource.from_api(payload["documentElectronicInvoice"]), + document_invoice_reference: DocumentInvoiceReferenceResource.from_api(payload["documentInvoiceReference"]), + tax_coupon_information: TaxCouponInformationResource.from_api(payload["taxCouponInformation"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/tax_regime.rb b/lib/nfe/generated/product_invoice_rtc_v1/tax_regime.rb new file mode 100644 index 0000000..79ba9f6 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/tax_regime.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module TaxRegime + None = "None" + LucroReal = "LucroReal" + LucroPresumido = "LucroPresumido" + SimplesNacional = "SimplesNacional" + SimplesNacionalExcessoSublimite = "SimplesNacionalExcessoSublimite" + MicroempreendedorIndividual = "MicroempreendedorIndividual" + Isento = "Isento" + ALL = [None, LucroReal, LucroPresumido, SimplesNacional, SimplesNacionalExcessoSublimite, MicroempreendedorIndividual, Isento].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/taxpayer_comments_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/taxpayer_comments_resource.rb new file mode 100644 index 0000000..ad21f58 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/taxpayer_comments_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TaxpayerCommentsResource = Data.define(:field, :text) do + def self.from_api(payload) + return nil if payload.nil? + + new( + field: payload["field"], + text: payload["text"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/total.rb b/lib/nfe/generated/product_invoice_rtc_v1/total.rb new file mode 100644 index 0000000..22f2e5f --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/total.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + Total = Data.define(:ibs_cbs_totals, :icms, :is_totals, :issqn, :total_invoice_amount, :withheld_taxes) do + def self.from_api(payload) + return nil if payload.nil? + + new( + ibs_cbs_totals: IBSCBSTotalsResource.from_api(payload["ibsCbsTotals"]), + icms: ICMSTotal.from_api(payload["icms"]), + is_totals: ISTotalsResource.from_api(payload["isTotals"]), + issqn: ISSQNTotal.from_api(payload["issqn"]), + total_invoice_amount: payload["totalInvoiceAmount"], + withheld_taxes: TotalsWithholdings.from_api(payload["withheldTaxes"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/total_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/total_resource.rb new file mode 100644 index 0000000..a066be5 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/total_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TotalResource = Data.define(:icms, :issqn) do + def self.from_api(payload) + return nil if payload.nil? + + new( + icms: ICMSTotalResource.from_api(payload["icms"]), + issqn: ISSQNTotalResource.from_api(payload["issqn"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/totals_withholdings.rb b/lib/nfe/generated/product_invoice_rtc_v1/totals_withholdings.rb new file mode 100644 index 0000000..934f419 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/totals_withholdings.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TotalsWithholdings = Data.define(:cofins_amount, :csll_amount, :irrf_amount, :irrf_basis, :pis_amount, :social_secutiry_amount, :social_secutiry_basis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cofins_amount: payload["cofinsAmount"], + csll_amount: payload["csllAmount"], + irrf_amount: payload["irrfAmount"], + irrf_basis: payload["irrfBasis"], + pis_amount: payload["pisAmount"], + social_secutiry_amount: payload["socialSecutiryAmount"], + social_secutiry_basis: payload["socialSecutiryBasis"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/transport_group_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/transport_group_resource.rb new file mode 100644 index 0000000..6924e97 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/transport_group_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TransportGroupResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :transport_retention, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + transport_retention: payload["transportRetention"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/transport_information_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/transport_information_resource.rb new file mode 100644 index 0000000..02ee193 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/transport_information_resource.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TransportInformationResource = Data.define(:freight_modality, :reboque, :seal_number, :transp_rate, :transport_group, :transport_vehicle, :volume) do + def self.from_api(payload) + return nil if payload.nil? + + new( + freight_modality: payload["freightModality"], + reboque: ReboqueResource.from_api(payload["reboque"]), + seal_number: payload["sealNumber"], + transp_rate: TransportRateResource.from_api(payload["transpRate"]), + transport_group: TransportGroupResource.from_api(payload["transportGroup"]), + transport_vehicle: TransportVehicleResource.from_api(payload["transportVehicle"]), + volume: VolumeResource.from_api(payload["volume"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/transport_rate_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/transport_rate_resource.rb new file mode 100644 index 0000000..e63fc0a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/transport_rate_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TransportRateResource = Data.define(:bc_retention_amount, :cfop, :city_generator_fact_code, :icms_retention_amount, :icms_retention_rate, :service_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + bc_retention_amount: payload["bcRetentionAmount"], + cfop: payload["cfop"], + city_generator_fact_code: payload["cityGeneratorFactCode"], + icms_retention_amount: payload["icmsRetentionAmount"], + icms_retention_rate: payload["icmsRetentionRate"], + service_amount: payload["serviceAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/transport_vehicle_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/transport_vehicle_resource.rb new file mode 100644 index 0000000..e9ae57a --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/transport_vehicle_resource.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + TransportVehicleResource = Data.define(:plate, :rntc, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + plate: payload["plate"], + rntc: payload["rntc"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/vehicle_detail_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/vehicle_detail_resource.rb new file mode 100644 index 0000000..e16e6e9 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/vehicle_detail_resource.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + VehicleDetailResource = Data.define(:brand_model_code, :chassis, :color_code, :color_description, :denatran_color_code, :engine_displacement, :engine_number, :engine_power, :fuel_type, :gross_weight, :manufacture_year, :maximum_traction_capacity, :model_year, :net_weight, :operation_type, :paint_type, :restriction_type, :seating_capacity, :serial_number, :vehicle_condition, :vehicle_species, :vehicle_type, :vin_condition, :wheel_base) do + def self.from_api(payload) + return nil if payload.nil? + + new( + brand_model_code: payload["brandModelCode"], + chassis: payload["chassis"], + color_code: payload["colorCode"], + color_description: payload["colorDescription"], + denatran_color_code: payload["denatranColorCode"], + engine_displacement: payload["engineDisplacement"], + engine_number: payload["engineNumber"], + engine_power: payload["enginePower"], + fuel_type: payload["fuelType"], + gross_weight: payload["grossWeight"], + manufacture_year: payload["manufactureYear"], + maximum_traction_capacity: payload["maximumTractionCapacity"], + model_year: payload["modelYear"], + net_weight: payload["netWeight"], + operation_type: payload["operationType"], + paint_type: payload["paintType"], + restriction_type: payload["restrictionType"], + seating_capacity: payload["seatingCapacity"], + serial_number: payload["serialNumber"], + vehicle_condition: payload["vehicleCondition"], + vehicle_species: payload["vehicleSpecies"], + vehicle_type: payload["vehicleType"], + vin_condition: payload["vinCondition"], + wheel_base: payload["wheelBase"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/volume_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/volume_resource.rb new file mode 100644 index 0000000..94d1015 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/volume_resource.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + VolumeResource = Data.define(:brand, :gross_weight, :net_weight, :species, :volume_numeration, :volume_quantity) do + def self.from_api(payload) + return nil if payload.nil? + + new( + brand: payload["brand"], + gross_weight: payload["grossWeight"], + net_weight: payload["netWeight"], + species: payload["species"], + volume_numeration: payload["volumeNumeration"], + volume_quantity: payload["volumeQuantity"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/withdrawal_information_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/withdrawal_information_resource.rb new file mode 100644 index 0000000..fbc4412 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/withdrawal_information_resource.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + WithdrawalInformationResource = Data.define(:account_id, :address, :email, :federal_tax_number, :id, :name, :state_tax_number, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + account_id: payload["accountId"], + address: AddressResource.from_api(payload["address"]), + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + id: payload["id"], + name: payload["name"], + state_tax_number: payload["stateTaxNumber"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_invoice_rtc_v1/zfm_presumed_credit_resource.rb b/lib/nfe/generated/product_invoice_rtc_v1/zfm_presumed_credit_resource.rb new file mode 100644 index 0000000..4f0ce65 --- /dev/null +++ b/lib/nfe/generated/product_invoice_rtc_v1/zfm_presumed_credit_resource.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + ZfmPresumedCreditResource = Data.define(:amount, :classification_code) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + classification_code: payload["classificationCode"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/cofins_tax_group.rb b/lib/nfe/generated/product_register_pt_br_v1/cofins_tax_group.rb new file mode 100644 index 0000000..58c47ec --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/cofins_tax_group.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + CofinsTaxGroup = Data.define(:cst, :p_cofins) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cst: payload["cst"], + p_cofins: payload["pCOFINS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/custom_tax_scenario.rb b/lib/nfe/generated/product_register_pt_br_v1/custom_tax_scenario.rb new file mode 100644 index 0000000..25aec47 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/custom_tax_scenario.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + CustomTaxScenario = Data.define(:operation_code, :inter_state, :intra_state, :issuer, :recipient) do + def self.from_api(payload) + return nil if payload.nil? + + new( + operation_code: payload["OperationCode"], + inter_state: InterStateTaxGroup.from_api(payload["interState"]), + intra_state: IntraStateTaxGroup.from_api(payload["intraState"]), + issuer: payload["issuer"], + recipient: payload["recipient"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/icms_tax_group.rb b/lib/nfe/generated/product_register_pt_br_v1/icms_tax_group.rb new file mode 100644 index 0000000..c8d16d6 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/icms_tax_group.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + IcmsTaxGroup = Data.define(:cst, :mod_bc, :mod_bcst, :mot_des_icms, :mot_des_icmsst, :p_cred_sn, :p_dif, :p_fcp, :p_fcpdif, :p_fcpst, :p_fcpstret, :p_icms, :p_icmsefet, :p_icmsst, :p_mvast, :p_red_bc, :p_red_bcefet, :p_red_bcst) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cst: payload["cst"], + mod_bc: payload["modBC"], + mod_bcst: payload["modBCST"], + mot_des_icms: payload["motDesICMS"], + mot_des_icmsst: payload["motDesICMSST"], + p_cred_sn: payload["pCredSN"], + p_dif: payload["pDif"], + p_fcp: payload["pFCP"], + p_fcpdif: payload["pFCPDif"], + p_fcpst: payload["pFCPST"], + p_fcpstret: payload["pFCPSTRet"], + p_icms: payload["pICMS"], + p_icmsefet: payload["pICMSEfet"], + p_icmsst: payload["pICMSST"], + p_mvast: payload["pMVAST"], + p_red_bc: payload["pRedBC"], + p_red_bcefet: payload["pRedBCEfet"], + p_red_bcst: payload["pRedBCST"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/inter_state_tax_group.rb b/lib/nfe/generated/product_register_pt_br_v1/inter_state_tax_group.rb new file mode 100644 index 0000000..2921090 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/inter_state_tax_group.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + InterStateTaxGroup = Data.define(:cfop, :cofins, :icms, :pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cfop: payload["cfop"], + cofins: CofinsTaxGroup.from_api(payload["cofins"]), + icms: IcmsTaxGroup.from_api(payload["icms"]), + pis: PisTaxGroup.from_api(payload["pis"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/intra_state_tax_group.rb b/lib/nfe/generated/product_register_pt_br_v1/intra_state_tax_group.rb new file mode 100644 index 0000000..d9f6011 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/intra_state_tax_group.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + IntraStateTaxGroup = Data.define(:cfop, :cofins, :icms, :pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cfop: payload["cfop"], + cofins: CofinsTaxGroup.from_api(payload["cofins"]), + icms: IcmsTaxGroup.from_api(payload["icms"]), + pis: PisTaxGroup.from_api(payload["pis"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/issuer_tax_profile_enum.rb b/lib/nfe/generated/product_register_pt_br_v1/issuer_tax_profile_enum.rb new file mode 100644 index 0000000..17f7150 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/issuer_tax_profile_enum.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + module IssuerTaxProfileEnum + None = "none" + Retail = "retail" + Wholesale = "wholesale" + WholesaleIndustry = "wholesale_industry" + Importer = "importer" + Industry = "industry" + Cooperative = "cooperative" + ALL = [None, Retail, Wholesale, WholesaleIndustry, Importer, Industry, Cooperative].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/pis_tax_group.rb b/lib/nfe/generated/product_register_pt_br_v1/pis_tax_group.rb new file mode 100644 index 0000000..85b08e2 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/pis_tax_group.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + PisTaxGroup = Data.define(:cst, :p_pis) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cst: payload["cst"], + p_pis: payload["pPIS"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/product.rb b/lib/nfe/generated/product_register_pt_br_v1/product.rb new file mode 100644 index 0000000..7116d40 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/product.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + Product = Data.define(:collection_id, :custom_tax, :description, :gtin, :id, :origin, :sku, :tax, :tax_gtin, :tenant_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + collection_id: payload["collectionId"], + custom_tax: (payload["customTax"] || []).map { |e| CustomTaxScenario.from_api(e) }, + description: payload["description"], + gtin: payload["gtin"], + id: payload["id"], + origin: payload["origin"], + sku: payload["sku"], + tax: payload["tax"], + tax_gtin: payload["taxGtin"], + tenant_id: payload["tenantId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/product_input.rb b/lib/nfe/generated/product_register_pt_br_v1/product_input.rb new file mode 100644 index 0000000..372dd11 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/product_input.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + ProductInput = Data.define(:collection_id, :custom_tax, :description, :gtin, :origin, :sku, :tax, :tax_gtin, :tenant_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + collection_id: payload["collectionId"], + custom_tax: (payload["customTax"] || []).map { |e| CustomTaxScenario.from_api(e) }, + description: payload["description"], + gtin: payload["gtin"], + origin: payload["origin"], + sku: payload["sku"], + tax: payload["tax"], + tax_gtin: payload["taxGtin"], + tenant_id: payload["tenantId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/recipient_tax_profile_enum.rb b/lib/nfe/generated/product_register_pt_br_v1/recipient_tax_profile_enum.rb new file mode 100644 index 0000000..b5b1c96 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/recipient_tax_profile_enum.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + module RecipientTaxProfileEnum + None = "none" + Industry = "industry" + FinalConsumerIcmsContributor = "final_consumer_icms_contributor" + FinalConsumerNonIcmsContributor = "final_consumer_non_icms_contributor" + GeneralWarehouse = "general_warehouse" + ClosedDeposit = "closed_deposit" + NaturalPerson = "natural_person" + CommercialExporter = "commercial_exporter" + Importer = "importer" + Coop = "coop" + Wholesale = "wholesale" + Retail = "retail" + InterdependentCompany = "interdependent_company" + RetailBranch = "retail_branch" + NonRetailBranch = "non_retail_branch" + WholesaleBranch = "wholesale_branch" + ClosedWarehouse = "closed_warehouse" + ALL = [None, Industry, FinalConsumerIcmsContributor, FinalConsumerNonIcmsContributor, GeneralWarehouse, ClosedDeposit, NaturalPerson, CommercialExporter, Importer, Coop, Wholesale, Retail, InterdependentCompany, RetailBranch, NonRetailBranch, WholesaleBranch, ClosedWarehouse].freeze + end + end + end +end diff --git a/lib/nfe/generated/product_register_pt_br_v1/tax_regime_enum.rb b/lib/nfe/generated/product_register_pt_br_v1/tax_regime_enum.rb new file mode 100644 index 0000000..51ad8b2 --- /dev/null +++ b/lib/nfe/generated/product_register_pt_br_v1/tax_regime_enum.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + module TaxRegimeEnum + NationalSimple = "NationalSimple" + NationalSimpleSublimitExceeded = "NationalSimpleSublimitExceeded" + RealProfit = "RealProfit" + PresumidProfile = "PresumidProfile" + ALL = [NationalSimple, NationalSimpleSublimitExceeded, RealProfit, PresumidProfile].freeze + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/activity_event.rb b/lib/nfe/generated/service_invoice_rtc_v1/activity_event.rb new file mode 100644 index 0000000..41b4cf3 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/activity_event.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ActivityEvent = Data.define(:code, :address, :begin_on, :end_on, :name) do + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["Code"], + address: AddressDefinition.from_api(payload["address"]), + begin_on: payload["beginOn"], + end_on: payload["endOn"], + name: payload["name"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/address_definition.rb b/lib/nfe/generated/service_invoice_rtc_v1/address_definition.rb new file mode 100644 index 0000000..d8600e5 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/address_definition.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + AddressDefinition = Data.define(:additional_information, :city, :country, :district, :number, :postal_code, :state, :street) do + def self.from_api(payload) + return nil if payload.nil? + + new( + additional_information: payload["additionalInformation"], + city: payload["city"], + country: payload["country"], + district: payload["district"], + number: payload["number"], + postal_code: payload["postalCode"], + state: payload["state"], + street: payload["street"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/approximate_tax.rb b/lib/nfe/generated/service_invoice_rtc_v1/approximate_tax.rb new file mode 100644 index 0000000..362ba0e --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/approximate_tax.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ApproximateTax = Data.define(:source, :total_amount, :total_rate, :version) do + def self.from_api(payload) + return nil if payload.nil? + + new( + source: payload["source"], + total_amount: payload["totalAmount"], + total_rate: payload["totalRate"], + version: payload["version"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/approximate_totals.rb b/lib/nfe/generated/service_invoice_rtc_v1/approximate_totals.rb new file mode 100644 index 0000000..35cc354 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/approximate_totals.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ApproximateTotals = Data.define(:amount, :federal, :municipal, :rate, :state) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + federal: payload["federal"], + municipal: payload["municipal"], + rate: payload["rate"], + state: payload["state"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/benefit.rb b/lib/nfe/generated/service_invoice_rtc_v1/benefit.rb new file mode 100644 index 0000000..390aeb3 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/benefit.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + Benefit = Data.define(:amount, :id, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + id: payload["id"], + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/construction.rb b/lib/nfe/generated/service_invoice_rtc_v1/construction.rb new file mode 100644 index 0000000..06b9c29 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/construction.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + Construction = Data.define(:cib_code, :encapsulation_number, :property_fiscal_registration, :site_address, :work_id) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cib_code: payload["cibCode"], + encapsulation_number: payload["encapsulationNumber"], + property_fiscal_registration: payload["propertyFiscalRegistration"], + site_address: AddressDefinition.from_api(payload["siteAddress"]), + work_id: payload["workId"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/deduction.rb b/lib/nfe/generated/service_invoice_rtc_v1/deduction.rb new file mode 100644 index 0000000..770b047 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/deduction.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + Deduction = Data.define(:amount, :documents, :rate) do + def self.from_api(payload) + return nil if payload.nil? + + new( + amount: payload["amount"], + documents: (payload["documents"] || []).map { |e| DeductionDocument.from_api(e) }, + rate: payload["rate"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/deduction_document.rb b/lib/nfe/generated/service_invoice_rtc_v1/deduction_document.rb new file mode 100644 index 0000000..9751f89 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/deduction_document.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + DeductionDocument = Data.define(:deductible_total, :deduction_type, :fiscal_document_number, :issue_date, :municipal_nfse, :nfe_key, :nfse_key, :non_fiscal_document_number, :other_deduction_description, :supplier, :used_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + deductible_total: payload["deductibleTotal"], + deduction_type: payload["deductionType"], + fiscal_document_number: payload["fiscalDocumentNumber"], + issue_date: payload["issueDate"], + municipal_nfse: payload["municipalNfse"], + nfe_key: payload["nfeKey"], + nfse_key: payload["nfseKey"], + non_fiscal_document_number: payload["nonFiscalDocumentNumber"], + other_deduction_description: payload["otherDeductionDescription"], + supplier: PartyDefinition.from_api(payload["supplier"]), + used_amount: payload["usedAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/foreign_trade.rb b/lib/nfe/generated/service_invoice_rtc_v1/foreign_trade.rb new file mode 100644 index 0000000..38f762a --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/foreign_trade.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ForeignTrade = Data.define(:currency, :export_registration, :import_declaration, :mdic_delivery, :relation_ship, :service_amount_in_currency, :service_mode, :support_mechanism_provider, :support_mechanism_receiver, :temporary_goods) do + def self.from_api(payload) + return nil if payload.nil? + + new( + currency: payload["currency"], + export_registration: payload["exportRegistration"], + import_declaration: payload["importDeclaration"], + mdic_delivery: payload["mdicDelivery"], + relation_ship: payload["relationShip"], + service_amount_in_currency: payload["serviceAmountInCurrency"], + service_mode: payload["serviceMode"], + support_mechanism_provider: payload["supportMechanismProvider"], + support_mechanism_receiver: payload["supportMechanismReceiver"], + temporary_goods: payload["temporaryGoods"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/ibs_cbs.rb b/lib/nfe/generated/service_invoice_rtc_v1/ibs_cbs.rb new file mode 100644 index 0000000..c1b39c7 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/ibs_cbs.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + IbsCbs = Data.define(:basis, :cbs, :class_code, :credit_transfer, :destination_indicator, :government_purchase, :ibs, :ibscbs_deduction_reduction_amount, :is_donation, :leased_movable_assets, :operation_indicator, :operation_type, :personal_use, :presumed_credits, :purpose, :regular_taxation, :reimbursed_resupplied_amount, :related_docs, :situation_code, :third_party_reimbursements) do + def self.from_api(payload) + return nil if payload.nil? + + new( + basis: payload["basis"], + cbs: payload["cbs"], + class_code: payload["classCode"], + credit_transfer: payload["creditTransfer"], + destination_indicator: payload["destinationIndicator"], + government_purchase: payload["governmentPurchase"], + ibs: payload["ibs"], + ibscbs_deduction_reduction_amount: payload["ibscbsDeductionReductionAmount"], + is_donation: payload["isDonation"], + leased_movable_assets: payload["leasedMovableAssets"], + operation_indicator: payload["operationIndicator"], + operation_type: payload["operationType"], + personal_use: payload["personalUse"], + presumed_credits: payload["presumedCredits"], + purpose: payload["purpose"], + regular_taxation: payload["regularTaxation"], + reimbursed_resupplied_amount: payload["reimbursedResuppliedAmount"], + related_docs: payload["relatedDocs"], + situation_code: payload["situationCode"], + third_party_reimbursements: payload["thirdPartyReimbursements"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/lease.rb b/lib/nfe/generated/service_invoice_rtc_v1/lease.rb new file mode 100644 index 0000000..a6c899f --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/lease.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + Lease = Data.define(:category, :object_type, :poles_count, :total_length) do + def self.from_api(payload) + return nil if payload.nil? + + new( + category: payload["category"], + object_type: payload["objectType"], + poles_count: payload["polesCount"], + total_length: payload["totalLength"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/nfse_request.rb b/lib/nfe/generated/service_invoice_rtc_v1/nfse_request.rb new file mode 100644 index 0000000..7dc724b --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/nfse_request.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + NFSeRequest = Data.define(:reference_substitution, :accrual_on, :activity_event, :additional_information, :additional_information_group, :approximate_tax, :approximate_totals, :benefit, :borrower, :city_service_code, :cnae_code, :cofins_amount, :cofins_amount_withheld, :cofins_rate, :construction, :csll_amount, :csll_amount_withheld, :csll_rate, :cst_pis_cofins, :deduction, :deductions_amount, :description, :discount_conditioned_amount, :discount_unconditioned_amount, :external_id, :federal_service_code, :foreign_trade, :ibs_cbs, :immunity_type, :inss_amount_withheld, :intermediary, :ipi_amount, :ipi_rate, :ir_amount_withheld, :is_early_installment_payment, :iss_amount_withheld, :iss_rate, :iss_tax_amount, :issued_on, :lease, :location, :nbs_code, :ncm_code, :others_amount_withheld, :paid_amount, :pis_amount, :pis_amount_withheld, :pis_cofins_base_tax, :pis_rate, :real_estate, :recipient, :retention_type, :rps_number, :rps_serial_number, :service_amount_details, :services_amount, :suspension, :taxation_type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + reference_substitution: ReferenceSubstitution.from_api(payload["ReferenceSubstitution"]), + accrual_on: payload["accrualOn"], + activity_event: ActivityEvent.from_api(payload["activityEvent"]), + additional_information: payload["additionalInformation"], + additional_information_group: payload["additionalInformationGroup"], + approximate_tax: ApproximateTax.from_api(payload["approximateTax"]), + approximate_totals: ApproximateTotals.from_api(payload["approximateTotals"]), + benefit: Benefit.from_api(payload["benefit"]), + borrower: PartyDefinition.from_api(payload["borrower"]), + city_service_code: payload["cityServiceCode"], + cnae_code: payload["cnaeCode"], + cofins_amount: payload["cofinsAmount"], + cofins_amount_withheld: payload["cofinsAmountWithheld"], + cofins_rate: payload["cofinsRate"], + construction: Construction.from_api(payload["construction"]), + csll_amount: payload["csllAmount"], + csll_amount_withheld: payload["csllAmountWithheld"], + csll_rate: payload["csllRate"], + cst_pis_cofins: payload["cstPisCofins"], + deduction: Deduction.from_api(payload["deduction"]), + deductions_amount: payload["deductionsAmount"], + description: payload["description"], + discount_conditioned_amount: payload["discountConditionedAmount"], + discount_unconditioned_amount: payload["discountUnconditionedAmount"], + external_id: payload["externalId"], + federal_service_code: payload["federalServiceCode"], + foreign_trade: ForeignTrade.from_api(payload["foreignTrade"]), + ibs_cbs: IbsCbs.from_api(payload["ibsCbs"]), + immunity_type: payload["immunityType"], + inss_amount_withheld: payload["inssAmountWithheld"], + intermediary: PartyDefinition.from_api(payload["intermediary"]), + ipi_amount: payload["ipiAmount"], + ipi_rate: payload["ipiRate"], + ir_amount_withheld: payload["irAmountWithheld"], + is_early_installment_payment: payload["isEarlyInstallmentPayment"], + iss_amount_withheld: payload["issAmountWithheld"], + iss_rate: payload["issRate"], + iss_tax_amount: payload["issTaxAmount"], + issued_on: payload["issuedOn"], + lease: Lease.from_api(payload["lease"]), + location: AddressDefinition.from_api(payload["location"]), + nbs_code: payload["nbsCode"], + ncm_code: payload["ncmCode"], + others_amount_withheld: payload["othersAmountWithheld"], + paid_amount: payload["paidAmount"], + pis_amount: payload["pisAmount"], + pis_amount_withheld: payload["pisAmountWithheld"], + pis_cofins_base_tax: payload["pisCofinsBaseTax"], + pis_rate: payload["pisRate"], + real_estate: RealEstate.from_api(payload["realEstate"]), + recipient: PartyDefinition.from_api(payload["recipient"]), + retention_type: payload["retentionType"], + rps_number: payload["rpsNumber"], + rps_serial_number: payload["rpsSerialNumber"], + service_amount_details: ServiceAmountDefinitions.from_api(payload["serviceAmountDetails"]), + services_amount: payload["servicesAmount"], + suspension: Suspension.from_api(payload["suspension"]), + taxation_type: payload["taxationType"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/party_definition.rb b/lib/nfe/generated/service_invoice_rtc_v1/party_definition.rb new file mode 100644 index 0000000..f81d241 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/party_definition.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + PartyDefinition = Data.define(:address, :caepf, :email, :federal_tax_number, :municipal_tax_number, :name, :no_tax_id_reason, :phone_number, :state_tax_number, :tax_regime, :type) do + def self.from_api(payload) + return nil if payload.nil? + + new( + address: AddressDefinition.from_api(payload["address"]), + caepf: payload["caepf"], + email: payload["email"], + federal_tax_number: payload["federalTaxNumber"], + municipal_tax_number: payload["municipalTaxNumber"], + name: payload["name"], + no_tax_id_reason: payload["noTaxIdReason"], + phone_number: payload["phoneNumber"], + state_tax_number: payload["stateTaxNumber"], + tax_regime: payload["taxRegime"], + type: payload["type"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/real_estate.rb b/lib/nfe/generated/service_invoice_rtc_v1/real_estate.rb new file mode 100644 index 0000000..ac84cbb --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/real_estate.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + RealEstate = Data.define(:cib_code, :property_fiscal_registration, :site_address) do + def self.from_api(payload) + return nil if payload.nil? + + new( + cib_code: payload["cibCode"], + property_fiscal_registration: payload["propertyFiscalRegistration"], + site_address: AddressDefinition.from_api(payload["siteAddress"]), + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/reference_substitution.rb b/lib/nfe/generated/service_invoice_rtc_v1/reference_substitution.rb new file mode 100644 index 0000000..9f2a674 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/reference_substitution.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ReferenceSubstitution = Data.define(:id, :reason, :reason_text) do + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + reason: payload["reason"], + reason_text: payload["reasonText"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/service_amount_definitions.rb b/lib/nfe/generated/service_invoice_rtc_v1/service_amount_definitions.rb new file mode 100644 index 0000000..ad43c02 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/service_amount_definitions.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ServiceAmountDefinitions = Data.define(:final_charged_amount, :fine_amount, :initial_charged_amount, :interest_amount) do + def self.from_api(payload) + return nil if payload.nil? + + new( + final_charged_amount: payload["finalChargedAmount"], + fine_amount: payload["fineAmount"], + initial_charged_amount: payload["initialChargedAmount"], + interest_amount: payload["interestAmount"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/suspension.rb b/lib/nfe/generated/service_invoice_rtc_v1/suspension.rb new file mode 100644 index 0000000..188e9c9 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/suspension.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + Suspension = Data.define(:process_number, :reason) do + def self.from_api(payload) + return nil if payload.nil? + + new( + process_number: payload["processNumber"], + reason: payload["reason"], + ) + end + end + end + end +end diff --git a/lib/nfe/generated/service_invoice_rtc_v1/third_party_reimbursement_document.rb b/lib/nfe/generated/service_invoice_rtc_v1/third_party_reimbursement_document.rb new file mode 100644 index 0000000..ed48cb1 --- /dev/null +++ b/lib/nfe/generated/service_invoice_rtc_v1/third_party_reimbursement_document.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + ThirdPartyReimbursementDocument = Data.define(:accrual_on, :amount, :cte_key, :issue_date, :nfe_key, :nfse_key, :other_doc, :other_fiscal_doc, :other_national_dfe, :reimbursement_type, :reimbursement_type_text, :supplier) do + def self.from_api(payload) + return nil if payload.nil? + + new( + accrual_on: payload["accrualOn"], + amount: payload["amount"], + cte_key: payload["cteKey"], + issue_date: payload["issueDate"], + nfe_key: payload["nfeKey"], + nfse_key: payload["nfseKey"], + other_doc: payload["otherDoc"], + other_fiscal_doc: payload["otherFiscalDoc"], + other_national_dfe: payload["otherNationalDfe"], + reimbursement_type: payload["reimbursementType"], + reimbursement_type_text: payload["reimbursementTypeText"], + supplier: PartyDefinition.from_api(payload["supplier"]), + ) + end + end + end + end +end diff --git a/lib/nfe/http/.gitkeep b/lib/nfe/http/.gitkeep new file mode 100644 index 0000000..5198467 --- /dev/null +++ b/lib/nfe/http/.gitkeep @@ -0,0 +1 @@ +# Net::HTTP-based transport, retry, and request/response value objects — added by add-http-transport. diff --git a/lib/nfe/http/net_http.rb b/lib/nfe/http/net_http.rb new file mode 100644 index 0000000..225f59d --- /dev/null +++ b/lib/nfe/http/net_http.rb @@ -0,0 +1,179 @@ +# frozen_string_literal: true + +require "net/http" +require "uri" +require "openssl" +require "zlib" +require "stringio" + +module Nfe + module Http + # Default, zero-dependency HTTP transport built on the Ruby standard library + # (+net/http+, +uri+, +openssl+, +zlib+, +stringio+). It satisfies the + # {Nfe::Http::Transport} contract: it returns 4xx/5xx as ordinary + # {Nfe::Http::Response} objects, raises only {Nfe::ApiConnectionError} (or its + # subclass {Nfe::TimeoutError}) on network failure, and never follows a + # redirect or 202. + # + # Connections are pooled per origin ("host:port") and kept alive for + # TCP/TLS reuse. The pool is guarded by a +Mutex+ and follows a + # checkout/check-in model: a connection is removed from the idle list while a + # request is in flight and only returned afterwards. A single instance is + # therefore safe to share across threads (Rails/Sidekiq/Puma): two in-flight + # requests never share the same socket, and a connection broken by a network + # error is closed instead of being returned to the pool. + # + # TLS is always enforced for +https+ origins with + # +OpenSSL::SSL::VERIFY_PEER+; verification is never disabled. An optional + # +ca_file+ provides an escape hatch for a legacy CA store. + class NetHttp + # Seconds an idle pooled connection is kept open for reuse. + KEEP_ALIVE_TIMEOUT = 30 + + def initialize(default_open_timeout: 10, default_read_timeout: 60, ca_file: nil) + @default_open_timeout = default_open_timeout + @default_read_timeout = default_read_timeout + @ca_file = ca_file + @pool = {} + @mutex = Mutex.new + end + + # Executes +request+ and returns an {Nfe::Http::Response}. Raises + # {Nfe::TimeoutError} on open/read timeout and {Nfe::ApiConnectionError} on + # any other network-level failure. + def call(request) + uri = URI.parse(request.url) + key = origin_key(uri) + http = nil + begin + # checkout starts the connection (http.start), which can itself raise a + # network error (e.g. ECONNREFUSED) — keep it inside the rescue. + http = checkout(key, uri, request) + net_response = http.request(build_net_request(uri, request)) + checkin(key, http) + build_response(net_response) + rescue Timeout::Error => e + # Net::OpenTimeout and Net::ReadTimeout both descend from Timeout::Error. + discard(http) if http + raise Nfe::TimeoutError, e.message + rescue SocketError, SystemCallError, OpenSSL::SSL::SSLError, + Net::HTTPBadResponse, IOError => e + # IOError covers EOFError; SystemCallError covers all Errno::* errors. + discard(http) if http + raise Nfe::ApiConnectionError, e.message + end + end + + private + + # Removes an idle connection for +key+ from the pool (or builds a fresh, + # started one) and hands it to the caller. While the connection is in flight + # it is owned exclusively by this call and absent from the pool, so no other + # thread can use the same socket concurrently. Timeouts are applied per call. + def checkout(key, uri, request) + http = @mutex.synchronize { (@pool[key] ||= []).pop } || build_connection(uri) + apply_timeouts(http, request) + http.start unless http.started? + http + end + + # Returns a healthy connection to the idle list for reuse. + def checkin(key, http) + @mutex.synchronize { (@pool[key] ||= []) << http } + end + + # Closes a connection broken by a network error so it is never reused. + def discard(http) + http.finish if http.started? + rescue IOError, SystemCallError + # Socket already torn down; nothing left to close. + end + + def build_connection(uri) + http = Net::HTTP.new(uri.host.to_s, uri.port) + http.keep_alive_timeout = KEEP_ALIVE_TIMEOUT + configure_tls(http, uri) + http + end + + def configure_tls(http, uri) + return unless uri.scheme == "https" + + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_PEER + http.ca_file = @ca_file if @ca_file + end + + def apply_timeouts(http, request) + http.open_timeout = request.open_timeout || @default_open_timeout + http.read_timeout = request.read_timeout || @default_read_timeout + end + + def origin_key(uri) + "#{uri.host}:#{uri.port}" + end + + # Builds the appropriate Net::HTTP request object, copying headers and body + # from the {Nfe::Http::Request} and defaulting +Accept-Encoding: gzip+ when + # the caller has not set it. + def build_net_request(uri, request) + net_request = request_class(request.method).new(uri) + request.headers.each { |name, value| net_request[name.to_s] = value } + net_request["Accept-Encoding"] = "gzip" unless accept_encoding_set?(request.headers) + net_request.body = request.body unless request.body.nil? + net_request + end + + def accept_encoding_set?(headers) + headers.any? { |name, _| name.to_s.downcase == "accept-encoding" } + end + + def request_class(method) + case method.to_s.upcase + when "GET" then Net::HTTP::Get + when "POST" then Net::HTTP::Post + when "PUT" then Net::HTTP::Put + when "DELETE" then Net::HTTP::Delete + when "HEAD" then Net::HTTP::Head + else raise Nfe::ApiConnectionError, "Unsupported HTTP method: #{method}" + end + end + + # Maps a Net::HTTPResponse into an {Nfe::Http::Response}: integer status, + # lowercase headers (multi-value joined with ", "), and a binary body. A + # gzip body is inflated transparently. Redirects and 202 are not followed. + def build_response(net_response) + status = net_response.code.to_i + headers = normalize_headers(net_response) + body = (net_response.body || "").dup.force_encoding(Encoding::ASCII_8BIT) + body, headers = decompress(body, headers) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def normalize_headers(net_response) + headers = {} #: Hash[String, String] + net_response.each_capitalized do |name, value| + key = name.downcase + headers[key] = headers.key?(key) ? "#{headers[key]}, #{value}" : value + end + headers + end + + # Inflates a gzip body and drops the now-stale +content-encoding+ and + # +content-length+ headers. On a malformed stream the raw body is kept and a + # warning is emitted, never raising. + def decompress(body, headers) + return [body, headers] unless headers["content-encoding"].to_s.downcase.include?("gzip") + + inflated = Zlib::GzipReader.new(StringIO.new(body)).read.to_s.force_encoding(Encoding::ASCII_8BIT) + cleaned = headers.dup + cleaned.delete("content-encoding") + cleaned.delete("content-length") + [inflated, cleaned] + rescue Zlib::Error => e + warn("Nfe::Http::NetHttp: failed to inflate gzip response body: #{e.message}") + [body, headers] + end + end + end +end diff --git a/lib/nfe/http/redactor.rb b/lib/nfe/http/redactor.rb new file mode 100644 index 0000000..972ea25 --- /dev/null +++ b/lib/nfe/http/redactor.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Nfe + module Http + # Replaces the values of sensitive headers with +"[REDACTED]"+ before they + # reach a log line, so an API key, bearer token, or idempotency key never + # appears verbatim in transport logs. + # + # A header is considered sensitive when its (case-insensitive) name is one of + # +x-nfe-apikey+, +authorization+, +idempotency-key+, or matches + # /secret|apikey|token/i. Benign headers are returned unchanged. + module Redactor + REDACTED = "[REDACTED]" + + # Exact (case-insensitive) header names that are always redacted. + SENSITIVE_NAMES = %w[x-nfe-apikey authorization idempotency-key].freeze + + # Substring pattern matched against header names. + SENSITIVE_PATTERN = /secret|apikey|token/i + + module_function + + # Returns a new Hash with the values of sensitive keys replaced by + # +"[REDACTED]"+. The input hash is never mutated; benign keys keep their + # original value and casing. + def headers(hash) + return hash unless hash.respond_to?(:each_pair) + + redacted = {} #: Hash[untyped, untyped] + hash.each_pair { |key, value| redacted[key] = sensitive?(key) ? REDACTED : value } + redacted + end + + # Returns +true+ when a header named +key+ must have its value redacted. + def sensitive?(key) + name = key.to_s.downcase + SENSITIVE_NAMES.include?(name) || SENSITIVE_PATTERN.match?(name) + end + end + end +end diff --git a/lib/nfe/http/request.rb b/lib/nfe/http/request.rb new file mode 100644 index 0000000..c48c38f --- /dev/null +++ b/lib/nfe/http/request.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require "uri" + +module Nfe + module Http + # Immutable value object describing a single outbound HTTP request. + # + # A +Request+ is transport-agnostic: it carries everything a transport needs + # to perform one HTTP call, including its own +base_url+ (enabling multi-host + # routing) and optional per-call timeout overrides. Headers, query, and body + # are supplied verbatim; the transport is responsible for wire encoding. + # + # request = Nfe::Http::Request.new( + # method: "GET", + # base_url: "https://api.nfse.io", + # path: "/v2/companies/abc/productinvoices", + # query: { environment: "Production", limit: 50 } + # ) + # request.url # => ".../productinvoices?environment=Production&limit=50" + # + # The +method+ member intentionally exposes the HTTP verb as +request.method+; + # it shadows +Object#method+, which the value object never relies on. + class Request < Data.define( + :method, :base_url, :path, :headers, :query, :body, + :open_timeout, :read_timeout, :idempotency_key + ) + # @param method [String] HTTP method (e.g. "GET", "POST"). + # @param base_url [String] origin + optional prefix (e.g. "https://api.nfse.io"). + # @param path [String] request path (e.g. "/v2/companies"). + # @param headers [Hash] request headers, sent verbatim by the transport. + # @param query [Hash] query parameters; array values become repeated keys. + # @param body [String, nil] raw request body, or nil. + # @param open_timeout [Numeric, nil] per-call connect timeout override. + # @param read_timeout [Numeric, nil] per-call read timeout override. + # @param idempotency_key [String, nil] optional key; makes a POST retry-eligible. + def initialize(method:, base_url:, path:, headers: {}, query: {}, body: nil, + open_timeout: nil, read_timeout: nil, idempotency_key: nil) + super + end + + # Composes the final URL from +base_url+, +path+, and the URL-encoded +query+. + # + # A trailing slash on +base_url+ is stripped. When +query+ is non-empty the + # encoded form is appended with "?" (or "&" when +path+ already contains a + # "?"). Array query values are emitted as repeated keys. + # + # @return [String] + def url + base = base_url.chomp("/") + path + return base if query.nil? || query.empty? + + separator = base.include?("?") ? "&" : "?" + "#{base}#{separator}#{URI.encode_www_form(query)}" + end + + # Whether this request is safe to retry. + # + # @return [Boolean] true for GET/HEAD/PUT/DELETE (case-insensitive) or any + # request carrying a non-nil +idempotency_key+. + def idempotent? + return true unless idempotency_key.nil? + + %w[GET HEAD PUT DELETE].include?(method.to_s.upcase) + end + end + end +end diff --git a/lib/nfe/http/response.rb b/lib/nfe/http/response.rb new file mode 100644 index 0000000..d61dc96 --- /dev/null +++ b/lib/nfe/http/response.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Nfe + module Http + # Immutable value object describing a single HTTP response. + # + # A +Response+ carries the raw status code, normalized headers (lowercase + # string keys), and a binary-safe body. HTTP errors (4xx/5xx) are returned as + # ordinary responses — never raised — so the retry decorator and + # {Nfe::ErrorFactory} can act on the status. Redirects and 202 are not + # followed by the transport; the +Location+ header is preserved here. + # + # response = Nfe::Http::Response.new(status: 200, headers: { "content-type" => "application/json" }, body: "{}") + # response.success? # => true + # response.header("Content-Type") # => "application/json" + class Response < Data.define(:status, :headers, :body) + # @param status [Integer] HTTP status code. + # @param headers [Hash{String=>String}] lowercase-keyed response headers. + # @param body [String, nil] ASCII-8BIT response body, or nil. + def initialize(status:, headers: {}, body: nil) + super + end + + # Case-insensitive header lookup. + # + # @param name [String] header name in any casing. + # @return [String, nil] the header value, or nil when absent. + def header(name) + headers[name.downcase] + end + + # @return [Boolean] true when the status is in the 2xx range. + def success? + (200..299).cover?(status) + end + + # @return [String, nil] the +Location+ header, or nil. + def location + header("location") + end + end + end +end diff --git a/lib/nfe/http/retry_policy.rb b/lib/nfe/http/retry_policy.rb new file mode 100644 index 0000000..7fecf37 --- /dev/null +++ b/lib/nfe/http/retry_policy.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Nfe + module Http + # Immutable retry policy describing exponential backoff with symmetric + # jitter. Consumed by {RetryingTransport} to decide how long to wait between + # attempts. + # + # +max_retries+ is the number of *retries* after the initial attempt, so a + # policy with +max_retries: 3+ makes at most four HTTP attempts. + # + # Use the {.default} factory for the recommended settings, or {.none} to + # disable retries entirely (exactly one HTTP attempt). + class RetryPolicy < Data.define(:max_retries, :base_delay, :max_delay, :jitter) + # Recommended defaults: 3 retries, 1s base, 30s cap, +/-30% jitter. + def self.default + new(max_retries: 3, base_delay: 1.0, max_delay: 30.0, jitter: 0.3) + end + + # No retries: exactly one HTTP attempt, zero delay. + def self.none + new(max_retries: 0, base_delay: 0.0, max_delay: 0.0, jitter: 0.0) + end + + # Delay in seconds before the given (1-based) retry +attempt+. + # + # Computes +min(max_delay, base_delay * 2**(attempt - 1))+ then applies + # symmetric jitter, with the final value capped at +max_delay+. + # + # @param attempt [Integer] 1-based retry index. + # @return [Float] + def delay_for(attempt) + base = [base_delay * (2**(attempt - 1)), max_delay].min + jittered = base * (1 - jitter + (2 * jitter * rand)) + [jittered, max_delay].min + end + end + end +end diff --git a/lib/nfe/http/retrying_transport.rb b/lib/nfe/http/retrying_transport.rb new file mode 100644 index 0000000..93fb590 --- /dev/null +++ b/lib/nfe/http/retrying_transport.rb @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +module Nfe + module Http + # Transport decorator that retries transient failures on idempotent + # requests. Wraps any +inner+ transport (any object responding to + # +call(request)+) and applies a {RetryPolicy}. + # + # Retries happen on HTTP 429, HTTP 500-599, and network errors + # ({Nfe::ApiConnectionError}, including {Nfe::TimeoutError}) -- but ONLY + # when {Request#idempotent?} is true. A +POST+ without an +idempotency_key+ + # is never retried, so an invoice is never re-issued automatically. + # + # An integer +Retry-After+ header (seconds) overrides the computed backoff, + # clamped to the policy's +max_delay+. + # + # When a duck-typed +logger+ (responding to +info+/+warn+/+error+) is + # supplied, the decorator logs request start (+info+), retries (+warn+), and + # final failures (+error+). Sensitive headers are redacted via + # {Redactor.headers} and request/response BODIES are never logged. Every log + # call is wrapped in +rescue StandardError+ so logging can never break the + # request. + class RetryingTransport + # @param inner [#call] the wrapped transport + # @param policy [RetryPolicy] backoff policy + # @param sleep_fn [#call] injectable sleep, called with seconds + # @param logger [#info, #warn, #error, nil] optional duck-typed logger + def initialize(inner:, policy: RetryPolicy.default, sleep_fn: ->(seconds) { Kernel.sleep(seconds) }, logger: nil) + @inner = inner + @policy = policy + @sleep_fn = sleep_fn + @logger = logger + end + + # Execute +request+ through the inner transport, retrying transient + # failures on idempotent requests. Returns an {Nfe::Http::Response}; on a + # non-retryable network failure (or after exhausting retries) re-raises + # the last {Nfe::ApiConnectionError}. + def call(request) + log_start(request) + attempt = 0 + + loop do + begin + response = @inner.call(request) + rescue Nfe::ApiConnectionError => e + attempt += 1 + unless retry_again?(attempt, request) + log_final_error(request, error: e) + raise + end + delay = @policy.delay_for(attempt) + log_retry(request, attempt: attempt, delay: delay, error: e) + @sleep_fn.call(delay) + next + end + + unless retryable_status?(response.status) && retry_again?(attempt + 1, request) + log_final_error(request, response: response) unless response.success? + return response + end + + attempt += 1 + delay = delay_for_response(attempt, response) + log_retry(request, attempt: attempt, delay: delay, status: response.status) + @sleep_fn.call(delay) + end + end + + # True for statuses that warrant a retry: 429 and 5xx. + def retryable_status?(status) + status == 429 || (500..599).cover?(status) + end + + private + + # An +attempt+ (1-based retry index) is permitted when it does not exceed + # the configured maximum and the request is idempotent. + def retry_again?(attempt, request) + attempt <= @policy.max_retries && request.idempotent? + end + + # Honor an integer +Retry-After+ (seconds), clamped to +max_delay+; + # otherwise fall back to the policy backoff. + def delay_for_response(attempt, response) + retry_after = parse_retry_after(response) + return [retry_after.to_f, @policy.max_delay].min if retry_after + + @policy.delay_for(attempt) + end + + def parse_retry_after(response) + raw = response.header("retry-after") + return nil if raw.nil? + return nil unless raw.to_s.match?(/\A\d+\z/) + + raw.to_i + end + + def log_start(request) + return unless @logger + + safe_log do + @logger.info("nfe-io request: #{request.method.to_s.upcase} #{request.url} " \ + "headers=#{Redactor.headers(request.headers).inspect}") + end + end + + def log_retry(request, attempt:, delay:, status: nil, error: nil) + return unless @logger + + reason = error ? "error=#{error.class}" : "status=#{status}" + safe_log do + @logger.warn("nfe-io retry ##{attempt} in #{delay}s: " \ + "#{request.method.to_s.upcase} #{request.url} #{reason}") + end + end + + def log_final_error(request, response: nil, error: nil) + return unless @logger + + detail = if error + "error=#{error.class}" + elsif response + "status=#{response.status} body=#{truncate(response.body)}" + else + "unknown failure" + end + safe_log do + @logger.error("nfe-io request failed: #{request.method.to_s.upcase} #{request.url} #{detail}") + end + end + + def truncate(body, limit = 256) + return "" if body.nil? + + string = body.to_s + string.bytesize > limit ? "#{string.byteslice(0, limit)}...(truncated)" : string + end + + # Logging must never break the request. + def safe_log + yield + rescue StandardError + nil + end + end + end +end diff --git a/lib/nfe/http/transport.rb b/lib/nfe/http/transport.rb new file mode 100644 index 0000000..f8a8733 --- /dev/null +++ b/lib/nfe/http/transport.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Nfe + module Http + # Transport contract: any object that turns a {Nfe::Http::Request} into a + # {Nfe::Http::Response}. + # + # The SDK routes every HTTP call through an object responding to + # +call(request)+. The default implementation is {Nfe::Http::NetHttp} (zero + # external dependencies), but any duck-typed object satisfying this contract + # may be substituted — a logging decorator, a retrying decorator, or an + # in-memory fake for tests. + # + # == Contract + # + # An implementation of +call(request)+: + # + # * SHALL accept a {Nfe::Http::Request} and return a {Nfe::Http::Response}. + # * SHALL return HTTP 4xx and 5xx outcomes as a +Response+ carrying that + # status — it SHALL NOT raise for them. The retry decorator and + # {Nfe::ErrorFactory} act on the status code. + # * SHALL raise ONLY {Nfe::ApiConnectionError} (or its subclass + # {Nfe::TimeoutError}) on network failures — connection refused, DNS, + # TLS, read/connect timeouts. + # * SHALL NOT follow HTTP 202 responses or redirects automatically; it + # SHALL preserve the raw status and the +Location+ header so the caller + # can implement the async Pending/Issued contract. + # * SHALL normalize response header keys to lowercase strings and return a + # binary-safe (ASCII-8BIT) body. + # + # Mix this module in to inherit the +NotImplementedError+ default, or simply + # define +call+ on any object (duck typing). + module Transport + # Perform the request. + # + # @param request [Nfe::Http::Request] + # @return [Nfe::Http::Response] + # @raise [NotImplementedError] unless overridden. + def call(request) + raise NotImplementedError, "#{self.class} must implement #call(request)" + end + end + end +end diff --git a/lib/nfe/http/user_agent.rb b/lib/nfe/http/user_agent.rb new file mode 100644 index 0000000..d5f5cf6 --- /dev/null +++ b/lib/nfe/http/user_agent.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Nfe + module Http + # Builds the +User-Agent+ string sent with every outgoing request. + # + # The format is + # NFE.io Ruby Client v ruby/ (), + # optionally followed by a caller-supplied suffix (e.g. the host + # application's name configured via +Nfe::Configuration#user_agent_suffix+). + # + # Injection of the resulting header onto a request is performed by the + # +Client+/+AbstractResource+ layer (see the +add-client-core+ change); the + # transport itself only transmits whatever +User-Agent+ the +Request+ carries. + module UserAgent + module_function + + # Returns the User-Agent string. When +suffix+ is a non-empty string it is + # appended after a single space. + def build(suffix = nil) + base = "NFE.io Ruby Client v#{Nfe::VERSION} ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM})" + return base if suffix.nil? || suffix.to_s.empty? + + "#{base} #{suffix}" + end + end + end +end diff --git a/lib/nfe/id_validator.rb b/lib/nfe/id_validator.rb new file mode 100644 index 0000000..a233783 --- /dev/null +++ b/lib/nfe/id_validator.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module Nfe + # Client-side validators for identifiers and document numbers. Each method + # runs before any HTTP request is issued (fail-fast) and raises + # {Nfe::InvalidRequestError} with a Portuguese-language message naming the + # offending argument. + # + # Normalizing validators (+access_key+, +cnpj+, +cpf+, +cep+, +state+) return + # a normalized +String+; CNPJ/CPF/CEP are NEVER coerced to Integer, so future + # alphanumeric CNPJ (v3) input is preserved. + module IdValidator + # The 27 Brazilian UFs plus +EX+ (foreign) and +NA+ (not applicable). + UF = %w[ + AC AL AP AM BA CE DF ES GO MA MT MS MG PA PB PR PE PI RJ RN RS RO RR SC SP SE TO + EX NA + ].freeze + + module_function + + # @return [String] the non-empty company id. + def company_id(value) + presence!(value, "company_id") + end + + # @return [String] the non-empty invoice id. + def invoice_id(value) + presence!(value, "invoice_id") + end + + # @return [String] the non-empty state-tax id. + def state_tax_id(value) + presence!(value, "state_tax_id") + end + + # @return [String] the non-empty event key. + def event_key(value) + presence!(value, "event_key") + end + + # Strips non-digits, validates the 44-digit length, returns the normalized + # digits-only string. + # + # @return [String] + def access_key(value) + digits = digits_only(value) + unless /\A\d{44}\z/.match?(digits) + raise Nfe::InvalidRequestError, "chave de acesso (access_key) deve conter 44 dígitos" + end + + digits + end + + # Normalizes to 14 digits without coercing to Integer (preserves future + # alphanumeric CNPJ v3). + # + # @return [String] + def cnpj(value) + normalized = strip_separators(value) + raise Nfe::InvalidRequestError, "CNPJ (cnpj) deve conter 14 caracteres" unless normalized.length == 14 + + normalized + end + + # @return [String] the 11-digit CPF. + def cpf(value) + digits = digits_only(value) + raise Nfe::InvalidRequestError, "CPF (cpf) deve conter 11 dígitos" unless digits.length == 11 + + digits + end + + # @return [String] the 8-digit CEP. + def cep(value) + digits = digits_only(value) + raise Nfe::InvalidRequestError, "CEP (cep) deve conter 8 dígitos" unless digits.length == 8 + + digits + end + + # @return [String] the validated, uppercased UF. + def state(value) + normalized = value.to_s.strip.upcase + raise Nfe::InvalidRequestError, "estado (state) inválido: #{value.inspect}" unless UF.include?(normalized) + + normalized + end + + # @api private + def presence!(value, name) + string = value.to_s + raise Nfe::InvalidRequestError, "#{name} não pode ser vazio" if string.strip.empty? + + value + end + + # @api private + def digits_only(value) + value.to_s.gsub(/\D/, "") + end + + # @api private + def strip_separators(value) + value.to_s.gsub(/[^0-9A-Za-z]/, "") + end + end +end diff --git a/lib/nfe/legal_people.rb b/lib/nfe/legal_people.rb deleted file mode 100644 index ae64b93..0000000 --- a/lib/nfe/legal_people.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Nfe - class LegalPeople < NfeObject - include ApiResource - include ApiOperations::List - include ApiOperations::Retrieve - - def self.company_id(company_id) - @company_id = company_id - end - - def self.url - "/v1/companies/#{@company_id}/legalpeople" - end - - def url - "#{self.class.url}/#{self.id}" - end - - def self.create_from(params) - obj = self.new - obj.reflesh_object(params["legalPeople"]) - end - end -end \ No newline at end of file diff --git a/lib/nfe/natural_people.rb b/lib/nfe/natural_people.rb deleted file mode 100644 index 39716dd..0000000 --- a/lib/nfe/natural_people.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Nfe - class NaturalPeople < NfeObject - include ApiResource - include ApiOperations::List - include ApiOperations::Retrieve - - def self.company_id(company_id) - @company_id = company_id - end - - def self.url - "/v1/companies/#{@company_id}/naturalpeople" - end - - def url - "#{self.class.url}/#{self.id}" - end - - def self.create_from(params) - obj = self.new - obj.reflesh_object(params["naturalPeople"]) - end - end -end \ No newline at end of file diff --git a/lib/nfe/nfe_object.rb b/lib/nfe/nfe_object.rb deleted file mode 100644 index 7282f4a..0000000 --- a/lib/nfe/nfe_object.rb +++ /dev/null @@ -1,111 +0,0 @@ -module Nfe - class NfeObject - @values - def metaclass - class << self; self; end - end - - def self.create_from(params) - obj = self.new - obj.reflesh_object(params) - end - - def reflesh_object(params) - if params.class == Array - params = create_list(params) - end - create_fields(params) - set_properties(params) - self - end - - def create_fields(params) - instance_eval do - metaclass.instance_eval do - params.keys.each do |key| - define_method(key) { @values[key] } - - define_method("#{key}=") do |value| - @values[key] = value - end - end - end - end - end - - def set_properties(params) - instance_eval do - params.each do |key, value| - if value.class == Hash - @values[key] = Util.get_object_type(value['object']).create_from(value) - elsif value.class == Array - @values[key] = value.map{ |v| Util.get_object_type(v['object']).create_from(v) } - else - @values[key] = value - end - end - end - end - - def self.url - "/v1/#{CGI.escape(class_name.downcase)}s" - end - - def url - "#{self.class.url}/#{self.id}" - end - - def self.class_name - self.name.split('::')[-1] - end - - def initialize() - @values = {} - end - - def method_missing(name, *args) - if name.to_s.end_with? '=' - name = name.to_s[0...-1].to_sym - end - - if serialize_params.include? name - @values[name] = args[0] - else - raise NoMemoryError.new ("Cannot set #{name} on this object") - end - end - - def to_hash - @values.inject({}) do |result, (key,value)| - if value.is_a? Array - list = [] - value.each do |obj| - list.push(obj.respond_to?(:to_hash) ? obj.to_hash : value) - end - result[key] = list - else if value.respond_to?(:to_hash) - result[key] = value.to_hash - else - result[key] = value - end - end - result - end - end - - def to_json(*a) - JSON.generate(@values) - end - - def to_s - JSON.generate(@values) - end - - def create_list(array) - hash = {} - hash[:data] = array - hash[:object] = 'list' - hash - end - end -end \ No newline at end of file diff --git a/lib/nfe/pagination.rb b/lib/nfe/pagination.rb new file mode 100644 index 0000000..ae6cc32 --- /dev/null +++ b/lib/nfe/pagination.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Nfe + # Pagination metadata for a list response. NFE.io endpoints paginate in one + # of two shapes; each resource populates only the half relevant to it: + # + # * page-style — +page_index+ / +page_count+ (cursor fields nil) + # * cursor-style — +starting_after+ / +ending_before+ (+page_index+ nil) + # + # +total+ is optional and may be present in either shape. + class ListPage < Data.define(:page_index, :page_count, :starting_after, :ending_before, :total) + # @return [Nfe::ListPage] a page-style page with cursor fields left nil. + def self.from_page(page_index: nil, page_count: nil, total: nil) + new(page_index: page_index, page_count: page_count, + starting_after: nil, ending_before: nil, total: total) + end + + # @return [Nfe::ListPage] a cursor-style page with +page_index+/+page_count+ nil. + def self.from_cursor(starting_after: nil, ending_before: nil, total: nil) + new(page_index: nil, page_count: nil, + starting_after: starting_after, ending_before: ending_before, total: total) + end + + def initialize(page_index: nil, page_count: nil, starting_after: nil, + ending_before: nil, total: nil) + super + end + end + + # A list of hydrated DTOs (+data+) plus its pagination metadata (+page+). + # +data+ is iterated identically regardless of pagination shape. + # + # Includes +Enumerable+ (delegating +each+ to +data+), so a list response is + # usable directly anywhere an Enumerable is expected — +map+, +select+, + # +each_with_index+, ... — without first reaching into +data+. + class ListResponse < Data.define(:data, :page) + include Enumerable + + def initialize(data: [], page: nil) + super + end + + # Iterate the hydrated DTOs in +data+. + # + # @yieldparam item each hydrated DTO. + # @return [Enumerator] when called without a block. + def each(&) + return enum_for(:each) unless block_given? + + data.each(&) + end + end +end diff --git a/lib/nfe/request_options.rb b/lib/nfe/request_options.rb new file mode 100644 index 0000000..0408e8d --- /dev/null +++ b/lib/nfe/request_options.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Nfe + # Immutable per-call overrides for a single request. Passing a + # +RequestOptions+ to {Nfe::Client#request} (or through a resource helper) + # overrides the family-resolved +api_key+, +base_url+, and +timeout+ for that + # one call; any nil field falls back to normal family resolution. + # + # This enables multi-tenant per-call keys without constructing a second + # +Nfe::Client+. + class RequestOptions < Data.define(:api_key, :base_url, :timeout) + def initialize(api_key: nil, base_url: nil, timeout: nil) + super + end + end +end diff --git a/lib/nfe/resources/.gitkeep b/lib/nfe/resources/.gitkeep new file mode 100644 index 0000000..7b0f8f9 --- /dev/null +++ b/lib/nfe/resources/.gitkeep @@ -0,0 +1,2 @@ +# Hand-written resource classes (Nfe::Resources::*) — added by +# add-{entity,invoice,lookup}-resources and add-rtc-invoice-emission. diff --git a/lib/nfe/resources/abstract_resource.rb b/lib/nfe/resources/abstract_resource.rb new file mode 100644 index 0000000..3a5261c --- /dev/null +++ b/lib/nfe/resources/abstract_resource.rb @@ -0,0 +1,267 @@ +# frozen_string_literal: true + +require "json" + +module Nfe + module Resources + # Base class for every SDK resource. Constructed with the owning + # {Nfe::Client}, it provides the HTTP verb helpers (+get+/+post+/+put+/ + # +delete+) routed through the client's transport for the resource's declared + # +api_family+, plus hydration and async-response helpers shared by every + # resource. + # + # Subclasses declare their +api_family+ (and optionally override + # +api_version+, which defaults to +"v1"+; the addresses resource returns + # +""+ because its host already embeds +/v2+). Business methods are added by + # the resource changes (add-invoice-resources, add-entity-resources, ...). + # + # All HTTP helpers accept an optional +request_options:+ ({Nfe::RequestOptions}) + # that is threaded through to {Nfe::Client#request} for per-call multi-tenant + # overrides. + class AbstractResource + # @param client [Nfe::Client] the owning client. + def initialize(client) + @client = client + end + + protected + + # @return [Nfe::Client] the owning client. + attr_reader :client + + # The product family this resource belongs to (e.g. +:main+, +:cte+). + # Subclasses MUST override. + # + # @return [Symbol] + def api_family + raise NotImplementedError, "#{self.class} must declare an api_family" + end + + # The path version segment prefixed to every request path. Defaults to + # +"v1"+; a resource whose host already embeds the version (addresses) + # overrides this to +""+. + # + # @return [String] + def api_version + "v1" + end + + # Issue a GET request for this resource's family. + def get(path, query: {}, request_options: nil, headers: {}) + client.request(:get, family: api_family, path: full_path(path), + query: query, headers: headers, + request_options: request_options) + end + + # Issue a POST request for this resource's family. + def post(path, body: nil, query: {}, request_options: nil, headers: {}, + idempotency_key: nil) + client.request(:post, family: api_family, path: full_path(path), + query: query, body: body, headers: headers, + idempotency_key: idempotency_key, + request_options: request_options) + end + + # Issue a PUT request for this resource's family. + def put(path, body: nil, query: {}, request_options: nil, headers: {}) + client.request(:put, family: api_family, path: full_path(path), + query: query, body: body, headers: headers, + request_options: request_options) + end + + # Issue a DELETE request for this resource's family. + def delete(path, query: {}, request_options: nil, headers: {}) + client.request(:delete, family: api_family, path: full_path(path), + query: query, headers: headers, + request_options: request_options) + end + + # Prefix +path+ with +/#{api_version}+ unless the version is empty (in + # which case +path+ is returned unchanged, avoiding a doubled slash). + # + # @param path [String] + # @return [String] + def full_path(path) + version = api_version.to_s + return path if version.empty? + + "/#{version}#{path}" + end + + # Materialize a generated DTO by delegating to its +from_api+ factory + # (camelCase -> snake_case, unknown-key drop, nested recursion). The + # factory itself is produced by add-openapi-pipeline; this is only the + # call site. + # + # @param klass [Class] a generated DTO class responding to +from_api+. + # @param payload [Hash, nil] + def hydrate(klass, payload) + klass.from_api(payload) + end + + # Perform a GET and return the response body as binary-safe bytes + # (+ASCII-8BIT+), so binary documents (PDF/XML/ZIP) are not corrupted. + # + # @return [String] the body, encoded +ASCII-8BIT+. + def download(path, query: {}, request_options: nil, headers: {}) + response = get(path, query: query, request_options: request_options, + headers: headers) + (response.body || "").dup.force_encoding(Encoding::ASCII_8BIT) + end + + # Unwrap +payload[wrapper_key]+, hydrate each item with +klass+, and build + # an {Nfe::ListResponse} whose +page+ reflects the pagination shape: + # page-style (+page_index+/+page_count+) or cursor-style + # (+starting_after+/+ending_before+). + # + # @param klass [Class] generated DTO class for each item. + # @param payload [Hash] the parsed response body. + # @param wrapper_key [String, Symbol] key carrying the item array. + # @return [Nfe::ListResponse] + def hydrate_list(klass, payload, wrapper_key:) + payload ||= {} #: Hash[untyped, untyped] + raw_items = payload[wrapper_key.to_s] || payload[wrapper_key.to_sym] || [] + items = raw_items.map { |item| hydrate(klass, item) } + Nfe::ListResponse.new(data: items, page: build_list_page(payload)) + end + + # Interpret an emission response. A 202 with a +Location+ header yields an + # {Nfe::Pending} (its +invoice_id+ parsed from the final path segment); a + # 202 without +Location+ is a protocol violation raising + # {Nfe::InvoiceProcessingError}. A 201/200 hydrates +issued_klass+ from the + # JSON body and yields an {Nfe::Issued}. + # + # @param response [Nfe::Http::Response] + # @param issued_klass [Class] generated DTO for the materialized resource. + # @return [Nfe::Pending, Nfe::Issued] + def handle_async_response(response, issued_klass:) + if response.status == 202 + location = response.location + if location.nil? || location.empty? + raise Nfe::InvoiceProcessingError.new( + "Resposta 202 sem cabeçalho Location: não é possível identificar a nota em processamento.", + status_code: response.status, response_headers: response.headers + ) + end + Nfe::Pending.new(invoice_id: extract_invoice_id(location), location: location) + else + Nfe::Issued.new(resource: hydrate(issued_klass, parse_json(response.body))) + end + end + + private + + # Detect the pagination shape of +payload+ and build the matching + # {Nfe::ListPage}. Page-style takes precedence when paging fields exist. + def build_list_page(payload) + page_index = dig_key(payload, "pageIndex", :page_index) + page_count = dig_key(payload, "pageCount", :page_count) + total = payload["totalResults"] || dig_key(payload, "total", :total) + + return page_list_page(page_index, page_count, total) if page_index || page_count + + cursor_list_page(payload, total) + end + + # Reads a value under either the camelCase (String) or snake_case (Symbol) key. + def dig_key(payload, camel_key, snake_key) + payload[camel_key] || payload[snake_key] + end + + def page_list_page(page_index, page_count, total) + Nfe::ListPage.new(page_index: page_index, page_count: page_count, total: total) + end + + def cursor_list_page(payload, total) + starting_after = dig_key(payload, "startingAfter", :starting_after) + ending_before = dig_key(payload, "endingBefore", :ending_before) + return Nfe::ListPage.new(total: total) unless starting_after || ending_before + + Nfe::ListPage.new(starting_after: starting_after, ending_before: ending_before, total: total) + end + + # Extract the trailing id from a +Location+ path, e.g. + # +/v1/companies/x/serviceinvoices/abc-123+ -> +"abc-123"+. + def extract_invoice_id(location) + match = location.match(%r{/([a-z0-9-]+)\z}i) + match ? match[1] : nil + end + + # Parse a JSON body, tolerating nil/empty/malformed bodies. + def parse_json(body) + return nil if body.nil? || body.empty? + + JSON.parse(body) + rescue JSON::ParserError + nil + end + + # Unwrap an API envelope: return +payload[key]+ when present (String or + # Symbol key), otherwise return +payload+ unchanged. Tolerant of a missing + # envelope so callers can pass a wrapped or already-unwrapped Hash. + # + # @param payload [Hash, nil] the parsed response body. + # @param key [String, Symbol] the envelope key (e.g. +"companies"+). + # @return [Object] the unwrapped value, or +payload+. + def unwrap(payload, key) + return payload unless payload.is_a?(Hash) + + if payload.key?(key.to_s) + payload[key.to_s] + elsif payload.key?(key.to_sym) + payload[key.to_sym] + else + payload + end + end + + # POST a +multipart/form-data+ body built from +parts+ using only Ruby + # stdlib, introducing no new runtime dependency. Each part is either a + # scalar field value (+String+) or a file part described by a Hash with + # +:filename+, +:content+, and optional +:content_type+. + # + # The body is assembled as binary (+ASCII-8BIT+) so certificate bytes are + # never corrupted, and the +Content-Type+ header carries the generated + # boundary. The multipart body is intentionally never logged. + # + # @param path [String] request path (already family-relative). + # @param parts [Hash{String,Symbol => String, Hash}] form fields/files. + # @return [Nfe::Http::Response] + def upload_multipart(path, parts) + boundary = "----NfeBoundary#{parts.object_id}" + body = build_multipart_body(parts, boundary) + headers = { "Content-Type" => "multipart/form-data; boundary=#{boundary}" } + post(path, body: body, headers: headers) + end + + # Assemble the raw multipart/form-data body for +parts+ under +boundary+. + def build_multipart_body(parts, boundary) + buffer = String.new(encoding: Encoding::ASCII_8BIT) + parts.each do |name, value| + buffer << "--#{boundary}\r\n".b + buffer << multipart_part(name.to_s, value) + end + buffer << "--#{boundary}--\r\n".b + buffer + end + + # Encode a single multipart part (scalar field or file). + def multipart_part(name, value) + part = String.new(encoding: Encoding::ASCII_8BIT) + if value.is_a?(Hash) + filename = value[:filename] || value["filename"] || "file" + content_type = value[:content_type] || value["content_type"] || "application/octet-stream" + content = value[:content] || value["content"] || "" + part << %(Content-Disposition: form-data; name="#{name}"; filename="#{filename}"\r\n).b + part << "Content-Type: #{content_type}\r\n\r\n".b + part << content.dup.force_encoding(Encoding::ASCII_8BIT) + else + part << %(Content-Disposition: form-data; name="#{name}"\r\n\r\n).b + part << value.to_s.dup.force_encoding(Encoding::ASCII_8BIT) + end + part << "\r\n".b + part + end + end + end +end diff --git a/lib/nfe/resources/addresses.rb b/lib/nfe/resources/addresses.rb new file mode 100644 index 0000000..363bf9d --- /dev/null +++ b/lib/nfe/resources/addresses.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require "cgi" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/addresses/address_lookup_response" + +module Nfe + module Resources + # Address lookup against the +:addresses+ data family + # (+address.api.nfe.io/v2+). The host already embeds the API version, so + # {#api_version} is +""+ and request paths are used verbatim. + # + # All three lookups return an {Nfe::AddressLookupResponse} wrapping the API + # +addresses+ array. + class Addresses < AbstractResource + # Look up addresses by Brazilian postal code (CEP). + # + # @param postal_code [String] CEP in any format (e.g. +"01310-100"+). + # @return [Nfe::AddressLookupResponse] + # @raise [Nfe::InvalidRequestError] when the CEP is not 8 digits. + def lookup_by_postal_code(postal_code) + cep = Nfe::IdValidator.cep(postal_code) + response = get("/addresses/#{cep}") + hydrate(Nfe::AddressLookupResponse, parse_json(response.body)) + end + + # Search addresses with an opaque OData +$filter+ expression. + # + # @param filter [String, nil] forwarded as +$filter+ when present. + # @return [Nfe::AddressLookupResponse] + def search(filter: nil) + query = {} #: Hash[String, untyped] + query["$filter"] = filter unless filter.nil? + response = get("/addresses", query: query) + hydrate(Nfe::AddressLookupResponse, parse_json(response.body)) + end + + # Look up addresses by a free-text term. + # + # @param term [String] a non-empty search term. + # @return [Nfe::AddressLookupResponse] + # @raise [Nfe::InvalidRequestError] when +term+ is empty/whitespace. + def lookup_by_term(term) + raise Nfe::InvalidRequestError, "termo (term) não pode ser vazio" if term.to_s.strip.empty? + + response = get("/addresses/#{CGI.escape(term.strip)}") + hydrate(Nfe::AddressLookupResponse, parse_json(response.body)) + end + + protected + + def api_family + :addresses + end + + # This family's host already embeds the API version, so no version + # segment is prefixed to the request path. + def api_version + "" + end + end + end +end diff --git a/lib/nfe/resources/companies.rb b/lib/nfe/resources/companies.rb new file mode 100644 index 0000000..bf57438 --- /dev/null +++ b/lib/nfe/resources/companies.rb @@ -0,0 +1,349 @@ +# frozen_string_literal: true + +require "json" +require "time" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/company" +require "nfe/certificate" + +module Nfe + module Resources + # Companies resource for the +:main+ host family + # (+https://api.nfe.io/v1/...+). Exposes the company CRUD plus the digital + # certificate lifecycle (upload/replace/validate/status) and convenience + # finders. The NFE.io API wraps company responses in a + # +{"companies" => }+ envelope, transparently unwrapped here + # before hydrating {Nfe::Company}. + # + # @example + # company = client.companies.create(name: "Acme", federalTaxNumber: "12345678000199") + # client.companies.retrieve(company.id) + class Companies < AbstractResource + ENVELOPE = "companies" + + protected + + def api_family + :main + end + + public + + # Create a company. Validates +federalTaxNumber+ format (11/14 digits, + # never coerced to Integer) and e-mail format when present. + # + # @param data [Hash] company attributes (camelCase keys per the API). + # @return [Nfe::Company] + def create(data) + validate_company_data(data) + response = post("/companies", body: json_body(data), headers: json_headers) + hydrate(Nfe::Company, unwrap(parse_json(response.body), ENVELOPE)) + end + + # List one page of companies. The public +page_index+ is 0-based and is + # sent to the API as its 1-based +pageIndex+ (which must be >= 1); the + # 1-based +page+ in the response is converted back to 0-based. + # + # @param page_index [Integer] 0-based page index. + # @param page_count [Integer] page size. + # @return [Nfe::ListResponse] + def list(page_index: 0, page_count: 100) + response = get("/companies", query: { pageIndex: page_index + 1, pageCount: page_count }) + payload = parse_json(response.body) || {} + items = (unwrap(payload, ENVELOPE) || []).map { |item| hydrate(Nfe::Company, item) } + resolved_index = resolve_page_index(payload, page_index) + Nfe::ListResponse.new( + data: items, + page: Nfe::ListPage.from_page(page_index: resolved_index, page_count: page_count) + ) + end + + # Fetch every company by auto-paginating with +page_count: 100+ until a + # short page is returned. Convenience helper; not optimized for large + # accounts. + # + # @return [Array] + def list_all + list_each.to_a + end + + # Stream companies lazily, one per +yield+, fetching pages on demand. + # Convenience helper; not optimized for large accounts. + # + # @return [Enumerator] + def list_each + Enumerator.new do |yielder| + page_index = 0 + loop do + page = list(page_index: page_index, page_count: 100) + page.data.each { |company| yielder << company } + break if page.data.length < 100 + + page_index += 1 + end + end + end + + # Retrieve a company by id. + # + # @param company_id [String] + # @return [Nfe::Company] + # @raise [Nfe::NotFoundError] when the API responds 404. + def retrieve(company_id) + id = Nfe::IdValidator.company_id(company_id) + response = get("/companies/#{id}") + hydrate(Nfe::Company, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Update a company. + # + # @param company_id [String] + # @param data [Hash] + # @return [Nfe::Company] + def update(company_id, data) + id = Nfe::IdValidator.company_id(company_id) + validate_company_data(data) + response = put("/companies/#{id}", body: json_body(data), headers: json_headers) + hydrate(Nfe::Company, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Delete a company. Named +remove+ to avoid clashing with +delete+ + # semantics (parity with the Node/PHP SDKs). + # + # @param company_id [String] + # @return [Hash] +{ deleted: true, id: company_id }+. + def remove(company_id) + id = Nfe::IdValidator.company_id(company_id) + delete("/companies/#{id}") + { deleted: true, id: id } + end + + # Find a company by federal tax number (CNPJ/CPF). Convenience helper built + # on {#list_all} plus client-side filtering; not optimized for large + # accounts. + # + # @param tax_number [String, Integer] + # @return [Nfe::Company, nil] + def find_by_tax_number(tax_number) + normalized = normalize_tax_number(tax_number) + list_each.find { |company| normalize_tax_number(company.federal_tax_number) == normalized } + end + + # Find companies whose name contains +name+ (case-insensitive). Convenience + # helper built on {#list_all}; not optimized for large accounts. + # + # @param name [String] + # @return [Array] + def find_by_name(name) + term = name.to_s.strip + raise Nfe::InvalidRequestError, "nome de busca (name) não pode ser vazio" if term.empty? + + term = term.downcase + list_all.select { |company| company.name.to_s.downcase.include?(term) } + end + + # Validate a PKCS#12 certificate locally (no HTTP) and extract its + # metadata. The password and bytes are handled in-memory only. + # + # @param file [String] a file path or the raw .pfx/.p12 bytes. + # @param password [String] + # @return [Nfe::CertificateInfo] + # @raise [Nfe::InvalidRequestError] on wrong password or malformed DER. + def validate_certificate(file:, password:) + Nfe::CertificateValidator.validate(read_certificate_bytes(file), password) + end + + # Upload a digital certificate, pre-validating it locally (fail-fast) + # before POSTing a +multipart/form-data+ body to + # +/companies/{id}/certificate+ with the +file+ and +password+ fields. + # + # @param company_id [String] + # @param file [String] file path or raw bytes. + # @param password [String] + # @param filename [String, nil] used for the extension check and part name. + # @return [Hash] +{ uploaded: bool, message: String? }+. + def upload_certificate(company_id, file:, password:, filename: nil) + id = Nfe::IdValidator.company_id(company_id) + if filename && !Nfe::CertificateValidator.supported_format?(filename) + raise Nfe::InvalidRequestError, + "formato de certificado não suportado: apenas .pfx e .p12 são aceitos" + end + + bytes = read_certificate_bytes(file) + Nfe::CertificateValidator.validate(bytes, password) # fail-fast, raises on invalid + + response = upload_multipart( + "/companies/#{id}/certificate", + "file" => { filename: filename || "certificate.pfx", + content: bytes, content_type: "application/x-pkcs12" }, + "password" => password + ) + payload = parse_json(response.body) || {} + { uploaded: true, message: payload["message"] } + end + + # Replace an existing certificate. Alias of {#upload_certificate} — the API + # handles replacement. + # + # @see #upload_certificate + def replace_certificate(company_id, file:, password:, filename: nil) + upload_certificate(company_id, file: file, password: password, filename: filename) + end + + # Fetch certificate status, computing +days_until_expiration+ and + # +expiring_soon+ client-side from +expires_on+ when present. + # + # @param company_id [String] + # @return [Nfe::CertificateStatus] + def get_certificate_status(company_id) + id = Nfe::IdValidator.company_id(company_id) + response = get("/companies/#{id}/certificate") + details = parse_json(response.body) || {} + build_certificate_status(details) + end + + # Return an expiry warning when the certificate expires within + # +threshold_days+, otherwise +nil+. + # + # @param company_id [String] + # @param threshold_days [Integer] + # @return [Hash, nil] +{ expiring: true, days_remaining:, expires_on: }+. + def check_certificate_expiration(company_id, threshold_days: 30) + status = get_certificate_status(company_id) + return nil unless status.has_certificate && status.expires_on + + days = status.days_until_expiration + return nil if days.nil? + + return unless days >= 0 && days < threshold_days + + { expiring: true, days_remaining: days, expires_on: status.expires_on } + end + + # List companies that have a valid certificate. Convenience helper: + # {#list_all} + one +get_certificate_status+ per company (companies whose + # status lookup fails are skipped). + # + # @return [Array] + def get_companies_with_certificates + list_all.select do |company| + status = certificate_status_or_nil(company.id.to_s) + status&.has_certificate && status.valid + end + end + + # List companies whose certificate expires within +threshold_days+. + # Convenience helper; companies whose status lookup fails are skipped. + # + # @param threshold_days [Integer] + # @return [Array] + def get_companies_with_expiring_certificates(threshold_days: 30) + list_all.select do |company| + expiring_or_nil(company.id.to_s, threshold_days) + end + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + # API uses 1-based +page+; convert to 0-based, falling back to the + # requested index when the API omits it. + def resolve_page_index(payload, requested_index) + api_page = payload["page"] || payload[:page] + return requested_index if api_page.nil? + + api_page - 1 + end + + # Validate +federalTaxNumber+ format/length and e-mail without coercing to + # Integer or running check-digit rules (design D12). Tolerant of both + # camelCase and snake_case keys. + def validate_company_data(data) + tax = data[:federalTaxNumber] || data["federalTaxNumber"] || + data[:federal_tax_number] || data["federal_tax_number"] + unless tax.nil? + digits = normalize_tax_number(tax) + unless [11, 14].include?(digits.length) + raise Nfe::InvalidRequestError, + "federalTaxNumber deve conter 11 dígitos (CPF) ou 14 (CNPJ)" + end + end + + email = data[:email] || data["email"] + return if email.nil? + return if valid_email?(email.to_s) + + raise Nfe::InvalidRequestError, "e-mail (email) com formato inválido" + end + + # Structural e-mail check without a backtracking-prone regex (avoids the + # polynomial ReDoS in +[^\s@]+@[^\s@]+\.[^\s@]++). Equivalent semantics: + # exactly one "@", no whitespace, and a dotted domain with non-empty + # leading/trailing labels. Every step is linear in the input length. + def valid_email?(value) + return false if value.match?(/\s/) + + local, separator, domain = value.partition("@") + return false if separator.empty? || local.empty? || domain.empty? + return false if domain.include?("@") + return false if domain.start_with?(".") || domain.end_with?(".") + + domain.include?(".") + end + + def normalize_tax_number(value) + value.to_s.gsub(/[^0-9A-Za-z]/, "") + end + + # Read certificate bytes from a file path or accept raw bytes verbatim. + # Raw PKCS#12 (DER) bytes contain NUL bytes, which would make +File.file?+ + # raise "path name contains null byte" — so a value with a NUL byte is + # always treated as content, and the path check runs only on NUL-free + # strings (which cannot trigger that error). + def read_certificate_bytes(file) + bytes = file.to_s.dup.force_encoding(Encoding::ASCII_8BIT) + return File.binread(file) if file.is_a?(String) && !bytes.include?("\x00".b) && File.file?(file) + + bytes + end + + def build_certificate_status(details) + has_certificate = details["hasCertificate"] || details["has_certificate"] || false + expires_on = details["expiresOn"] || details["expires_on"] + valid = details.key?("isValid") ? details["isValid"] : details["valid"] + + days = nil + expiring = nil + if has_certificate && expires_on + not_after = Time.parse(expires_on.to_s) + days = Nfe::CertificateValidator.days_until_expiration(not_after) + expiring = Nfe::CertificateValidator.expiring_soon?(not_after) + end + + Nfe::CertificateStatus.new( + has_certificate: has_certificate, expires_on: expires_on, valid: valid, + days_until_expiration: days, expiring_soon: expiring, details: details + ) + end + + def certificate_status_or_nil(company_id) + get_certificate_status(company_id) + rescue Nfe::Error + nil + end + + def expiring_or_nil(company_id, threshold_days) + check_certificate_expiration(company_id, threshold_days: threshold_days) + rescue Nfe::Error + nil + end + end + end +end diff --git a/lib/nfe/resources/consumer_invoice_query.rb b/lib/nfe/resources/consumer_invoice_query.rb new file mode 100644 index 0000000..234d186 --- /dev/null +++ b/lib/nfe/resources/consumer_invoice_query.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/consumer_invoice_query/tax_coupon" + +module Nfe + module Resources + # Query (consulta) of consumer invoices — NFC-e tax coupons (CFe-SAT) — by + # access key, served by the +:nfe_query+ family (+nfe.api.nfe.io+, +/v1+, + # +/coupon/+ path). + # + # This is DISTINCT from {Nfe::Resources::ConsumerInvoices} (NFC-e emission, + # +add-invoice-resources+): different host and API version. Here we only + # retrieve and download an already-issued coupon. + class ConsumerInvoiceQuery < AbstractResource + protected + + def api_family = :nfe_query + + # The version segment (+v1+) is embedded in the request path, so no version + # prefix is added by the base class. + def api_version = "" + + public + + # Retrieve a consumer-invoice tax coupon by its access key. + # + # @param access_key [String] the 44-digit NFC-e access key (normalized). + # @return [Nfe::TaxCoupon] + def retrieve(access_key) + key = Nfe::IdValidator.access_key(access_key) + hydrate(Nfe::TaxCoupon, parse_json(get("/v1/consumerinvoices/coupon/#{key}").body)) + end + + # Download the raw XML for a consumer-invoice tax coupon. + # + # @param access_key [String] the 44-digit NFC-e access key (normalized). + # @return [String] the XML document bytes (+ASCII-8BIT+). + def download_xml(access_key) + key = Nfe::IdValidator.access_key(access_key) + download("/v1/consumerinvoices/coupon/#{key}.xml", headers: { "Accept" => "application/xml" }) + end + end + end +end diff --git a/lib/nfe/resources/consumer_invoices.rb b/lib/nfe/resources/consumer_invoices.rb new file mode 100644 index 0000000..912666c --- /dev/null +++ b/lib/nfe/resources/consumer_invoices.rb @@ -0,0 +1,250 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/consumer_invoice" +require "nfe/resources/responses/consumer_invoice_pending" +require "nfe/resources/responses/consumer_invoice_issued" + +module Nfe + module Resources + # Consumer invoices (NFC-e — Nota Fiscal de Consumidor Eletrônica). + # + # Hosted at +https://api.nfse.io+ under +/v2+ (the +:cte+ family), backed by + # the paths exposed in +nf-consumidor-v2.yaml+. + # + # == Parity-plus + # This resource is a *parity-plus* addition: the Node.js SDK deliberately + # does NOT expose NFC-e emission (it covers only the read-only + # +consumerInvoiceQuery+). The NFE.io API has supported the full NFC-e + # lifecycle since v2, so this Ruby SDK extends beyond Node parity — useful + # for PoS and e-commerce integrations. + # + # == Intentional omissions (grounded in Brazilian fiscal law) + # Unlike {Nfe::Resources::ProductInvoices} (NF-e), this resource does NOT + # define: + # * +send_correction_letter+ — the Carta de Correção Eletrônica (CC-e) + # instrument applies only to NF-e/CT-e, never to NFC-e. + # * +download_epec_xml+ — there is no EPEC (Evento Prévio de Emissão em + # Contingência) for NFC-e. + # * a per-invoice +disable+ — NFC-e supports only *collective* inutilization + # of a number range via {#disable_range}, not per-document disablement. + # Calling any of these raises +NoMethodError+. + # + # == Emission contract + # {#create} and {#create_with_state_tax} return a discriminated result: + # {Nfe::Resources::ConsumerInvoicePending} on HTTP 202 (async) or + # {Nfe::Resources::ConsumerInvoiceIssued} on HTTP 201/200 (sync). Both accept + # an optional +idempotency_key:+ (sent as the +Idempotency-Key+ header; the + # SDK never auto-retries, so re-invoking with the SAME key after a timeout + # lets the server deduplicate) and +request_options:+ (per-call + # multi-tenant overrides). +create_and_wait+/+create_batch+ are deferred: + # poll manually with +result.pending?+ + {Nfe::FlowStatus.terminal?}. + # + # @example Emit an NFC-e and handle the discriminated result + # result = client.consumer_invoices.create(company_id: id, data: payload) + # case result + # in Nfe::Resources::ConsumerInvoicePending => p then poll(p.invoice_id) + # in Nfe::Resources::ConsumerInvoiceIssued => i then i.resource + # end + class ConsumerInvoices < AbstractResource + # Wrapper key for the list envelope. + ENVELOPE = "consumerInvoices" + + protected + + def api_family + :cte + end + + # The +:cte+ host (+api.nfse.io+) does not bake in a version, so this + # resource supplies the +/v2+ segment itself. + def api_version + "v2" + end + + public + + # Emit an NFC-e. Returns {ConsumerInvoicePending} (HTTP 202) or + # {ConsumerInvoiceIssued} (HTTP 201/200). + # + # @param company_id [String] + # @param data [Hash] NFC-e payload (camelCase keys per the API). + # @param idempotency_key [String, nil] sent as +Idempotency-Key+. + # @param request_options [Nfe::RequestOptions, nil] per-call overrides. + # @return [ConsumerInvoicePending, ConsumerInvoiceIssued] + def create(company_id:, data:, idempotency_key: nil, request_options: nil) + id = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{id}/consumerinvoices", body: json_body(data), + headers: json_headers, + idempotency_key: idempotency_key, + request_options: request_options) + discriminate(response) + end + + # Emit an NFC-e scoped to a specific state-tax registration. + # + # @param company_id [String] + # @param state_tax_id [String] + # @param data [Hash] + # @param idempotency_key [String, nil] + # @param request_options [Nfe::RequestOptions, nil] + # @return [ConsumerInvoicePending, ConsumerInvoiceIssued] + def create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + sid = Nfe::IdValidator.state_tax_id(state_tax_id) + response = post("/companies/#{cid}/statetaxes/#{sid}/consumerinvoices", + body: json_body(data), headers: json_headers, + idempotency_key: idempotency_key, request_options: request_options) + discriminate(response) + end + + # List NFC-e for a company (cursor pagination; wrapper +consumerInvoices+). + # + # @param company_id [String] + # @param options [Hash] cursor query params (+starting_after+, +limit+...). + # @return [Nfe::ListResponse] + def list(company_id:, environment:, **options) + id = Nfe::IdValidator.company_id(company_id) + require_environment(environment) + response = get("/companies/#{id}/consumerinvoices", + query: options.merge(environment: environment)) + hydrate_list(Nfe::ConsumerInvoice, parse_json(response.body), wrapper_key: ENVELOPE) + end + + # Retrieve a single NFC-e by id. + # + # @return [Nfe::ConsumerInvoice] + def retrieve(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + response = get("/companies/#{cid}/consumerinvoices/#{iid}") + hydrate(Nfe::ConsumerInvoice, parse_json(response.body)) + end + + # Cancel an NFC-e (synchronous); returns the updated model. + # + # @return [Nfe::ConsumerInvoice] + def cancel(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + response = delete("/companies/#{cid}/consumerinvoices/#{iid}") + hydrate(Nfe::ConsumerInvoice, parse_json(response.body)) + end + + # List the line items of an NFC-e. + # + # @return [Array] + def list_items(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + response = get("/companies/#{cid}/consumerinvoices/#{iid}/items") + unwrap_collection(parse_json(response.body), "items") + end + + # List the events of an NFC-e. + # + # @return [Array] + def list_events(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + response = get("/companies/#{cid}/consumerinvoices/#{iid}/events") + unwrap_collection(parse_json(response.body), "events") + end + + # Download the DANFE NFC-e PDF as binary bytes (unlike ProductInvoices, + # which returns a URI). + # + # @return [String] +ASCII-8BIT+ PDF bytes. + def download_pdf(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + download("/companies/#{cid}/consumerinvoices/#{iid}/pdf", + headers: { "Accept" => "application/pdf" }) + end + + # Download the authorized NFC-e XML as binary bytes. + # + # @return [String] +ASCII-8BIT+ XML bytes. + def download_xml(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + download("/companies/#{cid}/consumerinvoices/#{iid}/xml", + headers: { "Accept" => "application/xml" }) + end + + # Download the rejection XML (sefaz refusal) as binary bytes. + # + # @return [String] +ASCII-8BIT+ XML bytes. + def download_rejection_xml(company_id:, invoice_id:) + cid, iid = validate_pair(company_id, invoice_id) + download("/companies/#{cid}/consumerinvoices/#{iid}/xml/rejection", + headers: { "Accept" => "application/xml" }) + end + + # Collectively inutilize a range of NFC-e numbers. NFC-e supports only + # collective inutilization (no per-invoice disablement). + # + # @param company_id [String] + # @param data [Hash] +{ environment, serie, state, begin_number, last_number, reason? }+. + # @return [Hash] the parsed disablement result. + def disable_range(company_id:, data:) + id = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{id}/consumerinvoices/disablement", + body: json_body(data), headers: json_headers) + parse_json(response.body) || {} + end + + private + + # The API rejects a NFC-e listing without an +environment+; require it + # client-side (mirrors product_invoices#list). + def require_environment(environment) + return unless environment.nil? || environment.to_s.strip.empty? + + raise Nfe::InvalidRequestError, "environment é obrigatório (Production ou Test)" + end + + # Validate a (company_id, invoice_id) pair, returning both normalized. + def validate_pair(company_id, invoice_id) + [Nfe::IdValidator.company_id(company_id), Nfe::IdValidator.invoice_id(invoice_id)] + end + + # Interpret an emission response into the discriminated NFC-e result. + def discriminate(response) + return issued_result(response) unless response.status == 202 + + location = response.location + if location.nil? || location.empty? + raise Nfe::InvoiceProcessingError.new( + "Resposta 202 sem cabeçalho Location: não é possível identificar a NFC-e em processamento.", + status_code: response.status, response_headers: response.headers + ) + end + ConsumerInvoicePending.new(invoice_id: extract_invoice_id(location), location: location) + end + + def issued_result(response) + invoice = hydrate(Nfe::ConsumerInvoice, parse_json(response.body)) + ConsumerInvoiceIssued.new(resource: invoice) + end + + # Extract the trailing id from a +Location+ path. + def extract_invoice_id(location) + match = location.match(%r{/([a-z0-9-]+)\z}i) + match ? match[1] : nil + end + + # Unwrap a collection envelope, tolerating a bare array or a wrapped one. + def unwrap_collection(payload, key) + return payload if payload.is_a?(Array) + return [] unless payload.is_a?(Hash) + + wrapped = payload[key] || payload[key.to_sym] + wrapped.is_a?(Array) ? wrapped : [] + end + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + end + end +end diff --git a/lib/nfe/resources/dto/addresses/address_lookup_response.rb b/lib/nfe/resources/dto/addresses/address_lookup_response.rb new file mode 100644 index 0000000..71017f4 --- /dev/null +++ b/lib/nfe/resources/dto/addresses/address_lookup_response.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a single address as returned by the NFE.io + # +address.api.nfe.io/v2+ lookup API. All fields are optional; {from_api} + # maps API camelCase keys onto snake_case members and is nil-tolerant + # (+from_api(nil)+ returns +nil+). + # + # +city+ is hydrated into a nested {Nfe::Address::City} value object + # (+{code, name}+). +postal_code+, +number+, +number_min+ and +number_max+ + # are kept as +String+, never coerced to Integer (preserves leading zeros). + class Address < Data.define( + :street, + :street_suffix, + :number, + :number_min, + :number_max, + :additional_information, + :district, + :postal_code, + :city, + :state, + :country + ) + # Nested value object for the IBGE city code/name pair returned inside an + # address item. Both members are optional and nil-tolerant. + class City < Data.define(:code, :name) + # @param payload [Hash, nil] the +city+ sub-object. + # @return [Nfe::Address::City, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"]&.to_s, + name: payload["name"] + ) + end + end + + # @param payload [Hash, nil] a single address object. + # @return [Nfe::Address, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + street: payload["street"], + street_suffix: payload["streetSuffix"], + number: payload["number"]&.to_s, + number_min: payload["numberMin"]&.to_s, + number_max: payload["numberMax"]&.to_s, + additional_information: payload["additionalInformation"], + district: payload["district"], + postal_code: payload["postalCode"]&.to_s, + city: Nfe::Address::City.from_api(payload["city"]), + state: payload["state"], + country: payload["country"] + ) + end + end + + # Immutable value object wrapping the addresses returned by a lookup. + # {from_api} is nil-tolerant and accepts BOTH response shapes the API uses: + # the list shape (+{ "addresses" => [...] }+, e.g. term/$filter search) and + # the single-result shape the postal-code lookup actually returns + # (+{ "address" => {...} }+) — the latter is normalized into a one-element + # +addresses+ list, so callers always read +response.addresses+. + class AddressLookupResponse < Data.define(:addresses) + # @param payload [Hash, nil] the parsed lookup response body. + # @return [Nfe::AddressLookupResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + raw = payload["addresses"] || [payload["address"]].compact + new(addresses: raw.map { |item| Nfe::Address.from_api(item) }) + end + end +end diff --git a/lib/nfe/resources/dto/company.rb b/lib/nfe/resources/dto/company.rb new file mode 100644 index 0000000..1294799 --- /dev/null +++ b/lib/nfe/resources/dto/company.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a company (emitente) as returned by the NFE.io + # +api.nfe.io/v1+ entity API. + # + # Hand-written (rather than reusing the mangled generated +contribuintes_v2+ + # DTOs) so the public shape stays clean and snake_case. {from_api} maps the + # API camelCase keys onto the snake_case members, drops unknown keys, and is + # nil-tolerant (+from_api(nil)+ returns +nil+). + # + # +federal_tax_number+ is kept as a +String+ — never coerced to +Integer+ — + # so future alphanumeric CNPJ (IN RFB 2.229/2024) is preserved. + class Company < Data.define( + :id, + :name, + :trade_name, + :federal_tax_number, + :email, + :status, + :tax_regime, + :municipal_tax_number, + :address, + :state_taxes, + :municipal_taxes, + :environment, + :account_id, + :created_on, + :modified_on + ) + # Build a {Nfe::Company} from an API payload. + # + # @param payload [Hash, nil] the unwrapped company object. + # @return [Nfe::Company, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + name: payload["name"], + trade_name: payload["tradeName"], + federal_tax_number: stringify(payload["federalTaxNumber"]), + email: payload["email"], + status: payload["status"], + tax_regime: payload["taxRegime"], + municipal_tax_number: payload["municipalTaxNumber"], + address: payload["address"], + state_taxes: payload["stateTaxes"], + municipal_taxes: payload["municipalTaxes"], + environment: payload["environment"], + account_id: payload["accountId"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"] + ) + end + + # Coerce a tax number to a +String+ without numeric coercion, preserving + # alphanumeric CNPJ. +nil+ stays +nil+. + # + # @api private + def self.stringify(value) + value&.to_s + end + end +end diff --git a/lib/nfe/resources/dto/consumer_invoice.rb b/lib/nfe/resources/dto/consumer_invoice.rb new file mode 100644 index 0000000..8af27bf --- /dev/null +++ b/lib/nfe/resources/dto/consumer_invoice.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a consumer invoice (NFC-e — Nota Fiscal de + # Consumidor Eletrônica) emitted through the NFE.io +api.nfse.io+ v2 API. + # + # Hand-written (rather than reusing the verbose generated +nf-consumidor-v2+ + # DTOs) so the public shape stays clean and snake_case. {from_api} maps the + # API camelCase keys onto the snake_case members, drops unknown keys, and is + # nil-tolerant (+from_api(nil)+ returns +nil+). The full parsed payload is + # preserved under +raw+ for forward compatibility. + # + # Shape mirrors +POST /v2/companies/{id}/consumerinvoices+ and + # +GET .../consumerinvoices/{id}+ per +nf-consumidor-v2.yaml+. + # + # +number+/+serie+ are kept as returned (no Integer coercion) so leading + # zeros and string representations from the API survive untouched. + class ConsumerInvoice < Data.define( + :id, + :status, + :flow_status, + :flow_message, + :environment, + :access_key, + :number, + :serie, + :total_amount, + :issued_on, + :created_on, + :modified_on, + :cancelled_on, + :raw + ) + # Build a {Nfe::ConsumerInvoice} from an API payload. + # + # @param payload [Hash, nil] the parsed consumer-invoice object. + # @return [Nfe::ConsumerInvoice, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + status: payload["status"], + flow_status: payload["flowStatus"], + flow_message: payload["flowMessage"], + environment: payload["environment"], + access_key: payload["accessKey"], + number: payload["number"], + serie: payload["serie"], + total_amount: payload["totalAmount"], + issued_on: payload["issuedOn"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"], + cancelled_on: payload["cancelledOn"], + raw: payload + ) + end + end +end diff --git a/lib/nfe/resources/dto/consumer_invoice_query/tax_coupon.rb b/lib/nfe/resources/dto/consumer_invoice_query/tax_coupon.rb new file mode 100644 index 0000000..5549c51 --- /dev/null +++ b/lib/nfe/resources/dto/consumer_invoice_query/tax_coupon.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a consumer-invoice tax coupon (CFe-SAT) + # returned by the +nfe.api.nfe.io+ query API + # (+GET /v1/consumerinvoices/coupon/{accessKey}+). + # + # This is the QUERY (consulta) of an already-issued coupon by access key and + # is DISTINCT from {Nfe::ConsumerInvoice} (the emission model handled by + # {Nfe::Resources::ConsumerInvoices}) — different host and API version. + # + # All fields are optional; {from_api} maps the API camelCase keys onto the + # snake_case members, hydrates the nested value objects, and is nil-tolerant + # (+from_api(nil)+ returns +nil+). The nested objects ({Issuer}, {Buyer}, + # {Total}, {Delivery}, {AdditionalInformation}, {Item}, {Payment}) keep only a + # pragmatic subset of the most common fields, mapped against the real CFe-SAT + # +TaxCouponResource+ shape. + class TaxCoupon < Data.define( + :current_status, + :number, + :sat_serie, + :software_version, + :software_federal_tax_number, + :access_key, + :cashier, + :issued_on, + :created_on, + :xml_version, + :issuer, + :buyer, + :totals, + :delivery, + :additional_information, + :items, + :payment + ) + # Issuer (emitente / +emit+) of the coupon. + class Issuer < Data.define(:federal_tax_number, :name, :trade_name, :state_tax_number) + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"]&.to_s, + name: payload["name"], + trade_name: payload["tradeName"], + state_tax_number: payload["stateTaxNumber"]&.to_s + ) + end + end + + # Buyer (destinatário / consumidor / +dest+) of the coupon. + class Buyer < Data.define(:federal_tax_number, :name) + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"]&.to_s, + name: payload["name"] + ) + end + end + + # Monetary totals of the coupon (+total+). +total_amount+ is the approximate + # tax amount (vCFeLei12741) and +coupon_amount+ is the coupon grand total + # (vCFe). + class Total < Data.define(:total_amount, :coupon_amount) + def self.from_api(payload) + return nil if payload.nil? + + new( + total_amount: payload["totalAmount"], + coupon_amount: payload["couponAmount"] + ) + end + end + + # Delivery location (+entrega+) — the coupon delivery group only carries an + # address. + class Delivery < Data.define(:address) + def self.from_api(payload) + return nil if payload.nil? + + new( + address: Address.from_api(payload["address"]) + ) + end + end + + # Pragmatic subset of a CFe-SAT address (+enderEmit+ / +entrega.address+). + class Address < Data.define(:street, :number, :district, :postal_code, :city, :state, :country) + def self.from_api(payload) + return nil if payload.nil? + + new( + street: payload["street"], + number: payload["number"]&.to_s, + district: payload["district"], + postal_code: payload["postalCode"]&.to_s, + city: payload["city"], + state: payload["state"], + country: payload["country"] + ) + end + end + + # Free-form additional information block (+infAdic+). + class AdditionalInformation < Data.define(:taxpayer) + def self.from_api(payload) + return nil if payload.nil? + + new( + taxpayer: payload["taxpayer"] + ) + end + end + + # A single coupon line item (+det+ / +prod+). + class Item < Data.define(:code, :description, :quantity, :unit_amount, :net_amount, :gross_amount, :cfop) + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"]&.to_s, + description: payload["description"], + quantity: payload["quantity"], + unit_amount: payload["unitAmount"], + net_amount: payload["netAmount"], + gross_amount: payload["grossAmount"], + cfop: payload["cfop"] + ) + end + end + + # A single payment-method detail (+pgto.MP+). + class PaymentDetail < Data.define(:method, :amount, :card) + def self.from_api(payload) + return nil if payload.nil? + + new( + method: payload["method"], + amount: payload["amount"], + card: payload["card"] + ) + end + end + + # Payment group for the coupon (+pgto+). +pay_back+ is the change/troco + # (vTroco); +payment_details+ holds one entry per payment method. + class Payment < Data.define(:pay_back, :payment_details) + def self.from_api(payload) + return nil if payload.nil? + + new( + pay_back: payload["payBack"], + payment_details: (payload["paymentDetails"] || []).map { |d| PaymentDetail.from_api(d) } + ) + end + end + + # Build a {Nfe::TaxCoupon} from an API payload. + # + # @param payload [Hash, nil] the parsed coupon object. + # @return [Nfe::TaxCoupon, nil] +nil+ when +payload+ is +nil+. + # rubocop:disable Metrics/AbcSize -- wide value-object mapping kept inline for Steep keyword-arg verification + def self.from_api(payload) + return nil if payload.nil? + + new( + current_status: payload["currentStatus"], + number: payload["number"], + sat_serie: payload["satSerie"]&.to_s, + software_version: payload["softwareVersion"], + software_federal_tax_number: payload["softwareFederalTaxNumber"]&.to_s, + access_key: payload["accessKey"]&.to_s, + cashier: payload["cashier"], + issued_on: payload["issuedOn"], + created_on: payload["createdOn"], + xml_version: payload["xmlVersion"], + issuer: Issuer.from_api(payload["issuer"]), + buyer: Buyer.from_api(payload["buyer"]), + totals: Total.from_api(payload["totals"]), + delivery: Delivery.from_api(payload["delivery"]), + additional_information: AdditionalInformation.from_api(payload["additionalInformation"]), + items: (payload["items"] || []).map { |i| Item.from_api(i) }, + payment: Payment.from_api(payload["payment"]) + ) + end + # rubocop:enable Metrics/AbcSize + end +end diff --git a/lib/nfe/resources/dto/inbound_invoice_metadata.rb b/lib/nfe/resources/dto/inbound_invoice_metadata.rb new file mode 100644 index 0000000..fb73a82 --- /dev/null +++ b/lib/nfe/resources/dto/inbound_invoice_metadata.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for the metadata of an inbound document (CT-e or + # supplier NF-e) returned by the +api.nfse.io+ inbound endpoints when looked + # up by 44-digit access key, or by an event lookup. + # + # Hand-written so the public surface stays small and snake_case. {from_api} + # maps the API camelCase keys onto snake_case members, drops unknown keys, and + # is nil-tolerant. The full payload is preserved in +details+ (including the + # webhook-v2 +productInvoices+ array, when present) so callers can read fields + # the SDK does not surface yet. + class InboundInvoiceMetadata < Data.define( + :access_key, + :nsu, + :status, + :name_sender, + :federal_tax_number_sender, + :total_invoice_amount, + :issued_on, + :product_invoices, + :details + ) + # Build a {Nfe::InboundInvoiceMetadata} from an API payload. + # + # @param payload [Hash, nil] the inbound document metadata object. + # @return [Nfe::InboundInvoiceMetadata, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + access_key: payload["accessKey"] || payload["accesskey"], + nsu: payload["nsu"], + status: payload["status"], + name_sender: payload["nameSender"], + federal_tax_number_sender: stringify(payload["federalTaxNumberSender"]), + total_invoice_amount: payload["totalInvoiceAmount"], + issued_on: payload["issuedOn"], + product_invoices: payload["productInvoices"], + details: payload + ) + end + + # Coerce a tax number to a +String+ without numeric coercion. +nil+ stays + # +nil+. + # + # @api private + def self.stringify(value) + value&.to_s + end + end +end diff --git a/lib/nfe/resources/dto/inbound_settings.rb b/lib/nfe/resources/dto/inbound_settings.rb new file mode 100644 index 0000000..cd1b78d --- /dev/null +++ b/lib/nfe/resources/dto/inbound_settings.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for the inbound auto-fetch settings returned by the + # CT-e / inbound NF-e endpoints on +api.nfse.io+ + # (+/v2/companies/{id}/inbound/(transportation|product)invoices+). + # + # Hand-written (the +consulta-cte-v2+ generated tree does not expose a clean + # settings shape) so the public surface stays small and snake_case. + # {from_api} maps the API camelCase keys onto the snake_case members, drops + # unknown keys, and is nil-tolerant (+from_api(nil)+ returns +nil+). The raw + # payload is preserved in +details+ so callers can read fields the SDK does + # not surface yet. + class InboundSettings < Data.define( + :id, + :status, + :start_from_nsu, + :start_from_date, + :environment_sefaz, + :automatic_manifesting, + :webhook_version, + :created_on, + :modified_on, + :details + ) + # Build a {Nfe::InboundSettings} from an API payload. + # + # @param payload [Hash, nil] the inbound settings object. + # @return [Nfe::InboundSettings, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + status: payload["status"], + start_from_nsu: payload["startFromNsu"], + start_from_date: payload["startFromDate"], + environment_sefaz: payload["environmentSefaz"] || payload["environmentSEFAZ"], + automatic_manifesting: payload["automaticManifesting"], + webhook_version: payload["webhookVersion"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"], + details: payload + ) + end + end +end diff --git a/lib/nfe/resources/dto/legal_entity_lookup/legal_entity_responses.rb b/lib/nfe/resources/dto/legal_entity_lookup/legal_entity_responses.rb new file mode 100644 index 0000000..b05e7d7 --- /dev/null +++ b/lib/nfe/resources/dto/legal_entity_lookup/legal_entity_responses.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +require "nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity" + +module Nfe + # Immutable value object for a legal entity (pessoa jurídica) as returned by + # the NFE.io +legalentity.api.nfe.io+ +basicInfo+ lookup. All fields are + # optional; {from_api} maps API camelCase keys onto snake_case members and is + # nil-tolerant (+from_api(nil)+ returns +nil+). + # + # +federal_tax_number+ is kept as a +String+ (CNPJ), never coerced to + # Integer, preserving future alphanumeric CNPJ. +address+, +phones+, + # +partners+ and +economic_activities+ are passed through opaquely. + class LegalEntity < Data.define( + :federal_tax_number, + :name, + :trade_name, + :status, + :status_on, + :status_reason, + :legal_nature, + :size, + :opened_on, + :issued_on, + :special_status, + :special_status_on, + :responsable_entity, + :share_capital, + :registration_unit, + :unit, + :address, + :phones, + :email, + :economic_activities, + :partners + ) + # @param payload [Hash, nil] the unwrapped legal-entity object. + # @return [Nfe::LegalEntity, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"]&.to_s, + name: payload["name"], + trade_name: payload["tradeName"], + status: payload["status"], + status_on: payload["statusOn"], + status_reason: payload["statusReason"], + legal_nature: payload["legalNature"], + size: payload["size"], + opened_on: payload["openedOn"], + issued_on: payload["issuedOn"], + special_status: payload["specialStatus"], + special_status_on: payload["specialStatusOn"], + responsable_entity: payload["responsableEntity"], + share_capital: payload["shareCapital"], + registration_unit: payload["registrationUnit"], + unit: payload["unit"], + address: payload["address"], + phones: payload["phones"], + email: payload["email"], + economic_activities: payload["economicActivities"], + partners: payload["partners"] + ) + end + end + + # Immutable wrapper for a +basicInfo+ lookup response. + class LegalEntityBasicInfoResponse < Data.define(:legal_entity) + # @param payload [Hash, nil] the parsed response body. + # @return [Nfe::LegalEntityBasicInfoResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + legal_entity: Nfe::LegalEntity.from_api(payload["legalEntity"] || payload) + ) + end + end + + # Immutable wrapper for a +stateTaxInfo+ lookup response. The body wraps a + # +legalEntity+ object with the state-tax shape ({Nfe::StateTaxLegalEntity}); + # all state-tax data lives there (inside +stateTaxes+), not at the top level. + class LegalEntityStateTaxResponse < Data.define(:legal_entity) + # @param payload [Hash, nil] the parsed response body. + # @return [Nfe::LegalEntityStateTaxResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + legal_entity: Nfe::StateTaxLegalEntity.from_api(payload["legalEntity"] || payload) + ) + end + end + + # Immutable wrapper for a +stateTaxForInvoice+ / +stateTaxSuggestedForInvoice+ + # lookup response. Same +legalEntity+ state-tax shape as + # {Nfe::LegalEntityStateTaxResponse}; the per-IE status enum is extended for + # invoice evaluation but the structure is identical. + class LegalEntityStateTaxForInvoiceResponse < Data.define(:legal_entity) + # @param payload [Hash, nil] the parsed response body. + # @return [Nfe::LegalEntityStateTaxForInvoiceResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + legal_entity: Nfe::StateTaxLegalEntity.from_api(payload["legalEntity"] || payload) + ) + end + end +end diff --git a/lib/nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity.rb b/lib/nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity.rb new file mode 100644 index 0000000..66dd206 --- /dev/null +++ b/lib/nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for the +legalEntity+ object returned by the NFE.io + # state-tax lookup endpoints (+stateTaxInfo+, +stateTaxForInvoice+, + # +stateTaxSuggestedForInvoice+) on +legalentity.api.nfe.io+. + # + # This is a DIFFERENT shape from the +basicInfo+ {Nfe::LegalEntity}: it carries + # the company-level tax-regime fields plus a +stateTaxes+ collection of state + # registrations (Inscrições Estaduais). All fields are optional; {from_api} + # maps API camelCase keys onto snake_case members and is nil-tolerant + # (+from_api(nil)+ returns +nil+). + class StateTaxLegalEntity < Data.define( + :federal_tax_number, + :name, + :trade_name, + :tax_regime, + :legal_nature, + :fiscal_unit, + :created_unit, + :created_on, + :check_code, + :state_taxes + ) + # Address nested inside a state-tax registration. Pragmatic subset of the + # address fields exposed by the state-tax endpoints. + class Address < Data.define(:street, :number, :district, :postal_code, :city, :state, :country) + def self.from_api(payload) + return nil if payload.nil? + + new( + street: payload["street"], + number: payload["number"]&.to_s, + district: payload["district"], + postal_code: payload["postalCode"]&.to_s, + city: payload["city"], + state: payload["state"], + country: payload["country"] + ) + end + end + + # Economic activity (CNAE) nested inside a state-tax registration. + class EconomicActivity < Data.define(:type, :code, :description) + def self.from_api(payload) + return nil if payload.nil? + + new( + type: payload["type"], + code: payload["code"]&.to_s, + description: payload["description"] + ) + end + end + + # Fiscal-document contributor indicator (NFe/NFSe/CTe/NFCe) inside a + # state-tax registration. + class FiscalDocumentInfo < Data.define(:status, :description) + def self.from_api(payload) + return nil if payload.nil? + + new( + status: payload["status"], + description: payload["description"] + ) + end + end + + # A single state-tax registration (Inscrição Estadual) within + # +stateTaxes+. Carries its own status, dates, code, address and the + # per-document contributor indicators. + class StateTax < Data.define( + :status, + :tax_number, + :status_on, + :opened_on, + :closed_on, + :additional_information, + :code, + :address, + :economic_activities, + :nfe, + :nfse, + :cte, + :nfce + ) + def self.from_api(payload) + return nil if payload.nil? + + new( + status: payload["status"], + tax_number: payload["taxNumber"]&.to_s, + status_on: payload["statusOn"], + opened_on: payload["openedOn"], + closed_on: payload["closedOn"], + additional_information: payload["additionalInformation"], + code: payload["code"]&.to_s, + address: Address.from_api(payload["address"]), + economic_activities: (payload["economicActivities"] || []).map { |a| EconomicActivity.from_api(a) }, + nfe: FiscalDocumentInfo.from_api(payload["nfe"]), + nfse: FiscalDocumentInfo.from_api(payload["nfse"]), + cte: FiscalDocumentInfo.from_api(payload["cte"]), + nfce: FiscalDocumentInfo.from_api(payload["nfce"]) + ) + end + end + + # @param payload [Hash, nil] the unwrapped +legalEntity+ state-tax object. + # @return [Nfe::StateTaxLegalEntity, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"]&.to_s, + name: payload["name"], + trade_name: payload["tradeName"], + tax_regime: payload["taxRegime"], + legal_nature: payload["legalNature"], + fiscal_unit: payload["fiscalUnit"], + created_unit: payload["createdUnit"], + created_on: payload["createdOn"], + check_code: payload["checkCode"]&.to_s, + state_taxes: (payload["stateTaxes"] || []).map { |t| StateTax.from_api(t) } + ) + end + end +end diff --git a/lib/nfe/resources/dto/legal_person.rb b/lib/nfe/resources/dto/legal_person.rb new file mode 100644 index 0000000..f8b3dcd --- /dev/null +++ b/lib/nfe/resources/dto/legal_person.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a legal person (pessoa jurídica) tied to a + # company. {from_api} maps API camelCase onto snake_case, drops unknown keys, + # and is nil-tolerant. + # + # +federal_tax_number+ is kept as a +String+ (CNPJ), never coerced to Integer. + class LegalPerson < Data.define( + :id, + :name, + :trade_name, + :federal_tax_number, + :email, + :address, + :created_on, + :modified_on + ) + # @param payload [Hash, nil] the unwrapped legal-person object. + # @return [Nfe::LegalPerson, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + name: payload["name"], + trade_name: payload["tradeName"], + federal_tax_number: payload["federalTaxNumber"]&.to_s, + email: payload["email"], + address: payload["address"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/natural_person.rb b/lib/nfe/resources/dto/natural_person.rb new file mode 100644 index 0000000..c95ce8f --- /dev/null +++ b/lib/nfe/resources/dto/natural_person.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a natural person (pessoa física) tied to a + # company. {from_api} maps API camelCase onto snake_case, drops unknown keys, + # and is nil-tolerant. + # + # +federal_tax_number+ is kept as a +String+ (CPF), never coerced to Integer. + class NaturalPerson < Data.define( + :id, + :name, + :federal_tax_number, + :email, + :address, + :created_on, + :modified_on + ) + # @param payload [Hash, nil] the unwrapped natural-person object. + # @return [Nfe::NaturalPerson, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + name: payload["name"], + federal_tax_number: payload["federalTaxNumber"]&.to_s, + email: payload["email"], + address: payload["address"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rb b/lib/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rb new file mode 100644 index 0000000..0dceddb --- /dev/null +++ b/lib/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for the result of a natural-person (CPF) status + # lookup against the +naturalperson+ data API. {from_api} maps API camelCase + # onto snake_case, drops unknown keys, and is nil-tolerant. All fields are + # optional. + # + # +federal_tax_number+ is kept as a +String+ (CPF), never coerced to Integer. + class NaturalPersonStatusResponse < Data.define( + :name, + :federal_tax_number, + :birth_on, + :status, + :created_on + ) + # @param payload [Hash, nil] the unwrapped status object. + # @return [Nfe::NaturalPersonStatusResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + name: payload["name"], + federal_tax_number: payload["federalTaxNumber"]&.to_s, + birth_on: payload["birthOn"], + status: payload["status"], + created_on: payload["createdOn"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/nfe_file_resource.rb b/lib/nfe/resources/dto/nfe_file_resource.rb new file mode 100644 index 0000000..0c4a310 --- /dev/null +++ b/lib/nfe/resources/dto/nfe_file_resource.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object describing a downloadable file as returned by the + # +api.nfse.io/v2+ product-invoice download endpoints, which respond with a + # JSON envelope carrying a +uri+ to the file rather than the raw bytes. + # + # This is what distinguishes {Nfe::Resources::ProductInvoices} downloads + # (which return a +NfeFileResource+) from the byte-returning downloads on the + # other invoice resources. {from_api} maps camelCase keys onto snake_case + # members, drops unknown keys, and is nil-tolerant. + class NfeFileResource < Data.define(:uri, :name, :content_type, :size) + # Build a {Nfe::NfeFileResource} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::NfeFileResource, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + uri: payload["uri"] || payload["url"], + name: payload["name"], + content_type: payload["contentType"], + size: payload["size"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/product_invoice.rb b/lib/nfe/resources/dto/product_invoice.rb new file mode 100644 index 0000000..b59a5fe --- /dev/null +++ b/lib/nfe/resources/dto/product_invoice.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a product invoice (NF-e) as returned by the + # NFE.io +api.nfse.io/v2+ product-invoice API. + # + # Hand-written (rather than reusing the verbose/mangled generated + # +nf_produto_v2+ DTO names) so the public shape stays clean and snake_case. + # {from_api} maps the API camelCase keys onto snake_case members, drops + # unknown keys, and is nil-tolerant (+from_api(nil)+ returns +nil+). + # + # +flow_status+ drives the polling lifecycle; pass it to + # {Nfe::FlowStatus.terminal?} to decide when the document is settled. + class ProductInvoice < Data.define( + :id, + :flow_status, + :flow_message, + :status, + :environment, + :serie, + :number, + :operation_nature, + :operation_type, + :access_key, + :protocol, + :buyer, + :items, + :totals, + :issued_on, + :created_on, + :modified_on + ) + # Build a {Nfe::ProductInvoice} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::ProductInvoice, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + flow_status: payload["flowStatus"], + flow_message: payload["flowMessage"], + status: payload["status"], + environment: payload["environment"], + serie: payload["serie"], + number: payload["number"], + operation_nature: payload["operationNature"], + operation_type: payload["operationType"], + access_key: payload["accessKey"], + protocol: payload["protocol"], + buyer: payload["buyer"], + items: payload["items"], + totals: payload["totals"], + issued_on: payload["issuedOn"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/product_invoice_query/product_invoice_details.rb b/lib/nfe/resources/dto/product_invoice_query/product_invoice_details.rb new file mode 100644 index 0000000..eddd75c --- /dev/null +++ b/lib/nfe/resources/dto/product_invoice_query/product_invoice_details.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for the details of a product invoice (NF-e) fetched + # from the +nfe.api.nfe.io+ distribution/query API by its access key + # (+GET /v2/productinvoices/{accessKey}+). + # + # Hand-written (the +consulta_nfe_distribuicao_v1+ generated schema does not + # cover this pragmatic shape). {from_api} maps the API camelCase keys onto the + # snake_case members, hydrates the nested value objects, drops unknown keys, + # and is nil-tolerant (+from_api(nil)+ returns +nil+). All fields are optional. + # + # The access key is NOT a body field — it is the path parameter the caller + # already holds — so it is intentionally not exposed here. +current_status+ is + # the real top-level field (+currentStatus+, enum +unknown+/+authorized+/ + # +canceled+). The nested objects ({Issuer}, {Buyer}, {Totals}) keep only a + # pragmatic subset of the most common fields; +items+ is kept as the raw + # payload array (free-form line bodies), normalized to +[]+ when missing. + class ProductInvoiceDetails < Data.define( + :current_status, + :state_code, + :check_code, + :operation_nature, + :serie, + :number, + :issued_on, + :operation_on, + :issuer, + :buyer, + :totals, + :items + ) + # Issuer (emitente / emit) of the invoice. + class Issuer < Data.define(:federal_tax_number, :name, :trade_name, :state_tax_number) + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"]&.to_s, + name: payload["name"], + trade_name: payload["tradeName"], + state_tax_number: payload["stateTaxNumber"]&.to_s + ) + end + end + + # Buyer (destinatário / dest) of the invoice. + class Buyer < Data.define(:federal_tax_number, :name, :state_tax_number, :email) + def self.from_api(payload) + return nil if payload.nil? + + new( + federal_tax_number: payload["federalTaxNumber"]&.to_s, + name: payload["name"], + state_tax_number: payload["stateTaxNumber"]&.to_s, + email: payload["email"] + ) + end + end + + # Monetary totals of the invoice (the +icms+ subtotal group of +total+). + class Totals < Data.define(:product_amount, :invoice_amount, :discount_amount, :icms_amount) + def self.from_api(payload) + return nil if payload.nil? + + icms = payload["icms"] || {} + new( + product_amount: icms["productAmount"], + invoice_amount: icms["invoiceAmount"], + discount_amount: icms["discountAmount"], + icms_amount: icms["icmsAmount"] + ) + end + end + + # Build a {Nfe::ProductInvoiceDetails} from an API payload. + # + # @param payload [Hash, nil] the parsed invoice object. + # @return [Nfe::ProductInvoiceDetails, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + current_status: payload["currentStatus"], + state_code: payload["stateCode"], + check_code: payload["checkCode"]&.to_s, + operation_nature: payload["operationNature"], + serie: payload["serie"], + number: payload["number"], + issued_on: payload["issuedOn"], + operation_on: payload["operationOn"], + issuer: Issuer.from_api(payload["issuer"]), + buyer: Buyer.from_api(payload["buyer"]), + totals: Totals.from_api(payload["totals"]), + items: payload["items"] || [] + ) + end + end +end diff --git a/lib/nfe/resources/dto/product_invoice_query/product_invoice_events_response.rb b/lib/nfe/resources/dto/product_invoice_query/product_invoice_events_response.rb new file mode 100644 index 0000000..595a4ac --- /dev/null +++ b/lib/nfe/resources/dto/product_invoice_query/product_invoice_events_response.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for the events (eventos) associated with a product + # invoice (NF-e), fetched from the +nfe.api.nfe.io+ query API by access key. + # + # Hand-written (the +consulta_nfe_distribuicao_v1+ generated schema does not + # cover this shape). {from_api} maps API camelCase keys onto snake_case + # members, drops unknown keys, and is nil-tolerant (+from_api(nil)+ returns + # +nil+). All fields are optional. + # + # +events+ is kept as the raw payload array (free-form event bodies); a + # missing list normalizes to +[]+. + class ProductInvoiceEventsResponse < Data.define( + :events, + :created_on + ) + # Build a {Nfe::ProductInvoiceEventsResponse} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::ProductInvoiceEventsResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + events: payload["events"] || [], + created_on: payload["createdOn"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/service_invoice.rb b/lib/nfe/resources/dto/service_invoice.rb new file mode 100644 index 0000000..cce9756 --- /dev/null +++ b/lib/nfe/resources/dto/service_invoice.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a service invoice (NFS-e) as returned by the + # NFE.io +api.nfe.io/v1+ service-invoice API. + # + # The +nf-servico-v1.yaml+ OpenAPI spec defines NO component schemas (the + # shape is derived from the operations), so this DTO is hand-written — mirror + # of the fields the Node/PHP SDKs read. {from_api} maps the API camelCase keys + # onto snake_case members, drops unknown keys, and is nil-tolerant + # (+from_api(nil)+ returns +nil+). + # + # +flow_status+ drives the polling lifecycle; pass it to + # {Nfe::FlowStatus.terminal?} to decide when the document is settled. + class ServiceInvoice < Data.define( + :id, + :flow_status, + :flow_message, + :status, + :environment, + :rps_number, + :rps_serial_number, + :number, + :check_code, + :issued_on, + :cancelled_on, + :amount_net, + :services_amount, + :borrower, + :city_service_code, + :federal_service_code, + :description, + :pdf, + :xml, + :created_on, + :modified_on + ) + # Build a {Nfe::ServiceInvoice} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::ServiceInvoice, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + flow_status: payload["flowStatus"], + flow_message: payload["flowMessage"], + status: payload["status"], + environment: payload["environment"], + rps_number: payload["rpsNumber"], + rps_serial_number: payload["rpsSerialNumber"], + number: payload["number"], + check_code: payload["checkCode"], + issued_on: payload["issuedOn"], + cancelled_on: payload["cancelledOn"], + amount_net: payload["amountNet"], + services_amount: payload["servicesAmount"], + borrower: payload["borrower"], + city_service_code: payload["cityServiceCode"], + federal_service_code: payload["federalServiceCode"], + description: payload["description"], + pdf: payload["pdf"], + xml: payload["xml"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/state_taxes/nfe_state_tax.rb b/lib/nfe/resources/dto/state_taxes/nfe_state_tax.rb new file mode 100644 index 0000000..d1f8196 --- /dev/null +++ b/lib/nfe/resources/dto/state_taxes/nfe_state_tax.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a company's state-tax (Inscrição Estadual) + # registration entry, as returned by the CT-e +api.nfse.io+ state-tax API + # under +/v2/companies/{companyId}/statetaxes+. + # + # Hand-written: the generated +contribuintes-v2+ model lives under a different + # namespace/shape, so this top-level {Nfe::NfeStateTax} mirrors only the + # fields the Node/PHP SDKs read. {from_api} maps the API camelCase keys onto + # snake_case members, drops unknown keys, and is nil-tolerant + # (+from_api(nil)+ returns +nil+). All fields are optional. + class NfeStateTax < Data.define( + :id, + :tax_number, + :serie, + :number, + :code, + :environment_type, + :type, + :status + ) + # Build a {Nfe::NfeStateTax} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::NfeStateTax, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + tax_number: payload["taxNumber"], + serie: payload["serie"], + number: payload["number"], + code: payload["code"], + environment_type: payload["environmentType"], + type: payload["type"], + status: payload["status"] + ) + end + end +end diff --git a/lib/nfe/resources/dto/tax_codes/tax_code_paginated_response.rb b/lib/nfe/resources/dto/tax_codes/tax_code_paginated_response.rb new file mode 100644 index 0000000..ea8f9da --- /dev/null +++ b/lib/nfe/resources/dto/tax_codes/tax_code_paginated_response.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Nfe + # A single CT-e tax-code entry (operation code, acquisition purpose, issuer or + # recipient tax profile). Hand-written: the +consulta-cte+ tax-code endpoints + # are schema-less in the OpenAPI spec, so the generator produces no usable + # model. {from_api} maps the API camelCase keys onto snake_case members and is + # nil-tolerant (+from_api(nil)+ returns +nil+). + class TaxCode < Data.define(:code, :description) + # Build a {Nfe::TaxCode} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::TaxCode, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + code: payload["code"], + description: payload["description"] + ) + end + end + + # Page-style paginated response for the CT-e tax-code lookup endpoints + # (operation code, acquisition purpose, issuer/recipient tax profile). + # + # NOTE: unlike the cursor-style lists elsewhere in this SDK (which return an + # {Nfe::ListResponse} carrying +starting_after+/+ending_before+), these tax-code + # endpoints are 1-based page-style, so this resource returns this custom + # response object exposing +current_page+/+total_pages+/+total_count+ directly. + # + # +items+ is hydrated to an Array of {Nfe::TaxCode}. {from_api} is nil-tolerant + # (+from_api(nil)+ returns +nil+). + class TaxCodePaginatedResponse < Data.define(:current_page, :total_pages, :total_count, :items) + # Build a {Nfe::TaxCodePaginatedResponse} from an API payload. + # + # @param payload [Hash, nil] the response object. + # @return [Nfe::TaxCodePaginatedResponse, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + current_page: payload["currentPage"], + total_pages: payload["totalPages"], + total_count: payload["totalCount"], + items: (payload["items"] || []).map { |item| Nfe::TaxCode.from_api(item) } + ) + end + end +end diff --git a/lib/nfe/resources/dto/webhook.rb b/lib/nfe/resources/dto/webhook.rb new file mode 100644 index 0000000..dbbd28e --- /dev/null +++ b/lib/nfe/resources/dto/webhook.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a persisted webhook subscription, as returned by + # the +/companies/{id}/webhooks+ entity API. + # + # NOTE ON NAMING: the spec text refers to this DTO as "Nfe::Webhook", but that + # constant is reserved for the canonical signature-verification module + # ({Nfe::Webhook}, +lib/nfe/webhook.rb+). A Ruby +module+ and a +class+ cannot + # share a constant, so the subscription DTO is named +Nfe::WebhookSubscription+. + # Resources hydrating a webhook subscription (+Nfe::Resources::Webhooks+) MUST + # hydrate this class. + # + # {from_api} maps API camelCase onto snake_case, drops unknown keys, and is + # nil-tolerant (+from_api(nil)+ returns +nil+). + class WebhookSubscription < Data.define( + :id, + :url, + :events, + :secret, + :active, + :status, + :created_on, + :modified_on + ) + # @param payload [Hash, nil] the unwrapped webhook object. + # @return [Nfe::WebhookSubscription, nil] +nil+ when +payload+ is +nil+. + def self.from_api(payload) + return nil if payload.nil? + + new( + id: payload["id"], + url: payload["url"], + events: payload["events"], + secret: payload["secret"], + active: payload["active"], + status: payload["status"], + created_on: payload["createdOn"], + modified_on: payload["modifiedOn"] + ) + end + end +end diff --git a/lib/nfe/resources/inbound_product_invoices.rb b/lib/nfe/resources/inbound_product_invoices.rb new file mode 100644 index 0000000..bd4d8ed --- /dev/null +++ b/lib/nfe/resources/inbound_product_invoices.rb @@ -0,0 +1,241 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/inbound_settings" +require "nfe/resources/dto/inbound_invoice_metadata" + +module Nfe + module Resources + # Inbound supplier NF-e (Nota Fiscal Eletrônica de fornecedor) resource for + # the +:cte+ host family (+https://api.nfse.io+). Manages automatic NF-e + # fetch via SEFAZ Distribuição DFe, reads received NF-e documents/events, + # sends the recipient manifest (Manifestação do Destinatário) and reprocesses + # webhooks. + # + # This is an inbound/query resource (settings + access-key lookups), not an + # emission resource: there is no discriminated 202 +Pending+/+Issued+ + # contract here. The host carries no version segment, so paths embed +/v2+ + # literally and {#api_version} is +""+. + # + # There are two detail surfaces: the generic webhook-v1 path + # (+.../inbound/{key}+) and the recommended webhook-v2 path + # (+.../inbound/productinvoice/{key}+, which adds a +productInvoices+ array). + # + # @example Enable auto-fetch and manifest awareness of a received NF-e + # client.inbound_product_invoices.enable_auto_fetch(company_id: "co-1") + # client.inbound_product_invoices.manifest(company_id: "co-1", access_key: "3524...7890") + class InboundProductInvoices < AbstractResource + # Manifest event type — Ciência da Operação (awareness, default). + MANIFEST_AWARENESS = 210_210 + # Manifest event type — Confirmação da Operação (confirmation). + MANIFEST_CONFIRMATION = 210_220 + # Manifest event type — Operação não Realizada (operation not performed). + MANIFEST_NOT_PERFORMED = 210_240 + + protected + + def api_family + :cte + end + + # The +:cte+ host carries no version segment; +/v2+ is embedded per path. + def api_version + "" + end + + public + + # Enable automatic NF-e distribution fetch for a company. + # + # @param company_id [String] + # @param start_from_nsu [Integer, String, nil] + # @param start_from_date [String, nil] ISO 8601 starting date. + # @param environment_sefaz [String, nil] +"Production"+/+"Test"+. + # @param automatic_manifesting [Hash, nil] auto-manifesting config. + # @param webhook_version [String, Integer, nil] +"1"+/+"2"+. + # @return [Nfe::InboundSettings] + def enable_auto_fetch(company_id:, start_from_nsu: nil, start_from_date: nil, + environment_sefaz: nil, automatic_manifesting: nil, webhook_version: nil) + id = Nfe::IdValidator.company_id(company_id) + body = compact( + "startFromNsu" => start_from_nsu, "startFromDate" => start_from_date, + "environmentSEFAZ" => environment_sefaz, "automaticManifesting" => automatic_manifesting, + "webhookVersion" => webhook_version + ) + response = post("/v2/companies/#{id}/inbound/productinvoices", + body: json_body(body), headers: json_headers) + hydrate(Nfe::InboundSettings, parse_json(response.body)) + end + + # Disable automatic NF-e distribution fetch for a company. + # + # @param company_id [String] + # @return [Nfe::InboundSettings] + def disable_auto_fetch(company_id:) + id = Nfe::IdValidator.company_id(company_id) + response = delete("/v2/companies/#{id}/inbound/productinvoices") + hydrate(Nfe::InboundSettings, parse_json(response.body)) + end + + # Get the current automatic NF-e fetch settings. + # + # @param company_id [String] + # @return [Nfe::InboundSettings] + def get_settings(company_id:) + id = Nfe::IdValidator.company_id(company_id) + response = get("/v2/companies/#{id}/inbound/productinvoices") + hydrate(Nfe::InboundSettings, parse_json(response.body)) + end + + # Get details of an inbound document by access key (webhook-v1 format). + # + # @param company_id [String] + # @param access_key [String] + # @return [Nfe::InboundInvoiceMetadata] + def get_details(company_id:, access_key:) + id, key = company_and_key(company_id, access_key) + response = get("/v2/companies/#{id}/inbound/#{key}") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Get details of an inbound NF-e by access key (webhook-v2 format, + # recommended; adds the +product_invoices+ array). + # + # @param company_id [String] + # @param access_key [String] + # @return [Nfe::InboundInvoiceMetadata] + def get_product_invoice_details(company_id:, access_key:) + id, key = company_and_key(company_id, access_key) + response = get("/v2/companies/#{id}/inbound/productinvoice/#{key}") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Get details of an event related to an inbound document (webhook-v1). + # + # @param company_id [String] + # @param access_key [String] + # @param event_key [String] + # @return [Nfe::InboundInvoiceMetadata] + def get_event_details(company_id:, access_key:, event_key:) + id, key, ev = company_key_event(company_id, access_key, event_key) + response = get("/v2/companies/#{id}/inbound/#{key}/events/#{ev}") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Get details of an event related to an inbound NF-e (webhook-v2). + # + # @param company_id [String] + # @param access_key [String] + # @param event_key [String] + # @return [Nfe::InboundInvoiceMetadata] + def get_product_invoice_event_details(company_id:, access_key:, event_key:) + id, key, ev = company_key_event(company_id, access_key, event_key) + response = get("/v2/companies/#{id}/inbound/productinvoice/#{key}/events/#{ev}") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Download the XML of an inbound document by access key. + # + # @param company_id [String] + # @param access_key [String] + # @return [String] raw XML bytes (+ASCII-8BIT+). + def get_xml(company_id:, access_key:) + id, key = company_and_key(company_id, access_key) + download("/v2/companies/#{id}/inbound/#{key}/xml", headers: xml_accept) + end + + # Download the XML of an event related to an inbound document. + # + # @param company_id [String] + # @param access_key [String] + # @param event_key [String] + # @return [String] raw XML bytes (+ASCII-8BIT+). + def get_event_xml(company_id:, access_key:, event_key:) + id, key, ev = company_key_event(company_id, access_key, event_key) + download("/v2/companies/#{id}/inbound/#{key}/events/#{ev}/xml", headers: xml_accept) + end + + # Download the PDF (DANFE) of an inbound NF-e by access key. + # + # @param company_id [String] + # @param access_key [String] + # @return [String] raw PDF bytes (+ASCII-8BIT+). + def get_pdf(company_id:, access_key:) + id, key = company_and_key(company_id, access_key) + download("/v2/companies/#{id}/inbound/#{key}/pdf", headers: pdf_accept) + end + + # Get the structured JSON representation of an inbound NF-e by access key. + # + # @param company_id [String] + # @param access_key [String] + # @return [Nfe::InboundInvoiceMetadata] + def get_json(company_id:, access_key:) + id, key = company_and_key(company_id, access_key) + response = get("/v2/companies/#{id}/inbound/productinvoice/#{key}/json") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Send the recipient manifest (Manifestação do Destinatário) for an NF-e. + # +tp_event+ defaults to {MANIFEST_AWARENESS} (210210); the other codes are + # {MANIFEST_CONFIRMATION} (210220) and {MANIFEST_NOT_PERFORMED} (210240). + # + # @param company_id [String] + # @param access_key [String] + # @param tp_event [Integer] + # @return [String] the manifest response body. + def manifest(company_id:, access_key:, tp_event: MANIFEST_AWARENESS) + id, key = company_and_key(company_id, access_key) + response = post("/v2/companies/#{id}/inbound/#{key}/manifest", + query: { tpEvent: tp_event }) + response.body || "" + end + + # Reprocess the webhook for an inbound NF-e, identified by either a 44-digit + # access key OR a numeric NSU. A bare NSU is not rejected as an invalid key. + # + # @param company_id [String] + # @param access_key_or_nsu [String, Integer] + # @return [Nfe::InboundInvoiceMetadata] + def reprocess_webhook(company_id:, access_key_or_nsu:) + id = Nfe::IdValidator.company_id(company_id) + identifier = Nfe::IdValidator.presence!(access_key_or_nsu, "access_key_or_nsu") + response = post("/v2/companies/#{id}/inbound/productinvoice/#{identifier}/processwebhook") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + private + + def company_and_key(company_id, access_key) + [Nfe::IdValidator.company_id(company_id), Nfe::IdValidator.access_key(access_key)] + end + + def company_key_event(company_id, access_key, event_key) + [Nfe::IdValidator.company_id(company_id), Nfe::IdValidator.access_key(access_key), + Nfe::IdValidator.event_key(event_key)] + end + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + def xml_accept + { "Accept" => "application/xml" } + end + + def pdf_accept + { "Accept" => "application/pdf" } + end + + # Drop +nil+ values so optional fields are omitted from the body. + def compact(hash) + hash.compact + end + end + end +end diff --git a/lib/nfe/resources/legal_entity_lookup.rb b/lib/nfe/resources/legal_entity_lookup.rb new file mode 100644 index 0000000..af3612d --- /dev/null +++ b/lib/nfe/resources/legal_entity_lookup.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/legal_entity_lookup/legal_entity_responses" + +module Nfe + module Resources + # Legal-entity (pessoa jurídica) lookup against the +:legal_entity+ data + # family (+legalentity.api.nfe.io+). The version segment is embedded in + # each request path (+/v2/legalentities/...+), so {#api_version} is +""+. + class LegalEntityLookup < AbstractResource + # Retrieve basic registration info for a CNPJ. + # + # @param federal_tax_number [String] CNPJ in any format. + # @param update_address [Boolean, nil] forwarded as +updateAddress+ when set. + # @param update_city_code [Boolean, nil] forwarded as +updateCityCode+ when set. + # @return [Nfe::LegalEntityBasicInfoResponse] + # @raise [Nfe::InvalidRequestError] when the CNPJ is not 14 characters. + def get_basic_info(federal_tax_number, update_address: nil, update_city_code: nil) + cnpj = Nfe::IdValidator.cnpj(federal_tax_number) + query = { "updateAddress" => update_address, "updateCityCode" => update_city_code }.compact + response = get("/v2/legalentities/basicInfo/#{cnpj}", query: query) + hydrate(Nfe::LegalEntityBasicInfoResponse, parse_json(response.body)) + end + + # Retrieve state-tax registration info for a state + CNPJ. + # + # @param state [String] UF (case-insensitive). + # @param federal_tax_number [String] CNPJ in any format. + # @return [Nfe::LegalEntityStateTaxResponse] + # @raise [Nfe::InvalidRequestError] on an invalid UF or CNPJ. + def get_state_tax_info(state, federal_tax_number) + uf = Nfe::IdValidator.state(state) + cnpj = Nfe::IdValidator.cnpj(federal_tax_number) + response = get("/v2/legalentities/stateTaxInfo/#{uf}/#{cnpj}") + hydrate(Nfe::LegalEntityStateTaxResponse, parse_json(response.body)) + end + + # Retrieve the state-tax info suitable for invoicing. + # + # @param state [String] UF (case-insensitive). + # @param federal_tax_number [String] CNPJ in any format. + # @return [Nfe::LegalEntityStateTaxForInvoiceResponse] + # @raise [Nfe::InvalidRequestError] on an invalid UF or CNPJ. + def get_state_tax_for_invoice(state, federal_tax_number) + uf = Nfe::IdValidator.state(state) + cnpj = Nfe::IdValidator.cnpj(federal_tax_number) + response = get("/v2/legalentities/stateTaxForInvoice/#{uf}/#{cnpj}") + hydrate(Nfe::LegalEntityStateTaxForInvoiceResponse, parse_json(response.body)) + end + + # Retrieve the suggested state-tax info for invoicing. + # + # @param state [String] UF (case-insensitive). + # @param federal_tax_number [String] CNPJ in any format. + # @return [Nfe::LegalEntityStateTaxForInvoiceResponse] + # @raise [Nfe::InvalidRequestError] on an invalid UF or CNPJ. + def get_suggested_state_tax_for_invoice(state, federal_tax_number) + uf = Nfe::IdValidator.state(state) + cnpj = Nfe::IdValidator.cnpj(federal_tax_number) + response = get("/v2/legalentities/stateTaxSuggestedForInvoice/#{uf}/#{cnpj}") + hydrate(Nfe::LegalEntityStateTaxForInvoiceResponse, parse_json(response.body)) + end + + protected + + def api_family + :legal_entity + end + + # The version segment is embedded in each request path, so no version + # prefix is added by {#full_path}. + def api_version + "" + end + end + end +end diff --git a/lib/nfe/resources/legal_people.rb b/lib/nfe/resources/legal_people.rb new file mode 100644 index 0000000..6b8c405 --- /dev/null +++ b/lib/nfe/resources/legal_people.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/legal_person" + +module Nfe + module Resources + # Legal-people (pessoas jurídicas) resource, scoped by company under + # +/companies/{id}/legalpeople+ on the +:main+ host family. The API wraps + # responses in a +{"legalPeople" => ...}+ envelope, unwrapped here before + # hydrating {Nfe::LegalPerson}. + class LegalPeople < AbstractResource + ENVELOPE = "legalPeople" + + protected + + def api_family + :main + end + + public + + # List every legal person for a company (no pagination, parity with Node). + # + # @param company_id [String] + # @return [Nfe::ListResponse] + def list(company_id) + id = Nfe::IdValidator.company_id(company_id) + response = get("/companies/#{id}/legalpeople") + items = (unwrap(parse_json(response.body), ENVELOPE) || []) + .map { |item| hydrate(Nfe::LegalPerson, item) } + Nfe::ListResponse.new(data: items) + end + + # Create a legal person. + # + # @param company_id [String] + # @param data [Hash] + # @return [Nfe::LegalPerson] + def create(company_id, data) + id = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{id}/legalpeople", + body: json_body(data), headers: json_headers) + hydrate(Nfe::LegalPerson, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Retrieve a legal person by id. + # + # @param company_id [String] + # @param legal_person_id [String] + # @return [Nfe::LegalPerson] + def retrieve(company_id, legal_person_id) + id = Nfe::IdValidator.company_id(company_id) + lpid = Nfe::IdValidator.presence!(legal_person_id, "legal_person_id") + response = get("/companies/#{id}/legalpeople/#{lpid}") + hydrate(Nfe::LegalPerson, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Update a legal person. + # + # @param company_id [String] + # @param legal_person_id [String] + # @param data [Hash] + # @return [Nfe::LegalPerson] + def update(company_id, legal_person_id, data) + id = Nfe::IdValidator.company_id(company_id) + lpid = Nfe::IdValidator.presence!(legal_person_id, "legal_person_id") + response = put("/companies/#{id}/legalpeople/#{lpid}", + body: json_body(data), headers: json_headers) + hydrate(Nfe::LegalPerson, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Delete a legal person. + # + # @param company_id [String] + # @param legal_person_id [String] + # @return [nil] + def delete(company_id, legal_person_id) + id = Nfe::IdValidator.company_id(company_id) + lpid = Nfe::IdValidator.presence!(legal_person_id, "legal_person_id") + super("/companies/#{id}/legalpeople/#{lpid}") + nil + end + + # Create several legal people. Unlike the Node SDK (+Promise.all+), this + # runs the +create+ calls sequentially and returns them in order. + # + # @param company_id [String] + # @param list [Array] + # @return [Array] + def create_batch(company_id, list) + list.map { |data| create(company_id, data) } + end + + # Find a legal person by federal tax number (CNPJ). Convenience helper + # built on {#list} plus client-side filtering. + # + # @param company_id [String] + # @param federal_tax_number [String] + # @return [Nfe::LegalPerson, nil] + def find_by_tax_number(company_id, federal_tax_number) + target = federal_tax_number.to_s.gsub(/[^0-9A-Za-z]/, "") + list(company_id).data.find do |person| + person.federal_tax_number.to_s.gsub(/[^0-9A-Za-z]/, "") == target + end + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + end + end +end diff --git a/lib/nfe/resources/natural_people.rb b/lib/nfe/resources/natural_people.rb new file mode 100644 index 0000000..44db10f --- /dev/null +++ b/lib/nfe/resources/natural_people.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/natural_person" + +module Nfe + module Resources + # Natural-people (pessoas físicas) resource, scoped by company under + # +/companies/{id}/naturalpeople+ on the +:main+ host family. The API wraps + # responses in a +{"naturalPeople" => ...}+ envelope, unwrapped here before + # hydrating {Nfe::NaturalPerson}. + class NaturalPeople < AbstractResource + ENVELOPE = "naturalPeople" + + protected + + def api_family + :main + end + + public + + # List every natural person for a company (no pagination, parity with Node). + # + # @param company_id [String] + # @return [Nfe::ListResponse] + def list(company_id) + id = Nfe::IdValidator.company_id(company_id) + response = get("/companies/#{id}/naturalpeople") + items = (unwrap(parse_json(response.body), ENVELOPE) || []) + .map { |item| hydrate(Nfe::NaturalPerson, item) } + Nfe::ListResponse.new(data: items) + end + + # Create a natural person. + # + # @param company_id [String] + # @param data [Hash] + # @return [Nfe::NaturalPerson] + def create(company_id, data) + id = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{id}/naturalpeople", + body: json_body(data), headers: json_headers) + hydrate(Nfe::NaturalPerson, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Retrieve a natural person by id. + # + # @param company_id [String] + # @param natural_person_id [String] + # @return [Nfe::NaturalPerson] + def retrieve(company_id, natural_person_id) + id = Nfe::IdValidator.company_id(company_id) + npid = Nfe::IdValidator.presence!(natural_person_id, "natural_person_id") + response = get("/companies/#{id}/naturalpeople/#{npid}") + hydrate(Nfe::NaturalPerson, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Update a natural person. + # + # @param company_id [String] + # @param natural_person_id [String] + # @param data [Hash] + # @return [Nfe::NaturalPerson] + def update(company_id, natural_person_id, data) + id = Nfe::IdValidator.company_id(company_id) + npid = Nfe::IdValidator.presence!(natural_person_id, "natural_person_id") + response = put("/companies/#{id}/naturalpeople/#{npid}", + body: json_body(data), headers: json_headers) + hydrate(Nfe::NaturalPerson, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Delete a natural person. + # + # @param company_id [String] + # @param natural_person_id [String] + # @return [nil] + def delete(company_id, natural_person_id) + id = Nfe::IdValidator.company_id(company_id) + npid = Nfe::IdValidator.presence!(natural_person_id, "natural_person_id") + super("/companies/#{id}/naturalpeople/#{npid}") + nil + end + + # Create several natural people. Unlike the Node SDK (+Promise.all+), this + # runs the +create+ calls sequentially and returns them in order. + # + # @param company_id [String] + # @param list [Array] + # @return [Array] + def create_batch(company_id, list) + list.map { |data| create(company_id, data) } + end + + # Find a natural person by federal tax number (CPF). Normalises the input + # to 11 digits before filtering. Convenience helper built on {#list}. + # + # @param company_id [String] + # @param federal_tax_number [String] + # @return [Nfe::NaturalPerson, nil] + def find_by_tax_number(company_id, federal_tax_number) + target = federal_tax_number.to_s.gsub(/\D/, "") + list(company_id).data.find do |person| + person.federal_tax_number.to_s.gsub(/\D/, "") == target + end + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + end + end +end diff --git a/lib/nfe/resources/natural_person_lookup.rb b/lib/nfe/resources/natural_person_lookup.rb new file mode 100644 index 0000000..0dcac54 --- /dev/null +++ b/lib/nfe/resources/natural_person_lookup.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/natural_person_lookup/natural_person_status_response" + +module Nfe + module Resources + # Read-only lookups against the +naturalperson+ data API + # (+https://naturalperson.api.nfe.io+). The version segment is embedded in + # the request path, so +api_version+ is +""+. + class NaturalPersonLookup < AbstractResource + # Fetch the registration status of a natural person (CPF) at the federal + # tax authority. The CPF is normalized to 11 digits and the birth date to + # +YYYY-MM-DD+ before the request is issued (fail-fast). + # + # @param federal_tax_number [String] the CPF (with or without separators). + # @param birth_date [String, Date, Time, DateTime] the person's birth date. + # @return [Nfe::NaturalPersonStatusResponse, nil] + def get_status(federal_tax_number, birth_date) + cpf = Nfe::IdValidator.cpf(federal_tax_number) + date = Nfe::DateNormalizer.to_iso_date(birth_date) + response = get("/v1/naturalperson/status/#{cpf}/#{date}") + hydrate(Nfe::NaturalPersonStatusResponse, parse_json(response.body)) + end + + protected + + def api_family = :natural_person + + # This family's host embeds the version in the path, so no version segment + # is prefixed to the request path. + def api_version = "" + end + end +end diff --git a/lib/nfe/resources/product_invoice_query.rb b/lib/nfe/resources/product_invoice_query.rb new file mode 100644 index 0000000..5abc1e5 --- /dev/null +++ b/lib/nfe/resources/product_invoice_query.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/product_invoice_query/product_invoice_details" +require "nfe/resources/dto/product_invoice_query/product_invoice_events_response" + +module Nfe + module Resources + # Read-only queries against the NF-e distribution/query API + # (+https://nfe.api.nfe.io+). The version segment is embedded in the request + # path, so +api_version+ is +""+. + class ProductInvoiceQuery < AbstractResource + # Fetch the details of a product invoice (NF-e) by its access key. The key + # is normalized to 44 digits before the request is issued (fail-fast). + # + # @param access_key [String] the 44-digit NF-e access key. + # @return [Nfe::ProductInvoiceDetails, nil] + def retrieve(access_key) + key = Nfe::IdValidator.access_key(access_key) + response = get("/v2/productinvoices/#{key}") + hydrate(Nfe::ProductInvoiceDetails, parse_json(response.body)) + end + + # Download the PDF (DANFE) of a product invoice by its access key. + # + # @param access_key [String] the 44-digit NF-e access key. + # @return [String] the PDF bytes (+ASCII-8BIT+). + def download_pdf(access_key) + key = Nfe::IdValidator.access_key(access_key) + download("/v2/productinvoices/#{key}.pdf", headers: { "Accept" => "application/pdf" }) + end + + # Download the XML of a product invoice by its access key. + # + # @param access_key [String] the 44-digit NF-e access key. + # @return [String] the XML bytes (+ASCII-8BIT+). + def download_xml(access_key) + key = Nfe::IdValidator.access_key(access_key) + download("/v2/productinvoices/#{key}.xml", headers: { "Accept" => "application/xml" }) + end + + # List the events (eventos) associated with a product invoice by its + # access key. + # + # @param access_key [String] the 44-digit NF-e access key. + # @return [Nfe::ProductInvoiceEventsResponse, nil] + def list_events(access_key) + key = Nfe::IdValidator.access_key(access_key) + response = get("/v2/productinvoices/events/#{key}") + hydrate(Nfe::ProductInvoiceEventsResponse, parse_json(response.body)) + end + + protected + + def api_family = :nfe_query + + # This family's host embeds the version in the path, so no version segment + # is prefixed to the request path. + def api_version = "" + end + end +end diff --git a/lib/nfe/resources/product_invoices.rb b/lib/nfe/resources/product_invoices.rb new file mode 100644 index 0000000..d98d378 --- /dev/null +++ b/lib/nfe/resources/product_invoices.rb @@ -0,0 +1,290 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/product_invoice" +require "nfe/resources/dto/nfe_file_resource" +require "nfe/resources/responses/product_invoice_pending" +require "nfe/resources/responses/product_invoice_issued" + +module Nfe + module Resources + # Product invoices (NF-e) resource for the +:cte+ host family + # (+https://api.nfse.io/v2/...+). Full NF-e lifecycle: issue, list, retrieve, + # cancel, correction letters (CC-e), disablement (inutilização) and file + # downloads. + # + # Emission is asynchronous (HTTP 202, queued; completion via webhook): + # {#create}/{#create_with_state_tax} return either a + # {Nfe::Resources::ProductInvoicePending} or a + # {Nfe::Resources::ProductInvoiceIssued}. There is no + # +create_and_wait+/+create_batch+ in v1.0 — poll manually with + # {#retrieve} + {Nfe::FlowStatus.terminal?}. + # + # NOTE: unlike the other invoice resources, the download methods return a + # {Nfe::NfeFileResource} (a URI to the file), NOT raw bytes. + class ProductInvoices < AbstractResource + protected + + def api_family + :cte + end + + # The +:cte+ host serves the v2 API; paths embed +/v2+ explicitly, so no + # version segment is auto-prefixed. + def api_version + "" + end + + public + + # Issue a product invoice (NF-e). Returns a discriminated result: a + # {ProductInvoicePending} on HTTP 202 or a {ProductInvoiceIssued} on 201. + # + # @param company_id [String] + # @param data [Hash] invoice payload (camelCase keys per the API). + # @param idempotency_key [String, nil] sent as the +Idempotency-Key+ header. + # @param request_options [Nfe::RequestOptions, nil] per-call overrides. + # @return [ProductInvoicePending, ProductInvoiceIssued] + def create(company_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + response = post(base_path(cid), body: json_body(data), headers: json_headers, + idempotency_key: idempotency_key, + request_options: request_options) + discriminate(response) + end + + # Issue a product invoice scoped to a state tax registration. + # + # @param company_id [String] + # @param state_tax_id [String] + # @param data [Hash] + # @param idempotency_key [String, nil] + # @param request_options [Nfe::RequestOptions, nil] + # @return [ProductInvoicePending, ProductInvoiceIssued] + def create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + sid = Nfe::IdValidator.state_tax_id(state_tax_id) + response = post("/v2/companies/#{cid}/statetaxes/#{sid}/productinvoices", + body: json_body(data), headers: json_headers, + idempotency_key: idempotency_key, request_options: request_options) + discriminate(response) + end + + # List product invoices (cursor-style). +environment+ is REQUIRED. + # + # @param company_id [String] + # @param environment [String] +"Production"+ or +"Test"+ (required). + # @param options [Hash] +starting_after+, +ending_before+, +limit+, +q+. + # @return [Nfe::ListResponse] + # @raise [Nfe::InvalidRequestError] when +environment+ is missing. + def list(company_id:, environment:, **options) + cid = Nfe::IdValidator.company_id(company_id) + require_environment(environment) + query = cursor_query(options).merge(environment: environment) + response = get(base_path(cid), query: query) + hydrate_list(Nfe::ProductInvoice, parse_json(response.body), wrapper_key: "productInvoices") + end + + # Retrieve a product invoice by id. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::ProductInvoice] + def retrieve(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("#{base_path(cid)}/#{iid}") + hydrate(Nfe::ProductInvoice, parse_json(response.body)) + end + + # Cancel a product invoice (async); +reason+ forwarded as a query param. + # + # @param company_id [String] + # @param invoice_id [String] + # @param reason [String, nil] + # @return [Hash] the cancellation resource payload. + def cancel(company_id:, invoice_id:, reason: nil) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = delete("#{base_path(cid)}/#{iid}", query: { reason: reason }.compact) + parse_json(response.body) || {} + end + + # List items of an invoice (cursor-style). + # + # @return [Nfe::ListResponse] + def list_items(company_id:, invoice_id:, limit: nil, starting_after: nil) + sub_list(company_id: company_id, invoice_id: invoice_id, segment: "items", + limit: limit, starting_after: starting_after, wrapper_key: "items") + end + + # List fiscal events of an invoice (cursor-style). + # + # @return [Nfe::ListResponse] + def list_events(company_id:, invoice_id:, limit: nil, starting_after: nil) + sub_list(company_id: company_id, invoice_id: invoice_id, segment: "events", + limit: limit, starting_after: starting_after, wrapper_key: "events") + end + + # DANFE PDF file resource (URI, not bytes). +force+ regenerates the PDF. + # + # @return [Nfe::NfeFileResource] + def download_pdf(company_id:, invoice_id:, force: nil) + file_resource(company_id: company_id, invoice_id: invoice_id, + segment: "pdf", query: { force: force }.compact) + end + + # Authorized NF-e XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml") + end + + # Rejection XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_rejection_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml-rejection") + end + + # Contingency authorization (EPEC) XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_epec_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml-epec") + end + + # Send a correction letter (CC-e). +reason+ must be 15..1000 chars; the + # length is validated client-side before any HTTP request. + # + # @param company_id [String] + # @param invoice_id [String] + # @param reason [String] + # @return [Hash] the cancellation/CC-e resource payload. + # @raise [Nfe::InvalidRequestError] when +reason+ length is out of range. + def send_correction_letter(company_id:, invoice_id:, reason:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + validate_correction_reason(reason) + response = put("#{base_path(cid)}/#{iid}/correctionletter", + body: json_body({ reason: reason }), headers: json_headers) + parse_json(response.body) || {} + end + + # CC-e DANFE PDF file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_correction_letter_pdf(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "correctionletter/pdf") + end + + # CC-e XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_correction_letter_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "correctionletter/xml") + end + + # Disable (inutilizar) a single invoice (async). +reason+ optional. + # + # @return [Hash] the cancellation resource payload. + def disable(company_id:, invoice_id:, reason: nil) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = post("#{base_path(cid)}/#{iid}/disablement", query: { reason: reason }.compact) + parse_json(response.body) || {} + end + + # Disable a range of invoice numbers (single number = same begin/last). + # + # @param company_id [String] + # @param data [Hash] +{ environment, serie, state, begin_number, last_number, reason? }+. + # @return [Hash] the disablement resource payload. + def disable_range(company_id:, data:) + cid = Nfe::IdValidator.company_id(company_id) + response = post("#{base_path(cid)}/disablement", body: json_body(data), headers: json_headers) + parse_json(response.body) || {} + end + + private + + def base_path(company_id) + "/v2/companies/#{company_id}/productinvoices" + end + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + def require_environment(environment) + return unless environment.nil? || environment.to_s.strip.empty? + + raise Nfe::InvalidRequestError, "environment é obrigatório (Production ou Test)" + end + + def cursor_query(options) + { + startingAfter: options[:starting_after], endingBefore: options[:ending_before], + limit: options[:limit], q: options[:q] + }.compact + end + + def validate_correction_reason(reason) + length = reason.to_s.length + return if length.between?(15, 1000) + + raise Nfe::InvalidRequestError, + "motivo da carta de correção deve conter entre 15 e 1000 caracteres" + end + + def sub_list(company_id:, invoice_id:, segment:, limit:, starting_after:, wrapper_key:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + query = { limit: limit, startingAfter: starting_after }.compact + response = get("#{base_path(cid)}/#{iid}/#{segment}", query: query) + hydrate_list(Nfe::ProductInvoice, parse_json(response.body), wrapper_key: wrapper_key) + end + + def file_resource(company_id:, invoice_id:, segment:, query: {}) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("#{base_path(cid)}/#{iid}/#{segment}", query: query) + hydrate(Nfe::NfeFileResource, parse_json(response.body)) + end + + # Interpret the emission response into the discriminated value object. + def discriminate(response) + return build_pending(response) if response.status == 202 + + ProductInvoiceIssued.new(resource: hydrate(Nfe::ProductInvoice, parse_json(response.body))) + end + + # Build a {ProductInvoicePending} from a 202 response, or raise when the + # Location header is missing/unparsable. + def build_pending(response) + location = response.location + invoice_id = extract_invoice_id(location) + if location.nil? || location.empty? || invoice_id.nil? + raise Nfe::InvoiceProcessingError.new( + "Resposta 202 sem Location utilizável: não é possível identificar a NF-e em processamento.", + status_code: response.status, response_headers: response.headers + ) + end + ProductInvoicePending.new(invoice_id: invoice_id, location: location) + end + + def extract_invoice_id(location) + return nil if location.nil? + + match = location.match(%r{productinvoices/([a-z0-9-]+)}i) + match ? match[1] : nil + end + end + end +end diff --git a/lib/nfe/resources/product_invoices_rtc.rb b/lib/nfe/resources/product_invoices_rtc.rb new file mode 100644 index 0000000..6b71f44 --- /dev/null +++ b/lib/nfe/resources/product_invoices_rtc.rb @@ -0,0 +1,332 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/nfe_file_resource" +require "nfe/generated" +require "nfe/resources/responses/product_invoice_rtc_pending" +require "nfe/resources/responses/product_invoice_rtc_issued" + +module Nfe + module Resources + # RTC (Reforma Tributária do Consumo) product invoices (NF-e mod 55 / NFC-e + # mod 65) resource for the +:cte+ host family (+https://api.nfse.io/v2/...+). + # Full lifecycle: issue, list, retrieve, cancel, correction letters (CC-e), + # disablement (inutilização) and file downloads, hydrating the RTC generated + # DTOs in {Nfe::Generated::ProductInvoiceRtcV1}. + # + # This resource shares the SAME endpoints as the classic + # {Nfe::Resources::ProductInvoices}. There is NO discriminator header or + # query param: the RTC tax layout is selected by the API from the SHAPE of + # the payload — specifically the presence of the item-level +IBSCBS+ group + # (+items[].tax.IBSCBS+). NF-e (mod 55) vs NFC-e (mod 65) is likewise + # inferred from the payload shape. Use this resource (vs the classic one) + # when you want the RTC response DTOs hydrated. + # + # Emission is asynchronous (HTTP 202, queued; completion via webhook): + # {#create}/{#create_with_state_tax} return either a + # {Nfe::Resources::ProductInvoiceRtcPending} or a + # {Nfe::Resources::ProductInvoiceRtcIssued}. There is no + # +create_and_wait+/+create_batch+ — poll manually with {#retrieve} + + # {Nfe::FlowStatus.terminal?}. + # + # NOTE: as with the classic resource, the download methods return a + # {Nfe::NfeFileResource} (a URI to the file), NOT raw bytes — the API + # responds with a JSON +{ uri }+ envelope. + class ProductInvoicesRtc < AbstractResource + protected + + def api_family + :cte + end + + # The +:cte+ host serves the v2 API; paths embed +/v2+ explicitly, so no + # version segment is auto-prefixed. + def api_version + "" + end + + public + + # Issue an RTC product invoice (NF-e/NFC-e). Returns a discriminated + # result: a {ProductInvoiceRtcPending} on HTTP 202 or a + # {ProductInvoiceRtcIssued} (hydrating + # {Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource}) on 201. + # + # +data+ is a Hash with camelCase keys. The generated request DTO + # {Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest} documents + # the expected payload SHAPE; it is NOT accepted as input (the generated + # DTOs deserialize only and have no camelCase serialization path). The RTC + # layout is selected by the presence of the item-level +IBSCBS+ group + # (+items[].tax.IBSCBS+); NF-e (mod 55) vs NFC-e (mod 65) follows the + # payload shape. Same endpoint as the classic resource. + # + # @param company_id [String] + # @param data [Hash] invoice payload (camelCase keys per the API). + # @param idempotency_key [String, nil] sent as the +Idempotency-Key+ header. + # @param request_options [Nfe::RequestOptions, nil] per-call overrides. + # @return [ProductInvoiceRtcPending, ProductInvoiceRtcIssued] + def create(company_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + response = post(base_path(cid), body: json_body(data), headers: json_headers, + idempotency_key: idempotency_key, + request_options: request_options) + discriminate(response) + end + + # Issue an RTC product invoice scoped to a state tax registration. + # + # +data+ is a Hash with camelCase keys (see {#create} for the payload + # shape and RTC-layout selection notes). + # + # @param company_id [String] + # @param state_tax_id [String] + # @param data [Hash] + # @param idempotency_key [String, nil] + # @param request_options [Nfe::RequestOptions, nil] + # @return [ProductInvoiceRtcPending, ProductInvoiceRtcIssued] + def create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + sid = Nfe::IdValidator.state_tax_id(state_tax_id) + response = post("/v2/companies/#{cid}/statetaxes/#{sid}/productinvoices", + body: json_body(data), headers: json_headers, + idempotency_key: idempotency_key, request_options: request_options) + discriminate(response) + end + + # List RTC product invoices (cursor-style). +environment+ is REQUIRED. + # + # @param company_id [String] + # @param environment [String] +"Production"+ or +"Test"+ (required). + # @param starting_after [String, nil] + # @param ending_before [String, nil] + # @param limit [Integer, nil] + # @param q [String, nil] + # @return [Nfe::ListResponse] items hydrated as + # {Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource}. + # @raise [Nfe::InvalidRequestError] when +environment+ is missing. + def list(company_id:, environment:, starting_after: nil, ending_before: nil, limit: nil, q: nil) + cid = Nfe::IdValidator.company_id(company_id) + require_environment(environment) + query = list_query(starting_after: starting_after, ending_before: ending_before, + limit: limit, q: q).merge(environment: environment) + response = get(base_path(cid), query: query) + hydrate_list(Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource, + parse_json(response.body), wrapper_key: "productInvoices") + end + + # Retrieve an RTC product invoice by id. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource, nil] + # @raise [Nfe::NotFoundError] on HTTP 404. + def retrieve(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("#{base_path(cid)}/#{iid}") + hydrate(Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource, parse_json(response.body)) + end + + # Cancel an RTC product invoice (async); +reason+ forwarded as a query + # param. Hydrates + # {Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource}. + # + # @param company_id [String] + # @param invoice_id [String] + # @param reason [String, nil] + # @return [Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource, nil] + def cancel(company_id:, invoice_id:, reason: nil) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = delete("#{base_path(cid)}/#{iid}", query: { reason: reason }.compact) + hydrate(Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource, parse_json(response.body)) + end + + # List items of an invoice. Hydrates + # {Nfe::Generated::ProductInvoiceRtcV1::InvoiceItemsResource}. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::Generated::ProductInvoiceRtcV1::InvoiceItemsResource, nil] + def list_items(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("#{base_path(cid)}/#{iid}/items") + hydrate(Nfe::Generated::ProductInvoiceRtcV1::InvoiceItemsResource, parse_json(response.body)) + end + + # List fiscal events of an invoice. Hydrates + # {Nfe::Generated::ProductInvoiceRtcV1::InvoiceEventsResource}. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::Generated::ProductInvoiceRtcV1::InvoiceEventsResource, nil] + def list_events(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("#{base_path(cid)}/#{iid}/events") + hydrate(Nfe::Generated::ProductInvoiceRtcV1::InvoiceEventsResource, parse_json(response.body)) + end + + # DANFE PDF file resource (URI, not bytes). +force+ regenerates the PDF. + # + # @return [Nfe::NfeFileResource] + def download_pdf(company_id:, invoice_id:, force: false) + file_resource(company_id: company_id, invoice_id: invoice_id, + segment: "pdf", query: { force: force }.compact) + end + + # Authorized NF-e XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml") + end + + # Rejection XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_rejection_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml-rejection") + end + + # Contingency authorization (EPEC) XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_epec_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml-epec") + end + + # Send a correction letter (CC-e). +reason+ must be 15..1000 chars; the + # length is validated client-side before any HTTP request. + # + # @param company_id [String] + # @param invoice_id [String] + # @param reason [String] + # @return [Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource, nil] + # @raise [Nfe::InvalidRequestError] when +reason+ length is out of range. + def send_correction_letter(company_id:, invoice_id:, reason:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + validate_correction_reason(reason) + response = put("#{base_path(cid)}/#{iid}/correctionletter", + body: json_body({ reason: reason }), headers: json_headers) + hydrate(Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource, parse_json(response.body)) + end + + # CC-e DANFE PDF file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_correction_letter_pdf(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "correctionletter/pdf") + end + + # CC-e XML file resource (URI, not bytes). + # + # @return [Nfe::NfeFileResource] + def download_correction_letter_xml(company_id:, invoice_id:) + file_resource(company_id: company_id, invoice_id: invoice_id, segment: "correctionletter/xml") + end + + # Disable (inutilizar) a single invoice (async). +reason+ optional; + # forwarded as a query param. Hydrates + # {Nfe::Generated::ProductInvoiceRtcV1::DisablementResource}. + # + # @param company_id [String] + # @param invoice_id [String] + # @param reason [String, nil] + # @return [Nfe::Generated::ProductInvoiceRtcV1::DisablementResource, nil] + def disable(company_id:, invoice_id:, reason: nil) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = post("#{base_path(cid)}/#{iid}/disablement", query: { reason: reason }.compact) + hydrate(Nfe::Generated::ProductInvoiceRtcV1::DisablementResource, parse_json(response.body)) + end + + # Disable a range of invoice numbers (single number = same begin/last). + # +data+ is a Hash with camelCase keys. + # + # @param company_id [String] + # @param data [Hash] +{ environment, serie, state, beginNumber, lastNumber, reason? }+. + # @return [Nfe::Generated::ProductInvoiceRtcV1::DisablementResource, nil] + def disable_range(company_id:, data:) + cid = Nfe::IdValidator.company_id(company_id) + response = post("#{base_path(cid)}/disablement", body: json_body(data), headers: json_headers) + hydrate(Nfe::Generated::ProductInvoiceRtcV1::DisablementResource, parse_json(response.body)) + end + + private + + def base_path(company_id) + "/v2/companies/#{company_id}/productinvoices" + end + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + def require_environment(environment) + return unless environment.nil? || environment.to_s.strip.empty? + + raise Nfe::InvalidRequestError, "environment é obrigatório (Production ou Test)" + end + + def list_query(starting_after:, ending_before:, limit:, q:) + { + startingAfter: starting_after, endingBefore: ending_before, + limit: limit, q: q + }.compact + end + + def validate_correction_reason(reason) + length = reason.to_s.length + return if length.between?(15, 1000) + + raise Nfe::InvalidRequestError, + "motivo da carta de correção deve conter entre 15 e 1000 caracteres" + end + + def file_resource(company_id:, invoice_id:, segment:, query: {}) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("#{base_path(cid)}/#{iid}/#{segment}", query: query) + hydrate(Nfe::NfeFileResource, parse_json(response.body)) + end + + # Interpret the emission response into the discriminated value object. + def discriminate(response) + return build_pending(response) if response.status == 202 + + ProductInvoiceRtcIssued.new( + resource: hydrate(Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource, parse_json(response.body)) + ) + end + + # Build a {ProductInvoiceRtcPending} from a 202 response, or raise when the + # Location header is missing/unparsable. + def build_pending(response) + location = response.location + invoice_id = extract_invoice_id(location) + if location.nil? || location.empty? || invoice_id.nil? + raise Nfe::InvoiceProcessingError.new( + "Resposta 202 sem Location utilizável: não é possível identificar a NF-e em processamento.", + status_code: response.status, response_headers: response.headers + ) + end + ProductInvoiceRtcPending.new(invoice_id: invoice_id, location: location) + end + + def extract_invoice_id(location) + return nil if location.nil? + + match = location.match(%r{productinvoices/([a-z0-9-]+)}i) + match ? match[1] : nil + end + end + end +end diff --git a/lib/nfe/resources/responses/consumer_invoice_issued.rb b/lib/nfe/resources/responses/consumer_invoice_issued.rb new file mode 100644 index 0000000..c3e3cae --- /dev/null +++ b/lib/nfe/resources/responses/consumer_invoice_issued.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Discriminated result of a synchronous NFC-e emission (HTTP 201/200): the + # document was materialized immediately. +resource+ is the hydrated + # {Nfe::ConsumerInvoice} value object. + # + # Discriminate against {Nfe::Resources::ConsumerInvoicePending} with the + # +pending?+/+issued?+ predicates or +case+/+in+ pattern matching. + # + # @example + # result = client.consumer_invoices.create(company_id: id, data: payload) + # result.resource if result.issued? + class ConsumerInvoiceIssued < Data.define(:resource) + # @return [Boolean] always +false+ for an issued result. + def pending? + false + end + + # @return [Boolean] always +true+ for an issued result. + def issued? + true + end + end + end +end diff --git a/lib/nfe/resources/responses/consumer_invoice_pending.rb b/lib/nfe/resources/responses/consumer_invoice_pending.rb new file mode 100644 index 0000000..4d77d40 --- /dev/null +++ b/lib/nfe/resources/responses/consumer_invoice_pending.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Discriminated result of an asynchronous NFC-e emission (HTTP 202): the + # API accepted the request and is processing it; the document is not yet + # materialized. +invoice_id+ is parsed from the +Location+ header's final + # path segment and +location+ is the raw header value. + # + # Discriminate against {Nfe::Resources::ConsumerInvoiceIssued} with the + # +pending?+/+issued?+ predicates or +case+/+in+ pattern matching, then poll + # {Nfe::FlowStatus.terminal?} until the invoice settles. + # + # @example + # result = client.consumer_invoices.create(company_id: id, data: payload) + # result.pending? # => true + # result.invoice_id + class ConsumerInvoicePending < Data.define(:invoice_id, :location) + # @return [Boolean] always +true+ for a pending result. + def pending? + true + end + + # @return [Boolean] always +false+ for a pending result. + def issued? + false + end + end + end +end diff --git a/lib/nfe/resources/responses/product_invoice_issued.rb b/lib/nfe/resources/responses/product_invoice_issued.rb new file mode 100644 index 0000000..4fb0384 --- /dev/null +++ b/lib/nfe/resources/responses/product_invoice_issued.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an immediate (HTTP 201/200) product-invoice (NF-e) emission: the + # document was materialized synchronously. +resource+ is the hydrated + # {Nfe::ProductInvoice} value object. + # + # Discriminate against {Nfe::Resources::ProductInvoicePending} with + # +pending?+/+issued?+ or +case+ pattern matching. + class ProductInvoiceIssued < Data.define(:resource) + # @return [false] this is not an async (pending) result. + def pending? + false + end + + # @return [true] this is an immediate (issued) result. + def issued? + true + end + end + end +end diff --git a/lib/nfe/resources/responses/product_invoice_pending.rb b/lib/nfe/resources/responses/product_invoice_pending.rb new file mode 100644 index 0000000..6daa505 --- /dev/null +++ b/lib/nfe/resources/responses/product_invoice_pending.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an asynchronous (HTTP 202) product-invoice (NF-e) emission: the + # API enqueued the request and is processing it. Completion is notified via + # webhook. + # + # +invoice_id+ is parsed from the +Location+ header's final path segment; + # +location+ is the raw header value. Discriminate against + # {Nfe::Resources::ProductInvoiceIssued} with +pending?+/+issued?+ or +case+ + # pattern matching, then poll {Nfe::FlowStatus.terminal?} until settled. + class ProductInvoicePending < Data.define(:invoice_id, :location) + # @return [true] this is an async (pending) result. + def pending? + true + end + + # @return [false] this is not an immediate (issued) result. + def issued? + false + end + end + end +end diff --git a/lib/nfe/resources/responses/product_invoice_rtc_issued.rb b/lib/nfe/resources/responses/product_invoice_rtc_issued.rb new file mode 100644 index 0000000..6e3f4ab --- /dev/null +++ b/lib/nfe/resources/responses/product_invoice_rtc_issued.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an immediate (HTTP 201/200) RTC product-invoice (NF-e/NFC-e under + # the Reforma Tributária layout) emission: the document was materialized + # synchronously. +resource+ is the hydrated + # {Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource} value object. + # + # Discriminate against {Nfe::Resources::ProductInvoiceRtcPending} with + # +pending?+/+issued?+ or +case+ pattern matching. + class ProductInvoiceRtcIssued < Data.define(:resource) + # @return [false] this is not an async (pending) result. + def pending? + false + end + + # @return [true] this is an immediate (issued) result. + def issued? + true + end + end + end +end diff --git a/lib/nfe/resources/responses/product_invoice_rtc_pending.rb b/lib/nfe/resources/responses/product_invoice_rtc_pending.rb new file mode 100644 index 0000000..8a2d0e2 --- /dev/null +++ b/lib/nfe/resources/responses/product_invoice_rtc_pending.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an asynchronous (HTTP 202) RTC product-invoice (NF-e/NFC-e under + # the Reforma Tributária layout) emission: the API enqueued the request and + # is processing it. Completion is notified via webhook. + # + # +invoice_id+ is parsed from the +Location+ header's +productinvoices/{id}+ + # segment; +location+ is the raw header value. Discriminate against + # {Nfe::Resources::ProductInvoiceRtcIssued} with +pending?+/+issued?+ or + # +case+ pattern matching, then poll {Nfe::FlowStatus.terminal?} until + # settled. + class ProductInvoiceRtcPending < Data.define(:invoice_id, :location) + # @return [true] this is an async (pending) result. + def pending? + true + end + + # @return [false] this is not an immediate (issued) result. + def issued? + false + end + end + end +end diff --git a/lib/nfe/resources/responses/service_invoice_issued.rb b/lib/nfe/resources/responses/service_invoice_issued.rb new file mode 100644 index 0000000..3ef9f41 --- /dev/null +++ b/lib/nfe/resources/responses/service_invoice_issued.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an immediate (HTTP 201/200) service-invoice (NFS-e) emission: the + # document was materialized synchronously. +resource+ is the hydrated + # {Nfe::ServiceInvoice} value object. + # + # Discriminate against {Nfe::Resources::ServiceInvoicePending} with + # +pending?+/+issued?+ or +case+ pattern matching. + class ServiceInvoiceIssued < Data.define(:resource) + # @return [false] this is not an async (pending) result. + def pending? + false + end + + # @return [true] this is an immediate (issued) result. + def issued? + true + end + end + end +end diff --git a/lib/nfe/resources/responses/service_invoice_pending.rb b/lib/nfe/resources/responses/service_invoice_pending.rb new file mode 100644 index 0000000..c18ee6f --- /dev/null +++ b/lib/nfe/resources/responses/service_invoice_pending.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an asynchronous (HTTP 202) service-invoice (NFS-e) emission: the + # API accepted the request and is processing it. The document is not yet + # materialized. + # + # +invoice_id+ is parsed from the +Location+ header's final path segment; + # +location+ is the raw header value. Discriminate against + # {Nfe::Resources::ServiceInvoiceIssued} with +pending?+/+issued?+ or +case+ + # pattern matching, then poll {Nfe::FlowStatus.terminal?} until settled. + class ServiceInvoicePending < Data.define(:invoice_id, :location) + # @return [true] this is an async (pending) result. + def pending? + true + end + + # @return [false] this is not an immediate (issued) result. + def issued? + false + end + end + end +end diff --git a/lib/nfe/resources/responses/service_invoice_rtc_issued.rb b/lib/nfe/resources/responses/service_invoice_rtc_issued.rb new file mode 100644 index 0000000..d1980cb --- /dev/null +++ b/lib/nfe/resources/responses/service_invoice_rtc_issued.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an immediate (HTTP 201/200) RTC service-invoice (NFS-e) emission: + # the document was materialized synchronously. +resource+ is the hydrated + # {Nfe::ServiceInvoice} value object — the RTC create endpoint returns the + # standard NFS-e body shape, so the classic hand-written DTO is reused (the + # generated +ServiceInvoiceRtcV1::NFSeRequest+ describes only the request). + # + # Discriminate against {Nfe::Resources::ServiceInvoiceRtcPending} with + # +pending?+/+issued?+ or +case+ pattern matching. + class ServiceInvoiceRtcIssued < Data.define(:resource) + # @return [false] this is not an async (pending) result. + def pending? + false + end + + # @return [true] this is an immediate (issued) result. + def issued? + true + end + end + end +end diff --git a/lib/nfe/resources/responses/service_invoice_rtc_pending.rb b/lib/nfe/resources/responses/service_invoice_rtc_pending.rb new file mode 100644 index 0000000..291579a --- /dev/null +++ b/lib/nfe/resources/responses/service_invoice_rtc_pending.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Nfe + module Resources + # Result of an asynchronous (HTTP 202) RTC service-invoice (NFS-e) emission: + # the API accepted the request and is processing it. The document is not yet + # materialized. + # + # +invoice_id+ is parsed from the +Location+ header's final path segment; + # +location+ is the raw header value. Discriminate against + # {Nfe::Resources::ServiceInvoiceRtcIssued} with +pending?+/+issued?+ or + # +case+ pattern matching, then poll until the document settles. + # + # RTC and classic NFS-e share the same endpoint; the RTC layout is selected + # by the presence of the +ibsCbs+ group in the create payload, so the async + # 202 shape is identical to the classic flow. + class ServiceInvoiceRtcPending < Data.define(:invoice_id, :location) + # @return [true] this is an async (pending) result. + def pending? + true + end + + # @return [false] this is not an immediate (issued) result. + def issued? + false + end + end + end +end diff --git a/lib/nfe/resources/service_invoices.rb b/lib/nfe/resources/service_invoices.rb new file mode 100644 index 0000000..7bee2e4 --- /dev/null +++ b/lib/nfe/resources/service_invoices.rb @@ -0,0 +1,226 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/service_invoice" +require "nfe/resources/responses/service_invoice_pending" +require "nfe/resources/responses/service_invoice_issued" + +module Nfe + module Resources + # Service invoices (NFS-e) resource for the +:main+ host family + # (+https://api.nfe.io/v1/...+). This is the canonical emission resource of + # the platform. + # + # Emission is typically asynchronous: {#create} returns either a + # {Nfe::Resources::ServiceInvoicePending} (HTTP 202, queued) or a + # {Nfe::Resources::ServiceInvoiceIssued} (HTTP 201, materialized). There is + # no +create_and_wait+/+create_batch+ in v1.0 — poll manually: + # + # result = client.service_invoices.create(company_id: id, data: payload) + # if result.pending? + # loop do + # status = client.service_invoices.get_status(company_id: id, invoice_id: result.invoice_id) + # break if status.complete? + # sleep 2 + # end + # end + # + # @example + # client.service_invoices.create(company_id: "co_1", data: { borrower: {...}, ... }) + class ServiceInvoices < AbstractResource + # Derived status snapshot returned by {ServiceInvoices#get_status} without + # issuing an extra HTTP call. + class StatusResult < Data.define(:status, :invoice, :complete, :failed) + # @return [Boolean] true when the flow status is terminal. + def complete? + complete + end + + # @return [Boolean] true when the flow status is IssueFailed/CancelFailed. + def failed? + failed + end + end + + FAILED_STATUSES = %w[IssueFailed CancelFailed].freeze + + protected + + def api_family + :main + end + + public + + # Create (emit) a service invoice. Returns a discriminated result: a + # {ServiceInvoicePending} on HTTP 202 (queued, +invoice_id+ parsed from the + # +Location+ header) or a {ServiceInvoiceIssued} on HTTP 201 (materialized). + # + # @param company_id [String] + # @param data [Hash] invoice payload (camelCase keys per the API). + # @param idempotency_key [String, nil] sent as the +Idempotency-Key+ header. + # @param request_options [Nfe::RequestOptions, nil] per-call overrides. + # @return [ServiceInvoicePending, ServiceInvoiceIssued] + # @raise [Nfe::InvoiceProcessingError] on a 202 with no/unparsable Location. + def create(company_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{cid}/serviceinvoices", body: json_body(data), + headers: json_headers, + idempotency_key: idempotency_key, + request_options: request_options) + discriminate(response) + end + + # List service invoices (page-style pagination plus date filters). + # + # @param company_id [String] + # @param options [Hash] +page_index+, +page_count+, +issued_begin+, + # +issued_end+, +created_begin+, +created_end+, +has_totals+. + # @return [Nfe::ListResponse] + def list(company_id:, **options) + cid = Nfe::IdValidator.company_id(company_id) + response = get("/companies/#{cid}/serviceinvoices", query: list_query(options)) + hydrate_list(Nfe::ServiceInvoice, parse_json(response.body), wrapper_key: "serviceInvoices") + end + + # Retrieve a service invoice by id. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::ServiceInvoice] + # @raise [Nfe::NotFoundError] when the API responds 404 or an empty body. + def retrieve(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("/companies/#{cid}/serviceinvoices/#{iid}") + payload = parse_json(response.body) + raise Nfe::NotFoundError, "nota de serviço #{iid} não encontrada" if payload.nil? + + hydrate(Nfe::ServiceInvoice, payload) + end + + # Cancel a service invoice (synchronous); returns the updated model. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::ServiceInvoice] + def cancel(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = delete("/companies/#{cid}/serviceinvoices/#{iid}") + hydrate(Nfe::ServiceInvoice, parse_json(response.body)) + end + + # E-mail the invoice to the borrower. No e-mail list argument (Node parity). + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Hash] +{ sent:, message: }+. + def send_email(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = put("/companies/#{cid}/serviceinvoices/#{iid}/sendemail") + payload = parse_json(response.body) || {} + { sent: payload.fetch("sent", response.success?), message: payload["message"] } + end + + # Download the invoice PDF (or the company ZIP when +invoice_id+ is nil). + # + # @param company_id [String] + # @param invoice_id [String, nil] + # @return [String] PDF/ZIP bytes (ASCII-8BIT). + def download_pdf(company_id:, invoice_id: nil) + download_document(company_id: company_id, invoice_id: invoice_id, + ext: "pdf", accept: "application/pdf") + end + + # Download the invoice XML (or the company ZIP when +invoice_id+ is nil). + # + # @param company_id [String] + # @param invoice_id [String, nil] + # @return [String] XML/ZIP bytes (ASCII-8BIT). + def download_xml(company_id:, invoice_id: nil) + download_document(company_id: company_id, invoice_id: invoice_id, + ext: "xml", accept: "application/xml") + end + + # Status snapshot derived from {#retrieve} (Node parity — no extra HTTP). + # + # @param company_id [String] + # @param invoice_id [String] + # @return [StatusResult] + def get_status(company_id:, invoice_id:) + invoice = retrieve(company_id: company_id, invoice_id: invoice_id) + status = invoice&.flow_status || "WaitingSend" + StatusResult.new( + status: status, invoice: invoice, + complete: Nfe::FlowStatus.terminal?(status), + failed: FAILED_STATUSES.include?(status) + ) + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + # Map snake_case list options onto the API's camelCase query parameters, + # dropping nil values. + def list_query(options) + { + pageIndex: options[:page_index], pageCount: options[:page_count], + issuedBegin: options[:issued_begin], issuedEnd: options[:issued_end], + createdBegin: options[:created_begin], createdEnd: options[:created_end], + hasTotals: options[:has_totals] + }.compact + end + + # GET the single-invoice or bulk document path and return binary bytes. + def download_document(company_id:, invoice_id:, ext:, accept:) + cid = Nfe::IdValidator.company_id(company_id) + path = if invoice_id.nil? + "/companies/#{cid}/serviceinvoices/#{ext}" + else + iid = Nfe::IdValidator.invoice_id(invoice_id) + "/companies/#{cid}/serviceinvoices/#{iid}/#{ext}" + end + download(path, headers: { "Accept" => accept }) + end + + # Interpret the emission response into the discriminated value object. + def discriminate(response) + return build_pending(response) if response.status == 202 + + ServiceInvoiceIssued.new(resource: hydrate(Nfe::ServiceInvoice, parse_json(response.body))) + end + + # Build a {ServiceInvoicePending} from a 202 response, or raise when the + # Location header is missing/unparsable. + def build_pending(response) + location = response.location + invoice_id = extract_invoice_id(location) + if location.nil? || location.empty? || invoice_id.nil? + raise Nfe::InvoiceProcessingError.new( + "Resposta 202 sem Location utilizável: não é possível identificar a NFS-e em processamento.", + status_code: response.status, response_headers: response.headers + ) + end + ServiceInvoicePending.new(invoice_id: invoice_id, location: location) + end + + # Extract the trailing id from a +Location+ path. + def extract_invoice_id(location) + return nil if location.nil? + + match = location.match(%r{serviceinvoices/([a-z0-9-]+)}i) + match ? match[1] : nil + end + end + end +end diff --git a/lib/nfe/resources/service_invoices_rtc.rb b/lib/nfe/resources/service_invoices_rtc.rb new file mode 100644 index 0000000..92fa089 --- /dev/null +++ b/lib/nfe/resources/service_invoices_rtc.rb @@ -0,0 +1,159 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/service_invoice" +require "nfe/resources/responses/service_invoice_rtc_pending" +require "nfe/resources/responses/service_invoice_rtc_issued" + +module Nfe + module Resources + # RTC (Reforma Tributária do Consumo) service-invoice (NFS-e) emission + # resource for the +:main+ host family (+https://api.nfe.io/v1/...+). + # + # RTC reuses the SAME endpoints as the classic {Nfe::Resources::ServiceInvoices} + # resource (+/companies/{company_id}/serviceinvoices+). There is no + # discriminator header or query parameter: the API selects the RTC document + # layout from the PRESENCE of the +ibsCbs+ group in the create payload. When + # +ibsCbs+ is absent the API falls back to the classic NFS-e layout. + # + # Emission is typically asynchronous: {#create} returns either a + # {Nfe::Resources::ServiceInvoiceRtcPending} (HTTP 202, queued) or a + # {Nfe::Resources::ServiceInvoiceRtcIssued} (HTTP 201, materialized). There is + # no +create_and_wait+/+create_batch+ — poll {#retrieve} manually. + # + # @example RTC emission selected by the +ibsCbs+ group + # client.service_invoices_rtc.create( + # company_id: "co_1", + # data: { borrower: { ... }, servicesAmount: 100.0, ibsCbs: { cbs: { ... }, ibs: { ... } } } + # ) + class ServiceInvoicesRtc < AbstractResource + protected + + def api_family + :main + end + + def api_version + "v1" + end + + public + + # Create (emit) an RTC service invoice. Returns a discriminated result: a + # {ServiceInvoiceRtcPending} on HTTP 202 (queued, +invoice_id+ parsed from + # the +Location+ header) or a {ServiceInvoiceRtcIssued} on HTTP 201 + # (materialized, hydrating {Nfe::ServiceInvoice}). + # + # +data+ is a Hash with camelCase keys (JSON-encoded as-is). The generated + # +Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest+ DTO documents the + # expected payload SHAPE (including the nested +ibsCbs+, +borrower+, + # +location+, ... groups), but is NOT accepted as input: the generated DTOs + # deserialize only (+from_api+) and have no camelCase re-serializer, so + # passing the object would emit wrong keys. The RTC layout is selected by + # the presence of the +ibsCbs+ group in +data+ — same endpoint as the + # classic resource, no discriminator header/param. + # + # @param company_id [String] + # @param data [Hash] invoice payload (camelCase keys); include +ibsCbs+ to + # select the RTC layout. Mirrors +ServiceInvoiceRtcV1::NFSeRequest+. + # @param idempotency_key [String, nil] sent as the +Idempotency-Key+ header. + # @param request_options [Nfe::RequestOptions, nil] per-call overrides. + # @return [ServiceInvoiceRtcPending, ServiceInvoiceRtcIssued] + # @raise [Nfe::InvoiceProcessingError] on a 202 with no/unparsable Location. + def create(company_id:, data:, idempotency_key: nil, request_options: nil) + cid = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{cid}/serviceinvoices", body: json_body(data), + headers: json_headers, + idempotency_key: idempotency_key, + request_options: request_options) + discriminate(response) + end + + # Retrieve an RTC service invoice by id. The 201/GET body is the standard + # NFS-e shape, hydrated into {Nfe::ServiceInvoice}. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::ServiceInvoice] + # @raise [Nfe::NotFoundError] when the API responds 404 or an empty body. + def retrieve(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = get("/companies/#{cid}/serviceinvoices/#{iid}") + payload = parse_json(response.body) + raise Nfe::NotFoundError, "nota de serviço #{iid} não encontrada" if payload.nil? + + hydrate(Nfe::ServiceInvoice, payload) + end + + # Cancel an RTC service invoice (synchronous); returns the updated model. + # + # @param company_id [String] + # @param invoice_id [String] + # @return [Nfe::ServiceInvoice] + def cancel(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + response = delete("/companies/#{cid}/serviceinvoices/#{iid}") + hydrate(Nfe::ServiceInvoice, parse_json(response.body)) + end + + # Download the cancellation XML (ADN-only, available after the invoice + # reaches the +Cancelled+ state). Returns the raw bytes (+ASCII-8BIT+). + # + # @param company_id [String] + # @param invoice_id [String] + # @return [String] XML bytes (ASCII-8BIT). + # @raise [Nfe::NotFoundError] when the document is unavailable (404/empty). + def download_cancellation_xml(company_id:, invoice_id:) + cid = Nfe::IdValidator.company_id(company_id) + iid = Nfe::IdValidator.invoice_id(invoice_id) + bytes = download("/companies/#{cid}/serviceinvoices/#{iid}/cancellation-xml", + headers: { "Accept" => "application/xml" }) + raise Nfe::NotFoundError, "XML de cancelamento da nota #{iid} não encontrado" if bytes.empty? + + bytes + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + # Interpret the emission response into the discriminated value object. + def discriminate(response) + return build_pending(response) if response.status == 202 + + ServiceInvoiceRtcIssued.new(resource: hydrate(Nfe::ServiceInvoice, parse_json(response.body))) + end + + # Build a {ServiceInvoiceRtcPending} from a 202 response, or raise when the + # Location header is missing/unparsable. + def build_pending(response) + location = response.location + invoice_id = extract_rtc_invoice_id(location) + if location.nil? || location.empty? || invoice_id.nil? + raise Nfe::InvoiceProcessingError.new( + "Resposta 202 sem Location utilizável: não é possível identificar a NFS-e em processamento.", + status_code: response.status, response_headers: response.headers + ) + end + ServiceInvoiceRtcPending.new(invoice_id: invoice_id, location: location) + end + + # Extract the trailing id from a +Location+ path. + def extract_rtc_invoice_id(location) + return nil if location.nil? + + match = location.match(%r{serviceinvoices/([a-z0-9-]+)}i) + match ? match[1] : nil + end + end + end +end diff --git a/lib/nfe/resources/state_taxes.rb b/lib/nfe/resources/state_taxes.rb new file mode 100644 index 0000000..b2b5895 --- /dev/null +++ b/lib/nfe/resources/state_taxes.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/state_taxes/nfe_state_tax" + +module Nfe + module Resources + # Company state-tax (Inscrição Estadual) registrations for the +:cte+ host + # family (+https://api.nfse.io/v2/companies/{companyId}/statetaxes+). Exposes + # the full CRUD: list (cursor-style), create, retrieve, update and delete. + # + # The API wraps single state-tax objects in a +{"stateTax" => }+ + # envelope (and the list in +{"stateTaxes" => [...]}+), transparently + # unwrapped here before hydrating {Nfe::NfeStateTax}. + # + # @example + # client.state_taxes.create(company_id, code: "SP", taxNumber: "1234567890") + # client.state_taxes.list(company_id, limit: 50) + class StateTaxes < AbstractResource + # Envelope key for a single state-tax object. + ENVELOPE = "stateTax" + # Wrapper key for the list envelope. + LIST_ENVELOPE = "stateTaxes" + + protected + + def api_family + :cte + end + + # The +:cte+ host (+api.nfse.io+) does not bake in a version; the +/v2+ + # segment is carried in the base path instead. + def api_version + "" + end + + public + + # List a company's state-tax registrations (cursor-style pagination). + # + # @param company_id [String] + # @param starting_after [String, nil] cursor — items after this id. + # @param ending_before [String, nil] cursor — items before this id. + # @param limit [Integer, nil] page size. + # @return [Nfe::ListResponse] + def list(company_id, starting_after: nil, ending_before: nil, limit: nil) + cid = Nfe::IdValidator.company_id(company_id) + query = {} #: Hash[String, untyped] + query["startingAfter"] = starting_after unless starting_after.nil? + query["endingBefore"] = ending_before unless ending_before.nil? + query["limit"] = limit unless limit.nil? + response = get(base_path(cid), query: query) + hydrate_list(Nfe::NfeStateTax, parse_json(response.body), wrapper_key: LIST_ENVELOPE) + end + + # Create a state-tax registration. + # + # @param company_id [String] + # @param data [Hash] state-tax attributes (camelCase keys per the API). + # @return [Nfe::NfeStateTax] + def create(company_id, data) + cid = Nfe::IdValidator.company_id(company_id) + response = post(base_path(cid), body: JSON.generate({ ENVELOPE => data }), + headers: json_headers) + hydrate(Nfe::NfeStateTax, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Retrieve a single state-tax registration. + # + # @param company_id [String] + # @param state_tax_id [String] + # @return [Nfe::NfeStateTax] + def retrieve(company_id, state_tax_id) + cid = Nfe::IdValidator.company_id(company_id) + sid = Nfe::IdValidator.state_tax_id(state_tax_id) + response = get("#{base_path(cid)}/#{sid}") + hydrate(Nfe::NfeStateTax, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Update a state-tax registration. + # + # @param company_id [String] + # @param state_tax_id [String] + # @param data [Hash] state-tax attributes (camelCase keys per the API). + # @return [Nfe::NfeStateTax] + def update(company_id, state_tax_id, data) + cid = Nfe::IdValidator.company_id(company_id) + sid = Nfe::IdValidator.state_tax_id(state_tax_id) + response = put("#{base_path(cid)}/#{sid}", body: JSON.generate({ ENVELOPE => data }), + headers: json_headers) + hydrate(Nfe::NfeStateTax, unwrap(parse_json(response.body), ENVELOPE)) + end + + # Delete a state-tax registration. + # + # @param company_id [String] + # @param state_tax_id [String] + # @return [nil] + def delete(company_id, state_tax_id) + cid = Nfe::IdValidator.company_id(company_id) + sid = Nfe::IdValidator.state_tax_id(state_tax_id) + super("#{base_path(cid)}/#{sid}") + nil + end + + private + + def base_path(company_id) + "/v2/companies/#{company_id}/statetaxes" + end + + def json_headers + { "Content-Type" => "application/json" } + end + end + end +end diff --git a/lib/nfe/resources/tax_calculation.rb b/lib/nfe/resources/tax_calculation.rb new file mode 100644 index 0000000..a7af8f4 --- /dev/null +++ b/lib/nfe/resources/tax_calculation.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require "cgi" +require "json" +require "nfe/resources/abstract_resource" +require "nfe/generated/calculo_impostos_v1/cofins" +require "nfe/generated/calculo_impostos_v1/icms" +require "nfe/generated/calculo_impostos_v1/icms_uf_dest" +require "nfe/generated/calculo_impostos_v1/ii" +require "nfe/generated/calculo_impostos_v1/ipi" +require "nfe/generated/calculo_impostos_v1/pis" +require "nfe/generated/calculo_impostos_v1/calculate_item_response" +require "nfe/generated/calculo_impostos_v1/calculate_response" + +module Nfe + module Resources + # Tax calculation engine for the +:cte+ family (host +api.nfse.io+). Runs the + # tax rules engine for a tenant and returns a per-item tax breakdown. + class TaxCalculation < AbstractResource + protected + + def api_family = :cte + + # The path already carries its own segments, so no version prefix is added. + def api_version = "" + + public + + # Run the tax-rules engine for +tenant_id+ over +request+. + # + # Client-side validation runs FIRST (no HTTP when invalid): +tenant_id+ + # must be non-empty and +request+ must be a Hash carrying +operation_type+ + # (or +operationType+) plus a non-empty +items+ Array. + # + # +request+ accepts a plain Hash. For type-safety you may build it from + # {Nfe::Generated::CalculoImpostosV1::CalculateRequest#to_h}. + # + # @param tenant_id [String] the tenant identifier (URL-encoded into the path). + # @param request [Hash] the calculation request body. + # @return [Nfe::Generated::CalculoImpostosV1::CalculateResponse] + def calculate(tenant_id, request) + validate_calculate!(tenant_id, request) + path = "/tax-rules/#{CGI.escape(tenant_id.to_s.strip)}/engine/calculate" + response = post(path, body: JSON.generate(request), + headers: { "Content-Type" => "application/json" }) + hydrate(Nfe::Generated::CalculoImpostosV1::CalculateResponse, parse_json(response.body)) + end + + private + + # Fail fast (no HTTP) when the tenant or request shape is invalid. + def validate_calculate!(tenant_id, request) + Nfe::IdValidator.presence!(tenant_id, "tenant_id") + return if request.is_a?(Hash) && operation_type?(request) && items?(request) + + raise Nfe::InvalidRequestError, + "request deve conter operation_type (ou operationType) e items (Array não vazio)" + end + + def operation_type?(request) + !request[:operation_type].nil? || !request["operation_type"].nil? || + !request[:operationType].nil? || !request["operationType"].nil? + end + + def items?(request) + items = request[:items] || request["items"] + items.is_a?(Array) && !items.empty? + end + end + end +end diff --git a/lib/nfe/resources/tax_codes.rb b/lib/nfe/resources/tax_codes.rb new file mode 100644 index 0000000..14a3c2e --- /dev/null +++ b/lib/nfe/resources/tax_codes.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/tax_codes/tax_code_paginated_response" + +module Nfe + module Resources + # CT-e tax-code lookup tables for the +:cte+ host family + # (+https://api.nfse.io/tax-codes/...+). Exposes the four reference lists + # consumed when building a CT-e: operation codes, acquisition purposes, and + # the issuer/recipient tax profiles. + # + # These endpoints paginate page-style (1-based +pageIndex+/+pageCount+), so + # every method returns an {Nfe::TaxCodePaginatedResponse} (NOT an + # {Nfe::ListResponse}); see that class for why this differs from the + # cursor-style lists elsewhere in the SDK. + # + # @example + # client.tax_codes.list_operation_codes(page_index: 2, page_count: 20) + class TaxCodes < AbstractResource + protected + + def api_family + :cte + end + + # The +:cte+ host (+api.nfse.io+) does not bake in a version and these + # tax-code paths carry none, so no version segment is prefixed. + def api_version + "" + end + + public + + # List CT-e operation codes (Código de Operação). + # + # @param page_index [Integer, nil] 1-based page index (preserved as given). + # @param page_count [Integer, nil] page size. + # @return [Nfe::TaxCodePaginatedResponse] + def list_operation_codes(page_index: nil, page_count: nil) + list_tax_codes("/tax-codes/operation-code", page_index, page_count) + end + + # List CT-e acquisition purposes (Finalidade de Aquisição). + # + # @param page_index [Integer, nil] 1-based page index (preserved as given). + # @param page_count [Integer, nil] page size. + # @return [Nfe::TaxCodePaginatedResponse] + def list_acquisition_purposes(page_index: nil, page_count: nil) + list_tax_codes("/tax-codes/acquisition-purpose", page_index, page_count) + end + + # List CT-e issuer tax profiles (Perfil Tributário do Emitente). + # + # @param page_index [Integer, nil] 1-based page index (preserved as given). + # @param page_count [Integer, nil] page size. + # @return [Nfe::TaxCodePaginatedResponse] + def list_issuer_tax_profiles(page_index: nil, page_count: nil) + list_tax_codes("/tax-codes/issuer-tax-profile", page_index, page_count) + end + + # List CT-e recipient tax profiles (Perfil Tributário do Destinatário). + # + # @param page_index [Integer, nil] 1-based page index (preserved as given). + # @param page_count [Integer, nil] page size. + # @return [Nfe::TaxCodePaginatedResponse] + def list_recipient_tax_profiles(page_index: nil, page_count: nil) + list_tax_codes("/tax-codes/recipient-tax-profile", page_index, page_count) + end + + private + + # Shared GET + page-style query builder for the four tax-code endpoints. + # Only the non-nil paging parameters are sent, keeping them out of the URL + # when omitted. + def list_tax_codes(path, page_index, page_count) + query = {} #: Hash[String, untyped] + query["pageIndex"] = page_index unless page_index.nil? + query["pageCount"] = page_count unless page_count.nil? + response = get(path, query: query) + hydrate(Nfe::TaxCodePaginatedResponse, parse_json(response.body)) + end + end + end +end diff --git a/lib/nfe/resources/transportation_invoices.rb b/lib/nfe/resources/transportation_invoices.rb new file mode 100644 index 0000000..fa0e031 --- /dev/null +++ b/lib/nfe/resources/transportation_invoices.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/inbound_settings" +require "nfe/resources/dto/inbound_invoice_metadata" + +module Nfe + module Resources + # Inbound CT-e (Conhecimento de Transporte Eletrônico) resource for the + # +:cte+ host family (+https://api.nfse.io+). Manages automatic CT-e fetch + # via SEFAZ Distribuição DFe and reads received CT-e documents/events by + # 44-digit access key. + # + # This is an inbound/query resource (settings + access-key lookups), not an + # emission resource: there is no discriminated 202 +Pending+/+Issued+ + # contract here. The host already carries no version segment, so paths embed + # +/v2+ literally and {#api_version} is +""+. + # + # @example Enable auto-fetch and read a received CT-e + # client.transportation_invoices.enable(company_id: "co-1") + # cte = client.transportation_invoices.retrieve( + # company_id: "co-1", + # access_key: "3524...7890" + # ) + class TransportationInvoices < AbstractResource + protected + + def api_family + :cte + end + + # The +:cte+ host carries no version segment; +/v2+ is embedded per path. + def api_version + "" + end + + public + + # Enable automatic CT-e search for a company via Distribuição DFe. + # + # @param company_id [String] + # @param start_from_nsu [Integer, String, nil] optional starting NSU. + # @param start_from_date [String, nil] optional starting date (ISO 8601). + # @return [Nfe::InboundSettings] + def enable(company_id:, start_from_nsu: nil, start_from_date: nil) + id = Nfe::IdValidator.company_id(company_id) + body = compact("startFromNsu" => start_from_nsu, "startFromDate" => start_from_date) + response = post("/v2/companies/#{id}/inbound/transportationinvoices", + body: json_body(body), headers: json_headers) + hydrate(Nfe::InboundSettings, parse_json(response.body)) + end + + # Disable automatic CT-e search for a company. + # + # @param company_id [String] + # @return [Nfe::InboundSettings] + def disable(company_id:) + id = Nfe::IdValidator.company_id(company_id) + response = delete("/v2/companies/#{id}/inbound/transportationinvoices") + hydrate(Nfe::InboundSettings, parse_json(response.body)) + end + + # Get the current automatic CT-e search settings. + # + # @param company_id [String] + # @return [Nfe::InboundSettings] + def get_settings(company_id:) + id = Nfe::IdValidator.company_id(company_id) + response = get("/v2/companies/#{id}/inbound/transportationinvoices") + hydrate(Nfe::InboundSettings, parse_json(response.body)) + end + + # Retrieve CT-e metadata by its 44-digit access key (normalized). + # + # @param company_id [String] + # @param access_key [String] 44-digit key; separators are stripped. + # @return [Nfe::InboundInvoiceMetadata] + def retrieve(company_id:, access_key:) + id = Nfe::IdValidator.company_id(company_id) + key = Nfe::IdValidator.access_key(access_key) + response = get("/v2/companies/#{id}/inbound/#{key}") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Download the CT-e XML by access key. + # + # @param company_id [String] + # @param access_key [String] + # @return [String] raw XML bytes (+ASCII-8BIT+). + def download_xml(company_id:, access_key:) + id = Nfe::IdValidator.company_id(company_id) + key = Nfe::IdValidator.access_key(access_key) + download("/v2/companies/#{id}/inbound/#{key}/xml", headers: xml_accept) + end + + # Retrieve the metadata of an event related to a received CT-e. + # + # @param company_id [String] + # @param access_key [String] + # @param event_key [String] + # @return [Nfe::InboundInvoiceMetadata] + def get_event(company_id:, access_key:, event_key:) + id = Nfe::IdValidator.company_id(company_id) + key = Nfe::IdValidator.access_key(access_key) + ev = Nfe::IdValidator.event_key(event_key) + response = get("/v2/companies/#{id}/inbound/#{key}/events/#{ev}") + hydrate(Nfe::InboundInvoiceMetadata, parse_json(response.body)) + end + + # Download the XML of a CT-e event. + # + # @param company_id [String] + # @param access_key [String] + # @param event_key [String] + # @return [String] raw XML bytes (+ASCII-8BIT+). + def download_event_xml(company_id:, access_key:, event_key:) + id = Nfe::IdValidator.company_id(company_id) + key = Nfe::IdValidator.access_key(access_key) + ev = Nfe::IdValidator.event_key(event_key) + download("/v2/companies/#{id}/inbound/#{key}/events/#{ev}/xml", headers: xml_accept) + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + def xml_accept + { "Accept" => "application/xml" } + end + + # Drop +nil+ values so optional fields are omitted from the body. + def compact(hash) + hash.compact + end + end + end +end diff --git a/lib/nfe/resources/webhooks.rb b/lib/nfe/resources/webhooks.rb new file mode 100644 index 0000000..ca48c04 --- /dev/null +++ b/lib/nfe/resources/webhooks.rb @@ -0,0 +1,145 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/abstract_resource" +require "nfe/resources/dto/webhook" +require "nfe/webhook" + +module Nfe + module Resources + # Webhooks resource, company-scoped under +/companies/{id}/webhooks+ on the + # +:main+ host family. Exposes CRUD, a synthetic-delivery +test+, the static + # list of available events, and a thin {#verify_signature} delegation to + # {Nfe::Webhook} (the canonical signature-verification API is the module). + class Webhooks < AbstractResource + # The seven event types the NFE.io API can deliver (parity with Node). + AVAILABLE_EVENTS = %w[ + invoice.issued + invoice.cancelled + invoice.failed + invoice.processing + company.created + company.updated + company.deleted + ].freeze + + protected + + def api_family + :main + end + + public + + # List a company's webhook subscriptions. + # + # @param company_id [String] + # @return [Nfe::ListResponse] + def list(company_id) + id = Nfe::IdValidator.company_id(company_id) + response = get("/companies/#{id}/webhooks") + payload = parse_json(response.body) + items = webhook_items(payload).map { |item| hydrate(Nfe::WebhookSubscription, item) } + Nfe::ListResponse.new(data: items) + end + + # Create a webhook subscription. Accepts +url+, +events+, +secret+, +active+. + # + # @param company_id [String] + # @param data [Hash] + # @return [Nfe::Webhook] + def create(company_id, data) + id = Nfe::IdValidator.company_id(company_id) + response = post("/companies/#{id}/webhooks", + body: json_body(data), headers: json_headers) + hydrate(Nfe::WebhookSubscription, parse_json(response.body)) + end + + # Retrieve a webhook by id. + # + # @param company_id [String] + # @param webhook_id [String] + # @return [Nfe::Webhook] + def retrieve(company_id, webhook_id) + id = Nfe::IdValidator.company_id(company_id) + wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id") + response = get("/companies/#{id}/webhooks/#{wid}") + hydrate(Nfe::WebhookSubscription, parse_json(response.body)) + end + + # Update a webhook. + # + # @param company_id [String] + # @param webhook_id [String] + # @param data [Hash] + # @return [Nfe::Webhook] + def update(company_id, webhook_id, data) + id = Nfe::IdValidator.company_id(company_id) + wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id") + response = put("/companies/#{id}/webhooks/#{wid}", + body: json_body(data), headers: json_headers) + hydrate(Nfe::WebhookSubscription, parse_json(response.body)) + end + + # Delete a webhook. + # + # @param company_id [String] + # @param webhook_id [String] + # @return [nil] + def delete(company_id, webhook_id) + id = Nfe::IdValidator.company_id(company_id) + wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id") + super("/companies/#{id}/webhooks/#{wid}") + nil + end + + # Trigger a synthetic delivery to verify a webhook is reachable. + # + # @param company_id [String] + # @param webhook_id [String] + # @return [Hash] +{ success: bool, message: String? }+. + def test(company_id, webhook_id) + id = Nfe::IdValidator.company_id(company_id) + wid = Nfe::IdValidator.presence!(webhook_id, "webhook_id") + response = post("/companies/#{id}/webhooks/#{wid}/test", + body: json_body({}), headers: json_headers) + payload = parse_json(response.body) || {} + { success: payload["success"] || false, message: payload["message"] } + end + + # The static list of webhook event types the API can deliver. + # + # @return [Array] + def get_available_events + AVAILABLE_EVENTS.dup + end + + # Verify a webhook signature. Thin delegation to {Nfe::Webhook} for Node + # parity; the canonical API is the module. Never raises. + # + # @return [Boolean] + def verify_signature(payload:, signature:, secret:) + Nfe::Webhook.verify_signature(payload: payload, signature: signature, secret: secret) + end + + private + + def json_headers + { "Content-Type" => "application/json" } + end + + def json_body(data) + JSON.generate(data) + end + + # Tolerate either a bare array, a +data+-wrapped list, or a +webhooks+ + # envelope for the list response. + def webhook_items(payload) + return payload if payload.is_a?(Array) + return [] unless payload.is_a?(Hash) + + payload["data"] || payload["webhooks"] || payload[:data] || payload[:webhooks] || [] + end + end + end +end diff --git a/lib/nfe/results.rb b/lib/nfe/results.rb new file mode 100644 index 0000000..e7cb315 --- /dev/null +++ b/lib/nfe/results.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Nfe + # Result of an asynchronous (HTTP 202) invoice operation: the API accepted + # the request and is processing it. The document is not yet materialized. + # + # +invoice_id+ is parsed from the +Location+ header's final path segment; + # +location+ is the raw header value. Discriminate against {Nfe::Issued} with + # +is_a?+/+case+ and poll {Nfe::FlowStatus.terminal?} until settled. + class Pending < Data.define(:invoice_id, :location) + end + + # Result of a synchronous (HTTP 201/200) invoice operation: the document was + # materialized immediately. +resource+ is the hydrated DTO value object. + class Issued < Data.define(:resource) + end +end diff --git a/lib/nfe/service_invoice.rb b/lib/nfe/service_invoice.rb deleted file mode 100644 index cec050e..0000000 --- a/lib/nfe/service_invoice.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Nfe - class ServiceInvoice < NfeObject - include ApiResource - include ApiOperations::Create - include ApiOperations::List - include ApiOperations::Retrieve - include ApiOperations::Cancel - include ApiOperations::Update - include ApiOperations::Download - - def self.company_id(company_id) - @company_id = company_id - end - - def self.url - "/v1/companies/#{@company_id}/serviceinvoices" - end - - def url - self.class.url - end - - def self.create_from(params) - params - end - end -end diff --git a/lib/nfe/util.rb b/lib/nfe/util.rb deleted file mode 100644 index 8f41f69..0000000 --- a/lib/nfe/util.rb +++ /dev/null @@ -1,31 +0,0 @@ -module Nfe - class Util - OBJECT_TYPES = { - 'company' => Nfe::Company, - 'serviceInvoice' => Nfe::ServiceInvoice, - 'naturalPeople' => Nfe::NaturalPeople - } - - def self.get_object_type(type) - object_type = Nfe::NfeObject - object_type = OBJECT_TYPES[type] if OBJECT_TYPES[type] - object_type - end - - def self.symbolize_names(object) - case object - when Hash - new = {} - object.each do |key, value| - key = (key.to_sym rescue key) || key - new[key] = symbolize_names(value) - end - new - when Array - object.map { |value| symbolize_names(value) } - else - object - end - end - end -end \ No newline at end of file diff --git a/lib/nfe/version.rb b/lib/nfe/version.rb index 6371d70..b835341 100644 --- a/lib/nfe/version.rb +++ b/lib/nfe/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Nfe - VERSION = "0.3.2" + VERSION = "1.0.0" end diff --git a/lib/nfe/webhook.rb b/lib/nfe/webhook.rb new file mode 100644 index 0000000..99598d0 --- /dev/null +++ b/lib/nfe/webhook.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require "openssl" +require "json" + +module Nfe + # Stateless helpers for verifying NFE.io webhook deliveries. This is the + # canonical signature-verification API: it needs no {Nfe::Client}, reads no + # {Nfe::Configuration}, and performs no network access — the caller supplies + # the raw payload bytes, the +X-Hub-Signature+ header value, and the secret. + # + # == IMPORTANT: pass the RAW request body bytes + # NFE.io signs the exact bytes it delivered. Read the raw body BEFORE parsing + # JSON (e.g. +request.body.read+ in Rack/Rails) and pass those bytes. Do NOT + # re-serialize a parsed object (+payload.to_json+) — key order and whitespace + # will differ from the signed bytes and verification will fail unpredictably. + # + # raw = request.body.read + # sig = request.get_header("HTTP_X_HUB_SIGNATURE") + # if Nfe::Webhook.verify_signature(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) + # event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) + # # event.id => dedupe on this; NFE.io sends no timestamp/nonce, so a valid + # # signature proves authenticity but NOT freshness. Handlers MUST be + # # idempotent and dedupe on the event/invoice id. + # end + # + # Only the +X-Hub-Signature+ + HMAC-SHA1 scheme is supported. The legacy + # +X-NFe-Signature+ / HMAC-SHA256 scheme is intentionally NOT implemented; a + # +sha256=+ header is rejected. + module Webhook + # Wire prefix on the +X-Hub-Signature+ header value. + SIGNATURE_PREFIX = "sha1=" + private_constant :SIGNATURE_PREFIX + + # HMAC-SHA1 hex digests are always 40 lowercase hex characters. + HEX_RE = /\A[a-f0-9]{40}\z/ + private_constant :HEX_RE + + module_function + + # Verify an +X-Hub-Signature+ value against the payload and secret using + # constant-time comparison. Returns +true+ only on an exact HMAC-SHA1 match. + # + # Never raises: any missing, malformed, wrong-algorithm, wrong-length, or + # non-hex input yields +false+. + # + # @param payload [String] the raw, byte-exact request body. + # @param signature [String, Array, nil] the +X-Hub-Signature+ value; + # a single-element Array (repeated-header shape) uses its first element. + # @param secret [String, nil] the webhook secret. + # @return [Boolean] + def verify_signature(payload:, signature:, secret:) + return false if secret.nil? || secret.to_s.empty? + + signature = signature.first if signature.is_a?(Array) + return false if signature.nil? + + signature = signature.to_s + return false if signature.empty? + return false unless signature[0, SIGNATURE_PREFIX.length].to_s.downcase == SIGNATURE_PREFIX + + received = signature[SIGNATURE_PREFIX.length..].to_s.downcase + return false unless HEX_RE.match?(received) + + expected = OpenSSL::HMAC.hexdigest("SHA1", secret, payload.to_s) + OpenSSL.secure_compare(received, expected) + rescue StandardError + false + end + + # Verify, then parse and unwrap a delivery into a {Nfe::WebhookEvent}. + # + # @param payload [String] the raw, byte-exact request body. + # @param signature [String, Array, nil] the +X-Hub-Signature+ value. + # @param secret [String, nil] the webhook secret. + # @return [Nfe::WebhookEvent] + # @raise [Nfe::SignatureVerificationError] when the signature does not match + # or the payload is not valid JSON. + def construct_event(payload:, signature:, secret:) + unless verify_signature(payload: payload, signature: signature, secret: secret) + raise Nfe::SignatureVerificationError, "Assinatura de webhook inválida." + end + + decoded = parse_payload(payload) + build_event(decoded) + end + + # @api private + def parse_payload(payload) + decoded = JSON.parse(payload.to_s) + unless decoded.is_a?(Hash) + raise Nfe::SignatureVerificationError, "Payload de webhook não decodificou para um objeto." + end + + decoded + rescue JSON::ParserError + raise Nfe::SignatureVerificationError, "Payload de webhook não é JSON válido." + end + + # Unwrap the +action+/+payload+ or +event+/+data+ envelope into a + # {Nfe::WebhookEvent}; falls back to a flat +type+/+event_type+/+action+ + # shape carrying the whole body as +data+. + # + # @api private + def build_event(decoded) + type = first_string(decoded, "action", "event", "type", "event_type") + data = envelope_data(decoded) + + Nfe::WebhookEvent.new( + type: type, + data: data, + id: nullable_string(decoded["id"] || data["id"]), + created_at: nullable_string(decoded["createdAt"] || data["createdAt"]) + ) + end + + # @api private + def envelope_data(decoded) + candidate = decoded["payload"] || decoded["data"] + candidate.is_a?(Hash) ? candidate : decoded + end + + # @api private + def first_string(hash, *keys) + keys.each do |key| + value = hash[key] + return value if value.is_a?(String) && !value.empty? + end + nil + end + + # @api private + def nullable_string(value) + value.is_a?(String) ? value : nil + end + end +end diff --git a/lib/nfe/webhook_event.rb b/lib/nfe/webhook_event.rb new file mode 100644 index 0000000..13333b6 --- /dev/null +++ b/lib/nfe/webhook_event.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Nfe + # Immutable value object for a verified webhook delivery, produced by + # {Nfe::Webhook.construct_event} after the HMAC-SHA1 signature checks out. + # + # - +type+ is the event type (e.g. +"invoice.issued"+), unwrapped from the + # delivery envelope's +action+ or +event+ key. + # - +data+ is the payload +Hash+ (the envelope's +payload+ or +data+ key). + # - +id+ is a stable event/invoice id for deduplication, or +nil+ when the + # envelope carries none. NFE.io sends no timestamp/nonce, so a valid + # signature proves authenticity but NOT freshness — handlers MUST be + # idempotent and dedupe on this id. + # - +created_at+ is the delivery timestamp string, or +nil+. + class WebhookEvent < Data.define(:type, :data, :id, :created_at) + # Allow +id+ and +created_at+ to default to +nil+ so callers (and + # +construct_event+) can omit them. + def initialize(type:, data:, id: nil, created_at: nil) + super + end + end +end diff --git a/nfe-io.gemspec b/nfe-io.gemspec new file mode 100644 index 0000000..7d53ef4 --- /dev/null +++ b/nfe-io.gemspec @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require_relative "lib/nfe/version" + +Gem::Specification.new do |spec| + spec.name = "nfe-io" + spec.version = Nfe::VERSION + spec.authors = ["NFE.io Team"] + spec.email = ["suporte@nfe.io"] + + spec.summary = "Official NFE.io SDK for Ruby" + spec.description = "Official NFE.io SDK for Ruby — modern Ruby (3.2+), zero runtime " \ + "dependencies, for issuing and managing Brazilian electronic fiscal " \ + "documents (NFS-e, NF-e, NFC-e, CT-e)." + spec.homepage = "https://nfe.io" + spec.license = "MIT" + spec.required_ruby_version = ">= 3.2" + + spec.metadata = { + "homepage_uri" => spec.homepage, + "source_code_uri" => "https://github.com/nfe/client-ruby", + "changelog_uri" => "https://github.com/nfe/client-ruby/blob/master/CHANGELOG.md", + "documentation_uri" => "https://github.com/nfe/client-ruby/blob/master/README.md", + "bug_tracker_uri" => "https://github.com/nfe/client-ruby/issues", + "rubygems_mfa_required" => "true" + } + + spec.files = Dir[ + "lib/**/*.rb", + "sig/**/*.rbs", + "README.md", + "MIGRATION.md", + "CHANGELOG.md", + "LICENSE.txt" + ] + spec.require_paths = ["lib"] + + # Zero runtime dependencies — Ruby stdlib only (net/http, json, openssl, uri, ...). + # Development tooling only: + spec.add_development_dependency "rake", "~> 13.0" + spec.add_development_dependency "rbs", "~> 3.4" + spec.add_development_dependency "rspec", "~> 3.13" + spec.add_development_dependency "rubocop", "~> 1.75" + spec.add_development_dependency "rubocop-rspec", "~> 3.0" + spec.add_development_dependency "simplecov", "~> 0.22" + spec.add_development_dependency "steep", "~> 1.7" + spec.add_development_dependency "yard", "~> 0.9" +end diff --git a/nfe.gemspec b/nfe.gemspec deleted file mode 100644 index e1cb466..0000000 --- a/nfe.gemspec +++ /dev/null @@ -1,36 +0,0 @@ -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'nfe/version' - -Gem::Specification.new do |spec| - spec.name = "nfe-io" - spec.version = Nfe::VERSION - spec.authors = ["Ricardo Caldeira"] - spec.email = ["ricardo.nezz@gmail.com"] - - spec.summary = %q{Nfe.io's ruby gem} - spec.description = %q{Nfe.io's ruby gem} - spec.homepage = "https://pluga.co/" - spec.license = "MIT" - - # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or - # delete this section to allow pushing this gem to any host. - # if spec.respond_to?(:metadata) - # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" - # else - # raise "RubyGems 2.0 or newer is required to protect against public gem pushes." - # end - - spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - spec.bindir = "exe" - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.require_paths = ["lib"] - - spec.add_dependency "rest-client", "~> 2.0.2" - - spec.add_development_dependency "bundler", "~> 1.10" - spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "rspec" - spec.add_development_dependency "byebug" -end diff --git a/openapi/README.md b/openapi/README.md new file mode 100644 index 0000000..9fb4429 --- /dev/null +++ b/openapi/README.md @@ -0,0 +1,30 @@ +# OpenAPI specs + +These OpenAPI documents are the **source of truth** for the generated value +objects under `lib/nfe/generated/` (and their signatures under +`sig/nfe/generated/`). They are **copied manually** from the official +documentation repository after review — never hand-edited here. + +- **Source:** `nfeio-docs` → `docs/static/api/` (https://nfe.io). +- **Snapshot:** 2026-06-24. +- **Sync:** `rake openapi:sync` copies the spec set from `nfeio-docs` + (path configurable via `NFEIO_DOCS_PATH`) into this directory and reports the + diff. It does **not** run `rake generate` or commit — that is a deliberate + human review step. See `CONTRIBUTING.md`. + +## How specs map to generated code + +Each spec produces one generated family namespace `Nfe::Generated::` +(e.g. `service-invoice-rtc-v1.yaml` → `Nfe::Generated::ServiceInvoiceRtcV1`), +with one `Data.define` value object per schema under `components.schemas`. + +`.json` specs (e.g. `contribuintes-v2.json`, `consumer-invoice.json`) are parsed +directly — JSON is valid YAML, so the loader (Psych) reads both. + +## Specs without `components.schemas` + +Some specs declare their request/response shapes inline under `operations[...]` +rather than in `components.schemas`. Those produce **no** generated namespace; +the DTOs they would need are hand-written in the resource changes instead. The +generator logs each skipped spec. (Known examples include `nf-servico-v1.yaml` +and `cpf-api.yaml` — the definitive list is reported by `rake generate`.) diff --git a/openapi/calculo-impostos-v1.yaml b/openapi/calculo-impostos-v1.yaml new file mode 100644 index 0000000..8cdd57b --- /dev/null +++ b/openapi/calculo-impostos-v1.yaml @@ -0,0 +1,855 @@ +openapi: 3.0.1 +info: + title: Cálculo de Impostos + x-displayName: Introdução + description: "# Introdução\r\n\r\nSeja bem-vindo a documentação da API de Cálculo de Impostos!\r\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\r\n\r\n# Como usar a API?\r\nLogo a seguir você encontrará todos os recursos e métodos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\r\n\r\n# Autenticação\r\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API.\r\nPara isso você deve colocar sua chave de API no campo que se encontra no topo desta página para que os métodos funcionem corretamente.\r\nNo seu código de integração temos suporte para autenticação de diversas formas sendo eles:\r\nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key)." + version: v1 +servers: + - url: https://api.nfse.io + description: Produção +paths: + /tax-codes/operation-code: + get: + tags: + - Códigos Auxiliares + summary: Listar Códigos de Operação + parameters: + - name: pageIndex + in: query + description: Índice da página para paginação + schema: + type: integer + format: int32 + default: 1 + - name: pageCount + in: query + description: Número de itens por página + schema: + type: integer + format: int32 + default: 50 + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TaxCodePaginatedResponse' + /tax-codes/acquisition-purpose: + get: + tags: + - Códigos Auxiliares + summary: Listar Finalidades de Aquisição + parameters: + - name: pageIndex + in: query + description: Índice da página para paginação + schema: + type: integer + format: int32 + default: 1 + - name: pageCount + in: query + description: Número de itens por página + schema: + type: integer + format: int32 + default: 50 + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TaxCodePaginatedResponse' + /tax-codes/issuer-tax-profile: + get: + tags: + - Códigos Auxiliares + summary: Listar Perfis Fiscais do Emissor + parameters: + - name: pageIndex + in: query + description: Índice da página para paginação + schema: + type: integer + format: int32 + default: 1 + - name: pageCount + in: query + description: Número de itens por página + schema: + type: integer + format: int32 + default: 50 + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TaxCodePaginatedResponse' + /tax-codes/recipient-tax-profile: + get: + tags: + - Códigos Auxiliares + summary: Listar Perfis Fiscais do Destinatário + parameters: + - name: pageIndex + in: query + description: Índice da página para paginação + schema: + type: integer + format: int32 + default: 1 + - name: pageCount + in: query + description: Número de itens por página + schema: + type: integer + format: int32 + default: 50 + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TaxCodePaginatedResponse' + /tax-rules/{tenantId}/engine/calculate: + post: + tags: + - Motor de Cálculo + summary: Calcula os impostos de uma operação. + parameters: + - name: tenantId + in: path + description: O identificador da conta. + required: true + schema: + type: string + requestBody: + description: A solicitação contendo os detalhes da operação e produtos. + content: + application/json: + schema: + $ref: '#/components/schemas/CalculateRequest' + application/jose: + schema: + $ref: '#/components/schemas/CalculateRequest' + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/CalculateResponse' + application/jose: + schema: + $ref: '#/components/schemas/CalculateResponse' + "400": + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/jose: + schema: + $ref: '#/components/schemas/ProblemDetails' + "422": + description: Unprocessable Content + content: + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/jose: + schema: + $ref: '#/components/schemas/ProblemDetails' +components: + schemas: + CalculateItemRequest: + required: + - id + - operationCode + - origin + - quantity + - unitAmount + type: object + properties: + id: + minLength: 1 + type: string + description: Identificador do Item + operationCode: + maximum: 9999 + minimum: 1 + type: integer + description: Código interno para determinação de natureza de operação + format: int32 + acquisitionPurpose: + type: string + description: Finalidade + nullable: true + issuerTaxProfile: + type: string + description: Perfil do Emitente para Cálculo de Impostos do Item + nullable: true + recipientTaxProfile: + type: string + description: Perfil do Tomador para Cálculo de Impostos do Item + nullable: true + sku: + type: string + description: Código do Produto + nullable: true + ncm: + maxLength: 8 + minLength: 0 + type: string + description: Nomenclatura Comum do Mercosul + nullable: true + cest: + maxLength: 7 + minLength: 7 + type: string + description: Código Especificador da Substituição Tributária + nullable: true + benefit: + type: string + description: Código do benefício fiscal + nullable: true + exTipi: + maxLength: 3 + minLength: 1 + type: string + description: Código EX da TIPI + nullable: true + origin: + $ref: '#/components/schemas/Origin' + gtin: + type: string + description: Global Trade Item Number + nullable: true + quantity: + type: number + description: Quantidade Tributável + format: double + unitAmount: + type: number + description: Valor Unitário Tributável + format: double + freightAmount: + type: number + description: Valor do Frete + format: double + nullable: true + insuranceAmount: + type: number + description: Valor do Seguro + format: double + nullable: true + discountAmount: + type: number + description: Valor do Desconto + format: double + nullable: true + othersAmount: + type: number + description: Outras despesas acessórias + format: double + nullable: true + icms: + $ref: '#/components/schemas/Icms' + ii: + $ref: '#/components/schemas/Ii' + additionalProperties: false + CalculateItemResponse: + type: object + properties: + id: + type: string + description: Identificador do Item + nullable: true + cfop: + type: integer + description: Código Fiscal de Operações e Prestações + format: int32 + cest: + type: string + description: Código Especificador de Substituição Tributária + nullable: true + benefit: + type: string + description: Código do benefício fiscal + nullable: true + icms: + $ref: '#/components/schemas/Icms' + icmsUfDest: + $ref: '#/components/schemas/IcmsUfDest' + pis: + $ref: '#/components/schemas/Pis' + cofins: + $ref: '#/components/schemas/Cofins' + ipi: + $ref: '#/components/schemas/Ipi' + ii: + $ref: '#/components/schemas/Ii' + additionalInformation: + type: string + description: Informações Adicionais do Produto + nullable: true + lastModified: + type: string + description: Data da última alteração da regra + format: date-time + productId: + type: string + description: Registered Product Id + nullable: true + additionalProperties: false + CalculateRequest: + required: + - issuer + - items + - operationType + - recipient + type: object + properties: + collectionId: + type: string + description: Identificador da Coleção de Produtos + nullable: true + issuer: + $ref: '#/components/schemas/CalculateRequestIssuer' + recipient: + $ref: '#/components/schemas/CalculateRequestRecipient' + operationType: + $ref: '#/components/schemas/OperationType' + items: + type: array + items: + $ref: '#/components/schemas/CalculateItemRequest' + description: Lista de Produtos + isProductRegistration: + type: boolean + description: Identificador da tipo de requisição (emissão de nota fiscal ou cadastro de produto) + additionalProperties: false + CalculateRequestIssuer: + required: + - state + - taxRegime + type: object + properties: + taxRegime: + $ref: '#/components/schemas/TaxRegime' + taxProfile: + type: string + description: Perfil Padrão do Emitente para Cálculo de Impostos + nullable: true + state: + $ref: '#/components/schemas/State' + additionalProperties: false + CalculateRequestRecipient: + required: + - state + type: object + properties: + taxRegime: + $ref: '#/components/schemas/TaxRegime' + taxProfile: + type: string + description: Perfil Padrão do Tomador para Cálculo de Impostos + nullable: true + state: + $ref: '#/components/schemas/State' + additionalProperties: false + CalculateResponse: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/CalculateItemResponse' + nullable: true + additionalProperties: false + Cofins: + type: object + properties: + cst: + type: string + description: Código de Situação Tributária da COFINS + nullable: true + vBC: + type: string + description: Valor da Base de Cálculo do COFINS + nullable: true + pCOFINS: + type: string + description: Alíquota do COFINS (em percentual) + nullable: true + vCOFINS: + type: string + description: Valor do COFINS + nullable: true + qBCProd: + type: string + description: Quantidade Vendida + nullable: true + vAliqProd: + type: string + description: Alíquota do COFINS (em reais) + nullable: true + additionalProperties: false + Icms: + type: object + properties: + orig: + type: string + description: Origem da mercadoria + nullable: true + cst: + type: string + description: Tributação do ICMS + nullable: true + csosn: + type: string + description: Código de Situação da Operação – Simples Nacional + nullable: true + modBC: + type: string + description: Modalidade de determinação da BC do ICMS + nullable: true + vBC: + type: string + description: Valor da BC do ICMS + nullable: true + pRedBC: + type: string + description: Percentual da Redução de BC + nullable: true + cBenefRBC: + type: string + description: Código do benefício fiscal relacionado a redução de base + nullable: true + pICMS: + type: string + description: Alíquota do imposto + nullable: true + vICMS: + type: string + description: Valor do ICMS + nullable: true + vICMSOp: + type: string + description: Valor do ICMS da Operação + nullable: true + modBCST: + type: string + description: Modalidade de determinação da BC do ICMS ST + nullable: true + vBCST: + type: string + description: Valor da BC do ICMS ST + nullable: true + pRedBCST: + type: string + description: Percentual da Redução de BC do ICMS ST + nullable: true + pICMSST: + type: string + description: Alíquota do imposto do ICMS ST + nullable: true + vICMSST: + type: string + description: Valor do ICMS ST + nullable: true + pMVAST: + type: string + description: Percentual da margem de valor Adicionado do ICMS ST + nullable: true + pST: + type: string + description: Alíquota suportada pelo Consumidor Final + nullable: true + vBCSTRet: + type: string + description: Valor da BC do ICMS ST retido + nullable: true + vICMSSTRet: + type: string + description: Valor do ICMS ST retido + nullable: true + vBCFCP: + type: string + description: Valor da Base de Cálculo do FCP + nullable: true + pFCP: + type: string + description: Percentual do ICMS relativo ao Fundo de Combate à Pobreza(FCP) + nullable: true + vFCP: + type: string + description: Valor do Fundo de Combate à Pobreza (FCP) + nullable: true + vBCFCPST: + type: string + description: Valor da Base de Cálculo do FCP retido por Substituição Tributária + nullable: true + pFCPST: + type: string + description: Percentual do FCP retido por Substituição Tributária + nullable: true + vFCPST: + type: string + description: Valor do FCP retido por Substituição Tributária + nullable: true + vBCFCPSTRet: + type: string + description: Valor da Base de Cálculo do FCP retido anteriormente + nullable: true + pFCPSTRet: + type: string + description: Percentual do FCP retido anteriormente por Substituição Tributária + nullable: true + vFCPSTRet: + type: string + description: Valor do FCP retido por Substituição Tributária + nullable: true + vBCEfet: + type: string + description: Valor da base de cálculo efetiva + nullable: true + pRedBCEfet: + type: string + description: Percentual de redução da base de cálculo efetiva + nullable: true + pICMSEfet: + type: string + description: Alíquota do ICMS efetiva + nullable: true + vICMSEfet: + type: string + description: Valor do ICMS efetivo + nullable: true + pDif: + type: string + description: Percentual do diferimento + nullable: true + vICMSDif: + type: string + description: Valor do ICMS diferido + nullable: true + vICMSSubstituto: + type: string + description: Valor do ICMS próprio do Substituto + nullable: true + pCredSN: + type: string + description: Alíquota aplicável de cálculo do crédito (Simples Nacional) + nullable: true + vCredICMSSN: + type: string + description: Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) + nullable: true + pFCPDif: + type: string + description: Percentual do diferimento do ICMS relativo ao Fundo de Combate à Pobreza(FCP) + nullable: true + vFCPDif: + type: string + description: Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP) diferido + nullable: true + vFCPEfet: + type: string + description: Valor efetivo do ICMS relativo ao Fundo de Combate à Pobreza(FCP) + nullable: true + vICMSDeson: + type: string + description: Valor do ICMS desonerado + nullable: true + motDesICMS: + type: string + description: Motivo da desoneração do ICMS + nullable: true + vICMSSTDeson: + type: string + description: Valor do ICMS- ST desonerado + nullable: true + motDesICMSST: + type: string + description: Motivo da desoneração do ICMS- ST + nullable: true + indDeduzDeson: + type: string + description: Indica se o valor do ICMS desonerado (vICMSDeson) deduz do valor do item(vProd). + nullable: true + additionalProperties: false + IcmsUfDest: + type: object + properties: + vBCUFDest: + type: string + description: Valor da BC do ICMS na UF de destino + nullable: true + vBCFCPUFDest: + type: string + description: Valor da BC FCP na UF de destino + nullable: true + pFCPUFDest: + type: string + description: "Percentual do ICMS relativo ao Fundo de Combate à\r\nPobreza (FCP) na UF de destino" + nullable: true + pICMSUFDest: + type: string + description: Alíquota interna da UF de destino + nullable: true + pICMSInter: + type: string + description: Alíquota interestadual das UF envolvidas + nullable: true + pICMSInterPart: + type: string + description: Percentual provisório de partilha do ICMS Interestadual + nullable: true + vFCPUFDest: + type: string + description: Valor da BC FCP na UF de destino + nullable: true + vICMSUFDest: + type: string + description: Valor do ICMS Interestadual para a UF de destino + nullable: true + vICMSUFRemet: + type: string + description: Valor do ICMS Interestadual para a UF do remetente + nullable: true + additionalProperties: false + Ii: + type: object + properties: + vBC: + type: string + description: Valor BC do Imposto de Importação + nullable: true + vDespAdu: + type: string + description: Valor despesas aduaneiras + nullable: true + vII: + type: string + description: Valor Imposto de Importação + nullable: true + vIOF: + type: string + description: Valor Imposto sobre Operações Financeiras + nullable: true + vEncCamb: + type: string + description: Valor dos encargos cambiais + nullable: true + pCredSN: + type: string + description: Alíquota do Simples Nacional aplicável no cálculo do crédito pelo contribuinte destinatário. + nullable: true + vCredICMSSN: + type: string + description: Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) + nullable: true + infCustoAquis: + type: string + description: "Ativação do cálculo do custo de aquisição:\r\n0 – Inativo\r\n1 – Ativo" + nullable: true + additionalProperties: false + Ipi: + type: object + properties: + cEnq: + type: string + description: Código de Enquadramento Legal do IPI + nullable: true + cst: + type: string + description: Código da situação tributária do IPI + nullable: true + vBC: + type: string + description: Valor da BC do IPI + nullable: true + pIPI: + type: string + description: Alíquota do IPI + nullable: true + qUnid: + type: string + description: Quantidade total na unidade padrão para tributação (somente para os produtos tributados por unidade) + nullable: true + vUnid: + type: string + description: Valor por Unidade Tributável + nullable: true + vIPI: + type: string + description: Valor do IPI + nullable: true + additionalProperties: false + OperationType: + enum: + - Outgoing + - Incoming + type: string + description: "

Possible values:

\r\n
    \r\n
  • Outgoing: 0 - Saída
  • \r\n
  • Incoming: 1 - Entrada
  • \r\n
\r\n" + Origin: + enum: + - National + - ForeignDirectImport + - ForeignInternalMarket + - NationalWith40To70Import + - NationalPpb + - NationalWithLess40Import + - ForeignDirectImportWithoutNationalSimilar + - ForeignInternalMarketWithoutNationalSimilar + - NationalWithGreater70Import + type: string + description: "

Possible values:

\r\n
    \r\n
  • National: 0 - Nacional, exceto as indicadas nos códigos 3, 4, 5 e 8
  • \r\n
  • ForeignDirectImport: 1 - Estrangeira - Importação direta, exceto a indicada no código 6
  • \r\n
  • ForeignInternalMarket: 2 - Estrangeira - Adquirida no mercado interno, exceto a indicada no código 7
  • \r\n
  • NationalWith40To70Import: 3 - Nacional, mercadoria ou bem com Conteúdo de Importação superior a 40% e inferior ou igual a 70%
  • \r\n
  • NationalPpb: 4 - Nacional, cuja produção tenha sido feita em conformidade com os PPB de que tratam as legislações citadas nos ajustes
  • \r\n
  • NationalWithLess40Import: 5 - Nacional, mercadoria ou bem com Conteúdo de Importação inferior ou igual a 40%
  • \r\n
  • ForeignDirectImportWithoutNationalSimilar: 6 - Estrangeira - Importação direta, sem similar nacional, constante em lista da CAMEX e gás natural
  • \r\n
  • ForeignInternalMarketWithoutNationalSimilar: 7 - Estrangeira - Adquirida no mercado interno, sem similar nacional, constante em lista da CAMEX e gás natural
  • \r\n
  • NationalWithGreater70Import: 8 - Nacional, mercadoria ou bem com Conteúdo de Importação superior a 70%
  • \r\n
\r\n" + Pis: + type: object + properties: + cst: + type: string + description: Código de Situação Tributária do PIS + nullable: true + vBC: + type: string + description: Valor da Base de Cálculo do PIS + nullable: true + pPIS: + type: string + description: Alíquota do PIS (em percentual) + nullable: true + vPIS: + type: string + description: Valor do PIS + nullable: true + qBCProd: + type: string + description: Quantidade Vendida + nullable: true + vAliqProd: + type: string + description: Alíquota do PIS (em reais) + nullable: true + additionalProperties: false + ProblemDetails: + type: object + properties: + type: + type: string + nullable: true + title: + type: string + nullable: true + status: + type: integer + format: int32 + nullable: true + detail: + type: string + nullable: true + instance: + type: string + nullable: true + additionalProperties: {} + State: + enum: + - AC + - AL + - AP + - AM + - BA + - CE + - DF + - ES + - GO + - MA + - MT + - MS + - MG + - PA + - PB + - PR + - PE + - PI + - RJ + - RN + - RS + - RO + - RR + - SC + - SP + - SE + - TO + - EX + type: string + description: "

Possible values:

\r\n
    \r\n
  • AC: Acre
  • \r\n
  • AL: Alagoas
  • \r\n
  • AP: Amapá
  • \r\n
  • AM: Amazonas
  • \r\n
  • BA: Bahia
  • \r\n
  • CE: Ceará
  • \r\n
  • DF: Distrito Federal
  • \r\n
  • ES: Espírito Santo
  • \r\n
  • GO: Goiás
  • \r\n
  • MA: Maranhão
  • \r\n
  • MT: Mato Grosso
  • \r\n
  • MS: Mato Grosso do Sul
  • \r\n
  • MG: Minas Gerais
  • \r\n
  • PA: Pará
  • \r\n
  • PB: Paraíba
  • \r\n
  • PR: Paraná
  • \r\n
  • PE: Pernambuco
  • \r\n
  • PI: Piauí
  • \r\n
  • RJ: Rio de Janeiro
  • \r\n
  • RN: Rio Grande do Norte
  • \r\n
  • RS: Rio Grande do Sul
  • \r\n
  • RO: Rondônia
  • \r\n
  • RR: Roraima
  • \r\n
  • SC: Santa Catarina
  • \r\n
  • SP: São Paulo
  • \r\n
  • SE: Sergipe
  • \r\n
  • TO: Tocantins
  • \r\n
  • EX: Exterior
  • \r\n
\r\n" + TaxCode: + type: object + properties: + code: + type: string + nullable: true + description: + type: string + nullable: true + additionalProperties: false + TaxCodePaginatedResponse: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/TaxCode' + nullable: true + currentPage: + type: integer + format: int32 + totalPages: + type: integer + format: int32 + readOnly: true + totalCount: + type: integer + format: int64 + additionalProperties: false + TaxRegime: + enum: + - NationalSimple + - RealProfit + - PresumedProfit + - NationalSimpleSublimitExceeded + - IndividualMicroEnterprise + - Exempt + type: string + description: "

Possible values:

\r\n
    \r\n
  • NationalSimple: Simples Nacional
  • \r\n
  • RealProfit: Lucro Real
  • \r\n
  • PresumedProfit: Lucro Presumido
  • \r\n
  • NationalSimpleSublimitExceeded: Simples Nacional sublimite excedido
  • \r\n
  • IndividualMicroEnterprise: Microempreendedor Individual
  • \r\n
  • Exempt: Isento
  • \r\n
\r\n" + securitySchemes: + Authorization_Header: + type: apiKey + description: Autenticar usando o cabeçalho HTTP + name: Authorization + in: header + Authorization_QueryParam: + type: apiKey + description: Autenticar usando o parâmetro na URL + name: apikey + in: query + Authorization_JwtBearer: + type: http + description: Autenticar usando o cabeçalho HTTP + scheme: bearer + bearerFormat: Json Web Token +security: + - Authorization_Header: [] + Authorization_QueryParam: [] + - Authorization_JwtBearer: [] +tags: + - name: Códigos Auxiliares + description: Nesta sessão estão disponíveis informações necessárias para listar os códigos auxiliares disponíveis para serem utilizados nas chamadas com cálculo de impostos. diff --git a/openapi/consulta-cnpj.yaml b/openapi/consulta-cnpj.yaml new file mode 100644 index 0000000..f7fd69b --- /dev/null +++ b/openapi/consulta-cnpj.yaml @@ -0,0 +1,1131 @@ +swagger: "2.0" +info: + version: v2 + title: Legal Entities API + x-sidebarLabel: Introdução + x-description: Teste + description:

Como utilizar esta documentação ?

Certifique-se que sua chave da API está preenchida no topo desta página para este recurso funcionar da maneira correta. Abaixo você poderá conferir a lista de recursos que podem ser manipulados através da API. Clicando em cada um dos métodos, você poderá verificar a lista de parâmetros, possíveis retornos e também um formulário. Este formulário pode ser utilizado para efetuar requisições reais na API.

+host: legalentity.api.nfe.io +schemes: + - https +paths: + /v2/legalentities/basicInfo/{federalTaxNumber}: + get: + tags: + - LegalEntities + summary: Consulta de dados do CNPJ + description: Você precisará do APIKEY da Empresa + operationId: V2LegalentitiesBasicInfoByFederalTaxNumberGet + consumes: [] + produces: + - application/json + parameters: + - name: federalTaxNumber + in: path + description: CNPJ + required: true + type: integer + format: int64 + - name: updateAddress + in: query + description: 'Define se deseja ou não atualizar o endereço do cartão CNPJ com base nos correios (Default: true)' + required: false + type: boolean + - name: updateCityCode + in: query + description: 'Quando updateAddress=false, define se deseja ou não atualizar somente o código da cidade utilizando o código postal com base nos correios (Default: false)' + required: false + type: boolean + responses: + "200": + description: Sucesso na requisição + schema: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.LegalPersonResourceV2' + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Empresa não encontrada para o CNPJ informado + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - CheckClaimOrRole + - Authorization_QueryParam: + - CheckClaimOrRole + /v2/legalentities/stateTaxInfo/{state}/{federalTaxNumber}: + get: + tags: + - LegalEntities + summary: Consulta de Inscrição Estadual por CNPJ + description: Você precisará do APIKEY da Empresa + operationId: V2LegalentitiesStateTaxInfoByStateByFederalTaxNumberGet + consumes: [] + produces: + - application/json + parameters: + - name: state + in: path + description: Código do IBGE do Estado que deseja consultar + required: true + type: string + enum: + - AC + - AL + - AM + - AP + - BA + - CE + - DF + - ES + - GO + - MA + - MG + - MS + - MT + - PA + - PB + - PE + - PI + - PR + - RJ + - RN + - RO + - RR + - RS + - SC + - SE + - SP + - TO + - EX + - NA + - name: federalTaxNumber + in: path + description: Número do documento que deseja consultar + required: true + type: integer + format: int64 + responses: + "200": + description: Sucesso na requisição + schema: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxResourceV2' + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "500": + description: Erro no processamento + schema: + type: string + "403": + description: Accesso proibido + security: + - Authorization_Header: + - CheckClaimOrRole + - Authorization_QueryParam: + - CheckClaimOrRole + /v2/legalentities/stateTaxForInvoice/{state}/{federalTaxNumber}: + get: + tags: + - LegalEntities + summary: Consulta de Inscrição Estadual por CNPJ para avalição de Emissão de Nota Fiscal de Produto + description: Você precisará do APIKEY da Empresa + operationId: V2LegalentitiesStateTaxForInvoiceByStateByFederalTaxNumberGet + consumes: [] + produces: + - application/json + parameters: + - name: state + in: path + description: Código do IBGE do Estado que deseja consultar + required: true + type: string + enum: + - AC + - AL + - AM + - AP + - BA + - CE + - DF + - ES + - GO + - MA + - MG + - MS + - MT + - PA + - PB + - PE + - PI + - PR + - RJ + - RN + - RO + - RR + - RS + - SC + - SE + - SP + - TO + - EX + - NA + - name: federalTaxNumber + in: path + description: Número do documento que deseja consultar + required: true + type: integer + format: int64 + responses: + "200": + description: Sucesso na requisição + schema: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceCompleteResource' + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "500": + description: Erro no processamento + schema: + type: string + "403": + description: Accesso proibido + security: + - Authorization_Header: + - CheckClaimOrRole + - Authorization_QueryParam: + - CheckClaimOrRole + /v2/legalentities/stateTaxSuggestedForInvoice/{state}/{federalTaxNumber}: + get: + tags: + - LegalEntities + summary: "Consulta de Inscrição Estadual por CNPJ para avalição de Emissão de Nota Fiscal de Produto\r\nCaso existir mais de uma HABILITADA, será retornado a melhor inscrição estadual para emitir nota em critério de avaliação da NFE.io" + description: Você precisará do APIKEY da Empresa + operationId: V2LegalentitiesStateTaxSuggestedForInvoiceByStateByFederalTaxNumberGet + consumes: [] + produces: + - application/json + parameters: + - name: state + in: path + description: Código do IBGE do Estado que deseja consultar + required: true + type: string + enum: + - AC + - AL + - AM + - AP + - BA + - CE + - DF + - ES + - GO + - MA + - MG + - MS + - MT + - PA + - PB + - PE + - PI + - PR + - RJ + - RN + - RO + - RR + - RS + - SC + - SE + - SP + - TO + - EX + - NA + - name: federalTaxNumber + in: path + description: Número do documento que deseja consultar + required: true + type: integer + format: int64 + responses: + "200": + description: Sucesso na requisição + schema: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceCompleteResource' + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "500": + description: Erro no processamento + schema: + type: string + "403": + description: Accesso proibido + security: + - Authorization_Header: + - CheckClaimOrRole + - Authorization_QueryParam: + - CheckClaimOrRole +definitions: + DataTech.Api.Resources.LegalEntities.TaxRegimeResource: + type: object + properties: + createdOn: + format: date-time + description: 'Data de Consulta do usuário - Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.' + type: string + optedInOn: + format: date-time + description: 'Data de opção pelo atual Regime Tributário - Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.' + type: string + taxRegime: + description: Regime Tributário Atual + type: string + name: + description: Razão social + type: string + federalTaxNumber: + description: Número da inscrição na Receita Federal (CNPJ) + type: string + previousDetails: + description: Lista de Períodos Anteriores + type: array + items: + $ref: '#/definitions/DataTech.Services.Domain.Models.SimplesNacionalScrapOutItem+History' + DataTech.Services.Domain.Models.SimplesNacionalScrapOutItem+History: + type: object + properties: + taxRegime: + description: Regime Tributário + type: string + beginOn: + format: date-time + description: 'Data Inicial - Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.' + type: string + endOn: + format: date-time + description: 'Data Final - Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.' + type: string + description: + description: Detalhamento + type: string + DataTech.Api.Resources.LegalEntities.LegalPersonResource: + type: object + properties: + tradeName: + description: Nome fantasia + type: string + name: + description: Razão social + type: string + federalTaxNumber: + description: Número da inscrição na Receita Federal (CNPJ) + type: string + size: + description: Porte + type: string + openedOn: + format: date-time + description: Data da abertura + type: string + address: + $ref: '#/definitions/DataTech.Services.Domain.Models.Address' + description: Endereço + phones: + description: Número de telefone + type: array + items: + $ref: '#/definitions/DataTech.Services.Domain.Models.Phone' + statusOn: + format: date-time + description: Data da situação cadastral + type: string + status: + description: Situação cadastral + type: string + email: + description: Correio eletrônico + type: string + responsableEntity: + description: Ente Federativo Responsável (EFR) + type: string + specialStatus: + description: Situação Especial + type: string + specialStatusOn: + format: date-time + description: Data da Situação Especial + type: string + issuedOn: + format: date-time + description: Data de Consulta do usuário + type: string + statusReason: + description: Motivo da Situação Cadastral + type: string + shareCapital: + format: double + description: Capital sócial (em reais) + type: number + economicActivities: + description: Objeto com Código e descrição das atividades econômicas principal e secundárias + type: array + items: + $ref: '#/definitions/DataTech.Services.Domain.Models.Activity' + legalNature: + $ref: '#/definitions/DataTech.Services.Domain.Models.Item' + description: Objeto com Código e descrição da Natureza Legal + partners: + description: Objeto com nome e qualificação dos sócios e administradores + type: array + items: + $ref: '#/definitions/DataTech.Services.Domain.Models.Partner' + registrationUnit: + description: Objeto com a cidade/unidade registradora do certificado de baixa + type: string + unit: + description: Objeto que define se é matriz, filial ou sucursal + enum: + - Headoffice + - Subsidiary + type: string + DataTech.Services.Domain.Models.Address: + type: object + properties: + state: + description: Estado (UF) + type: string + city: + $ref: '#/definitions/DataTech.Services.Domain.Models.CityBase' + description: Cidade + district: + description: Bairro (xBairro) + type: string + additionalInformation: + description: Complemento (xCpl) + type: string + streetSuffix: + description: Tipo do Logradouro + type: string + street: + description: Logradouro do Endereco (xLgr) + type: string + number: + description: Número (nro) + type: string + postalCode: + description: Código Endereço Postal (CEP) + type: string + country: + description: País + type: string + DataTech.Services.Domain.Models.Phone: + type: object + properties: + ddd: + description: Prefixo + type: string + number: + description: Número do telefone + type: string + source: + description: Origem da Informação + enum: + - RFB + type: string + DataTech.Services.Domain.Models.Activity: + type: object + properties: + isMain: + description: Verificador se é atividade principal ou secundária + type: boolean + code: + description: Código da Atividade Econômica + type: string + description: + description: Descrição da Atividade Econômica + type: string + DataTech.Services.Domain.Models.Item: + type: object + properties: + code: + description: Código da Atividade Econômica + type: string + description: + description: Descrição da Atividade Econômica + type: string + DataTech.Services.Domain.Models.Partner: + type: object + properties: + name: + description: Nome/Nome Empresarial + type: string + qualification: + $ref: '#/definitions/DataTech.Services.Domain.Models.Qualification' + description: Qualificação do Quadro de Sócios e Administradores + DataTech.Services.Domain.Models.CityBase: + type: object + properties: + code: + description: Código do município (cMun) + type: string + name: + description: Nome do município (xMun) + type: string + DataTech.Services.Domain.Models.Qualification: + type: object + properties: + code: + description: Código Qualificação do Quadro de Sócios e Administradores + type: string + description: + description: Descrição da Qualificação do Quadro de Sócios e Administradores + type: string + DataTech.Api.Resources.LegalEntities.StateTaxInfoResource: + type: object + properties: + createdOn: + format: date-time + description: Data de Consulta + type: string + name: + description: Razão social + type: string + tradeName: + description: Nome Fantasia + type: string + federalTaxNumber: + description: Número da inscrição na Receita Federal (CNPJ) + type: string + taxPayer: + description: Lista de Contribuites(Inscrição Estadual) + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.TaxPayerResource' + DataTech.Api.Resources.LegalEntities.TaxPayerResource: + type: object + properties: + stateTaxNumber: + description: Inscrição Estadual (IE) + type: string + state: + $ref: '#/definitions/DataTech.Services.Domain.Models.StateBase' + description: Estado (IE) + typeStateTax: + description: Tipo Inscrição Estadual (IE) + type: string + statusOnStateTax: + format: date-time + description: Data da situação na UF + type: string + statusStateTax: + description: Situação IE + type: string + statusFederalTax: + description: Situação CNPJ + type: string + openedOn: + format: date-time + description: Data da abertura + type: string + closedOn: + format: date-time + description: Data fim atividade + type: string + cnae: + format: int64 + description: CNAE fiscal (CNAE) + type: integer + DataTech.Services.Domain.Models.StateBase: + type: object + properties: + code: + type: string + abbreviation: + type: string + name: + type: string + DataTech.Api.Resources.LegalEntities.LegalPersonResourceV2: + type: object + properties: + legalEntity: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.LegalPersonResourceV2Item' + description: Pessoa jurídica + DataTech.Api.Resources.LegalEntities.LegalPersonResourceV2Item: + type: object + properties: + tradeName: + description: Nome fantasia + type: string + name: + description: Razão social + type: string + federalTaxNumber: + format: int64 + description: Número da inscrição na Receita Federal (CNPJ) + type: integer + size: + description: Porte + enum: + - Unknown + - ME + - EPP + - DEMAIS + type: string + openedOn: + format: date-time + description: Data da abertura + type: string + address: + $ref: '#/definitions/DataTech.Api.Resources.AddressResourceItem' + description: Endereço + phones: + description: Número de telefone + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.PhoneResource' + statusOn: + format: date-time + description: Data da situação cadastral + type: string + status: + description: Situação cadastral + enum: + - Unknown + - Active + - Suspended + - Cancelled + - Unabled + - "Null" + type: string + email: + description: Correio eletrônico + type: string + responsableEntity: + description: Ente Federativo Responsável (EFR) + type: string + specialStatus: + description: Situação Especial + type: string + specialStatusOn: + format: date-time + description: Data da Situação Especial + type: string + issuedOn: + format: date-time + description: Data de Consulta do usuário + type: string + statusReason: + description: Motivo da Situação Cadastral + type: string + shareCapital: + format: double + description: Capital sócial (em reais) + type: number + economicActivities: + description: Objeto com Código e descrição das atividades econômicas principal e secundárias + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.EconomicActivityResource' + legalNature: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.LegalEntityNatureResource' + description: Objeto com Código e descrição da Natureza Legal + partners: + description: Objeto com nome e qualificação dos sócios e administradores + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.PartnerResource' + registrationUnit: + description: Objeto com a cidade/unidade registradora do certificado de baixa + type: string + unit: + description: Objeto que define se é matriz, filial ou sucursal + enum: + - Headoffice + - Subsidiary + type: string + DataTech.Api.Resources.AddressResourceItem: + description: Endereço + type: object + properties: + state: + description: Estado + type: string + city: + $ref: '#/definitions/DataTech.Services.Domain.Models.CityBase' + description: Cidade + district: + description: Bairro + type: string + additionalInformation: + description: Informações adicionais + type: string + streetSuffix: + description: Sufixo da rua + type: string + street: + description: Nome da rua + type: string + number: + description: Número + type: string + numberMin: + type: string + numberMax: + type: string + postalCode: + description: CEP + type: string + country: + description: País + type: string + DataTech.Api.Resources.LegalEntities.PhoneResource: + type: object + properties: + ddd: + description: Prefixo + type: string + number: + description: Número do telefone + type: string + source: + description: Origem da Informação + enum: + - RFB + type: string + DataTech.Api.Resources.LegalEntities.EconomicActivityResource: + description: Objeto com Código e descrição das atividades econômicas principal e secundárias + type: object + properties: + type: + description: Classificação da atividade + enum: + - Main + - Secondary + type: string + code: + format: int32 + description: Código da atividade (CNAE) + type: integer + description: + description: Descrição da atividade (CNAE) + type: string + DataTech.Api.Resources.LegalEntities.LegalEntityNatureResource: + type: object + properties: + code: + description: Código da Natureza Legal + type: string + description: + description: Descrição da Natureza Legal + type: string + DataTech.Api.Resources.LegalEntities.PartnerResource: + type: object + properties: + name: + description: Nome/Nome Empresarial + type: string + qualification: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.QualificationResource' + description: Qualificação do Quadro de Sócios e Administradores + DataTech.Api.Resources.LegalEntities.QualificationResource: + type: object + properties: + code: + description: Código Qualificação do Quadro de Sócios e Administradores + type: string + description: + description: Descrição da Qualificação do Quadro de Sócios e Administradores + type: string + DataTech.Api.Resources.LegalEntities.StateTaxResourceV2: + type: object + properties: + legalEntity: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxResourceItemV2' + DataTech.Api.Resources.LegalEntities.StateTaxResourceItemV2: + type: object + properties: + tradeName: + description: Nome fantasia + type: string + name: + description: Razão social + type: string + federalTaxNumber: + format: int64 + description: Número da inscrição na Receita Federal (CNPJ) + type: integer + createdOn: + format: date-time + description: Data de Consulta do usuário + type: string + taxRegime: + description: "Código de Regime Tributário (CRT)\r\n\r\n 0 - Desconhecido (Necessário mapear)\r\n 1 - Simples Nacional\r\n 2 - MEI\r\n 3 - Regime Normal - Lucro Presumido ou Lucro Real (Normal_Regime)\r\n" + enum: + - Unknown + - SimplesNacional + - MEI + - Normal + type: string + legalNature: + description: Código da Natureza Jurídica + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + - OutrasSemFimLucrativo + - Unknown + type: string + fiscalUnit: + description: Unidade de fiscalização + type: string + createdUnit: + description: Unidade de cadastro + type: string + checkCode: + description: Código de verificação + type: string + stateTaxes: + description: Inscrições estaduais + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxResource' + DataTech.Api.Resources.LegalEntities.StateTaxResource: + description: Inscrições estaduais + type: object + properties: + status: + description: Situação cadastral + enum: + - Abled + - Unabled + - Cancelled + - Unknown + type: string + taxNumber: + description: Inscrição Estadual (IE) + type: string + statusOn: + format: date-time + description: Data da situação cadastral + type: string + openedOn: + format: date-time + description: Data da abertura + type: string + closedOn: + format: date-time + description: Data fim atividade + type: string + additionalInformation: + description: Informações adicionais + type: string + code: + description: Estado + enum: + - AC + - AL + - AM + - AP + - BA + - CE + - DF + - ES + - GO + - MA + - MG + - MS + - MT + - PA + - PB + - PE + - PI + - PR + - RJ + - RN + - RO + - RR + - RS + - SC + - SE + - SP + - TO + - EX + - NA + type: string + address: + $ref: '#/definitions/DataTech.Api.Resources.AddressResourceItem' + description: Endereço + economicActivities: + description: Objeto com Código e descrição das atividades econômicas principal e secundárias (CNAE) + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.EconomicActivityResource' + nfe: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Nota Fiscal de Eletrônica (NFE) + nfse: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Nota Fiscal de Serviço Eletrônica (NFSE) + cte: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Conhecimento de Transporte Eletrônico (CTE) + nfce: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Nota Fiscal de Consumidor Eletrônica (NFCE) + DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource: + description: Informações do contribuinte + type: object + properties: + status: + description: "Status da Situação do Contribuinte\r\n AbledUnabledUnknown" + enum: + - Abled + - Unabled + - Unknown + type: string + description: + description: Descrição da fonte de dados + type: string + DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceCompleteResource: + type: object + properties: + legalEntity: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceItemResource' + DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceItemResource: + type: object + properties: + tradeName: + description: Nome fantasia + type: string + name: + description: Razão social + type: string + federalTaxNumber: + format: int64 + description: Número da inscrição na Receita Federal (CNPJ) + type: integer + createdOn: + format: date-time + description: Data de Consulta do usuário + type: string + taxRegime: + description: "Código de Regime Tributário (CRT)\r\n\r\n 0 - Desconhecido (Necessário mapear)\r\n 1 - Simples Nacional\r\n 2 - MEI\r\n 3 - Regime Normal - Lucro Presumido ou Lucro Real (Normal_Regime)\r\n" + enum: + - Unknown + - SimplesNacional + - MEI + - Normal + type: string + legalNature: + description: Código da Natureza Jurídica + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + - OutrasSemFimLucrativo + - Unknown + type: string + fiscalUnit: + description: Unidade de fiscalização + type: string + createdUnit: + description: Unidade de cadastro + type: string + checkCode: + description: Código de verificação + type: string + stateTaxes: + description: Inscrições estaduais + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceResource' + DataTech.Api.Resources.LegalEntities.StateTaxToIssueInvoiceResource: + description: Inscrições estaduais + type: object + properties: + status: + description: Situação cadastral + enum: + - Abled + - Unabled + - Cancelled + - UnabledTemp + - UnabledNotConfirmed + - Unknown + - UnknownTemp + - UnknownNotConfirmed + type: string + taxNumber: + description: Inscrição Estadual (IE) + type: string + statusOn: + format: date-time + description: Data da situação cadastral + type: string + openedOn: + format: date-time + description: Data da abertura + type: string + closedOn: + format: date-time + description: Data fim atividade + type: string + additionalInformation: + description: Informações adicionais + type: string + code: + description: Estado + enum: + - AC + - AL + - AM + - AP + - BA + - CE + - DF + - ES + - GO + - MA + - MG + - MS + - MT + - PA + - PB + - PE + - PI + - PR + - RJ + - RN + - RO + - RR + - RS + - SC + - SE + - SP + - TO + - EX + - NA + type: string + address: + $ref: '#/definitions/DataTech.Api.Resources.AddressResourceItem' + description: Endereço + economicActivities: + description: Objeto com Código e descrição das atividades econômicas principal e secundárias (CNAE) + type: array + items: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.EconomicActivityResource' + nfe: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Nota Fiscal de Eletrônica (NFE) + nfse: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Nota Fiscal de Serviço Eletrônica (NFSE) + cte: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Conhecimento de Transporte Eletrônico (CTE) + nfce: + $ref: '#/definitions/DataTech.Api.Resources.LegalEntities.FiscalDocumentDescriptionResource' + description: Indicador de Nota Fiscal de Consumidor Eletrônica (NFCE) +securityDefinitions: + Authorization_Header: + name: Authorization + in: header + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + Authorization_QueryParam: + name: apikey + in: query + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' +security: + - Authorization_Header: [] + Authorization_QueryParam: [] diff --git a/openapi/consulta-cte-v2.yaml b/openapi/consulta-cte-v2.yaml new file mode 100644 index 0000000..1b8ffa3 --- /dev/null +++ b/openapi/consulta-cte-v2.yaml @@ -0,0 +1,578 @@ +openapi: 3.0.1 +servers: + - url: https://api.nfse.io +info: + title: Consulta de CT-e (Distribuição) + x-displayName: Introdução + version: v2 + description: "# Introducão\nSeja bem-vindo a documentação da API de Consulta de CT-e (Distribuição)!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\nEsta API tem como objetivo manipular o produto de consulta de CT-e. O processo tem como pré-requisitos o cadastro de uma empresa, na sequência o cadastro de um certificado A1 válido desta empresa, e o cadastro de um endpoint de webhook para você receber as notificações. Para mais detalhes de como cadastrar empresa, certificado e webhook, você pode ver nossa documentação da nota fiscal de produto, ou fazer o procedimento via dashboard da nfe.io. \n\nCom os pré-requisitos atendidos, o próximo passo é habilitar a busca automática e observar os webhooks chegando em seu endpoint cadastrado.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra no topo desta página para que os métodos funcionem corretamente.\nNo seu código de integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n" +tags: + - name: Transportation Invoices + description: | + Utilize estas requisições para habilitar ou desabilitar a busca automática de CT-e + - name: Inbound + description: | + Utilize estas requisições para consultar metadados ou XMLs de CT-e encontrados pela processo de busca automática +paths: + /v2/companies/{companyId}/inbound/transportationinvoices: + post: + tags: + - Transportation Invoices + summary: Ativar busca automática de documentos e Eventos relacionados a Conhecimento de Transporte Eletrônico (CT-e) + description: Você precisará do APIKEY para utilização + parameters: + - name: companyId + in: path + required: true + schema: + type: string + requestBody: + content: + application/json-patch+json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.EnableTransportationInvoiceInboundResource' + application/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.EnableTransportationInvoiceInboundResource' + text/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.EnableTransportationInvoiceInboundResource' + application/*+json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.EnableTransportationInvoiceInboundResource' + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.TransportationInvoiceInboundResource' + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + delete: + tags: + - Transportation Invoices + summary: Inativar busca automática de documentos e Eventos relacionados a Conhecimento de Transporte Eletrônico (CT-e) + description: Você precisará do APIKEY para utilização + parameters: + - name: companyId + in: path + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.TransportationInvoiceInboundResource' + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + get: + tags: + - Transportation Invoices + summary: Obter as configurações ativas usadas na busca automática de Conhecimento de Transporte Eletrônico (CT-e) + description: Você precisará do APIKEY para utilização + parameters: + - name: companyId + in: path + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.TransportationInvoiceInboundResource' + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/companies/{company_id}/inbound/{access_key}: + get: + tags: + - Inbound + summary: Obter os detalhes de um CT-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + parameters: + - name: company_id + in: path + required: true + schema: + type: string + - name: access_key + in: path + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.MetadataResource' + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/companies/{company_id}/inbound/{access_key}/xml: + get: + tags: + - Inbound + summary: Obter o XML de um CT-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + parameters: + - name: company_id + in: path + required: true + schema: + type: string + - name: access_key + in: path + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: string + format: binary + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/companies/{company_id}/inbound/{access_key}/events/{event_key}: + get: + tags: + - Inbound + summary: Obter os detalhes de um evento ref. a um CT-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + parameters: + - name: company_id + in: path + required: true + schema: + type: string + - name: access_key + in: path + required: true + schema: + type: string + - name: event_key + in: path + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.MetadataResource' + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/companies/{company_id}/inbound/{access_key}/events/{event_key}/xml: + get: + tags: + - Inbound + summary: Obter o XML de um evento ref. a um CT-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + parameters: + - name: company_id + in: path + required: true + schema: + type: string + - name: access_key + in: path + required: true + schema: + type: string + - name: event_key + in: path + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + content: + application/json: + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Não encontrado + content: + application/json: + schema: + type: string + "500": + description: Erro no processamento + content: + application/json: + schema: + type: string + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess +components: + schemas: + DFe.NetCore.Domain.Enums.EntityStatus: + enum: + - 0 + - 1 + - -1 + type: integer + format: int32 + DFe.NetCore.Domain.Enums.MetadataResourceType: + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + type: integer + format: int32 + DFe.NetCore.Domain.Resources.CompanyResource: + type: object + properties: + id: + type: string + nullable: true + federalTaxNumber: + type: string + nullable: true + state: + type: string + nullable: true + stateTaxNumber: + type: string + nullable: true + additionalProperties: false + DFe.NetCore.Domain.Resources.EnableInboundProductInvoiceResource: + type: object + properties: + startFromNsu: + type: integer + format: int64 + startFromDate: + type: string + format: date-time + automaticManifesting: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.ManifestAutomaticRulesResource' + additionalProperties: false + DFe.NetCore.Domain.Resources.EnableTransportationInvoiceInboundResource: + type: object + properties: + startFromNsu: + type: integer + format: int64 + startFromDate: + type: string + format: date-time + additionalProperties: false + DFe.NetCore.Domain.Resources.ManifestAutomaticRulesResource: + type: object + properties: + minutesToWaitAwarenessOperation: + type: integer + format: int32 + additionalProperties: false + DFe.NetCore.Domain.Resources.MetadataResource: + type: object + properties: + id: + type: string + nullable: true + createdOn: + type: string + format: date-time + nullable: true + accessKey: + type: string + nullable: true + parentAccessKey: + type: string + nullable: true + productInvoices: + type: array + items: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.ProductInvoiceResource' + nullable: true + company: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.CompanyResource' + type: + $ref: '#/components/schemas/DFe.NetCore.Domain.Enums.MetadataResourceType' + nsu: + type: integer + format: int64 + issuedOn: + type: string + format: date-time + nullable: true + description: + type: string + nullable: true + xmlUrl: + type: string + nullable: true + federalTaxNumberSender: + type: string + nullable: true + nameSender: + type: string + nullable: true + totalInvoiceAmount: + type: string + nullable: true + additionalProperties: false + DFe.NetCore.Domain.Resources.ProductInvoiceInboundResource: + type: object + properties: + startFromNsu: + type: integer + format: int64 + startFromDate: + type: string + format: date-time + automaticManifesting: + $ref: '#/components/schemas/DFe.NetCore.Domain.Resources.ManifestAutomaticRulesResource' + companyId: + type: string + nullable: true + status: + $ref: '#/components/schemas/DFe.NetCore.Domain.Enums.EntityStatus' + createdOn: + type: string + format: date-time + modifiedOn: + type: string + format: date-time + nullable: true + additionalProperties: false + DFe.NetCore.Domain.Resources.ProductInvoiceResource: + type: object + properties: + accessKey: + type: string + nullable: true + additionalProperties: false + DFe.NetCore.Domain.Resources.TransportationInvoiceInboundResource: + type: object + properties: + startFromNsu: + type: integer + format: int64 + startFromDate: + type: string + format: date-time + companyId: + type: string + nullable: true + status: + $ref: '#/components/schemas/DFe.NetCore.Domain.Enums.EntityStatus' + createdOn: + type: string + format: date-time + modifiedOn: + type: string + format: date-time + nullable: true + additionalProperties: false + securitySchemes: + Authorization_Header: + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + name: Authorization + in: header + Authorization_QueryParam: + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' + name: apikey + in: query +security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess diff --git a/openapi/consulta-dfe-distribuicao-v2.yaml b/openapi/consulta-dfe-distribuicao-v2.yaml new file mode 100644 index 0000000..756226e --- /dev/null +++ b/openapi/consulta-dfe-distribuicao-v2.yaml @@ -0,0 +1,868 @@ +openapi: 3.0.1 +info: + title: DFeDistribution - Inbound API + description: | + API de Consulta de NF-e e CT-e (Distribuição) da plataforma nfe.io. + Permite habilitar/desabilitar a busca automatica de documentos fiscais, + consultar metadados, XMLs, PDFs, eventos e listar documentos via OData. + version: "v2" + +servers: + - url: https://api.nfse.io + description: Producao + - url: https://api.nfse.io + description: Homologacao + +security: + - Authorization_Header: [] + Authorization_QueryParam: [] + - Authorization_JwtBearer: [] + +tags: + - name: Product Invoices + description: Endpoints para NF-e (Nota Fiscal Eletronica) + - name: Product Invoices OData + description: Listagem paginada de NF-e e eventos via OData + - name: Transportation Invoices + description: Endpoints para CT-e (Conhecimento de Transporte Eletronico) + - name: Transportation Invoices OData + description: Listagem paginada de CT-e e eventos via OData + - name: Inbound + description: Consulta generica de metadados, XMLs, PDFs e eventos (NF-e e CT-e) + +paths: + # ===== PRODUCT INVOICES (NF-e) ===== + /v2/companies/{company_id}/inbound/productinvoices: + post: + tags: [Product Invoices] + summary: Ativar busca automatica de NF-e + operationId: enableInboundProductInvoice + parameters: + - $ref: '#/components/parameters/company_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EnableInboundProductInvoiceResource' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceInboundResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + get: + tags: [Product Invoices] + summary: Obter configuracao do servico de distribuicao NF-e + operationId: getInboundProductInvoice + parameters: + - $ref: '#/components/parameters/company_id' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceInboundResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + delete: + tags: [Product Invoices] + summary: Desativar busca automatica de NF-e + operationId: disableInboundProductInvoice + parameters: + - $ref: '#/components/parameters/company_id' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceInboundResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{company_id}/inbound/productinvoices/{access_key}: + get: + tags: [Product Invoices] + summary: Obter metadados de uma NF-e pela chave de acesso + operationId: getInboundNFeMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/NFeMetadataResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{company_id}/inbound/productinvoices/{access_key}/json: + get: + tags: [Product Invoices] + summary: Obter JSON de uma NF-e pela chave de acesso + operationId: getInboundNFeJson + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + type: object + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{company_id}/inbound/productinvoices/{access_key}/events/{event_key}: + get: + tags: [Product Invoices] + summary: Obter detalhes de um evento de NF-e + operationId: getInboundNFeEventMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + - $ref: '#/components/parameters/event_key' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/NFeMetadataResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{company_id}/inbound/productinvoices/{access_key_or_nsu}/processwebhook: + post: + tags: [Product Invoices] + summary: Reprocessar webhook por chave de acesso ou NSU + operationId: processWebhookByAccessKeyOrNsu + parameters: + - $ref: '#/components/parameters/company_id' + - name: access_key_or_nsu + in: path + required: true + schema: + type: string + description: Chave de acesso (44 digitos) ou NSU + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/MessageResource' + '400': { $ref: '#/components/responses/BadRequest' } + '500': { $ref: '#/components/responses/InternalError' } + + # ===== NF-e OData (NOVOS) ===== + /v2/companies/{company_id}/inbound/odata/ProductInvoices: + get: + tags: [Product Invoices OData] + summary: Listar NF-e com paginacao OData + description: | + Lista documentos NFeMetadata filtrados por companyId + EnvironmentType. + Suporta paginacao cursor-based via $skiptoken (NSU). + **Filtro obrigatorio:** `$filter=environmentType eq {value}` + operationId: listNFeMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - name: $filter + in: query + required: true + schema: + type: string + description: "Filtro obrigatorio. Ex: environmentType eq 1" + example: "environmentType eq 1" + - name: $top + in: query + required: false + schema: + type: integer + minimum: 1 + maximum: 1000 + default: 50 + description: Quantidade maxima de registros (max 1000) + - name: $skiptoken + in: query + required: false + schema: + type: integer + description: Cursor de paginacao (ultimo NSU retornado) + - name: $count + in: query + required: false + schema: + type: boolean + description: Incluir contagem total + responses: + '200': + description: Lista de NF-e + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NFeMetadataODataResource' + '400': { $ref: '#/components/responses/BadRequest' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{company_id}/inbound/odata/ProductInvoiceEvents: + get: + tags: [Product Invoices OData] + summary: Listar eventos de NF-e com paginacao OData + description: | + Lista documentos NFeEventMetadata filtrados por companyId + AccessKey (da NF-e pai). + Suporta paginacao cursor-based via $skiptoken (NSU). + **Filtro obrigatorio:** `$filter=accessKey eq '{chave_acesso}'` + operationId: listNFeEventMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - name: $filter + in: query + required: true + schema: + type: string + description: "Filtro obrigatorio. Ex: accessKey eq '35240612345678000195550010000012341123456789'" + example: "accessKey eq '35240612345678000195550010000012341123456789'" + - name: $top + in: query + required: false + schema: + type: integer + minimum: 1 + maximum: 1000 + default: 50 + - name: $skiptoken + in: query + required: false + schema: + type: integer + description: Cursor de paginacao (ultimo NSU retornado) + - name: $count + in: query + required: false + schema: + type: boolean + responses: + '200': + description: Lista de eventos de NF-e + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NFeEventMetadataODataResource' + '400': { $ref: '#/components/responses/BadRequest' } + '500': { $ref: '#/components/responses/InternalError' } + + # ===== CT-e OData ===== + /v2/companies/{company_id}/inbound/odata/TransportationInvoices: + get: + tags: [Transportation Invoices OData] + summary: Listar CT-e com paginacao OData + description: | + Filtro obrigatorio: `$filter=issuedOn eq {data}` + operationId: listCTeMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - name: $filter + in: query + required: true + schema: + type: string + example: "issuedOn eq 2026-04-01" + - name: $top + in: query + schema: + type: integer + maximum: 1000 + default: 50 + - name: $skiptoken + in: query + schema: + type: integer + - name: $count + in: query + schema: + type: boolean + responses: + '200': + description: Lista de CT-e + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/CTeMetadataResource' + '400': { $ref: '#/components/responses/BadRequest' } + + /v2/companies/{company_id}/inbound/odata/TransportationInvoiceEvents: + get: + tags: [Transportation Invoices OData] + summary: Listar eventos de CT-e com paginacao OData + description: | + Filtro obrigatorio: `$filter=receiptOn eq {data}` + operationId: listCTeEventMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - name: $filter + in: query + required: true + schema: + type: string + example: "receiptOn eq 2026-04-01" + - name: $top + in: query + schema: + type: integer + maximum: 1000 + default: 50 + - name: $skiptoken + in: query + schema: + type: integer + - name: $count + in: query + schema: + type: boolean + responses: + '200': + description: Lista de eventos de CT-e + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/CTeEventMetadataResource' + '400': { $ref: '#/components/responses/BadRequest' } + + # ===== TRANSPORTATION INVOICES (CT-e) ===== + /v2/companies/{companyId}/inbound/transportationinvoices: + post: + tags: [Transportation Invoices] + summary: Ativar busca automatica de CT-e + operationId: enableTransportationInvoiceInbound + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EnableTransportationInvoiceInboundResource' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/TransportationInvoiceInboundResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + get: + tags: [Transportation Invoices] + summary: Obter configuracao de busca automatica de CT-e + operationId: getTransportationInvoiceInbound + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/TransportationInvoiceInboundResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + delete: + tags: [Transportation Invoices] + summary: Desativar busca automatica de CT-e + operationId: disableTransportationInvoiceInbound + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + responses: + '200': + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/TransportationInvoiceInboundResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{companyId}/inbound/transportationinvoices/reprocess/webhook: + post: + tags: [Transportation Invoices] + summary: Reprocessar webhook de CT-e + operationId: reprocessWebhookCTe + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProcessWebhookResource' + responses: + '204': { description: Processamento iniciado em background } + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + + /v2/companies/{companyId}/inbound/transportationinvoices/reprocess/item: + put: + tags: [Transportation Invoices] + summary: Reprocessar lista de NSU de CT-e + operationId: reprocessCTeItem + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + requestBody: + required: true + content: + application/json: + schema: + type: array + items: { type: integer, format: int64 } + responses: + '204': { description: Sucesso } + '400': { $ref: '#/components/responses/BadRequest' } + + /v2/companies/{companyId}/inbound/transportationinvoices/process/item: + put: + tags: [Transportation Invoices] + summary: Processar lista de NSU de CT-e + operationId: processCTeItem + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + requestBody: + required: true + content: + application/json: + schema: + type: array + items: { type: integer, format: int64 } + responses: + '204': { description: Sucesso } + '400': { $ref: '#/components/responses/BadRequest' } + + /v2/companies/{companyId}/inbound/transportationinvoices/reprocess/batch: + put: + tags: [Transportation Invoices] + summary: Reprocessar lote de CT-e por NSU + operationId: reprocessCTeBatch + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + requestBody: + required: true + content: + application/json: + schema: + type: array + items: { type: integer, format: int64 } + responses: + '204': { description: Sucesso } + '400': { $ref: '#/components/responses/BadRequest' } + + /v2/companies/{companyId}/inbound/transportationinvoices/batch/consolidation: + put: + tags: [Transportation Invoices] + summary: Consolidar lotes de CT-e + operationId: consolidateCTeBatch + parameters: + - name: companyId + in: path + required: true + schema: { type: string } + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + startNSU: { type: integer, format: int64 } + endNSU: { type: integer, format: int64 } + responses: + '204': { description: Sucesso } + '400': { $ref: '#/components/responses/BadRequest' } + + # ===== INBOUND (generico NF-e / CT-e) ===== + /v2/companies/{company_id}/inbound/{access_key}: + get: + tags: [Inbound] + summary: Obter metadados de NF-e ou CT-e pela chave de acesso + operationId: getInboundMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/NFeMetadataResource' + - $ref: '#/components/schemas/MetadataResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + '500': { $ref: '#/components/responses/InternalError' } + + /v2/companies/{company_id}/inbound/{access_key}/xml: + get: + tags: [Inbound] + summary: Obter XML de NF-e ou CT-e + operationId: getInboundXml + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + responses: + '200': + description: URL temporaria do XML + content: + application/json: + schema: + $ref: '#/components/schemas/XmlFileResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + + /v2/companies/{company_id}/inbound/{access_key}/pdf: + get: + tags: [Inbound] + summary: Obter PDF de NF-e (DANFE) + operationId: getInboundPdf + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + responses: + '200': + description: URL temporaria do PDF + content: + application/json: + schema: + $ref: '#/components/schemas/XmlFileResource' + '204': { description: Nao disponivel para CT-e } + '404': { $ref: '#/components/responses/NotFound' } + + /v2/companies/{company_id}/inbound/{access_key}/events/{event_key}: + get: + tags: [Inbound] + summary: Obter detalhes de evento de NF-e ou CT-e + operationId: getInboundEventMetadata + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + - $ref: '#/components/parameters/event_key' + responses: + '200': + description: Sucesso + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/NFeMetadataResource' + - $ref: '#/components/schemas/MetadataResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + + /v2/companies/{company_id}/inbound/{access_key}/events/{event_key}/xml: + get: + tags: [Inbound] + summary: Obter XML de evento de NF-e ou CT-e + operationId: getEventInboundXml + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + - $ref: '#/components/parameters/event_key' + responses: + '200': + description: URL temporaria do XML + content: + application/json: + schema: + $ref: '#/components/schemas/XmlFileResource' + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + + /v2/companies/{company_id}/inbound/{access_key}/manifest: + post: + tags: [Inbound] + summary: Enviar evento de manifestacao do destinatario + operationId: processManifest + parameters: + - $ref: '#/components/parameters/company_id' + - $ref: '#/components/parameters/access_key' + - name: tpEvent + in: query + schema: + type: integer + format: int64 + default: 210210 + description: "Tipo do evento (210210=Ciencia da Operacao)" + responses: + '200': + description: Sucesso + content: + application/json: + schema: { type: string } + '400': { $ref: '#/components/responses/BadRequest' } + '404': { $ref: '#/components/responses/NotFound' } + +components: + securitySchemes: + ApiKey: + type: apiKey + in: header + name: Authorization + description: API Key da conta nfe.io + + parameters: + company_id: + name: company_id + in: path + required: true + schema: { type: string } + description: ID da empresa na plataforma nfe.io + access_key: + name: access_key + in: path + required: true + schema: { type: string } + description: Chave de acesso do documento (44 digitos) + event_key: + name: event_key + in: path + required: true + schema: { type: string } + description: Chave do evento + + responses: + BadRequest: + description: Parametro invalido + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + NotFound: + description: Nao encontrado + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + InternalError: + description: Erro interno + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + schemas: + ErrorResponse: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + format: int32 + description: Código do erro + message: + type: string + description: Mensagem contendo os detalhes do erro + NFeMetadataODataResource: + type: object + properties: + accessKey: { type: string, description: Chave de acesso (44 digitos) } + createdOn: { type: string, format: date-time } + company: { $ref: '#/components/schemas/InboundCompanyResource' } + type: { type: string, enum: [productInvoice] } + nsu: { type: string, description: Numero Sequencial Unico } + issuedOn: { type: string, format: date-time } + nfeNumber: { type: string } + nfeSerialNumber: { type: string } + operationType: { type: string, enum: [Incoming, Outgoing] } + totalInvoiceAmount: { type: string } + federalTaxNumberSender: { type: string } + nameSender: { type: string } + xmlUrl: { type: string, format: uri } + + NFeEventMetadataODataResource: + type: object + properties: + id: { type: string } + createdOn: { type: string, format: date-time } + company: { $ref: '#/components/schemas/InboundCompanyResource' } + accessKey: { type: string } + type: { type: string, enum: [productInvoiceEvent] } + nsu: { type: integer, format: int64 } + receiptOn: { type: string, format: date-time } + description: { type: string } + xmlUrl: { type: string, format: uri } + + NFeMetadataResource: + type: object + properties: + accessKey: { type: string } + createdOn: { type: string, format: date-time } + parentAccessKey: { type: string } + company: { $ref: '#/components/schemas/InboundCompanyResource' } + issuer: { $ref: '#/components/schemas/IssuerResource' } + buyer: { $ref: '#/components/schemas/BuyerResource' } + transportation: { $ref: '#/components/schemas/TransportationResource' } + xmlUrl: { type: string, format: uri } + federalTaxNumberSender: { type: string } + nameSender: { type: string } + type: { type: string } + nsu: { type: string } + nsuParent: { type: string } + nfeNumber: { type: string } + nfeSerialNumber: { type: string } + issuedOn: { type: string, format: date-time } + description: { type: string } + totalInvoiceAmount: { type: string } + operationType: { type: string, enum: [Incoming, Outgoing] } + + MetadataResource: + type: object + properties: + id: { type: string } + createdOn: { type: string, format: date-time } + accessKey: { type: string } + parentAccessKey: { type: string } + nsu: { type: integer, format: int64 } + company: { $ref: '#/components/schemas/InboundCompanyResource' } + type: { type: string } + description: { type: string } + xmlUrl: { type: string, format: uri } + + CTeMetadataResource: + allOf: + - $ref: '#/components/schemas/MetadataResource' + - type: object + properties: + issuedOn: { type: string, format: date-time } + + CTeEventMetadataResource: + allOf: + - $ref: '#/components/schemas/MetadataResource' + - type: object + properties: + receiptOn: { type: string, format: date-time } + + InboundCompanyResource: + type: object + properties: + id: { type: string } + federalTaxNumber: { type: string } + + IssuerResource: + type: object + properties: + federalTaxNumber: { type: string } + name: { type: string } + + BuyerResource: + type: object + properties: + federalTaxNumber: { type: string } + name: { type: string } + + TransportationResource: + type: object + properties: + federalTaxNumber: { type: string } + name: { type: string } + + XmlFileResource: + type: object + properties: + url: { type: string, format: uri } + + MessageResource: + type: object + properties: + message: { type: string } + + EnableInboundProductInvoiceResource: + type: object + properties: + startFromDate: { type: string, format: date-time } + startFromNsu: { type: integer, format: int64 } + environmentSEFAZ: { type: string, enum: [None, Test, Production] } + automaticManifesting: + type: object + properties: + minutesToWaitAwarenessOperation: { type: integer } + + ProductInvoiceInboundResource: + type: object + properties: + status: { type: string } + environmentSEFAZ: { type: string } + startFromDate: { type: string, format: date-time } + + EnableTransportationInvoiceInboundResource: + type: object + properties: + startFromDate: { type: string, format: date-time } + startFromNsu: { type: integer, format: int64 } + environmentSEFAZ: { type: string, enum: [None, Test, Production] } + + TransportationInvoiceInboundResource: + type: object + properties: + status: { type: string } + environmentSEFAZ: { type: string } + startFromDate: { type: string, format: date-time } + + ProcessWebhookResource: + type: object + properties: + key: { type: string } + date: { type: string, format: date-time } diff --git a/openapi/consulta-endereco.yaml b/openapi/consulta-endereco.yaml new file mode 100644 index 0000000..ba34e97 --- /dev/null +++ b/openapi/consulta-endereco.yaml @@ -0,0 +1,345 @@ +swagger: "2.0" +host: address.api.nfe.io +schemes: + - https +info: + title: Consulta de Endereço + version: v2 + x-displayName: Introdução + description: "# Introducão\nSeja bem-vindo a documentação da API de consulta de Endereços!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra topo desta página para que os métodos funcionem corretamente.\nNo seu código e integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n\n" +paths: + /v2/addresses/{postalCode}: + get: + tags: + - Addresses + summary: Consulta de Endereço por CEP + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de um **Endereço** através do CEP.\r\nOs dados do **Endereço** são consultados no Diretório Nacional de Endereço (DNE) dos Correios \r\nunificando com os dados de Cidades do IBGE." + operationId: V2AddressesByPostalCodeGet + consumes: [] + produces: + - application/json + parameters: + - name: postalCode + in: path + description: Código do CEP + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + addresses: + type: array + items: + type: object + properties: + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + numberMin: + type: string + numberMax: + type: string + postalCode: + type: string + country: + type: string + "400": + description: Algum parametro informado não é válido, verificar resposta + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nenhum endereço foi encontrado com o CEP informado + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + "500": + description: Erro no processamento + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/addresses: + get: + tags: + - Addresses + summary: Pesquisa de Endereço por campos + description: Você precisará do APIKEY da Empresa + operationId: V2AddressesGet + consumes: [] + produces: + - application/json + parameters: + - name: $filter + in: query + description: Termo genérico de pesquisa + required: false + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + addresses: + type: array + items: + type: object + properties: + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + numberMin: + type: string + numberMax: + type: string + postalCode: + type: string + country: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Termos não encontrados + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + "500": + description: Erro no processamento + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/addresses/{term}: + get: + tags: + - Addresses + summary: Pesquisa de Endereço por termo genérico + description: Você precisará do APIKEY da Empresa + operationId: V2AddressesByTermGet + consumes: [] + produces: + - application/json + parameters: + - name: term + in: path + description: Termo genérico de pesquisa + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + addresses: + type: array + items: + type: object + properties: + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + numberMin: + type: string + numberMax: + type: string + postalCode: + type: string + country: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nenhum endereço encontrado para o termo + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + "500": + description: Erro no processamento + schema: + type: object + properties: + errors: + type: array + items: + type: object + properties: + code: + format: int32 + type: integer + message: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey +securityDefinitions: + Authorization_Header: + name: Authorization + in: header + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + Authorization_QueryParam: + name: apikey + in: query + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' diff --git a/openapi/consulta-nf-v3.yaml b/openapi/consulta-nf-v3.yaml new file mode 100644 index 0000000..d50b00a --- /dev/null +++ b/openapi/consulta-nf-v3.yaml @@ -0,0 +1,77 @@ +swagger: "2.0" +host: nfe.api.nfe.io +schemes: + - https +info: + title: Consulta de Notas Fiscais + version: v3 + x-displayName: Introdução + description: "# Consulta de Nota Fiscal — V3 (Consulta Irrestrita)\nA V3 da Consulta Irrestrita devolve o XML da NF-e exatamente como o provedor SERPRO entrega, SEM normalização para o esquema canônico camelCase da NFE.io.\n\nUse quando precisar preservar a autenticidade do payload original do provedor — auditoria fiscal, repasse legal ou sistemas legados que esperam o XML SERPRO original.\n\nPara a maioria das integrações (JSON normalizado, XML traduzido e DANFE em PDF), prefira a [V2](/docs/desenvolvedores/rest-api/consulta-de-nota-fiscal/v2/).\n\n# Autenticação\nInforme sua Chave de Dados no header `Authorization` (sem prefixo `Bearer`) ou via query string `apikey`.\n\nDocumentação funcional: [Consulta Irrestrita](/docs/documentacao/consultas/notas-fiscais/consulta-irrestrita/).\n" +tags: + - name: Irrestrita + x-displayName: Consulta Irrestrita + description: Consulta Irrestrita da NFE.io — fonte nacional unificada de NF-e autorizadas. A V3 retorna o XML cru entregue pelo provedor SERPRO, sem tradução de campos. +paths: + /v3/productinvoices/serpro/{accessKey}.xml: + get: + tags: + - Irrestrita + summary: Consulta Irrestrita de NF-e por Chave de Acesso (XML) + description: "Retorna o XML da NF-e exatamente como o provedor SERPRO entrega, SEM normalização para o esquema canônico camelCase da NFE.io. Use a Chave de Dados no header `Authorization` SEM prefixo `Bearer`. Indicado para auditoria fiscal, repasse legal e sistemas legados que esperam o XML original do provedor. Para a maioria das integrações, prefira a V2." + operationId: V3ProductinvoicesSerproByAccessKey}.xmlGet + consumes: [] + produces: + - application/xml + parameters: + - name: accessKey + in: path + description: Chave de Acesso (44 dígitos numéricos) + required: true + type: string + - name: X-Client-Timeout-Seconds + in: header + description: Timeout customizado em segundos para a consulta ao provedor SERPRO. Default 180. + required: false + type: integer + format: int32 + responses: + "200": + description: Sucesso na requisição. O corpo é o XML cru entregue pelo provedor SERPRO (nfeProc), sem tradução de campos. + schema: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + "504": + description: Timeout ao consultar o provedor SERPRO. Tente novamente, opcionalmente aumentando o header X-Client-Timeout-Seconds. + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey +securityDefinitions: + Authorization_Header: + name: Authorization + in: header + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + Authorization_QueryParam: + name: apikey + in: query + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' diff --git a/openapi/consulta-nf.yaml b/openapi/consulta-nf.yaml new file mode 100644 index 0000000..f00998b --- /dev/null +++ b/openapi/consulta-nf.yaml @@ -0,0 +1,6143 @@ +swagger: "2.0" +host: nfe.api.nfe.io +schemes: + - https +info: + title: Consulta de Notas Fiscais + version: v2 + x-displayName: Introdução + description: "# Introducão\nSeja bem-vindo a documentação da API de consulta de Notas Fiscais!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra topo desta página para que os métodos funcionem corretamente.\nNo seu código e integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n\n\n# Fontes de consulta\nA NFE.io oferece duas opções de consulta de NF-e pela mesma chave de acesso, ambas com cobertura nacional:\n- **Consulta SEFAZ** (endpoints sem `/serpro/`): usa o portal público nacional da Receita Federal (`nfe.fazenda.gov.br`). Inclui consulta de eventos da nota.\n- **Consulta Irrestrita** (endpoints com `/serpro/`): usa um provedor oficial autorizado pela autoridade federal, com maior previsibilidade.\n\nDocumentação funcional:\n- [Consulta SEFAZ](/docs/documentacao/consultas/notas-fiscais/consulta-sefaz/)\n- [Consulta Irrestrita](/docs/documentacao/consultas/notas-fiscais/consulta-irrestrita/)\n" +tags: + - name: SEFAZ + x-displayName: Consulta na SEFAZ + description: Consulta de NF-e direto na SEFAZ. Retorno em JSON, XML oficial, DANFE em PDF e eventos (cancelamento, CC-e, manifestação). + - name: Irrestrita + x-displayName: Consulta Irrestrita + description: Consulta Irrestrita da NFE.io — fonte nacional unificada de NF-e autorizadas, sem depender de portais estaduais individuais. Retorno em JSON, XML oficial e DANFE em PDF. +paths: + /v2/productinvoices/{accessKey}: + get: + tags: + - SEFAZ + summary: Consulta de Nota Fiscal Eletrônica na SEFAZ por Chave de Acesso + description: Você precisará do APIKEY da Empresa + operationId: V2ProductinvoicesByAccessKeyGet + consumes: [] + produces: + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + currentStatus: + description: Situação Atual + enum: + - unknown + - authorized + - canceled + type: string + stateCode: + format: int32 + description: Código da UF do emitente do Documento Fiscal (cUF) + type: integer + checkCode: + format: int64 + description: Código Numérico que compõe a Chave de Acesso (cNF) + type: integer + operationNature: + description: Descrição da Natureza da Operação (natOp) + type: string + paymentType: + description: "Indicador da forma de pagamento (indPag)\r\n\r\n 0 - Pagamento à vista (InCash)\r\n 1 - Pagamento a prazo (Term)\r\n 2 - Outros (Others)\r\n" + enum: + - inCash + - term + - others + type: string + codeModel: + format: int32 + description: Código do Modelo do Documento Fiscal (mod) + type: integer + serie: + format: int32 + description: Série do Documento Fiscal (serie) + type: integer + number: + format: int64 + description: Número do Documento Fiscal (nNF) + type: integer + issuedOn: + format: date-time + description: "Data de emissão do Documento Fiscal (dhEmi)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + type: string + operationOn: + format: date-time + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + type: string + operationType: + description: Tipo de Operação (tpNF) + enum: + - incoming + - outgoing + type: string + destination: + description: Identificador de local de destino da operação (idDest) + enum: + - international_Operation + - interstate_Operation + - internal_Operation + type: string + cityCode: + format: int32 + description: Código do Município de Ocorrência do Fato Gerador (cMunFG) + type: integer + printType: + description: Formato de Impressão do DANFE (tpImp) + enum: + - none + - nFeNormalPortrait + - nFeNormalLandscape + - nFeSimplified + - dANFE_NFC_E + - dANFE_NFC_E_MSG_ELETRONICA + type: string + issueType: + description: Tipo de Emissão da NF-e (tpEmis) + enum: + - cONTINGENCIA_OFF_LINE_NFC_E + - cONTINGENCIA_SVC_RS + - cONTINGENCIA_SVC_AN + - cONTINGENCIA_FS_DA + - cONTINGENCIA_DPEC + - cONTINGENCIA_SCAN + - cONTINGENCIA_FS_IA + - normal + type: string + checkCodeDigit: + format: int32 + description: Dígito Verificador da Chave de Acesso da NF-e (cDV) + type: integer + environmentType: + description: Identificação do Ambiente (tpAmb) + enum: + - production + - test + type: string + purposeType: + description: Finalidade de emissão da NF-e (finNFe) + enum: + - devolution + - adjustment + - complement + - normal + type: string + consumerType: + description: Indica operação com Consumidor final (indFinal) + enum: + - normal + - finalConsumer + type: string + presenceType: + description: Indicador de presença do comprador no estabelecimento comercial no momento da operação (indPres) + enum: + - none + - presence + - internet + - telephone + - delivery + - presenceOutOfStore + - othersNoPresente + type: string + processType: + description: Processo de emissão da NF-e (procEmi) + enum: + - ownSoftware + - fiscoSingle + - taxPayerSingle + - fiscoSoftware + type: string + invoiceVersion: + description: Versão do Processo de emissão da NF-e (verProc) + type: string + xmlVersion: + description: Versão do leiaute (versao) + type: string + contingencyOn: + format: date-time + description: "Data e Hora da entrada em contingência (dhCont)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + type: string + contingencyJustification: + description: Justificativa da entrada em contingência (xJust) + type: string + issuer: + description: Grupo de identificação do emitente da NF-e (emit) + type: object + properties: + federalTaxNumber: + format: double + description: CNPJ do emitente (CNPJ) / CPF do remetente (CPF) + type: number + name: + description: Razão Social ou Nome do emitente (xNome) + type: string + tradeName: + description: Nome fantasia (xFant) + type: string + address: + description: Endereço do emitente (enderEmit) + type: object + properties: + phone: + type: string + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + postalCode: + type: string + country: + type: string + stateTaxNumber: + description: Inscrição Estadual (IE) + type: string + codeTaxRegime: + description: Código de Regime Tributário (CRT) + enum: + - national_Simple + - national_Simple_Brute + - normal_Regime + type: string + cnae: + format: int64 + description: CNAE fiscal (CNAE) + type: integer + im: + description: Inscrição Municipal do Prestador de Serviço (IM) + type: string + iest: + format: int64 + description: IE do Substituto Tributário (IEST) + type: integer + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - undefined + - naturalPerson + - legalEntity + type: string + buyer: + description: Grupo de identificação do Destinatário da NF-e (dest) + type: object + properties: + federalTaxNumber: + format: double + description: "CNPJ do Destinantario (CNPJ) / CPF do destinatário (CPF) /\r\nIdentificação do destinatário no caso de comprador estrangeiro (idEstrangeiro)" + type: number + name: + description: Razão Social ou nome do destinatário (xNome) + type: string + address: + description: Identificação do Endereço (enderDest) + type: object + properties: + phone: + type: string + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + postalCode: + type: string + country: + type: string + stateTaxNumber: + description: Inscrição Estadual (IE) + type: string + stateTaxNumberIndicator: + format: int32 + description: Indicador Inscrição Estadual (indIEDest) + type: integer + email: + description: Email (email) + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - undefined + - naturalPerson + - legalEntity + type: string + totals: + description: Grupo Totais da NF-e (total) + type: object + properties: + icms: + description: Grupo de Valores Totais referentes ao ICMS (ICMSTot) + type: object + properties: + baseTax: + format: double + description: Base de Cálculo do ICMS (vBC) + type: number + icmsAmount: + format: double + description: Valor Total do ICMS (vICMS) + type: number + icmsExemptAmount: + format: double + description: Valor ICMS Total desonerado (vICMSDeson) + type: number + stCalculationBasisAmount: + format: double + description: Base de Cálculo do ICMS Substituição Tributária (vBCST) + type: number + stAmount: + format: double + description: Valor Total do ICMS ST (vST) + type: number + productAmount: + format: double + description: Valor Total dos produtos e serviços (vProd) + type: number + freightAmount: + format: double + description: Valor Total do Frete (vFrete) + type: number + insuranceAmount: + format: double + description: Valor Total do Seguro (vSeg) + type: number + discountAmount: + format: double + description: Valor Total do Desconto (vDesc) + type: number + iiAmount: + format: double + description: Valor Total do Imposto de Importação (vII) + type: number + ipiAmount: + format: double + description: Valor Total do IPI (vIPI) + type: number + pisAmount: + format: double + description: Valor do PIS (vPIS) + type: number + cofinsAmount: + format: double + description: Valor do COFINS (vCOFINS) + type: number + othersAmount: + format: double + description: Outras Despesas acessórias (vOutro) + type: number + invoiceAmount: + format: double + description: Valor Total da NF-e (vNF) + type: number + fcpufDestinationAmount: + format: double + description: Valor Total ICMS FCP UF Destino + type: number + icmsufDestinationAmount: + format: double + description: Valor Total ICMS Interestadual UF Destino + type: number + icmsufSenderAmount: + format: double + description: Valor Total ICMS Interestadual UF Rem. + type: number + federalTaxesAmount: + format: double + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + type: number + fcpAmount: + format: double + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + type: number + fcpstAmount: + format: double + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido por substituição tributária. + type: number + fcpstRetAmount: + format: double + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido anteriormente por substituição tributária. + type: number + ipiDevolAmount: + format: double + description: Valor total do IPI devolvido (vIPIDevol) + type: number + issqn: + description: Grupo de Valores Totais referentes ao ISSQN (ISSQNtot) + type: object + properties: + totalServiceNotTaxedICMS: + format: double + description: Valor Total Serv.Não Tributados p/ ICMS + type: number + baseRateISS: + format: double + description: Base de Cálculo do ISS + type: number + totalISS: + format: double + description: Valor Total do ISS + type: number + valueServicePIS: + format: double + description: Valor do PIS sobre Serviços + type: number + valueServiceCOFINS: + format: double + description: Valor da COFINS sobre Serviços + type: number + provisionService: + format: date-time + description: Data Prestação Serviço + type: string + deductionReductionBC: + format: double + description: Valor Dedução para Redução da BC + type: number + valueOtherRetention: + format: double + description: Valor Outras Retenções + type: number + discountUnconditional: + format: double + description: Valor Desconto Incondicionado + type: number + discountConditioning: + format: double + description: Valor Desconto Condicionado + type: number + totalRetentionISS: + format: double + description: Valor Total Retenção ISS + type: number + codeTaxRegime: + format: double + description: Código Regime Tributação + type: number + transport: + description: Grupo de Informações do Transporte da NF-e (transp) + type: object + properties: + freightModality: + format: int32 + description: Modalidade do frete (modFrete) + type: integer + transportGroup: + description: Grupo Transportador (transporta) + type: object + properties: + cityName: + description: Nome do Município (xMun) + type: string + federalTaxNumber: + description: CNPJ do Transportador (CNPJ) ou CPF do Transportador (CPF) + type: string + cpf: + description: CPF do Transportador (CPF) + type: string + name: + description: Razão Social ou nome (xNome) + type: string + stateTaxNumber: + description: Inscrição Estadual do Transportador (IE) + type: string + fullAddress: + description: Endereço Completo (xEnder) + type: string + state: + description: Sigla da UF (UF) + type: string + transportRetention: + description: Grupo de Retenção do ICMS do transporte + type: string + reboque: + description: Grupo Reboque (reboque) + type: object + properties: + plate: + description: Placa do Veiculo (placa) + type: string + uf: + description: UF Veiculo Reboque (UF) + type: string + rntc: + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + type: string + wagon: + description: Identificação do Vagão (vagao) + type: string + ferry: + description: Identificação da Balsa (balsa) + type: string + volume: + description: Grupo Volumes (vol) + type: object + properties: + volumeQuantity: + format: int32 + description: Quantidade de volumes transportados (qVol) + type: integer + species: + description: Espécie dos volumes transportados (esp) + type: string + brand: + description: Marca dos Volumes Transportados (marca) + type: string + volumeNumeration: + description: Numeração dos Volumes Transportados (nVol) + type: string + netWeight: + format: double + description: Peso Liquido(em Kg) (pesoL) + type: number + grossWeight: + format: double + description: Peso Bruto(em Kg) (pesoB) + type: number + transportVehicle: + description: Grupo Veiculo (veicTransp) + type: object + properties: + plate: + description: Placa do Veiculo (placa) + type: string + state: + description: Sigla da UF (UF) + type: string + rntc: + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + type: string + sealNumber: + description: Número dos Lacres + type: string + transpRate: + description: Grupo Retenção ICMS transporte (retTransp) + type: object + properties: + serviceAmount: + format: double + description: Valor do Serviço (vServ) + type: number + bcRetentionAmount: + format: double + description: BC da Retenção do ICMS (vBCRet) + type: number + icmsRetentionRate: + format: double + description: Alíquota da Retenção (pICMSRet) //Change to Rate + type: number + icmsRetentionAmount: + format: double + description: Valor do ICMS Retido (vICMSRet) + type: number + cfop: + format: int64 + description: CFOP de Serviço de Transporte (CFOP) + type: integer + cityGeneratorFactCode: + format: int64 + description: Código do Municipio de ocorrencia do fato gerador do ICMS do Transpote (cMunFG) + type: integer + additionalInformation: + description: Informacoes Adicionais (infAdic) + type: object + properties: + fisco: + description: Informações Adicionais de Interesse do Fisco (infAdFisco) + type: string + taxpayer: + description: Informações Complementares de interesse do Contribuinte (infCpl) + type: string + xmlAuthorized: + description: Informações Complementares de interesse do Contribuinte (infCpl) + type: array + items: + format: int64 + type: integer + effort: + type: string + order: + type: string + contract: + type: string + taxDocumentsReference: + description: Documentos Fiscais Referenciados (NFref) + type: array + items: + type: object + properties: + taxCouponInformation: + description: Informações do Cupom Fiscal referenciado (refECF) + type: object + properties: + modelDocumentFiscal: + description: Modelo de Documento Fiscal + type: string + orderECF: + description: Número de Ordem Sequencial do ECF + type: string + orderCountOperation: + format: int32 + description: Número do Contador de Ordem de Operação + type: integer + documentInvoiceReference: + description: Informação da NF modelo 1/1A referenciada (refNF) + type: object + properties: + state: + format: double + description: Código da UF + type: number + yearMonth: + description: Ano / Mês + type: string + federalTaxNumber: + description: CNPJ + type: string + model: + description: Modelo + type: string + series: + description: Série + type: string + number: + description: Número + type: string + accessKey: + description: Chave de Acesso (refNFe) + type: string + taxpayerComments: + description: Grupo do campo de uso livre do contribuinte (obsCont) + type: array + items: + type: object + properties: + field: + description: Campo + type: string + text: + description: Texto + type: string + referencedProcess: + description: Grupo do Processos referenciados (procRef) + type: array + items: + type: object + properties: + identifierConcessory: + type: string + identifierOrigin: + format: int32 + type: integer + protocol: + description: Informações do Protocolo de resposta. TAG a ser assinada (protNFe) + type: object + properties: + id: + description: Identificador da TAG a ser assinada, somente precisa ser informado se a UF assinar a resposta. (ID) + type: string + environmentType: + description: 'Identificação do Ambiente: 1 – Produção/2 - Homologação (tpAmb)' + enum: + - production + - test + type: string + applicationVersion: + description: Versão do Aplicativo que processou o Lote (verAplic) + type: string + accessKey: + description: Chave de Acesso da NF-e (chNFe) + type: string + receiptOn: + format: date-time + description: "Preenchido com a data e hora do processamento (dhRecbto)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + type: string + protocolNumber: + description: Número do Protocolo da NF-e (nProt) + type: string + validatorDigit: + description: (Digest Value) da NF-e processada Utilizado para conferir a integridade da NFe original. (digVal) + type: string + statusCode: + format: int32 + description: Código do status da resposta para a NF-e (cStat) + type: integer + description: + description: Descrição literal do status da resposta para a NF-e (xMotivo) + type: string + signature: + description: "Assinatura XML do grupo identificado pelo atributo “Id” (Signature)\r\nA decisão de assinar a mensagem fica a critério da UF interessada." + type: string + items: + type: array + items: + description: Grupo do detalhamento de Produtos e Serviços da NF-e (det) + type: object + properties: + code: + description: Código do produto ou serviço (cProd) + type: string + codeGTIN: + description: "GTIN (Global Trade Item Number) do produto, \r\nantigo código EAN ou código de barras (cEAN)" + type: string + description: + description: Descrição do produto ou serviço (xProd) + type: string + ncm: + description: Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM) + type: string + extipi: + description: EX_TIPI (EXTIPI) + type: string + cfop: + format: int64 + description: Código Fiscal de Operações e Prestações (CFOP) + type: integer + unit: + description: Unidade Comercial (uCom) + type: string + quantity: + format: double + description: Quantidade Comercial (qCom) + type: number + unitAmount: + format: double + description: Valor Unitário de Comercialização (vUnCom) + type: number + totalAmount: + format: double + description: Valor Total Bruto dos Produtos ou Serviços (vProd) + type: number + eanTaxableCode: + description: "GTIN (Global Trade Item Number) da unidade tributável, \r\nantigo código EAN ou código de barras (cEANTrib)" + type: string + unitTax: + description: Unidade Tributável (uTrib) + type: string + quantityTax: + format: double + description: Quantidade Tributável (qTrib) + type: number + taxUnitAmount: + format: double + description: Valor Unitário de tributação (vUnTrib) + type: number + freightAmount: + format: double + description: Valor Total do Frete (vFrete) + type: number + insuranceAmount: + format: double + description: Valor Total do Seguro (vSeg) + type: number + discountAmount: + format: double + description: Valor do Desconto (vDesc) + type: number + othersAmount: + format: double + description: Outras despesas acessórias (vOutro) + type: number + totalIndicator: + description: "Indica se valor do Item (vProd) \r\nentra no valor total da NF-e (vProd) (indTot)" + type: boolean + cest: + description: Código especificador da substituição tributária (CEST) + type: string + tax: + description: Tributos incidentes no Produto ou Serviço (imposto) + type: object + properties: + totalTax: + format: double + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + type: number + icms: + description: Dados do ICMS Normal e ST (ICMS) + type: object + properties: + origin: + description: Origem da mercadoria (orig) + type: string + cst: + description: Tributação do ICMS (CST) + type: string + baseTaxModality: + description: Modalidade de determinação da BC do ICMS (modBC) + type: string + baseTax: + format: double + description: Valor da BC do ICMS (vBC) + type: number + baseTaxSTModality: + description: Modalidade de determinação da BC do ICMS ST (modBCST) + type: string + baseTaxSTReduction: + format: double + description: "pRedBCST\r\nPercentual da Redução de BC do ICMS ST (pRedBCST)" + type: number + baseTaxSTAmount: + format: double + description: Valor da BC do ICMS ST (vBCST) + type: number + baseTaxReduction: + format: double + description: Percentual da Redução de BC (pRedBC) + type: number + stRate: + format: double + description: Alíquota do imposto do ICMS ST (pICMSST) + type: number + stAmount: + format: double + description: Valor do ICMS ST (vICMSST) + type: number + stMarginAmount: + format: double + description: Percentual da margem de valor Adicionado do ICMS ST (pMVAST) + type: number + csosn: + description: "101- Tributada pelo Simples Nacional com permissão de crédito. (v.2.0) (CSOSN)\r\nCódigo de Situação da Operação – Simples Nacional" + type: string + rate: + format: double + description: Alíquota do imposto (pICMS) + type: number + amount: + format: double + description: "Valor do ICMS (vICMS)\r\n\r\nO valor do ICMS desonerado será informado apenas nas operações:\r\na) com produtos beneficiados com a desoneração condicional do ICMS.\r\nb) destinadas à SUFRAMA, informando-se o valor que seria devido se não houvesse isenção.\r\nc) de venda a órgãos da administração pública direta e suas fundações e\r\nautarquias com isenção do ICMS. (NT 2011/004)" + type: number + snCreditRate: + description: Alíquota aplicável de cálculo do crédito (Simples Nacional). (pCredSN) + type: string + snCreditAmount: + description: Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) + type: string + stMarginAddedAmount: + description: "Percentual da margem de valor Adicionado do ICMS ST (vCredICMSSN)\r\n0 – Preço tabelado ou máximo sugerido;\r\n1 - Lista Negativa (valor);\r\n2 - Lista Positiva (valor);\r\n3 - Lista Neutra (valor);\r\n4 - Margem Valor Agregado (%);\r\n5 - Pauta (valor);" + type: string + stRetentionAmount: + description: "Valor do ICMS ST retido (vICMSSTRet)\r\nValor do ICMS ST cobrado anteriormente por ST (v2.0) (vICMS)" + type: string + baseSTRetentionAmount: + description: Valor da BC do ICMS ST retido + type: string + baseTaxOperationPercentual: + type: string + ufst: + description: "UF para qual é devido o ICMS ST (UFST)\r\nSigla da UF para qual é devido o ICMS ST da operação. (v2.0)" + type: string + amountSTUnfounded: + format: double + description: Valor ICMS Desonerado + type: number + amountSTReason: + description: Motivo Desoneração ICMS + type: string + baseSNRetentionAmount: + description: Valor da BC do ICMS ST retido + type: string + snRetentionAmount: + description: Valor do ICMS ST retido + type: string + amountOperation: + description: Valor do ICMS da Operação + type: string + percentualDeferment: + description: Percentual do Diferimento + type: string + baseDeferred: + description: Valor do ICMS Diferido + type: string + fcpRate: + format: double + description: Percentual do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCP) (Percentual máximo permitido é 2%) + type: number + fcpAmount: + format: double + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + type: number + fcpstRate: + format: double + description: Percentual do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCPST) retido por substituição tributária. + type: number + fcpstAmount: + format: double + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCPST) retido por substituição tributária. + type: number + fcpstRetRate: + format: double + description: Percentual do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCPSTRet) retido anteriormente por substituição tributária. + type: number + fcpstRetAmount: + format: double + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCPSTRet) retido anteriormente por substituição tributária. + type: number + bcfcpstAmount: + format: double + description: Informar o valor da Base de Cálculo do FCP (vBCFCPST) + type: number + finalConsumerRate: + format: double + description: Modalidade de determinação da BC do ICMS (pST) + type: number + bcstRetIssuerAmount: + format: double + description: Valor do BC do ICMS ST retido na UF remetente (vBCSTRet) + type: number + stRetIssuerAmout: + format: double + description: Valor do ICMS ST retido na UF remetente (vICMSSTRet) + type: number + bcstBuyerAmount: + format: double + description: Valor da BC do ICMS ST da UF destino (vBCSTDest) + type: number + stBuyerAmout: + format: double + description: Valor do ICMS ST da UF destino (vICMSSTDest) + type: number + substituteAmount: + format: double + description: 'Valor do ICMS próprio do Substituto (tag: vICMSSubstituto)' + type: number + ipi: + description: Grupo IPI (IPI) + type: object + properties: + classification: + description: "clEnq\r\nClasse de enquadramento do IPI para Cigarros e Bebidas (clEnq)" + type: string + producerCNPJ: + description: CNPJ do produtor da mercadoria, quando diferente do emitente. Somente para os casos de exportação direta ou indireta. (CNPJProd) + type: string + stampCode: + description: Código do selo de controle IPI (cSelo)( + type: string + stampQuantity: + format: double + description: Quantidade de selo de controle (qSelo) + type: number + classificationCode: + description: Código de Enquadramento Legal do IPI (cEnq) + type: string + cst: + description: Código da situação tributária do IPI (CST) + type: string + base: + description: Valor da BC do IPI (vBC) + type: string + rate: + format: double + description: Alíquota do IPI (pIPI) + type: number + unitQuantity: + format: double + description: Quantidade total na unidade padrão para tributação (somente para os produtos tributados por unidade) (qUnid) + type: number + unitAmount: + format: double + description: Valor por Unidade Tributável (vUnid) + type: number + amount: + format: double + description: Valor IPI (vIPI) + type: number + ii: + description: Grupo Imposto de Importação (II) + type: object + properties: + baseTax: + description: Valor BC do Imposto de Importação (vBC) + type: string + customsExpenditureAmount: + description: Valor despesas aduaneiras (vDespAdu) + type: string + amount: + format: double + description: Valor Imposto de Importação (vII) + type: number + iofAmount: + format: double + description: Valor Imposto sobre Operações Financeiras (vIOF) + type: number + pis: + description: Grupo PIS (PIS) + type: object + properties: + cst: + description: Código de Situação Tributária do PIS (CST) + type: string + baseTax: + format: double + description: Valor da Base de Cálculo do PIS (vBC) + type: number + rate: + format: double + description: Alíquota do PIS (em percentual) (pPIS) + type: number + amount: + format: double + description: Valor do PIS (vPIS) + type: number + baseTaxProductQuantity: + format: double + description: Quantidade Vendida (qBCProd) + type: number + productRate: + format: double + description: Alíquota do PIS (em reais) (vAliqProd) + type: number + cofins: + description: Grupo COFINS (COFINS) + type: object + properties: + cst: + description: "Código de Situação Tributária da COFINS\r\nObs: 01 – Operação Tributável (base de cálculo = valor da operação \r\nalíquota normal (cumulativo/não cumulativo));\r\n02 - Operação Tributável (base de cálculo = valor da operação (alíquota diferenciada)); (CST)" + type: string + baseTax: + format: double + description: Valor da Base de Cálculo da COFINS (vBC) + type: number + rate: + format: double + description: Alíquota da COFINS (em percentual) (pCOFINS) + type: number + amount: + format: double + description: Valor da COFINS (vCOFINS) + type: number + baseTaxProductQuantity: + format: double + description: Quantidade Vendida (qBCProd) + type: number + productRate: + format: double + description: Alíquota da COFINS (em reais) (vAliqProd) + type: number + icmsDestination: + description: Informação do ICMS Interestadual (ICMSUFDest) + type: object + properties: + vBCUFDest: + format: double + description: Valor da Base de Cálculo do ICMS na UF de destino. (vBCUFDest) + type: number + pFCPUFDest: + format: double + description: Percentual adicional inserido na alíquota interna da UF de destino, relativo ao Fundo de Combate à Pobreza (FCP) naquela UF (pFCPUFDest) + type: number + pICMSUFDest: + format: double + description: Alíquota adotada nas operações internas na UF de destino para o produto / mercadoria (pICMSUFDest) + type: number + pICMSInter: + format: double + description: Alíquota interestadual das UF envolvidas (pICMSInter) + type: number + pICMSInterPart: + format: double + description: Percentual de ICMS Interestadual para a UF de destino (pICMSInterPart) + type: number + vFCPUFDest: + format: double + description: Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP) da UF de destino (vFCPUFDest) + type: number + vICMSUFDest: + format: double + description: Valor do ICMS Interestadual para a UF de destino (vICMSUFDest) + type: number + vICMSUFRemet: + format: double + description: Valor do ICMS Interestadual para a UF do remetente (vICMSUFRemet) + type: number + vBCFCPUFDest: + format: double + description: Valor da BC FCP na UF de destino (vBCFCPUFDest) + type: number + additionalInformation: + description: Informações Adicionais do Produto (infAdProd) + type: string + numberOrderBuy: + description: Número do pedido de compra (xPed) + type: string + itemNumberOrderBuy: + format: int32 + description: Item do Pedido de Compra (nItemPed) + type: integer + medicineDetail: + description: Detalhamento de Medicamentos e de matérias-primas farmacêuticas (med) + type: object + properties: + maximumPrice: + format: double + description: Preço máximo consumidor (vPMC) + type: number + anvisaCode: + description: Código de Produto da ANVISA (cProdANVISA); + type: string + batchId: + description: Número do Lote de medicamentos ou de matérias-primas farmacêuticas (nLote) + type: string + batchQuantity: + format: double + description: Quantidade de produto no Lote de medicamentos ou de matérias-primas farmacêuticas (qLote) + type: number + manufacturedOn: + format: date-time + description: Data de fabricação (dFab) + type: string + expireOn: + format: date-time + description: Data de validade (dVal) + type: string + fuel: + description: Detalhamento de combustível (comb) + type: object + properties: + codeANP: + description: " LA02 - Código de produto da ANP (cProdANP)\r\nVersão 3.00\r\nVersão 4.00" + type: string + percentageNG: + format: double + description: " LA03 - Percentual de Gás Natural para o produto GLP (cProdANP=210203001) (pMixGN)\r\nVersão 3.00" + type: number + descriptionANP: + description: "LA03 - Descrição do produto conforme ANP (descANP)\r\nVersão 4.00" + type: string + percentageGLP: + format: double + description: "LA03a - Percentual do GLP derivado do petróleo no produto GLP (cProdANP=210203001) (pGLP)\r\nVersão 4.00" + type: number + percentageNGn: + format: double + description: "LA03b - Percentual de Gás Natural Nacional – GLGNn para o produto GLP (cProdANP= 210203001) (pGNn)\r\nVersão 4.00" + type: number + percentageGNi: + format: double + description: "LA03c - Percentual de Gás Natural Importado – GLGNi para o produto GLP (cProdANP= 210203001) (pGNi)\r\nVersão 4.00" + type: number + startingAmount: + format: double + description: "LA03d - Valor de partida (cProdANP=210203001) (vPart)\r\nVersão 4.00" + type: number + codif: + description: LA04 - Código de autorização / registro do CODIF (CODIF) + type: string + amountTemp: + format: double + description: LA05 - Quantidade de combustível faturada à temperatura ambiente (qTemp) + type: number + stateBuyer: + description: LA06 - Sigla da UF de consumo (UFCons) + type: string + cide: + description: LA07 - Informações da CIDE (CIDE) + type: object + properties: + bc: + format: double + description: LA08 - BC da CIDE (qBCProd) + type: number + rate: + format: double + description: LA09 - Valor da alíquota da CIDE (vAliqProd) + type: number + cideAmount: + format: double + description: LA10 - Valor da CIDE (vCIDE) + type: number + pump: + description: LA11 - Informações do grupo de “encerrante” (encerrante) + type: object + properties: + spoutNumber: + format: int32 + description: LA12 - Número de identificação do bico utilizado no abastecimento (nBico) + type: integer + number: + format: int32 + description: LA13 - Número de identificação da bomba ao qual o bico está interligado (nBomba) + type: integer + tankNumber: + format: int32 + description: LA14 - Número de identificação do tanque ao qual o bico está interligado (nTanque) + type: integer + beginningAmount: + format: double + description: LA15 - Valor do Encerrante no início do abastecimento (vEncIni) + type: number + endAmount: + format: double + description: LA16 - Valor do Encerrante no final do abastecimento (vEncFin) + type: number + billing: + description: Grupo Cobrança (cobr) + type: object + properties: + bill: + description: Grupo Fatura (fat) + type: object + properties: + number: + description: Número da Fatura (nFat) + type: string + originalAmount: + format: double + description: Valor Original da Fatura (vOrig) + type: number + discountAmount: + format: double + description: Valor do desconto (vDesc) + type: number + netAmount: + format: double + description: Valor Líquido da Fatura (vLiq) + type: number + duplicates: + description: Grupo Duplicata (dup) + type: array + items: + type: object + properties: + duplicateNumber: + description: Número da Duplicata (nDup) + type: string + expirationOn: + format: date-time + description: Data de vencimento (dVenc) + type: string + amount: + format: double + description: Valor da duplicata (vDup) + type: number + payment: + description: Grupo de Formas de Pagamento (pag) + type: array + items: + description: Grupo de Formas de Pagamento (pag) + type: object + properties: + paymentDetail: + description: "YA01a - Grupo Detalhamento da Forma de Pagamento (detPag)\r\nVERSÃO 4.00" + type: array + items: + type: object + properties: + method: + description: Forma de pagamento (tPag) + enum: + - cash + - cheque + - creditCard + - debitCard + - storeCredict + - foodVouchers + - mealVouchers + - giftVouchers + - fuelVouchers + - commercialDuplicate + - bankSlip + - unpaid + - others + type: string + amount: + format: double + description: Valor do Pagamento (vPag) + type: number + card: + description: Grupo de Cartões (card) + type: object + properties: + federalTaxNumber: + description: CNPJ da Credenciadora de cartão de crédito e/ou débito (CNPJ) + type: string + flag: + description: Bandeira da operadora de cartão de crédito e/ou débito (tBand) + enum: + - visa + - mastercard + - americanExpress + - sorocred + - dinnersClub + - elo + - hipercard + - aura + - cabal + - outros + type: string + authorization: + description: Número de autorização da operação cartão de crédito e/ou débito (cAut) + type: string + integrationPaymentType: + description: YA04a - Tipo de Integração para pagamento (tpIntegra) + enum: + - integrated + - notIntegrated + type: string + payBack: + format: double + description: "Valor do troco (vTroco)\r\nVERSÃO 4.00" + type: number + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/productinvoices/{accessKey}.pdf: + get: + tags: + - SEFAZ + summary: Consulta de Nota Fiscal Eletrônica na SEFAZ por Chave de Acesso gerando pdf + description: Você precisará do APIKEY da Empresa + operationId: V2ProductinvoicesByAccessKey}.pdfGet + consumes: [] + produces: + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + fileStream: + type: object + properties: + canRead: + type: boolean + readOnly: true + canSeek: + type: boolean + readOnly: true + canTimeout: + type: boolean + readOnly: true + canWrite: + type: boolean + readOnly: true + length: + format: int64 + type: integer + readOnly: true + position: + format: int64 + type: integer + readTimeout: + format: int32 + type: integer + writeTimeout: + format: int32 + type: integer + contentType: + type: string + readOnly: true + fileDownloadName: + type: string + lastModified: + format: date-time + type: string + entityTag: + type: object + properties: + tag: + readOnly: true + type: object + properties: + buffer: + type: string + readOnly: true + offset: + format: int32 + type: integer + readOnly: true + length: + format: int32 + type: integer + readOnly: true + value: + type: string + readOnly: true + hasValue: + type: boolean + readOnly: true + isWeak: + type: boolean + readOnly: true + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/productinvoices/{accessKey}.xml: + get: + tags: + - SEFAZ + summary: Consulta de Nota Fiscal Eletrônica na SEFAZ por Chave de Acesso + description: Você precisará do APIKEY da Empresa + operationId: V2ProductinvoicesByAccessKey}.xmlGet + consumes: [] + produces: + - application/xml + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + versao: + type: string + nFe: + type: object + properties: + infNFe: + type: object + properties: + versao: + type: string + id: + type: string + ide: + type: object + properties: + cUF: + enum: + - aC + - aL + - aP + - aM + - bA + - cE + - dF + - eS + - gO + - mA + - mT + - mS + - mG + - pA + - pB + - pR + - pE + - pI + - rJ + - rN + - rS + - rO + - rR + - sC + - sP + - sE + - tO + - aN + - eX + type: string + cNF: + type: string + natOp: + type: string + indPag: + enum: + - ipVista + - ipPrazo + - ipOutras + type: string + indPagSpecified: + type: boolean + readOnly: true + mod: + enum: + - nFe + - mDFe + - nFCe + - cTe + - cTeOS + type: string + serie: + format: int32 + type: integer + nNF: + format: int64 + type: integer + dEmi: + format: date-time + type: string + proxydEmi: + type: string + dSaiEnt: + format: date-time + type: string + proxydSaiEnt: + type: string + dhEmi: + format: date-time + type: string + proxyDhEmi: + type: string + dhSaiEnt: + format: date-time + type: string + proxydhSaiEnt: + type: string + tpNF: + enum: + - tnEntrada + - tnSaida + type: string + idDest: + enum: + - doInterna + - doInterestadual + - doExterior + type: string + cMunFG: + format: int64 + type: integer + tpImp: + enum: + - tiSemGeracao + - tiRetrato + - tiPaisagem + - tiSimplificado + - tiNFCe + - tiMsgEletronica + type: string + tpEmis: + enum: + - teNormal + - teFSIA + - teSCAN + - teEPEC + - teFSDA + - teSVCAN + - teSVCRS + - teOffLine + type: string + cDV: + format: int32 + type: integer + tpAmb: + enum: + - taProducao + - taHomologacao + type: string + finNFe: + enum: + - fnNormal + - fnComplementar + - fnAjuste + - fnDevolucao + type: string + indFinal: + enum: + - cfNao + - cfConsumidorFinal + type: string + indPres: + enum: + - pcNao + - pcPresencial + - pcInternet + - pcTeleatendimento + - pcEntregaDomicilio + - pcPresencialForaEstabelecimento + - pcOutros + type: string + procEmi: + enum: + - peAplicativoContribuinte + - peAvulsaFisco + - peAvulsaContribuinte + - peContribuinteAplicativoFisco + type: string + verProc: + type: string + dhCont: + format: date-time + type: string + proxydhCont: + type: string + xJust: + type: string + nFref: + type: array + items: + type: object + properties: + refNFe: + type: string + refNF: + type: object + properties: + cUF: + enum: + - aC + - aL + - aP + - aM + - bA + - cE + - dF + - eS + - gO + - mA + - mT + - mS + - mG + - pA + - pB + - pR + - pE + - pI + - rJ + - rN + - rS + - rO + - rR + - sC + - sP + - sE + - tO + - aN + - eX + type: string + aamm: + type: string + cnpj: + type: string + mod: + enum: + - modelo + - modelo2 + type: string + serie: + format: int32 + type: integer + nNF: + format: int32 + type: integer + refNFP: + type: object + properties: + cUF: + enum: + - aC + - aL + - aP + - aM + - bA + - cE + - dF + - eS + - gO + - mA + - mT + - mS + - mG + - pA + - pB + - pR + - pE + - pI + - rJ + - rN + - rS + - rO + - rR + - sC + - sP + - sE + - tO + - aN + - eX + type: string + aamm: + type: string + cnpj: + type: string + cpf: + type: string + ie: + type: string + mod: + type: string + serie: + format: int32 + type: integer + nNF: + format: int32 + type: integer + refCTe: + type: string + refECF: + type: object + properties: + mod: + type: string + nECF: + format: int32 + type: integer + nCOO: + format: int32 + type: integer + emit: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xNome: + type: string + xFant: + type: string + enderEmit: + type: object + properties: + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + cep: + type: string + cPais: + format: int32 + type: integer + xPais: + type: string + fone: + format: int64 + type: integer + ie: + type: string + iest: + type: string + im: + type: string + cnae: + type: string + crt: + enum: + - simplesNacional + - simplesNacionalExcessoSublimite + - regimeNormal + type: string + avulsa: + type: object + properties: + cnpj: + type: string + xOrgao: + type: string + matr: + type: string + xAgente: + type: string + fone: + type: string + uf: + type: string + nDAR: + type: string + dEmi: + type: string + vDAR: + format: double + type: number + repEmi: + type: string + dPag: + type: string + dest: + type: object + properties: + cnpj: + type: string + cpf: + type: string + idEstrangeiro: + type: string + xNome: + type: string + enderDest: + type: object + properties: + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + cep: + type: string + cPais: + format: int32 + type: integer + xPais: + type: string + fone: + format: int64 + type: integer + indIEDest: + enum: + - contribuinteICMS + - isento + - naoContribuinte + type: string + ie: + type: string + isuf: + type: string + im: + type: string + email: + type: string + retirada: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + entrega: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + autXML: + type: array + items: + type: object + properties: + cnpj: + type: string + cpf: + type: string + det: + type: array + items: + type: object + properties: + nItem: + format: int32 + type: integer + prod: + type: object + properties: + cProd: + type: string + cEAN: + type: string + xProd: + type: string + ncm: + type: string + nve: + type: array + items: + type: string + cest: + type: string + indEscala: + enum: + - s + - n + type: string + indEscalaSpecified: + type: boolean + readOnly: true + cnpjFab: + type: string + cBenef: + type: string + extipi: + type: string + cfop: + format: int32 + type: integer + uCom: + type: string + qCom: + format: double + type: number + vUnCom: + format: double + type: number + vProd: + format: double + type: number + cEANTrib: + type: string + uTrib: + type: string + qTrib: + format: double + type: number + vUnTrib: + format: double + type: number + vFrete: + format: double + type: number + vSeg: + format: double + type: number + vDesc: + format: double + type: number + vOutro: + format: double + type: number + indTot: + enum: + - valorDoItemNaoCompoeTotalNF + - valorDoItemCompoeTotalNF + type: string + di: + type: array + items: + type: object + properties: + nDI: + type: string + dDI: + format: date-time + type: string + proxydDI: + type: string + xLocDesemb: + type: string + ufDesemb: + type: string + dDesemb: + format: date-time + type: string + proxydDesemb: + type: string + tpViaTransp: + enum: + - maritima + - fluvial + - lacustre + - aerea + - postal + - ferroviaria + - rodoviaria + - condutoRedeTransmissão + - meiosProprios + - entradaSaidaficta + - courier + - handcarry + type: string + vAFRMM: + format: double + type: number + tpIntermedio: + enum: + - contaPropria + - contaeOrdem + - porEncomenda + type: string + cnpj: + type: string + ufTerceiro: + type: string + cExportador: + type: string + adi: + type: array + items: + type: object + properties: + nAdicao: + format: int32 + type: integer + nSeqAdic: + format: int32 + type: integer + cFabricante: + type: string + vDescDI: + format: double + type: number + nDraw: + type: string + detExport: + type: array + items: + type: object + properties: + nDraw: + type: string + exportInd: + type: object + properties: + nRE: + type: string + chNFe: + type: string + qExport: + format: double + type: number + xPed: + type: string + nItemPed: + format: int32 + type: integer + nFCI: + type: string + rastro: + type: array + items: + type: object + properties: + nLote: + type: string + qLote: + format: double + type: number + dFab: + format: date-time + type: string + proxydFab: + type: string + dVal: + format: date-time + type: string + proxydVal: + type: string + cAgreg: + type: string + produtoEspecifico: + type: object + properties: {} + nRECOPI: + type: string + imposto: + type: object + properties: + vTotTrib: + format: double + type: number + icms: + type: object + properties: + tipoICMS: + type: object + properties: {} + issqn: + type: object + properties: + vBC: + format: double + type: number + vAliq: + format: double + type: number + vISSQN: + format: double + type: number + cMunFG: + format: int64 + type: integer + cListServ: + type: string + vDeducao: + format: double + type: number + vOutro: + format: double + type: number + vDescIncond: + format: double + type: number + vDescCond: + format: double + type: number + vISSRet: + format: double + type: number + indISS: + enum: + - iiExigivel + - iiNaoIncidencia + - iiIsencao + - iiExportacao + - iiImunidade + - iiExigSuspDecisaoJudicial + - iiExigSuspProcessoAdm + type: string + cServico: + type: string + cMun: + format: int64 + type: integer + cPais: + format: int32 + type: integer + nProcesso: + type: string + indIncentivo: + enum: + - iiSim + - iiNao + type: string + ipi: + type: object + properties: + clEnq: + type: string + cnpjProd: + type: string + cSelo: + type: string + qSelo: + format: int32 + type: integer + cEnq: + format: int32 + type: integer + tipoIPI: + type: object + properties: {} + ii: + type: object + properties: + vBC: + format: double + type: number + vDespAdu: + format: double + type: number + vII: + format: double + type: number + vIOF: + format: double + type: number + pis: + type: object + properties: + tipoPIS: + type: object + properties: {} + pisst: + type: object + properties: + vBC: + format: double + type: number + pPIS: + format: double + type: number + qBCProd: + format: double + type: number + vAliqProd: + format: double + type: number + vPIS: + format: double + type: number + cofins: + type: object + properties: + tipoCOFINS: + type: object + properties: {} + cofinsst: + type: object + properties: + vBC: + format: double + type: number + pCOFINS: + format: double + type: number + qBCProd: + format: double + type: number + vAliqProd: + format: double + type: number + vCOFINS: + format: double + type: number + icmsufDest: + type: object + properties: + vBCUFDest: + format: double + type: number + vBCFCPUFDest: + format: double + type: number + vBCFCPUFDestSpecified: + type: boolean + readOnly: true + pFCPUFDest: + format: double + type: number + pICMSUFDest: + format: double + type: number + pICMSInter: + format: double + type: number + pICMSInterPart: + format: double + type: number + vFCPUFDest: + format: double + type: number + vICMSUFDest: + format: double + type: number + vICMSUFRemet: + format: double + type: number + impostoDevol: + type: object + properties: + pDevol: + format: double + type: number + ipi: + type: object + properties: + vIPIDevol: + format: double + type: number + infAdProd: + type: string + total: + type: object + properties: + icmsTot: + type: object + properties: + vBC: + format: double + type: number + vICMS: + format: double + type: number + vICMSDeson: + format: double + type: number + vFCPUFDest: + format: double + type: number + vICMSUFDest: + format: double + type: number + vICMSUFRemet: + format: double + type: number + vFCP: + format: double + type: number + vFCPSpecified: + type: boolean + readOnly: true + vBCST: + format: double + type: number + vST: + format: double + type: number + vFCPST: + format: double + type: number + vFCPSTSpecified: + type: boolean + readOnly: true + vFCPSTRet: + format: double + type: number + vFCPSTRetSpecified: + type: boolean + readOnly: true + vProd: + format: double + type: number + vFrete: + format: double + type: number + vSeg: + format: double + type: number + vDesc: + format: double + type: number + vII: + format: double + type: number + vIPI: + format: double + type: number + vIPIDevol: + format: double + type: number + vIPIDevolSpecified: + type: boolean + readOnly: true + vPIS: + format: double + type: number + vCOFINS: + format: double + type: number + vOutro: + format: double + type: number + vNF: + format: double + type: number + vTotTrib: + format: double + type: number + issqNtot: + type: object + properties: + vServ: + format: double + type: number + vBC: + format: double + type: number + vISS: + format: double + type: number + vPIS: + format: double + type: number + vCOFINS: + format: double + type: number + dCompet: + type: string + vDeducao: + format: double + type: number + vOutro: + format: double + type: number + vDescIncond: + format: double + type: number + vDescCond: + format: double + type: number + vISSRet: + format: double + type: number + cRegTrib: + enum: + - tISSMicroempresaMunicipal + - rTISSEstimativa + - rTISSSociedadeProfissionais + - rTISSCooperativa + - rTISSMEI + - rTISSMEEPP + type: string + retTrib: + type: object + properties: + vRetPIS: + format: double + type: number + vRetCOFINS: + format: double + type: number + vRetCSLL: + format: double + type: number + vBCIRRF: + format: double + type: number + vIRRF: + format: double + type: number + vBCRetPrev: + format: double + type: number + vRetPrev: + format: double + type: number + transp: + type: object + properties: + modFrete: + enum: + - mfContaEmitenteOumfContaRemetente + - mfContaDestinatario + - mfContaTerceiros + - mfProprioContaRemente + - mfProprioContaDestinatario + - mfSemFrete + type: string + modFreteSpecified: + type: boolean + readOnly: true + transporta: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xNome: + type: string + ie: + type: string + xEnder: + type: string + xMun: + type: string + uf: + type: string + retTransp: + type: object + properties: + vServ: + format: double + type: number + vBCRet: + format: double + type: number + pICMSRet: + format: double + type: number + vICMSRet: + format: double + type: number + cfop: + format: int32 + type: integer + cMunFG: + format: int64 + type: integer + veicTransp: + type: object + properties: + placa: + type: string + uf: + type: string + rntc: + type: string + reboque: + type: array + items: + type: object + properties: + placa: + type: string + uf: + type: string + rntc: + type: string + vol: + type: array + items: + type: object + properties: + qVol: + format: int32 + type: integer + esp: + type: string + marca: + type: string + nVol: + type: string + pesoL: + format: double + type: number + pesoB: + format: double + type: number + lacres: + type: array + items: + type: object + properties: + nLacre: + type: string + vagao: + type: string + balsa: + type: string + cobr: + type: object + properties: + fat: + type: object + properties: + nFat: + type: string + vOrig: + format: double + type: number + vDesc: + format: double + type: number + vLiq: + format: double + type: number + dup: + type: array + items: + type: object + properties: + nDup: + type: string + dVenc: + format: date-time + type: string + proxydVenc: + type: string + vDup: + format: double + type: number + pag: + type: array + items: + type: object + properties: + detPag: + type: array + items: + type: object + properties: + indPag: + enum: + - ipDetPgVista + - ipDetPgPrazo + type: string + indPagSpecified: + type: boolean + readOnly: true + tPag: + enum: + - fpDinheiro + - fpCheque + - fpCartaoCredito + - fpCartaoDebito + - fpCreditoLoja + - fpValeAlimentacao + - fpValeRefeicao + - fpValePresente + - fpValeCombustivel + - fpDuplicataMercantil + - fpBoletoBancario + - fpSemPagamento + - fpOutro + type: string + vPag: + format: double + type: number + card: + type: object + properties: + tpIntegra: + enum: + - tipIntegradoAutomacao + - tipNaoIntegrado + type: string + cnpj: + type: string + tBand: + enum: + - bcVisa + - bcMasterCard + - bcAmericanExpress + - bcSorocred + - bcDinersClub + - elo + - hipercard + - aura + - cabal + - bcOutros + type: string + cAut: + type: string + vTroco: + format: double + type: number + vTrocoSpecified: + type: boolean + readOnly: true + tPag: + enum: + - fpDinheiro + - fpCheque + - fpCartaoCredito + - fpCartaoDebito + - fpCreditoLoja + - fpValeAlimentacao + - fpValeRefeicao + - fpValePresente + - fpValeCombustivel + - fpDuplicataMercantil + - fpBoletoBancario + - fpSemPagamento + - fpOutro + type: string + tPagSpecified: + type: boolean + readOnly: true + vPag: + format: double + type: number + vPagSpecified: + type: boolean + readOnly: true + card: + type: object + properties: + tpIntegra: + enum: + - tipIntegradoAutomacao + - tipNaoIntegrado + type: string + cnpj: + type: string + tBand: + enum: + - bcVisa + - bcMasterCard + - bcAmericanExpress + - bcSorocred + - bcDinersClub + - elo + - hipercard + - aura + - cabal + - bcOutros + type: string + cAut: + type: string + infAdic: + type: object + properties: + infAdFisco: + type: string + infCpl: + type: string + obsCont: + type: array + items: + type: object + properties: + xCampo: + type: string + xTexto: + type: string + obsFisco: + type: array + items: + type: object + properties: + xCampo: + type: string + xTexto: + type: string + procRef: + type: array + items: + type: object + properties: + nProc: + type: string + indProc: + enum: + - ipSEFAZ + - ipJusticaFederal + - ipJusticaEstadual + - ipSecexRFB + - ipOutros + type: string + exporta: + type: object + properties: + ufSaidaPais: + type: string + xLocExporta: + type: string + xLocDespacho: + type: string + compra: + type: object + properties: + xNEmp: + type: string + xPed: + type: string + xCont: + type: string + cana: + type: object + properties: + safra: + type: string + ref: + type: string + forDia: + type: array + items: + type: object + properties: + dia: + format: int32 + type: integer + qtde: + format: double + type: number + qTotMes: + format: double + type: number + qTotAnt: + format: double + type: number + qTotGer: + format: double + type: number + deduc: + type: array + items: + type: object + properties: + xDed: + type: string + vDed: + format: double + type: number + vFor: + format: double + type: number + vTotDed: + format: double + type: number + vLiqFor: + format: double + type: number + infRespTec: + type: object + properties: + cnpj: + type: string + xContato: + type: string + email: + type: string + fone: + type: string + idCSRT: + type: string + proxyidCSRT: + type: string + hashCSRT: + type: string + infNFeSupl: + type: object + properties: + qrCode: + type: string + urlChave: + type: string + signature: + type: object + properties: + signedInfo: + type: object + properties: + canonicalizationMethod: + type: object + properties: + algorithm: + type: string + signatureMethod: + type: object + properties: + algorithm: + type: string + reference: + type: object + properties: + uri: + type: string + transforms: + type: array + items: + type: object + properties: + algorithm: + type: string + digestMethod: + type: object + properties: + algorithm: + type: string + digestValue: + type: string + signatureValue: + type: string + keyInfo: + type: object + properties: + x509Data: + type: object + properties: + x509Certificate: + type: string + protNFe: + type: object + properties: + versao: + type: string + infProt: + type: object + properties: + id: + type: string + tpAmb: + enum: + - taProducao + - taHomologacao + type: string + verAplic: + type: string + chNFe: + type: string + dhRecbto: + format: date-time + type: string + proxyDhRecbto: + type: string + nProt: + type: string + digVal: + type: string + cStat: + format: int32 + type: integer + xMotivo: + type: string + signature: + type: object + properties: + signedInfo: + type: object + properties: + canonicalizationMethod: + type: object + properties: + algorithm: + type: string + signatureMethod: + type: object + properties: + algorithm: + type: string + reference: + type: object + properties: + uri: + type: string + transforms: + type: array + items: + type: object + properties: + algorithm: + type: string + digestMethod: + type: object + properties: + algorithm: + type: string + digestValue: + type: string + signatureValue: + type: string + keyInfo: + type: object + properties: + x509Data: + type: object + properties: + x509Certificate: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/productinvoices/events/{accessKey}: + get: + tags: + - SEFAZ + summary: Consulta de Eventos da Nota Fiscal Eletrônica na SEFAZ por Chave de Acesso + description: Você precisará do APIKEY da Empresa + operationId: V2ProductinvoicesEventsByAccessKeyGet + consumes: [] + produces: + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + events: + description: Lista de eventos vinculado à nota fiscal + type: array + items: + required: + - authorizedOn + - description + type: object + properties: + stateCode: + format: int32 + description: "Órgão autor do registro do evento\r\nAC = 12,\r\nAL = 27,\r\nAM = 13,\r\nAP = 16,\r\nBA = 29,\r\nCE = 23,\r\nDF = 53,\r\nES = 32,\r\nGO = 52,\r\nMA = 21,\r\nMG = 31,\r\nMS = 50,\r\nMT = 51,\r\nPA = 15,\r\nPB = 25,\r\nPE = 26,\r\nPI = 22,\r\nPR = 41,\r\nRJ = 33,\r\nRN = 24,\r\nRR = 14,\r\nRS = 43,\r\nSC = 42,\r\nSE = 28,\r\nSP = 35,\r\nTO = 17,\r\nRO = 11,\r\nAN = 91, (Ambiente Nacional)" + type: integer + type: + format: int32 + description: Código do Tipo do Evento + type: integer + sequence: + format: int32 + description: Sequencial do evento para o mesmo tipo de evento (nSeqEvento) + type: integer + authorFederalTaxNumber: + description: CNPJ/CPF do autor do evento + type: string + id: + description: Identificador da TAG a ser assinada + type: string + protocol: + format: int64 + description: Número do Protocolo do evento + type: integer + authorizedOn: + format: date-time + description: "Data de autorização da ocorrência/evento\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + type: string + description: + description: Descrição do Evento – “Cancelamento registrado” + type: string + createdOn: + format: date-time + description: "Data de consulta\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/productinvoices/serpro/{accessKey}: + get: + tags: + - Irrestrita + summary: Consulta Irrestrita de NF-e por Chave de Acesso (JSON) + description: "Consulta Irrestrita da NFE.io — fonte nacional unificada de NF-e autorizadas. Retorna o documento em JSON com a NF-e normalizada em `camelCase` (campos `issuer`, `buyer`, `items[]`, `totals`, `protocol` etc.) — equivalente ao XML oficial. Para o XML oficial (`nfeProc`), use o sufixo `.xml`. Use a Chave de Dados no header `Authorization` SEM prefixo `Bearer`." + operationId: V2ProductinvoicesSerproByAccessKeyGet + consumes: [] + produces: + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + currentStatus: + description: Situação Atual + enum: + - unknown + - authorized + - canceled + type: string + stateCode: + format: int32 + description: Código da UF do emitente do Documento Fiscal (cUF) + type: integer + checkCode: + format: int64 + description: Código Numérico que compõe a Chave de Acesso (cNF) + type: integer + operationNature: + description: Descrição da Natureza da Operação (natOp) + type: string + paymentType: + description: "Indicador da forma de pagamento (indPag)\r\n\r\n 0 - Pagamento à vista (InCash)\r\n 1 - Pagamento a prazo (Term)\r\n 2 - Outros (Others)\r\n" + enum: + - inCash + - term + - others + type: string + codeModel: + format: int32 + description: Código do Modelo do Documento Fiscal (mod) + type: integer + serie: + format: int32 + description: Série do Documento Fiscal (serie) + type: integer + number: + format: int64 + description: Número do Documento Fiscal (nNF) + type: integer + issuedOn: + format: date-time + description: "Data de emissão do Documento Fiscal (dhEmi)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + type: string + operationOn: + format: date-time + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + type: string + operationType: + description: Tipo de Operação (tpNF) + enum: + - incoming + - outgoing + type: string + destination: + description: Identificador de local de destino da operação (idDest) + enum: + - international_Operation + - interstate_Operation + - internal_Operation + type: string + cityCode: + format: int32 + description: Código do Município de Ocorrência do Fato Gerador (cMunFG) + type: integer + printType: + description: Formato de Impressão do DANFE (tpImp) + enum: + - none + - nFeNormalPortrait + - nFeNormalLandscape + - nFeSimplified + - dANFE_NFC_E + - dANFE_NFC_E_MSG_ELETRONICA + type: string + issueType: + description: Tipo de Emissão da NF-e (tpEmis) + enum: + - cONTINGENCIA_OFF_LINE_NFC_E + - cONTINGENCIA_SVC_RS + - cONTINGENCIA_SVC_AN + - cONTINGENCIA_FS_DA + - cONTINGENCIA_DPEC + - cONTINGENCIA_SCAN + - cONTINGENCIA_FS_IA + - normal + type: string + checkCodeDigit: + format: int32 + description: Dígito Verificador da Chave de Acesso da NF-e (cDV) + type: integer + environmentType: + description: Identificação do Ambiente (tpAmb) + enum: + - production + - test + type: string + purposeType: + description: Finalidade de emissão da NF-e (finNFe) + enum: + - devolution + - adjustment + - complement + - normal + type: string + consumerType: + description: Indica operação com Consumidor final (indFinal) + enum: + - normal + - finalConsumer + type: string + presenceType: + description: Indicador de presença do comprador no estabelecimento comercial no momento da operação (indPres) + enum: + - none + - presence + - internet + - telephone + - delivery + - presenceOutOfStore + - othersNoPresente + type: string + processType: + description: Processo de emissão da NF-e (procEmi) + enum: + - ownSoftware + - fiscoSingle + - taxPayerSingle + - fiscoSoftware + type: string + invoiceVersion: + description: Versão do Processo de emissão da NF-e (verProc) + type: string + xmlVersion: + description: Versão do leiaute (versao) + type: string + contingencyOn: + format: date-time + description: "Data e Hora da entrada em contingência (dhCont)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + type: string + contingencyJustification: + description: Justificativa da entrada em contingência (xJust) + type: string + issuer: + description: Grupo de identificação do emitente da NF-e (emit) + type: object + properties: + federalTaxNumber: + format: double + description: CNPJ do emitente (CNPJ) / CPF do remetente (CPF) + type: number + name: + description: Razão Social ou Nome do emitente (xNome) + type: string + tradeName: + description: Nome fantasia (xFant) + type: string + address: + description: Endereço do emitente (enderEmit) + type: object + properties: + phone: + type: string + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + postalCode: + type: string + country: + type: string + stateTaxNumber: + description: Inscrição Estadual (IE) + type: string + codeTaxRegime: + description: Código de Regime Tributário (CRT) + enum: + - national_Simple + - national_Simple_Brute + - normal_Regime + type: string + cnae: + format: int64 + description: CNAE fiscal (CNAE) + type: integer + im: + description: Inscrição Municipal do Prestador de Serviço (IM) + type: string + iest: + format: int64 + description: IE do Substituto Tributário (IEST) + type: integer + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - undefined + - naturalPerson + - legalEntity + type: string + buyer: + description: Grupo de identificação do Destinatário da NF-e (dest) + type: object + properties: + federalTaxNumber: + format: double + description: "CNPJ do Destinantario (CNPJ) / CPF do destinatário (CPF) /\r\nIdentificação do destinatário no caso de comprador estrangeiro (idEstrangeiro)" + type: number + name: + description: Razão Social ou nome do destinatário (xNome) + type: string + address: + description: Identificação do Endereço (enderDest) + type: object + properties: + phone: + type: string + state: + type: string + city: + type: object + properties: + code: + type: string + name: + type: string + district: + type: string + additionalInformation: + type: string + streetSuffix: + type: string + street: + type: string + number: + type: string + postalCode: + type: string + country: + type: string + stateTaxNumber: + description: Inscrição Estadual (IE) + type: string + stateTaxNumberIndicator: + format: int32 + description: Indicador Inscrição Estadual (indIEDest) + type: integer + email: + description: Email (email) + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - undefined + - naturalPerson + - legalEntity + type: string + totals: + description: Grupo Totais da NF-e (total) + type: object + properties: + icms: + description: Grupo de Valores Totais referentes ao ICMS (ICMSTot) + type: object + properties: + baseTax: + format: double + description: Base de Cálculo do ICMS (vBC) + type: number + icmsAmount: + format: double + description: Valor Total do ICMS (vICMS) + type: number + icmsExemptAmount: + format: double + description: Valor ICMS Total desonerado (vICMSDeson) + type: number + stCalculationBasisAmount: + format: double + description: Base de Cálculo do ICMS Substituição Tributária (vBCST) + type: number + stAmount: + format: double + description: Valor Total do ICMS ST (vST) + type: number + productAmount: + format: double + description: Valor Total dos produtos e serviços (vProd) + type: number + freightAmount: + format: double + description: Valor Total do Frete (vFrete) + type: number + insuranceAmount: + format: double + description: Valor Total do Seguro (vSeg) + type: number + discountAmount: + format: double + description: Valor Total do Desconto (vDesc) + type: number + iiAmount: + format: double + description: Valor Total do Imposto de Importação (vII) + type: number + ipiAmount: + format: double + description: Valor Total do IPI (vIPI) + type: number + pisAmount: + format: double + description: Valor do PIS (vPIS) + type: number + cofinsAmount: + format: double + description: Valor do COFINS (vCOFINS) + type: number + othersAmount: + format: double + description: Outras Despesas acessórias (vOutro) + type: number + invoiceAmount: + format: double + description: Valor Total da NF-e (vNF) + type: number + fcpufDestinationAmount: + format: double + description: Valor Total ICMS FCP UF Destino + type: number + icmsufDestinationAmount: + format: double + description: Valor Total ICMS Interestadual UF Destino + type: number + icmsufSenderAmount: + format: double + description: Valor Total ICMS Interestadual UF Rem. + type: number + federalTaxesAmount: + format: double + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + type: number + fcpAmount: + format: double + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + type: number + fcpstAmount: + format: double + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido por substituição tributária. + type: number + fcpstRetAmount: + format: double + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido anteriormente por substituição tributária. + type: number + ipiDevolAmount: + format: double + description: Valor total do IPI devolvido (vIPIDevol) + type: number + issqn: + description: Grupo de Valores Totais referentes ao ISSQN (ISSQNtot) + type: object + properties: + totalServiceNotTaxedICMS: + format: double + description: Valor Total Serv.Não Tributados p/ ICMS + type: number + baseRateISS: + format: double + description: Base de Cálculo do ISS + type: number + totalISS: + format: double + description: Valor Total do ISS + type: number + valueServicePIS: + format: double + description: Valor do PIS sobre Serviços + type: number + valueServiceCOFINS: + format: double + description: Valor da COFINS sobre Serviços + type: number + provisionService: + format: date-time + description: Data Prestação Serviço + type: string + deductionReductionBC: + format: double + description: Valor Dedução para Redução da BC + type: number + valueOtherRetention: + format: double + description: Valor Outras Retenções + type: number + discountUnconditional: + format: double + description: Valor Desconto Incondicionado + type: number + discountConditioning: + format: double + description: Valor Desconto Condicionado + type: number + totalRetentionISS: + format: double + description: Valor Total Retenção ISS + type: number + codeTaxRegime: + format: double + description: Código Regime Tributação + type: number + transport: + description: Grupo de Informações do Transporte da NF-e (transp) + type: object + properties: + freightModality: + format: int32 + description: Modalidade do frete (modFrete) + type: integer + transportGroup: + description: Grupo Transportador (transporta) + type: object + properties: + cityName: + description: Nome do Município (xMun) + type: string + federalTaxNumber: + description: CNPJ do Transportador (CNPJ) ou CPF do Transportador (CPF) + type: string + cpf: + description: CPF do Transportador (CPF) + type: string + name: + description: Razão Social ou nome (xNome) + type: string + stateTaxNumber: + description: Inscrição Estadual do Transportador (IE) + type: string + fullAddress: + description: Endereço Completo (xEnder) + type: string + state: + description: Sigla da UF (UF) + type: string + transportRetention: + description: Grupo de Retenção do ICMS do transporte + type: string + reboque: + description: Grupo Reboque (reboque) + type: object + properties: + plate: + description: Placa do Veiculo (placa) + type: string + uf: + description: UF Veiculo Reboque (UF) + type: string + rntc: + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + type: string + wagon: + description: Identificação do Vagão (vagao) + type: string + ferry: + description: Identificação da Balsa (balsa) + type: string + volume: + description: Grupo Volumes (vol) + type: object + properties: + volumeQuantity: + format: int32 + description: Quantidade de volumes transportados (qVol) + type: integer + species: + description: Espécie dos volumes transportados (esp) + type: string + brand: + description: Marca dos Volumes Transportados (marca) + type: string + volumeNumeration: + description: Numeração dos Volumes Transportados (nVol) + type: string + netWeight: + format: double + description: Peso Liquido(em Kg) (pesoL) + type: number + grossWeight: + format: double + description: Peso Bruto(em Kg) (pesoB) + type: number + transportVehicle: + description: Grupo Veiculo (veicTransp) + type: object + properties: + plate: + description: Placa do Veiculo (placa) + type: string + state: + description: Sigla da UF (UF) + type: string + rntc: + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + type: string + sealNumber: + description: Número dos Lacres + type: string + transpRate: + description: Grupo Retenção ICMS transporte (retTransp) + type: object + properties: + serviceAmount: + format: double + description: Valor do Serviço (vServ) + type: number + bcRetentionAmount: + format: double + description: BC da Retenção do ICMS (vBCRet) + type: number + icmsRetentionRate: + format: double + description: Alíquota da Retenção (pICMSRet) //Change to Rate + type: number + icmsRetentionAmount: + format: double + description: Valor do ICMS Retido (vICMSRet) + type: number + cfop: + format: int64 + description: CFOP de Serviço de Transporte (CFOP) + type: integer + cityGeneratorFactCode: + format: int64 + description: Código do Municipio de ocorrencia do fato gerador do ICMS do Transpote (cMunFG) + type: integer + additionalInformation: + description: Informacoes Adicionais (infAdic) + type: object + properties: + fisco: + description: Informações Adicionais de Interesse do Fisco (infAdFisco) + type: string + taxpayer: + description: Informações Complementares de interesse do Contribuinte (infCpl) + type: string + xmlAuthorized: + description: Informações Complementares de interesse do Contribuinte (infCpl) + type: array + items: + format: int64 + type: integer + effort: + type: string + order: + type: string + contract: + type: string + taxDocumentsReference: + description: Documentos Fiscais Referenciados (NFref) + type: array + items: + type: object + properties: + taxCouponInformation: + description: Informações do Cupom Fiscal referenciado (refECF) + type: object + properties: + modelDocumentFiscal: + description: Modelo de Documento Fiscal + type: string + orderECF: + description: Número de Ordem Sequencial do ECF + type: string + orderCountOperation: + format: int32 + description: Número do Contador de Ordem de Operação + type: integer + documentInvoiceReference: + description: Informação da NF modelo 1/1A referenciada (refNF) + type: object + properties: + state: + format: double + description: Código da UF + type: number + yearMonth: + description: Ano / Mês + type: string + federalTaxNumber: + description: CNPJ + type: string + model: + description: Modelo + type: string + series: + description: Série + type: string + number: + description: Número + type: string + accessKey: + description: Chave de Acesso (refNFe) + type: string + taxpayerComments: + description: Grupo do campo de uso livre do contribuinte (obsCont) + type: array + items: + type: object + properties: + field: + description: Campo + type: string + text: + description: Texto + type: string + referencedProcess: + description: Grupo do Processos referenciados (procRef) + type: array + items: + type: object + properties: + identifierConcessory: + type: string + identifierOrigin: + format: int32 + type: integer + protocol: + description: Informações do Protocolo de resposta. TAG a ser assinada (protNFe) + type: object + properties: + id: + description: Identificador da TAG a ser assinada, somente precisa ser informado se a UF assinar a resposta. (ID) + type: string + environmentType: + description: 'Identificação do Ambiente: 1 – Produção/2 - Homologação (tpAmb)' + enum: + - production + - test + type: string + applicationVersion: + description: Versão do Aplicativo que processou o Lote (verAplic) + type: string + accessKey: + description: Chave de Acesso da NF-e (chNFe) + type: string + receiptOn: + format: date-time + description: "Preenchido com a data e hora do processamento (dhRecbto)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + type: string + protocolNumber: + description: Número do Protocolo da NF-e (nProt) + type: string + validatorDigit: + description: (Digest Value) da NF-e processada Utilizado para conferir a integridade da NFe original. (digVal) + type: string + statusCode: + format: int32 + description: Código do status da resposta para a NF-e (cStat) + type: integer + description: + description: Descrição literal do status da resposta para a NF-e (xMotivo) + type: string + signature: + description: "Assinatura XML do grupo identificado pelo atributo “Id” (Signature)\r\nA decisão de assinar a mensagem fica a critério da UF interessada." + type: string + items: + type: array + items: + description: Grupo do detalhamento de Produtos e Serviços da NF-e (det) + type: object + properties: + code: + description: Código do produto ou serviço (cProd) + type: string + codeGTIN: + description: "GTIN (Global Trade Item Number) do produto, \r\nantigo código EAN ou código de barras (cEAN)" + type: string + description: + description: Descrição do produto ou serviço (xProd) + type: string + ncm: + description: Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM) + type: string + extipi: + description: EX_TIPI (EXTIPI) + type: string + cfop: + format: int64 + description: Código Fiscal de Operações e Prestações (CFOP) + type: integer + unit: + description: Unidade Comercial (uCom) + type: string + quantity: + format: double + description: Quantidade Comercial (qCom) + type: number + unitAmount: + format: double + description: Valor Unitário de Comercialização (vUnCom) + type: number + totalAmount: + format: double + description: Valor Total Bruto dos Produtos ou Serviços (vProd) + type: number + eanTaxableCode: + description: "GTIN (Global Trade Item Number) da unidade tributável, \r\nantigo código EAN ou código de barras (cEANTrib)" + type: string + unitTax: + description: Unidade Tributável (uTrib) + type: string + quantityTax: + format: double + description: Quantidade Tributável (qTrib) + type: number + taxUnitAmount: + format: double + description: Valor Unitário de tributação (vUnTrib) + type: number + freightAmount: + format: double + description: Valor Total do Frete (vFrete) + type: number + insuranceAmount: + format: double + description: Valor Total do Seguro (vSeg) + type: number + discountAmount: + format: double + description: Valor do Desconto (vDesc) + type: number + othersAmount: + format: double + description: Outras despesas acessórias (vOutro) + type: number + totalIndicator: + description: "Indica se valor do Item (vProd) \r\nentra no valor total da NF-e (vProd) (indTot)" + type: boolean + cest: + description: Código especificador da substituição tributária (CEST) + type: string + tax: + description: Tributos incidentes no Produto ou Serviço (imposto) + type: object + properties: + totalTax: + format: double + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + type: number + icms: + description: Dados do ICMS Normal e ST (ICMS) + type: object + properties: + origin: + description: Origem da mercadoria (orig) + type: string + cst: + description: Tributação do ICMS (CST) + type: string + baseTaxModality: + description: Modalidade de determinação da BC do ICMS (modBC) + type: string + baseTax: + format: double + description: Valor da BC do ICMS (vBC) + type: number + baseTaxSTModality: + description: Modalidade de determinação da BC do ICMS ST (modBCST) + type: string + baseTaxSTReduction: + format: double + description: "pRedBCST\r\nPercentual da Redução de BC do ICMS ST (pRedBCST)" + type: number + baseTaxSTAmount: + format: double + description: Valor da BC do ICMS ST (vBCST) + type: number + baseTaxReduction: + format: double + description: Percentual da Redução de BC (pRedBC) + type: number + stRate: + format: double + description: Alíquota do imposto do ICMS ST (pICMSST) + type: number + stAmount: + format: double + description: Valor do ICMS ST (vICMSST) + type: number + stMarginAmount: + format: double + description: Percentual da margem de valor Adicionado do ICMS ST (pMVAST) + type: number + csosn: + description: "101- Tributada pelo Simples Nacional com permissão de crédito. (v.2.0) (CSOSN)\r\nCódigo de Situação da Operação – Simples Nacional" + type: string + rate: + format: double + description: Alíquota do imposto (pICMS) + type: number + amount: + format: double + description: "Valor do ICMS (vICMS)\r\n\r\nO valor do ICMS desonerado será informado apenas nas operações:\r\na) com produtos beneficiados com a desoneração condicional do ICMS.\r\nb) destinadas à SUFRAMA, informando-se o valor que seria devido se não houvesse isenção.\r\nc) de venda a órgãos da administração pública direta e suas fundações e\r\nautarquias com isenção do ICMS. (NT 2011/004)" + type: number + snCreditRate: + description: Alíquota aplicável de cálculo do crédito (Simples Nacional). (pCredSN) + type: string + snCreditAmount: + description: Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 (Simples Nacional) + type: string + stMarginAddedAmount: + description: "Percentual da margem de valor Adicionado do ICMS ST (vCredICMSSN)\r\n0 – Preço tabelado ou máximo sugerido;\r\n1 - Lista Negativa (valor);\r\n2 - Lista Positiva (valor);\r\n3 - Lista Neutra (valor);\r\n4 - Margem Valor Agregado (%);\r\n5 - Pauta (valor);" + type: string + stRetentionAmount: + description: "Valor do ICMS ST retido (vICMSSTRet)\r\nValor do ICMS ST cobrado anteriormente por ST (v2.0) (vICMS)" + type: string + baseSTRetentionAmount: + description: Valor da BC do ICMS ST retido + type: string + baseTaxOperationPercentual: + type: string + ufst: + description: "UF para qual é devido o ICMS ST (UFST)\r\nSigla da UF para qual é devido o ICMS ST da operação. (v2.0)" + type: string + amountSTUnfounded: + format: double + description: Valor ICMS Desonerado + type: number + amountSTReason: + description: Motivo Desoneração ICMS + type: string + baseSNRetentionAmount: + description: Valor da BC do ICMS ST retido + type: string + snRetentionAmount: + description: Valor do ICMS ST retido + type: string + amountOperation: + description: Valor do ICMS da Operação + type: string + percentualDeferment: + description: Percentual do Diferimento + type: string + baseDeferred: + description: Valor do ICMS Diferido + type: string + fcpRate: + format: double + description: Percentual do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCP) (Percentual máximo permitido é 2%) + type: number + fcpAmount: + format: double + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + type: number + fcpstRate: + format: double + description: Percentual do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCPST) retido por substituição tributária. + type: number + fcpstAmount: + format: double + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCPST) retido por substituição tributária. + type: number + fcpstRetRate: + format: double + description: Percentual do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCPSTRet) retido anteriormente por substituição tributária. + type: number + fcpstRetAmount: + format: double + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCPSTRet) retido anteriormente por substituição tributária. + type: number + bcfcpstAmount: + format: double + description: Informar o valor da Base de Cálculo do FCP (vBCFCPST) + type: number + finalConsumerRate: + format: double + description: Modalidade de determinação da BC do ICMS (pST) + type: number + bcstRetIssuerAmount: + format: double + description: Valor do BC do ICMS ST retido na UF remetente (vBCSTRet) + type: number + stRetIssuerAmout: + format: double + description: Valor do ICMS ST retido na UF remetente (vICMSSTRet) + type: number + bcstBuyerAmount: + format: double + description: Valor da BC do ICMS ST da UF destino (vBCSTDest) + type: number + stBuyerAmout: + format: double + description: Valor do ICMS ST da UF destino (vICMSSTDest) + type: number + substituteAmount: + format: double + description: 'Valor do ICMS próprio do Substituto (tag: vICMSSubstituto)' + type: number + ipi: + description: Grupo IPI (IPI) + type: object + properties: + classification: + description: "clEnq\r\nClasse de enquadramento do IPI para Cigarros e Bebidas (clEnq)" + type: string + producerCNPJ: + description: CNPJ do produtor da mercadoria, quando diferente do emitente. Somente para os casos de exportação direta ou indireta. (CNPJProd) + type: string + stampCode: + description: Código do selo de controle IPI (cSelo)( + type: string + stampQuantity: + format: double + description: Quantidade de selo de controle (qSelo) + type: number + classificationCode: + description: Código de Enquadramento Legal do IPI (cEnq) + type: string + cst: + description: Código da situação tributária do IPI (CST) + type: string + base: + description: Valor da BC do IPI (vBC) + type: string + rate: + format: double + description: Alíquota do IPI (pIPI) + type: number + unitQuantity: + format: double + description: Quantidade total na unidade padrão para tributação (somente para os produtos tributados por unidade) (qUnid) + type: number + unitAmount: + format: double + description: Valor por Unidade Tributável (vUnid) + type: number + amount: + format: double + description: Valor IPI (vIPI) + type: number + ii: + description: Grupo Imposto de Importação (II) + type: object + properties: + baseTax: + description: Valor BC do Imposto de Importação (vBC) + type: string + customsExpenditureAmount: + description: Valor despesas aduaneiras (vDespAdu) + type: string + amount: + format: double + description: Valor Imposto de Importação (vII) + type: number + iofAmount: + format: double + description: Valor Imposto sobre Operações Financeiras (vIOF) + type: number + pis: + description: Grupo PIS (PIS) + type: object + properties: + cst: + description: Código de Situação Tributária do PIS (CST) + type: string + baseTax: + format: double + description: Valor da Base de Cálculo do PIS (vBC) + type: number + rate: + format: double + description: Alíquota do PIS (em percentual) (pPIS) + type: number + amount: + format: double + description: Valor do PIS (vPIS) + type: number + baseTaxProductQuantity: + format: double + description: Quantidade Vendida (qBCProd) + type: number + productRate: + format: double + description: Alíquota do PIS (em reais) (vAliqProd) + type: number + cofins: + description: Grupo COFINS (COFINS) + type: object + properties: + cst: + description: "Código de Situação Tributária da COFINS\r\nObs: 01 – Operação Tributável (base de cálculo = valor da operação \r\nalíquota normal (cumulativo/não cumulativo));\r\n02 - Operação Tributável (base de cálculo = valor da operação (alíquota diferenciada)); (CST)" + type: string + baseTax: + format: double + description: Valor da Base de Cálculo da COFINS (vBC) + type: number + rate: + format: double + description: Alíquota da COFINS (em percentual) (pCOFINS) + type: number + amount: + format: double + description: Valor da COFINS (vCOFINS) + type: number + baseTaxProductQuantity: + format: double + description: Quantidade Vendida (qBCProd) + type: number + productRate: + format: double + description: Alíquota da COFINS (em reais) (vAliqProd) + type: number + icmsDestination: + description: Informação do ICMS Interestadual (ICMSUFDest) + type: object + properties: + vBCUFDest: + format: double + description: Valor da Base de Cálculo do ICMS na UF de destino. (vBCUFDest) + type: number + pFCPUFDest: + format: double + description: Percentual adicional inserido na alíquota interna da UF de destino, relativo ao Fundo de Combate à Pobreza (FCP) naquela UF (pFCPUFDest) + type: number + pICMSUFDest: + format: double + description: Alíquota adotada nas operações internas na UF de destino para o produto / mercadoria (pICMSUFDest) + type: number + pICMSInter: + format: double + description: Alíquota interestadual das UF envolvidas (pICMSInter) + type: number + pICMSInterPart: + format: double + description: Percentual de ICMS Interestadual para a UF de destino (pICMSInterPart) + type: number + vFCPUFDest: + format: double + description: Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP) da UF de destino (vFCPUFDest) + type: number + vICMSUFDest: + format: double + description: Valor do ICMS Interestadual para a UF de destino (vICMSUFDest) + type: number + vICMSUFRemet: + format: double + description: Valor do ICMS Interestadual para a UF do remetente (vICMSUFRemet) + type: number + vBCFCPUFDest: + format: double + description: Valor da BC FCP na UF de destino (vBCFCPUFDest) + type: number + additionalInformation: + description: Informações Adicionais do Produto (infAdProd) + type: string + numberOrderBuy: + description: Número do pedido de compra (xPed) + type: string + itemNumberOrderBuy: + format: int32 + description: Item do Pedido de Compra (nItemPed) + type: integer + medicineDetail: + description: Detalhamento de Medicamentos e de matérias-primas farmacêuticas (med) + type: object + properties: + maximumPrice: + format: double + description: Preço máximo consumidor (vPMC) + type: number + anvisaCode: + description: Código de Produto da ANVISA (cProdANVISA); + type: string + batchId: + description: Número do Lote de medicamentos ou de matérias-primas farmacêuticas (nLote) + type: string + batchQuantity: + format: double + description: Quantidade de produto no Lote de medicamentos ou de matérias-primas farmacêuticas (qLote) + type: number + manufacturedOn: + format: date-time + description: Data de fabricação (dFab) + type: string + expireOn: + format: date-time + description: Data de validade (dVal) + type: string + fuel: + description: Detalhamento de combustível (comb) + type: object + properties: + codeANP: + description: " LA02 - Código de produto da ANP (cProdANP)\r\nVersão 3.00\r\nVersão 4.00" + type: string + percentageNG: + format: double + description: " LA03 - Percentual de Gás Natural para o produto GLP (cProdANP=210203001) (pMixGN)\r\nVersão 3.00" + type: number + descriptionANP: + description: "LA03 - Descrição do produto conforme ANP (descANP)\r\nVersão 4.00" + type: string + percentageGLP: + format: double + description: "LA03a - Percentual do GLP derivado do petróleo no produto GLP (cProdANP=210203001) (pGLP)\r\nVersão 4.00" + type: number + percentageNGn: + format: double + description: "LA03b - Percentual de Gás Natural Nacional – GLGNn para o produto GLP (cProdANP= 210203001) (pGNn)\r\nVersão 4.00" + type: number + percentageGNi: + format: double + description: "LA03c - Percentual de Gás Natural Importado – GLGNi para o produto GLP (cProdANP= 210203001) (pGNi)\r\nVersão 4.00" + type: number + startingAmount: + format: double + description: "LA03d - Valor de partida (cProdANP=210203001) (vPart)\r\nVersão 4.00" + type: number + codif: + description: LA04 - Código de autorização / registro do CODIF (CODIF) + type: string + amountTemp: + format: double + description: LA05 - Quantidade de combustível faturada à temperatura ambiente (qTemp) + type: number + stateBuyer: + description: LA06 - Sigla da UF de consumo (UFCons) + type: string + cide: + description: LA07 - Informações da CIDE (CIDE) + type: object + properties: + bc: + format: double + description: LA08 - BC da CIDE (qBCProd) + type: number + rate: + format: double + description: LA09 - Valor da alíquota da CIDE (vAliqProd) + type: number + cideAmount: + format: double + description: LA10 - Valor da CIDE (vCIDE) + type: number + pump: + description: LA11 - Informações do grupo de “encerrante” (encerrante) + type: object + properties: + spoutNumber: + format: int32 + description: LA12 - Número de identificação do bico utilizado no abastecimento (nBico) + type: integer + number: + format: int32 + description: LA13 - Número de identificação da bomba ao qual o bico está interligado (nBomba) + type: integer + tankNumber: + format: int32 + description: LA14 - Número de identificação do tanque ao qual o bico está interligado (nTanque) + type: integer + beginningAmount: + format: double + description: LA15 - Valor do Encerrante no início do abastecimento (vEncIni) + type: number + endAmount: + format: double + description: LA16 - Valor do Encerrante no final do abastecimento (vEncFin) + type: number + billing: + description: Grupo Cobrança (cobr) + type: object + properties: + bill: + description: Grupo Fatura (fat) + type: object + properties: + number: + description: Número da Fatura (nFat) + type: string + originalAmount: + format: double + description: Valor Original da Fatura (vOrig) + type: number + discountAmount: + format: double + description: Valor do desconto (vDesc) + type: number + netAmount: + format: double + description: Valor Líquido da Fatura (vLiq) + type: number + duplicates: + description: Grupo Duplicata (dup) + type: array + items: + type: object + properties: + duplicateNumber: + description: Número da Duplicata (nDup) + type: string + expirationOn: + format: date-time + description: Data de vencimento (dVenc) + type: string + amount: + format: double + description: Valor da duplicata (vDup) + type: number + payment: + description: Grupo de Formas de Pagamento (pag) + type: array + items: + description: Grupo de Formas de Pagamento (pag) + type: object + properties: + paymentDetail: + description: "YA01a - Grupo Detalhamento da Forma de Pagamento (detPag)\r\nVERSÃO 4.00" + type: array + items: + type: object + properties: + method: + description: Forma de pagamento (tPag) + enum: + - cash + - cheque + - creditCard + - debitCard + - storeCredict + - foodVouchers + - mealVouchers + - giftVouchers + - fuelVouchers + - commercialDuplicate + - bankSlip + - unpaid + - others + type: string + amount: + format: double + description: Valor do Pagamento (vPag) + type: number + card: + description: Grupo de Cartões (card) + type: object + properties: + federalTaxNumber: + description: CNPJ da Credenciadora de cartão de crédito e/ou débito (CNPJ) + type: string + flag: + description: Bandeira da operadora de cartão de crédito e/ou débito (tBand) + enum: + - visa + - mastercard + - americanExpress + - sorocred + - dinnersClub + - elo + - hipercard + - aura + - cabal + - outros + type: string + authorization: + description: Número de autorização da operação cartão de crédito e/ou débito (cAut) + type: string + integrationPaymentType: + description: YA04a - Tipo de Integração para pagamento (tpIntegra) + enum: + - integrated + - notIntegrated + type: string + payBack: + format: double + description: "Valor do troco (vTroco)\r\nVERSÃO 4.00" + type: number + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/productinvoices/serpro/{accessKey}.pdf: + get: + tags: + - Irrestrita + summary: Consulta Irrestrita de NF-e por Chave de Acesso (DANFE em PDF) + description: "Retorna o DANFE em PDF renderizado a partir do XML autorizado, via Consulta Irrestrita. Use a Chave de Dados no header `Authorization` SEM prefixo `Bearer`." + operationId: V2ProductinvoicesSerproByAccessKey}.pdfGet + consumes: [] + produces: + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + fileStream: + type: object + properties: + canRead: + type: boolean + readOnly: true + canSeek: + type: boolean + readOnly: true + canTimeout: + type: boolean + readOnly: true + canWrite: + type: boolean + readOnly: true + length: + format: int64 + type: integer + readOnly: true + position: + format: int64 + type: integer + readTimeout: + format: int32 + type: integer + writeTimeout: + format: int32 + type: integer + contentType: + type: string + readOnly: true + fileDownloadName: + type: string + lastModified: + format: date-time + type: string + entityTag: + type: object + properties: + tag: + readOnly: true + type: object + properties: + buffer: + type: string + readOnly: true + offset: + format: int32 + type: integer + readOnly: true + length: + format: int32 + type: integer + readOnly: true + value: + type: string + readOnly: true + hasValue: + type: boolean + readOnly: true + isWeak: + type: boolean + readOnly: true + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/productinvoices/serpro/{accessKey}.xml: + get: + tags: + - Irrestrita + summary: Consulta Irrestrita de NF-e por Chave de Acesso (XML) + description: "Retorna o XML oficial NF-e (`nfeProc`) conforme schema SEFAZ, via Consulta Irrestrita. Use a Chave de Dados no header `Authorization` SEM prefixo `Bearer`." + operationId: V2ProductinvoicesSerproByAccessKey}.xmlGet + consumes: [] + produces: + - application/xml + - application/json + parameters: + - name: accessKey + in: path + description: Chave de Acesso + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + versao: + type: string + nFe: + type: object + properties: + infNFe: + type: object + properties: + versao: + type: string + id: + type: string + ide: + type: object + properties: + cUF: + enum: + - aC + - aL + - aP + - aM + - bA + - cE + - dF + - eS + - gO + - mA + - mT + - mS + - mG + - pA + - pB + - pR + - pE + - pI + - rJ + - rN + - rS + - rO + - rR + - sC + - sP + - sE + - tO + - aN + - eX + type: string + cNF: + type: string + natOp: + type: string + indPag: + enum: + - ipVista + - ipPrazo + - ipOutras + type: string + indPagSpecified: + type: boolean + readOnly: true + mod: + enum: + - nFe + - mDFe + - nFCe + - cTe + - cTeOS + type: string + serie: + format: int32 + type: integer + nNF: + format: int64 + type: integer + dEmi: + format: date-time + type: string + proxydEmi: + type: string + dSaiEnt: + format: date-time + type: string + proxydSaiEnt: + type: string + dhEmi: + format: date-time + type: string + proxyDhEmi: + type: string + dhSaiEnt: + format: date-time + type: string + proxydhSaiEnt: + type: string + tpNF: + enum: + - tnEntrada + - tnSaida + type: string + idDest: + enum: + - doInterna + - doInterestadual + - doExterior + type: string + cMunFG: + format: int64 + type: integer + tpImp: + enum: + - tiSemGeracao + - tiRetrato + - tiPaisagem + - tiSimplificado + - tiNFCe + - tiMsgEletronica + type: string + tpEmis: + enum: + - teNormal + - teFSIA + - teSCAN + - teEPEC + - teFSDA + - teSVCAN + - teSVCRS + - teOffLine + type: string + cDV: + format: int32 + type: integer + tpAmb: + enum: + - taProducao + - taHomologacao + type: string + finNFe: + enum: + - fnNormal + - fnComplementar + - fnAjuste + - fnDevolucao + type: string + indFinal: + enum: + - cfNao + - cfConsumidorFinal + type: string + indPres: + enum: + - pcNao + - pcPresencial + - pcInternet + - pcTeleatendimento + - pcEntregaDomicilio + - pcPresencialForaEstabelecimento + - pcOutros + type: string + procEmi: + enum: + - peAplicativoContribuinte + - peAvulsaFisco + - peAvulsaContribuinte + - peContribuinteAplicativoFisco + type: string + verProc: + type: string + dhCont: + format: date-time + type: string + proxydhCont: + type: string + xJust: + type: string + nFref: + type: array + items: + type: object + properties: + refNFe: + type: string + refNF: + type: object + properties: + cUF: + enum: + - aC + - aL + - aP + - aM + - bA + - cE + - dF + - eS + - gO + - mA + - mT + - mS + - mG + - pA + - pB + - pR + - pE + - pI + - rJ + - rN + - rS + - rO + - rR + - sC + - sP + - sE + - tO + - aN + - eX + type: string + aamm: + type: string + cnpj: + type: string + mod: + enum: + - modelo + - modelo2 + type: string + serie: + format: int32 + type: integer + nNF: + format: int32 + type: integer + refNFP: + type: object + properties: + cUF: + enum: + - aC + - aL + - aP + - aM + - bA + - cE + - dF + - eS + - gO + - mA + - mT + - mS + - mG + - pA + - pB + - pR + - pE + - pI + - rJ + - rN + - rS + - rO + - rR + - sC + - sP + - sE + - tO + - aN + - eX + type: string + aamm: + type: string + cnpj: + type: string + cpf: + type: string + ie: + type: string + mod: + type: string + serie: + format: int32 + type: integer + nNF: + format: int32 + type: integer + refCTe: + type: string + refECF: + type: object + properties: + mod: + type: string + nECF: + format: int32 + type: integer + nCOO: + format: int32 + type: integer + emit: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xNome: + type: string + xFant: + type: string + enderEmit: + type: object + properties: + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + cep: + type: string + cPais: + format: int32 + type: integer + xPais: + type: string + fone: + format: int64 + type: integer + ie: + type: string + iest: + type: string + im: + type: string + cnae: + type: string + crt: + enum: + - simplesNacional + - simplesNacionalExcessoSublimite + - regimeNormal + type: string + avulsa: + type: object + properties: + cnpj: + type: string + xOrgao: + type: string + matr: + type: string + xAgente: + type: string + fone: + type: string + uf: + type: string + nDAR: + type: string + dEmi: + type: string + vDAR: + format: double + type: number + repEmi: + type: string + dPag: + type: string + dest: + type: object + properties: + cnpj: + type: string + cpf: + type: string + idEstrangeiro: + type: string + xNome: + type: string + enderDest: + type: object + properties: + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + cep: + type: string + cPais: + format: int32 + type: integer + xPais: + type: string + fone: + format: int64 + type: integer + indIEDest: + enum: + - contribuinteICMS + - isento + - naoContribuinte + type: string + ie: + type: string + isuf: + type: string + im: + type: string + email: + type: string + retirada: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + entrega: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xLgr: + type: string + nro: + type: string + xCpl: + type: string + xBairro: + type: string + cMun: + format: int64 + type: integer + xMun: + type: string + uf: + type: string + autXML: + type: array + items: + type: object + properties: + cnpj: + type: string + cpf: + type: string + det: + type: array + items: + type: object + properties: + nItem: + format: int32 + type: integer + prod: + type: object + properties: + cProd: + type: string + cEAN: + type: string + xProd: + type: string + ncm: + type: string + nve: + type: array + items: + type: string + cest: + type: string + indEscala: + enum: + - s + - n + type: string + indEscalaSpecified: + type: boolean + readOnly: true + cnpjFab: + type: string + cBenef: + type: string + extipi: + type: string + cfop: + format: int32 + type: integer + uCom: + type: string + qCom: + format: double + type: number + vUnCom: + format: double + type: number + vProd: + format: double + type: number + cEANTrib: + type: string + uTrib: + type: string + qTrib: + format: double + type: number + vUnTrib: + format: double + type: number + vFrete: + format: double + type: number + vSeg: + format: double + type: number + vDesc: + format: double + type: number + vOutro: + format: double + type: number + indTot: + enum: + - valorDoItemNaoCompoeTotalNF + - valorDoItemCompoeTotalNF + type: string + di: + type: array + items: + type: object + properties: + nDI: + type: string + dDI: + format: date-time + type: string + proxydDI: + type: string + xLocDesemb: + type: string + ufDesemb: + type: string + dDesemb: + format: date-time + type: string + proxydDesemb: + type: string + tpViaTransp: + enum: + - maritima + - fluvial + - lacustre + - aerea + - postal + - ferroviaria + - rodoviaria + - condutoRedeTransmissão + - meiosProprios + - entradaSaidaficta + - courier + - handcarry + type: string + vAFRMM: + format: double + type: number + tpIntermedio: + enum: + - contaPropria + - contaeOrdem + - porEncomenda + type: string + cnpj: + type: string + ufTerceiro: + type: string + cExportador: + type: string + adi: + type: array + items: + type: object + properties: + nAdicao: + format: int32 + type: integer + nSeqAdic: + format: int32 + type: integer + cFabricante: + type: string + vDescDI: + format: double + type: number + nDraw: + type: string + detExport: + type: array + items: + type: object + properties: + nDraw: + type: string + exportInd: + type: object + properties: + nRE: + type: string + chNFe: + type: string + qExport: + format: double + type: number + xPed: + type: string + nItemPed: + format: int32 + type: integer + nFCI: + type: string + rastro: + type: array + items: + type: object + properties: + nLote: + type: string + qLote: + format: double + type: number + dFab: + format: date-time + type: string + proxydFab: + type: string + dVal: + format: date-time + type: string + proxydVal: + type: string + cAgreg: + type: string + produtoEspecifico: + type: object + properties: {} + nRECOPI: + type: string + imposto: + type: object + properties: + vTotTrib: + format: double + type: number + icms: + type: object + properties: + tipoICMS: + type: object + properties: {} + issqn: + type: object + properties: + vBC: + format: double + type: number + vAliq: + format: double + type: number + vISSQN: + format: double + type: number + cMunFG: + format: int64 + type: integer + cListServ: + type: string + vDeducao: + format: double + type: number + vOutro: + format: double + type: number + vDescIncond: + format: double + type: number + vDescCond: + format: double + type: number + vISSRet: + format: double + type: number + indISS: + enum: + - iiExigivel + - iiNaoIncidencia + - iiIsencao + - iiExportacao + - iiImunidade + - iiExigSuspDecisaoJudicial + - iiExigSuspProcessoAdm + type: string + cServico: + type: string + cMun: + format: int64 + type: integer + cPais: + format: int32 + type: integer + nProcesso: + type: string + indIncentivo: + enum: + - iiSim + - iiNao + type: string + ipi: + type: object + properties: + clEnq: + type: string + cnpjProd: + type: string + cSelo: + type: string + qSelo: + format: int32 + type: integer + cEnq: + format: int32 + type: integer + tipoIPI: + type: object + properties: {} + ii: + type: object + properties: + vBC: + format: double + type: number + vDespAdu: + format: double + type: number + vII: + format: double + type: number + vIOF: + format: double + type: number + pis: + type: object + properties: + tipoPIS: + type: object + properties: {} + pisst: + type: object + properties: + vBC: + format: double + type: number + pPIS: + format: double + type: number + qBCProd: + format: double + type: number + vAliqProd: + format: double + type: number + vPIS: + format: double + type: number + cofins: + type: object + properties: + tipoCOFINS: + type: object + properties: {} + cofinsst: + type: object + properties: + vBC: + format: double + type: number + pCOFINS: + format: double + type: number + qBCProd: + format: double + type: number + vAliqProd: + format: double + type: number + vCOFINS: + format: double + type: number + icmsufDest: + type: object + properties: + vBCUFDest: + format: double + type: number + vBCFCPUFDest: + format: double + type: number + vBCFCPUFDestSpecified: + type: boolean + readOnly: true + pFCPUFDest: + format: double + type: number + pICMSUFDest: + format: double + type: number + pICMSInter: + format: double + type: number + pICMSInterPart: + format: double + type: number + vFCPUFDest: + format: double + type: number + vICMSUFDest: + format: double + type: number + vICMSUFRemet: + format: double + type: number + impostoDevol: + type: object + properties: + pDevol: + format: double + type: number + ipi: + type: object + properties: + vIPIDevol: + format: double + type: number + infAdProd: + type: string + total: + type: object + properties: + icmsTot: + type: object + properties: + vBC: + format: double + type: number + vICMS: + format: double + type: number + vICMSDeson: + format: double + type: number + vFCPUFDest: + format: double + type: number + vICMSUFDest: + format: double + type: number + vICMSUFRemet: + format: double + type: number + vFCP: + format: double + type: number + vFCPSpecified: + type: boolean + readOnly: true + vBCST: + format: double + type: number + vST: + format: double + type: number + vFCPST: + format: double + type: number + vFCPSTSpecified: + type: boolean + readOnly: true + vFCPSTRet: + format: double + type: number + vFCPSTRetSpecified: + type: boolean + readOnly: true + vProd: + format: double + type: number + vFrete: + format: double + type: number + vSeg: + format: double + type: number + vDesc: + format: double + type: number + vII: + format: double + type: number + vIPI: + format: double + type: number + vIPIDevol: + format: double + type: number + vIPIDevolSpecified: + type: boolean + readOnly: true + vPIS: + format: double + type: number + vCOFINS: + format: double + type: number + vOutro: + format: double + type: number + vNF: + format: double + type: number + vTotTrib: + format: double + type: number + issqNtot: + type: object + properties: + vServ: + format: double + type: number + vBC: + format: double + type: number + vISS: + format: double + type: number + vPIS: + format: double + type: number + vCOFINS: + format: double + type: number + dCompet: + type: string + vDeducao: + format: double + type: number + vOutro: + format: double + type: number + vDescIncond: + format: double + type: number + vDescCond: + format: double + type: number + vISSRet: + format: double + type: number + cRegTrib: + enum: + - tISSMicroempresaMunicipal + - rTISSEstimativa + - rTISSSociedadeProfissionais + - rTISSCooperativa + - rTISSMEI + - rTISSMEEPP + type: string + retTrib: + type: object + properties: + vRetPIS: + format: double + type: number + vRetCOFINS: + format: double + type: number + vRetCSLL: + format: double + type: number + vBCIRRF: + format: double + type: number + vIRRF: + format: double + type: number + vBCRetPrev: + format: double + type: number + vRetPrev: + format: double + type: number + transp: + type: object + properties: + modFrete: + enum: + - mfContaEmitenteOumfContaRemetente + - mfContaDestinatario + - mfContaTerceiros + - mfProprioContaRemente + - mfProprioContaDestinatario + - mfSemFrete + type: string + modFreteSpecified: + type: boolean + readOnly: true + transporta: + type: object + properties: + cnpj: + type: string + cpf: + type: string + xNome: + type: string + ie: + type: string + xEnder: + type: string + xMun: + type: string + uf: + type: string + retTransp: + type: object + properties: + vServ: + format: double + type: number + vBCRet: + format: double + type: number + pICMSRet: + format: double + type: number + vICMSRet: + format: double + type: number + cfop: + format: int32 + type: integer + cMunFG: + format: int64 + type: integer + veicTransp: + type: object + properties: + placa: + type: string + uf: + type: string + rntc: + type: string + reboque: + type: array + items: + type: object + properties: + placa: + type: string + uf: + type: string + rntc: + type: string + vol: + type: array + items: + type: object + properties: + qVol: + format: int32 + type: integer + esp: + type: string + marca: + type: string + nVol: + type: string + pesoL: + format: double + type: number + pesoB: + format: double + type: number + lacres: + type: array + items: + type: object + properties: + nLacre: + type: string + vagao: + type: string + balsa: + type: string + cobr: + type: object + properties: + fat: + type: object + properties: + nFat: + type: string + vOrig: + format: double + type: number + vDesc: + format: double + type: number + vLiq: + format: double + type: number + dup: + type: array + items: + type: object + properties: + nDup: + type: string + dVenc: + format: date-time + type: string + proxydVenc: + type: string + vDup: + format: double + type: number + pag: + type: array + items: + type: object + properties: + detPag: + type: array + items: + type: object + properties: + indPag: + enum: + - ipDetPgVista + - ipDetPgPrazo + type: string + indPagSpecified: + type: boolean + readOnly: true + tPag: + enum: + - fpDinheiro + - fpCheque + - fpCartaoCredito + - fpCartaoDebito + - fpCreditoLoja + - fpValeAlimentacao + - fpValeRefeicao + - fpValePresente + - fpValeCombustivel + - fpDuplicataMercantil + - fpBoletoBancario + - fpSemPagamento + - fpOutro + type: string + vPag: + format: double + type: number + card: + type: object + properties: + tpIntegra: + enum: + - tipIntegradoAutomacao + - tipNaoIntegrado + type: string + cnpj: + type: string + tBand: + enum: + - bcVisa + - bcMasterCard + - bcAmericanExpress + - bcSorocred + - bcDinersClub + - elo + - hipercard + - aura + - cabal + - bcOutros + type: string + cAut: + type: string + vTroco: + format: double + type: number + vTrocoSpecified: + type: boolean + readOnly: true + tPag: + enum: + - fpDinheiro + - fpCheque + - fpCartaoCredito + - fpCartaoDebito + - fpCreditoLoja + - fpValeAlimentacao + - fpValeRefeicao + - fpValePresente + - fpValeCombustivel + - fpDuplicataMercantil + - fpBoletoBancario + - fpSemPagamento + - fpOutro + type: string + tPagSpecified: + type: boolean + readOnly: true + vPag: + format: double + type: number + vPagSpecified: + type: boolean + readOnly: true + card: + type: object + properties: + tpIntegra: + enum: + - tipIntegradoAutomacao + - tipNaoIntegrado + type: string + cnpj: + type: string + tBand: + enum: + - bcVisa + - bcMasterCard + - bcAmericanExpress + - bcSorocred + - bcDinersClub + - elo + - hipercard + - aura + - cabal + - bcOutros + type: string + cAut: + type: string + infAdic: + type: object + properties: + infAdFisco: + type: string + infCpl: + type: string + obsCont: + type: array + items: + type: object + properties: + xCampo: + type: string + xTexto: + type: string + obsFisco: + type: array + items: + type: object + properties: + xCampo: + type: string + xTexto: + type: string + procRef: + type: array + items: + type: object + properties: + nProc: + type: string + indProc: + enum: + - ipSEFAZ + - ipJusticaFederal + - ipJusticaEstadual + - ipSecexRFB + - ipOutros + type: string + exporta: + type: object + properties: + ufSaidaPais: + type: string + xLocExporta: + type: string + xLocDespacho: + type: string + compra: + type: object + properties: + xNEmp: + type: string + xPed: + type: string + xCont: + type: string + cana: + type: object + properties: + safra: + type: string + ref: + type: string + forDia: + type: array + items: + type: object + properties: + dia: + format: int32 + type: integer + qtde: + format: double + type: number + qTotMes: + format: double + type: number + qTotAnt: + format: double + type: number + qTotGer: + format: double + type: number + deduc: + type: array + items: + type: object + properties: + xDed: + type: string + vDed: + format: double + type: number + vFor: + format: double + type: number + vTotDed: + format: double + type: number + vLiqFor: + format: double + type: number + infRespTec: + type: object + properties: + cnpj: + type: string + xContato: + type: string + email: + type: string + fone: + type: string + idCSRT: + type: string + proxyidCSRT: + type: string + hashCSRT: + type: string + infNFeSupl: + type: object + properties: + qrCode: + type: string + urlChave: + type: string + signature: + type: object + properties: + signedInfo: + type: object + properties: + canonicalizationMethod: + type: object + properties: + algorithm: + type: string + signatureMethod: + type: object + properties: + algorithm: + type: string + reference: + type: object + properties: + uri: + type: string + transforms: + type: array + items: + type: object + properties: + algorithm: + type: string + digestMethod: + type: object + properties: + algorithm: + type: string + digestValue: + type: string + signatureValue: + type: string + keyInfo: + type: object + properties: + x509Data: + type: object + properties: + x509Certificate: + type: string + protNFe: + type: object + properties: + versao: + type: string + infProt: + type: object + properties: + id: + type: string + tpAmb: + enum: + - taProducao + - taHomologacao + type: string + verAplic: + type: string + chNFe: + type: string + dhRecbto: + format: date-time + type: string + proxyDhRecbto: + type: string + nProt: + type: string + digVal: + type: string + cStat: + format: int32 + type: integer + xMotivo: + type: string + signature: + type: object + properties: + signedInfo: + type: object + properties: + canonicalizationMethod: + type: object + properties: + algorithm: + type: string + signatureMethod: + type: object + properties: + algorithm: + type: string + reference: + type: object + properties: + uri: + type: string + transforms: + type: array + items: + type: object + properties: + algorithm: + type: string + digestMethod: + type: object + properties: + algorithm: + type: string + digestValue: + type: string + signatureValue: + type: string + keyInfo: + type: object + properties: + x509Data: + type: object + properties: + x509Certificate: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Nota Fiscal não foi encontrada + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey +securityDefinitions: + Authorization_Header: + name: Authorization + in: header + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + Authorization_QueryParam: + name: apikey + in: query + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' diff --git a/openapi/consulta-nfe-distribuicao-v1.yaml b/openapi/consulta-nfe-distribuicao-v1.yaml new file mode 100644 index 0000000..ac1df84 --- /dev/null +++ b/openapi/consulta-nfe-distribuicao-v1.yaml @@ -0,0 +1,1775 @@ +openapi: 3.0.0 +info: + title: Consulta de NF-e (Distribuição) + x-displayName: Introdução + description: "# Introdução\nSeja bem-vindo a documentação da API de Consulta de NF-e (Distribuição)!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\nEsta API tem como objetivo manipular o produto de consulta de NF-e. O processo tem como pré-requisitos o cadastro de uma empresa, na sequência o cadastro de um certificado A1 válido desta empresa, e o cadastro de um endpoint de webhook para você receber as notificações. Para mais detalhes de como cadastrar empresa, certificado e webhook, você pode ver nossa documentação da nota fiscal de produto, ou fazer o procedimento via dashboard da nfe.io. \n\nCom os pré-requisitos atendidos, o próximo passo é habilitar a busca automática e observar os webhooks chegando em seu endpoint cadastrado.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra no topo desta página para que os métodos funcionem corretamente.\nNo seu código de integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n" + contact: {} + version: "1.0" +servers: + - url: https://api.nfse.io/v2/companies/{company_id}/inbound + variables: + company_id: + default: + description: '(Required) ' +paths: + /{access_key}/xml: + get: + tags: + - xml + summary: Obter o XML de um CT-e ou NF-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: ObteroXMLdeumCT-eouNF-epelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /{access_key}/events/{event_key}/xml: + get: + tags: + - xml + summary: Obter o XML de um evento ref. a um CT-e ou NF-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: ObteroXMLdeumeventoref.aumCT-eouNF-epelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: event_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /{access_key}/pdf: + get: + tags: + - pdf + summary: Obter o PDF de uma NF-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: ObteroPDFdeumaNF-epelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /{access_key}/events/{event_key}: + get: + tags: + - '{event_key}' + summary: Obter os detalhes de um evento ref. a um CT-e ou NF-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: Obterosdetalhesdeumeventoref.aumCT-eouNF-epelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: event_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio' + - example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /productinvoice/{access_key}/events/{event_key}: + get: + tags: + - '{event_key}' + summary: Obter os detalhes de um evento ref. a um CT-e ou NF-e pela chave de acesso de 44 dígitos1 + description: Você precisará da APIKEY para utilização + operationId: Obterosdetalhesdeumeventoref.aumCT-eouNF-epelachavedeacessode44dígitos1 + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: event_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio6' + - example: + id: + createdOn: + accessKey: + parentAccessKey: + productInvoices: + - accessKey: + - accessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + type: null + nsu: + nfeNumber: + issuedOn: + description: + xmlUrl: + federalTaxNumberSender: + nameSender: + totalInvoiceAmount: + links: + xml: + pdf: + example: + id: + createdOn: + accessKey: + parentAccessKey: + productInvoices: + - accessKey: + - accessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + type: null + nsu: + nfeNumber: + issuedOn: + description: + xmlUrl: + federalTaxNumberSender: + nameSender: + totalInvoiceAmount: + links: + xml: + pdf: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /{access_key}/manifest: + post: + tags: + - manifest + summary: Enviar o evento de ciência da operação pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: Enviaroeventodeciênciadaoperaçãopelachavedeacessode44dígitos + parameters: + - name: tpEvent + in: query + description: Informar o tipo do evento de manifestação do destinatário (default = 210210 "Ciência da Operação) + required: true + style: form + explode: true + schema: + type: integer + format: int32 + example: 210210 + - name: access_key + in: path + description: (Required) Informar a chave de acesso da nota + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /{access_key}: + get: + tags: + - '{access_key}' + summary: Obter os detalhes de um CT-e ou NF-e (webhook v1) pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: ObterosdetalhesdeumCT-eouNF-e(webhookv1)pelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio' + - example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /productinvoice/{access_key}: + get: + tags: + - '{access_key}' + summary: Obter os detalhes de uma NF-e (webhook v2) pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: ObterosdetalhesdeumaNF-e(webhookv2)pelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio' + - example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /productinvoices: + post: + tags: + - productinvoices + summary: Ativar busca automática de documentos e Eventos relacionados a Nota Fiscal Eletrônica (NF-e) + description: Você precisará do APIKEY para utilização + operationId: AtivarbuscaautomáticadedocumentoseEventosrelacionadosaNotaFiscalEletrônica(NF-e) + parameters: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + requestBody: + description: "" + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/AtivarbuscaautomticadedocumentoseEventosrelacionadosaNotaFiscalEletrnicaNF-eRequest' + - example: + startFromNsu: "999999" + startFromDate: + environmentSEFAZ: Production + automaticManifesting: + minutesToWaitAwarenessOperation: "30" + webhookVersion: "2" + example: + startFromNsu: "999999" + startFromDate: + environmentSEFAZ: Production + automaticManifesting: + minutesToWaitAwarenessOperation: "30" + webhookVersion: "2" + required: true + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio2' + - example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + delete: + tags: + - productinvoices + summary: Desativar busca automática de documentos e Eventos relacionados a Nota Fiscal Eletrônica (NF-e) + description: Você precisará do APIKEY para utilização + operationId: DesativarbuscaautomáticadedocumentoseEventosrelacionadosaNotaFiscalEletrônica(NF-e) + parameters: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio2' + - example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + get: + tags: + - productinvoices + summary: Obter detalhes da parametrização do serviço de distribuição (NF-e) + description: Você precisará do APIKEY para utilização + operationId: Obterdetalhesdaparametrizaçãodoserviçodedistribuição(NF-e) + parameters: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio2' + - example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /productinvoice/{access_key}/json: + get: + tags: + - json + summary: Obter o json de uma NF-e pela chave de acesso de 44 dígitos + description: Você precisará da APIKEY para utilização + operationId: ObterojsondeumaNF-epelachavedeacessode44dígitos + parameters: + - name: access_key + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio' + - example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false + /productinvoice/{access_key_or_nsu}/processwebhook: + post: + tags: + - processwebhook + summary: Reprocessar o webhook pela chave de acesso de 44 dígitos ou pelo NSU + description: Você precisará da APIKEY para utilização + operationId: Reprocessarowebhookpelachavedeacessode44dígitosoupeloNSU + parameters: + - name: access_key_or_nsu + in: path + description: (Required) + required: true + style: simple + schema: + type: string + example: + - name: Accept + in: header + description: "" + required: true + style: simple + schema: + type: string + example: application/json + responses: + "200": + description: OK + headers: {} + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Sucessonarequisio6' + - example: + id: + createdOn: + accessKey: + parentAccessKey: + productInvoices: + - accessKey: + - accessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + type: null + nsu: + nfeNumber: + issuedOn: + description: + xmlUrl: + federalTaxNumberSender: + nameSender: + totalInvoiceAmount: + links: + xml: + pdf: + example: + id: + createdOn: + accessKey: + parentAccessKey: + productInvoices: + - accessKey: + - accessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + type: null + nsu: + nfeNumber: + issuedOn: + description: + xmlUrl: + federalTaxNumberSender: + nameSender: + totalInvoiceAmount: + links: + xml: + pdf: + "400": + description: Bad Request + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "401": + description: Unauthorized + headers: {} + content: {} + "403": + description: Forbidden + headers: {} + content: {} + "404": + description: Not Found + headers: {} + content: + application/json: + schema: + type: string + example: + example: + "500": + description: Internal Server Error + headers: {} + content: + application/json: + schema: + type: string + example: + example: + deprecated: false +components: + schemas: + Sucessonarequisio: + title: Sucessonarequisio + required: + - id + - createdOn + - accessKey + - parentAccessKey + - company + - issuer + - buyer + - transportation + - links + - xmlUrl + - federalTaxNumberSender + - nameSender + - type + - nsu + - nsuParent + - nfeNumber + - nfeSerialNumber + - issuedOn + - description + - totalInvoiceAmount + - operationType + type: object + properties: + id: + type: string + createdOn: + type: string + accessKey: + type: string + parentAccessKey: + type: string + company: + $ref: '#/components/schemas/Company' + issuer: + $ref: '#/components/schemas/Issuer' + buyer: + $ref: '#/components/schemas/Buyer' + transportation: + $ref: '#/components/schemas/Transportation' + links: + $ref: '#/components/schemas/Links' + xmlUrl: + type: string + federalTaxNumberSender: + type: string + nameSender: + type: string + type: + type: string + nullable: true + nsu: + type: string + nsuParent: + type: string + nfeNumber: + type: string + nfeSerialNumber: + type: string + issuedOn: + type: string + description: + type: string + totalInvoiceAmount: + type: string + operationType: + type: string + nullable: true + example: + id: + createdOn: + accessKey: + parentAccessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + links: + xml: + pdf: + xmlUrl: + federalTaxNumberSender: + nameSender: + type: null + nsu: + nsuParent: + nfeNumber: + nfeSerialNumber: + issuedOn: + description: + totalInvoiceAmount: + operationType: null + Company: + title: Company + required: + - id + - federalTaxNumber + type: object + properties: + id: + type: string + federalTaxNumber: + type: string + example: + id: + federalTaxNumber: + Issuer: + title: Issuer + required: + - federalTaxNumber + - name + type: object + properties: + federalTaxNumber: + type: string + name: + type: string + example: + federalTaxNumber: + name: + Buyer: + title: Buyer + required: + - federalTaxNumber + - name + type: object + properties: + federalTaxNumber: + type: string + name: + type: string + example: + federalTaxNumber: + name: + Transportation: + title: Transportation + required: + - federalTaxNumber + - name + type: object + properties: + federalTaxNumber: + type: string + name: + type: string + example: + federalTaxNumber: + name: + Links: + title: Links + required: + - xml + - pdf + type: object + properties: + xml: + type: string + pdf: + type: string + example: + xml: + pdf: + AtivarbuscaautomticadedocumentoseEventosrelacionadosaNotaFiscalEletrnicaNF-eRequest: + title: AtivarbuscaautomticadedocumentoseEventosrelacionadosaNotaFiscalEletrnicaNF-eRequest + required: + - startFromNsu + - startFromDate + - environmentSEFAZ + - automaticManifesting + - webhookVersion + type: object + properties: + startFromNsu: + type: string + startFromDate: + type: string + environmentSEFAZ: + type: string + automaticManifesting: + $ref: '#/components/schemas/AutomaticManifesting' + webhookVersion: + type: string + example: + startFromNsu: "999999" + startFromDate: + environmentSEFAZ: Production + automaticManifesting: + minutesToWaitAwarenessOperation: "30" + webhookVersion: "2" + AutomaticManifesting: + title: AutomaticManifesting + required: + - minutesToWaitAwarenessOperation + type: object + properties: + minutesToWaitAwarenessOperation: + type: string + example: + minutesToWaitAwarenessOperation: "30" + Sucessonarequisio2: + title: Sucessonarequisio2 + required: + - startFromNsu + - startFromDate + - environmentSEFAZ + - automaticManifesting + - webhookVersion + - companyId + - status + - createdOn + - modifiedOn + type: object + properties: + startFromNsu: + type: string + startFromDate: + type: string + environmentSEFAZ: + type: string + nullable: true + automaticManifesting: + $ref: '#/components/schemas/AutomaticManifesting' + webhookVersion: + type: string + companyId: + type: string + status: + type: string + nullable: true + createdOn: + type: string + modifiedOn: + type: string + example: + startFromNsu: + startFromDate: + environmentSEFAZ: null + automaticManifesting: + minutesToWaitAwarenessOperation: + webhookVersion: + companyId: + status: null + createdOn: + modifiedOn: + Sucessonarequisio6: + title: Sucessonarequisio6 + required: + - id + - createdOn + - accessKey + - parentAccessKey + - productInvoices + - company + - issuer + - buyer + - transportation + - type + - nsu + - nfeNumber + - issuedOn + - description + - xmlUrl + - federalTaxNumberSender + - nameSender + - totalInvoiceAmount + - links + type: object + properties: + id: + type: string + createdOn: + type: string + accessKey: + type: string + parentAccessKey: + type: string + productInvoices: + type: array + items: + $ref: '#/components/schemas/ProductInvoice' + description: "" + company: + $ref: '#/components/schemas/Company' + issuer: + $ref: '#/components/schemas/Issuer' + buyer: + $ref: '#/components/schemas/Buyer' + transportation: + $ref: '#/components/schemas/Transportation' + type: + type: string + nullable: true + nsu: + type: string + nfeNumber: + type: string + issuedOn: + type: string + description: + type: string + xmlUrl: + type: string + federalTaxNumberSender: + type: string + nameSender: + type: string + totalInvoiceAmount: + type: string + links: + $ref: '#/components/schemas/Links' + example: + id: + createdOn: + accessKey: + parentAccessKey: + productInvoices: + - accessKey: + - accessKey: + company: + id: + federalTaxNumber: + issuer: + federalTaxNumber: + name: + buyer: + federalTaxNumber: + name: + transportation: + federalTaxNumber: + name: + type: null + nsu: + nfeNumber: + issuedOn: + description: + xmlUrl: + federalTaxNumberSender: + nameSender: + totalInvoiceAmount: + links: + xml: + pdf: + ProductInvoice: + title: ProductInvoice + required: + - accessKey + type: object + properties: + accessKey: + type: string + example: + accessKey: + securitySchemes: + apiKey: + type: apiKey + name: Authorization + in: header +security: + - apiKey: [] +tags: + - name: xml + - name: pdf + - name: '{event_key}' + - name: manifest + - name: '{access_key}' + - name: productinvoices + - name: json + - name: processwebhook diff --git a/openapi/consumer-invoice.json b/openapi/consumer-invoice.json new file mode 100644 index 0000000..8f95252 --- /dev/null +++ b/openapi/consumer-invoice.json @@ -0,0 +1 @@ +{"swagger":"2.0","info":{"version":"v1","title":"Consumer Invoices API","description":"

Como utilizar esta documentação ?

Certifique-se que sua chave da API está preenchida no topo desta página para este recurso funcionar da maneira correta. Abaixo você poderá conferir a lista de recursos que podem ser manipulados através da API. Clicando em cada um dos métodos, você poderá verificar a lista de parâmetros, possíveis retornos e também um formulário. Este formulário pode ser utilizado para efetuar requisições reais na API.

"},"host":"nfe.api.nfe.io","paths":{"/v1/consumerinvoices/coupon/{accessKey}":{"get":{"tags":["Coupon"],"summary":"Consulta de Cupom Fiscal Eletrônico por Chave de Acesso","description":"Você precisará do APIKEY da Empresa","operationId":"V1ConsumerinvoicesCouponByAccessKeyGet","consumes":[],"produces":["application/json"],"parameters":[{"name":"accessKey","in":"path","description":"Chave de Acesso","required":true,"type":"string"}],"responses":{"200":{"description":"Sucesso na requisição","schema":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.TaxCouponResource"}},"400":{"description":"Algum parametro informado não é válido","schema":{"type":"string"}},"401":{"description":"Não autorizado, verificar o cabeçalho do HTTP Authorization"},"403":{"description":"Accesso proibido"},"404":{"description":"Nota Fiscal não foi encontrada","schema":{"type":"string"}},"500":{"description":"Erro no processamento","schema":{"type":"string"}}},"security":[{"Authorization_Header":["apiKey"]},{"Authorization_QueryParam":["apiKey"]}]}},"/v1/consumerinvoices/coupon/{accessKey}.xml":{"get":{"tags":["Coupon"],"summary":"Consulta de Cupom Fiscal Eletrônico por Chave de Acesso","description":"Você precisará do APIKEY da Empresa","operationId":"V1ConsumerinvoicesCouponByAccessKey}.xmlGet","consumes":[],"produces":["application/xml","application/json"],"parameters":[{"name":"accessKey","in":"path","description":"Chave de Acesso","required":true,"type":"string"}],"responses":{"200":{"description":"Sucesso na requisição","schema":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFe"}},"400":{"description":"Algum parametro informado não é válido","schema":{"type":"string"}},"401":{"description":"Não autorizado, verificar o cabeçalho do HTTP Authorization"},"403":{"description":"Accesso proibido"},"404":{"description":"Nota Fiscal não foi encontrada","schema":{"type":"string"}},"500":{"description":"Erro no processamento","schema":{"type":"string"}}},"security":[{"Authorization_Header":["apiKey"]},{"Authorization_QueryParam":["apiKey"]}]}}},"definitions":{"DataTech.Services.Domain.Models.Cfe.TaxCouponResource":{"description":"Cupom fiscal eletrônico (CFe)","type":"object","properties":{"currentStatus":{"description":"Situação Atual","enum":["Unknown","Authorized","Canceled"],"type":"string"},"number":{"format":"int64","description":"Número do Documento Fiscal (nNF)","type":"integer"},"satSerie":{"description":"Número de Série do SAT (nserieSAT)","type":"string"},"softwareVersion":{"description":"Versão do Software Básico (versaoSB)","type":"string"},"softwareFederalTaxNumber":{"format":"int64","description":"CNPJ Software House (CNPJ)","type":"integer"},"accessKey":{"description":"Chave de Acesso (Id)","type":"string"},"cashier":{"format":"int64","description":"Número do Caixa (numeroCaixa)","type":"integer"},"issuedOn":{"format":"date-time","description":"Data de emissão do Documento Fiscal\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n","type":"string"},"createdOn":{"format":"date-time","description":"Data de consulta\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n","type":"string"},"xmlVersion":{"description":"Versão do leiaute (versaoDadosEnt)","type":"string"},"issuer":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponIssuerResource","description":"Emitente (emit)"},"buyer":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponBuyerResource","description":"Destinatario (dest)"},"totals":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponTotalResource","description":"Grupo de Valores Totais (total)"},"delivery":{"$ref":"#/definitions/DataTech.Api.Resources.TaxCoupon.CouponDeliveryResource","description":"Dados do Local da Entrega (entrega)"},"additionalInformation":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponAdditionalInformationResource","description":"Informacoes Adicionais (infAdic)"},"items":{"description":"Detalhamento do produto (det)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponItemResource"}},"payment":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponPaymentResource","description":"Grupo de Formas de Pagamento (pgto)"}}},"DataTech.Services.Domain.Models.Cfe.CouponIssuerResource":{"description":"Emitente (emit)","type":"object","properties":{"federalTaxNumber":{"format":"int64","description":"CNPJ do emitente (CNPJ) / CPF do remetente (CPF)","type":"integer"},"type":{"description":"Tipo da pessoa: Jurídica ou Física","enum":["Undefined","NaturalPerson","LegalEntity"],"type":"string"},"name":{"description":"Razão Social ou Nome do emitente (xNome)","type":"string"},"tradeName":{"description":"Nome fantasia (xFant)","type":"string"},"address":{"$ref":"#/definitions/DataTech.Api.Resources.AddressResourceItem","description":"Endereço do emitente (enderEmit)"},"stateTaxNumber":{"description":"Inscrição Estadual (IE)","type":"string"},"taxRegime":{"description":"Código de Regime Tributário (CRT)\r\n\r\n 1 - Simples Nacional (National_Simple)\r\n 2 - Simples Nacional, excesso sublimite de receita bruta (National_Simple_Brute)\r\n 3 - Regime Normal (Normal_Regime)\r\n","enum":["National_Simple","National_Simple_Brute","Normal_Regime"],"type":"string"},"municipalTaxNumber":{"description":"Inscrição Municipal do Prestador de Serviço (IM)","type":"string"},"iss":{"description":"Regime Especial de Tributação do ISSQN (cRegTrib)","type":"string"},"avarageIndicator":{"description":"Indicador de Rateio do Desconto Sobre Subtotal (indRatISSQN)","type":"boolean"}}},"DataTech.Services.Domain.Models.Cfe.CouponBuyerResource":{"type":"object","properties":{"pretectedPersonalInformation":{"description":"CNPJ do Destinantario (CNPJ) / CPF do destinatário (CPF) - Protegido","type":"string"},"federalTaxNumber":{"format":"int64","description":"CNPJ do Destinantario (CNPJ) / CPF do destinatário (CPF)","type":"integer"},"name":{"description":"Razão Social ou nome do destinatário (xNome)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.CouponTotalResource":{"description":"Grupo de Valores Totais do CF-e","type":"object","properties":{"icms":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponICMSTotalResource","description":"Grupo de Valores Totais referentes ao ICMS (ICMSTot)"},"issqn":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponISSQNTotalResource","description":"Grupo de Valores Totais referentes ao ISSQN (ISSQNtot)"},"totalAmount":{"format":"double","description":"Valor dos Tributos Aproximado do CFe-SAT Lei12471/12 (vCFeLei12741)","type":"number"},"couponAmount":{"format":"double","description":"Valor Total do CF-e (vCFe)","type":"number"}}},"DataTech.Api.Resources.TaxCoupon.CouponDeliveryResource":{"type":"object","properties":{"address":{"$ref":"#/definitions/DataTech.Api.Resources.AddressResourceItem","description":"Endereço"}}},"DataTech.Services.Domain.Models.Cfe.CouponAdditionalInformationResource":{"description":"Informacoes Adicionais (infAdic)","type":"object","properties":{"taxpayer":{"description":"Informações Complementares de interesse do Contribuinte (infCpl)","type":"string"},"fisco":{"description":"Informações Adicionais de Interesse do Fisco (obsFisco)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.FiscoFieldsResource"}},"referencedDocuments":{"description":"Documentos Fiscais Referenciados","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponTaxReferencedDocumentsResource"}}}},"DataTech.Services.Domain.Models.Cfe.CouponItemResource":{"description":"Produto (prod)","type":"object","properties":{"description":{"description":"Descrição do produto ou serviço (xProd)","type":"string"},"quantity":{"format":"double","description":"Quantidade Comercial (qCom)","type":"number"},"unit":{"description":"Unidade Comercial (uCom)","type":"string"},"code":{"description":"Código do produto ou serviço (cProd)","type":"string"},"codeGTIN":{"description":"GTIN (Global Trade Item Number) do produto, \r\nantigo código EAN ou código de barras (cEAN)","type":"string"},"ncm":{"description":"Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM)","type":"string"},"cfop":{"format":"int64","description":"Código Fiscal de Operações e Prestações (CFOP)","type":"integer"},"cest":{"description":"Código especificador da substituição tributária (CEST)","type":"string"},"unitAmount":{"format":"double","description":"Valor Unitário de Comercialização (vUnCom)","type":"number"},"discountAmount":{"format":"double","description":"Valor do Desconto (vDesc)","type":"number"},"othersAmount":{"format":"double","description":"Outras despesas acessórias (vOutro)","type":"number"},"additionalInformation":{"description":"Informações Adicionais do Produto (infAdProd)","type":"string"},"itemNumberOrderBuy":{"format":"int32","description":"Item do Pedido de Compra (nItem)","type":"integer"},"netAmount":{"format":"double","description":"Valor Líquido (vItem)","type":"number"},"grossAmount":{"format":"double","description":"Valor Bruto (vProd)","type":"number"},"rule":{"description":"Indicador da regra de cálculo utilizada para Valor Bruto dos Produtos e Serviços\r\n A - ArredondamentoT - Truncamento","type":"string"},"apportionmentDiscountAmount":{"format":"double","description":"Rateio desconto (vRatDesc)","type":"number"},"apportionmentAmount":{"format":"double","description":"Rateio acréscimo (vRatAcr)","type":"number"},"fisco":{"description":"Observação fisco (obsFiscoDet)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.FiscoFieldsResource"}},"tax":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponItemTaxResource","description":"Tributos incidentes no Produto ou Serviço (imposto)"}}},"DataTech.Services.Domain.Models.Cfe.CouponPaymentResource":{"description":"Grupo de Formas de Pagamento (pgto)","type":"object","properties":{"payBack":{"format":"double","description":"Valor do troco (vTroco)","type":"number"},"paymentDetails":{"description":"Grupo Detalhamento da Forma de Pagamento (MP)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponPaymentDetailResource"}}}},"DataTech.Api.Resources.AddressResourceItem":{"description":"Endereço","type":"object","properties":{"state":{"description":"Estado","type":"string"},"city":{"$ref":"#/definitions/DataTech.Services.Domain.Models.CityBase","description":"Cidade"},"district":{"description":"Bairro","type":"string"},"additionalInformation":{"description":"Informações adicionais","type":"string"},"streetSuffix":{"description":"Sufixo da rua","type":"string"},"street":{"description":"Nome da rua","type":"string"},"number":{"description":"Número","type":"string"},"numberMin":{"type":"string"},"numberMax":{"type":"string"},"postalCode":{"description":"CEP","type":"string"},"country":{"description":"País","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.CouponICMSTotalResource":{"description":"Grupo de Valores Totais referentes ao ICMS (ICMSTot)","type":"object","properties":{"productAmount":{"format":"double","description":"Valor Total dos produtos e serviços (vProd)","type":"number"},"discountAmount":{"format":"double","description":"Valor Total do Desconto (vDesc)","type":"number"},"othersAmount":{"format":"double","description":"Outras Despesas acessórias (vOutro)","type":"number"},"icmsAmount":{"format":"double","description":"Valor total de ICMS (vICMS)","type":"number"},"inputDiscountAmount":{"format":"double","description":"Valor de Entrada de desconto sobre subtotal (vDescSubtot)","type":"number"},"inputAdditionAmount":{"format":"double","description":"Valor de Entrada de acréscimo sobre subtotal (vAcresSubtot)","type":"number"},"pisAmount":{"format":"double","description":"Valor do PIS (vPIS)","type":"number"},"cofinsAmount":{"format":"double","description":"Valor do COFINS (vCOFINS)","type":"number"},"pisstAmount":{"format":"double","description":"Valor do PIS ST (vPISST)","type":"number"},"cofinsstAmount":{"format":"double","description":"Valor do COFINS ST (vCOFINSST)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.CouponISSQNTotalResource":{"description":"Grupo de Valores Totais referentes ao ISSQN (ISSQNtot)","type":"object","properties":{"baseAmount":{"format":"double","description":"Base de Cálculo do ISSQN (vBC)","type":"number"},"issAmount":{"format":"double","description":"Valor total de ISSQN (vISS)","type":"number"},"pisAmount":{"format":"double","description":"Valor do PIS (vPIS)","type":"number"},"cofinsAmount":{"format":"double","description":"Valor do COFINS (vCOFINS)","type":"number"},"pisstAmount":{"format":"double","description":"Valor do PIS ST (vPISST)","type":"number"},"cofinsstAmount":{"format":"double","description":"Valor do COFINS ST (vCOFINSST)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.FiscoFieldsResource":{"description":"Observação fisco (obsFiscoDet)","type":"object","properties":{"key":{"description":"Campo (xCampoDet)","type":"string"},"value":{"description":"Texto (xTextoDet)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.CouponTaxReferencedDocumentsResource":{"type":"object","properties":{"accessKey":{"description":"Chave de Acesso (refNFe)","type":"string"},"order":{"format":"int32","description":"Número da ordem","type":"integer"}}},"DataTech.Services.Domain.Models.Cfe.CouponItemTaxResource":{"description":"Tributos incidentes no Produto ou Serviço (imposto)","type":"object","properties":{"totalTax":{"format":"double","description":"Valor aproximado total de tributos federais, estaduais e municipais. (vItem12741)","type":"number"},"icms":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponIcmsTaxResource","description":"Dados do ICMS Normal e ST (ICMS)"},"pis":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponPisTaxResource","description":"Grupo PIS (PIS)"},"cofins":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponCofinsTaxResource","description":"Grupo COFINS (COFINS)"},"issqn":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponISSQNResource","description":"Grupo Imposto Sobre Serviço de Qualquer Natureza (ISSQN)"}}},"DataTech.Services.Domain.Models.Cfe.CouponPaymentDetailResource":{"description":"Grupo Detalhamento da Forma de Pagamento (MP)","type":"object","properties":{"method":{"description":"Código do meio de pagamento (cMP)","enum":["Cash","Cheque","CreditCard","DebitCard","StoreCredict","FoodVouchers","MealVouchers","GiftVouchers","FuelVouchers","CommercialDuplicate","BankSlip","BankDeposit","InstantPayment","WireTransfer","Cashback","Unpaid","Others"],"type":"string"},"amount":{"format":"double","description":"Valor do meio de pagamento (vMP)","type":"number"},"card":{"description":"Grupo de Cartões (card)","type":"string"}}},"DataTech.Services.Domain.Models.CityBase":{"type":"object","properties":{"code":{"description":"Código do município (cMun)","type":"string"},"name":{"description":"Nome do município (xMun)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.CouponIcmsTaxResource":{"description":"Dados do ICMS Normal e ST (ICMS)","type":"object","properties":{"origin":{"description":"Origem da mercadoria (Orig)","type":"string"},"cst":{"description":"Tributação do ICMS (CST)","type":"string"},"csosn":{"description":"101- Tributada pelo Simples Nacional com permissão de crédito. (v.2.0) (CSOSN)\r\nCódigo de Situação da Operação – Simples Nacional","type":"string"},"amount":{"format":"double","description":"Valor do ICMS (vICMS)\r\n\r\nO valor do ICMS desonerado será informado apenas nas operações:\r\na) com produtos beneficiados com a desoneração condicional do ICMS.\r\nb) destinadas à SUFRAMA, informando-se o valor que seria devido se não houvesse isenção.\r\nc) de venda a órgãos da administração pública direta e suas fundações e\r\nautarquias com isenção do ICMS. (NT 2011/004)","type":"number"},"rate":{"format":"double","description":"Alíquota do imposto (pICMS)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.CouponPisTaxResource":{"description":"Grupo PIS (PIS)","type":"object","properties":{"cst":{"description":"Código de Situação Tributária do PIS (CST)","type":"string"},"st":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponTaxBaseResource","description":"Substituição Tributária"},"baseTax":{"format":"double","description":"Valor da Base de Cálculo (vBC)","type":"number"},"rate":{"format":"double","description":"Alíquota do (em percentual) (pPIS)","type":"number"},"amount":{"format":"double","description":"Valor","type":"number"},"rateAmount":{"format":"double","description":"Alíquota (em reais) (vAliqProd)","type":"number"},"quantity":{"format":"double","description":"Quantidade Vendida (qBCProd)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.CouponCofinsTaxResource":{"description":"Grupo COFINS (COFINS)","type":"object","properties":{"cst":{"description":"Código de Situação Tributária da COFINS\r\nObs: 01 – Operação Tributável (base de cálculo = valor da operação \r\nalíquota normal (cumulativo/não cumulativo));\r\n02 - Operação Tributável (base de cálculo = valor da operação (alíquota diferenciada)); (CST)","type":"string"},"st":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.CouponTaxBaseResource","description":"Substituição Tributária"},"baseTax":{"format":"double","description":"Valor da Base de Cálculo (vBC)","type":"number"},"rate":{"format":"double","description":"Alíquota do (em percentual) (pPIS)","type":"number"},"amount":{"format":"double","description":"Valor","type":"number"},"rateAmount":{"format":"double","description":"Alíquota (em reais) (vAliqProd)","type":"number"},"quantity":{"format":"double","description":"Quantidade Vendida (qBCProd)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.CouponISSQNResource":{"description":"Grupo Imposto Sobre Serviço de Qualquer Natureza (ISSQN)","type":"object","properties":{"deductionsAmount":{"format":"double","description":"Valor dedução para redução da Base de Cálculo (vDeducISSQN)","type":"number"},"baseTax":{"format":"double","description":"Valor da Base de Cálculo do ISSQN (vBC)","type":"number"},"rate":{"format":"double","description":"Alíquota do ISSQN (vAliq)","type":"number"},"amount":{"format":"double","description":"Valor do ISSQN (vISSQN)","type":"number"},"federalServiceCode":{"description":"Item da Lista de Serviços (cListServ)","type":"string"},"cityServiceCode":{"description":"Código do serviço prestado dentro do município (cServTribMun)","type":"string"},"cityCode":{"format":"int64","description":"Código do Município do Fato Gerador do ISSQN (cMunFG)","type":"integer"},"taxIncentive":{"description":"Incentivo Fiscal do ISSQN (indIncFisc)","enum":["Yes","No"],"type":"string"},"operationNature":{"description":"Natureza de operação do ISSQN (cNatOp)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.CouponTaxBaseResource":{"type":"object","properties":{"baseTax":{"format":"double","description":"Valor da Base de Cálculo (vBC)","type":"number"},"rate":{"format":"double","description":"Alíquota do (em percentual) (pPIS)","type":"number"},"amount":{"format":"double","description":"Valor","type":"number"},"rateAmount":{"format":"double","description":"Alíquota (em reais) (vAliqProd)","type":"number"},"quantity":{"format":"double","description":"Quantidade Vendida (qBCProd)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFe":{"description":"Cupom fiscal eletrônico (CFe)","type":"object","properties":{"infCFe":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.InfCFe","description":"Grupo das informações (infCFe)"}}},"DataTech.Services.Domain.Models.Cfe.xml.InfCFe":{"type":"object","properties":{"ide":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Ide","description":"Grupo das informações de identificação (ide)"},"emit":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Emit","description":"Emitente (emit)"},"dest":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Dest","description":"Destinatario (dest)"},"det":{"description":"Detalhamento do produto (det)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Det"}},"total":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeTotal","description":"Grupo de Valores Totais (total)"},"pgto":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Pgto","description":"Grupo de Formas de Pagamento (pgto)"},"infAdic":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.InfAdic","description":"Informacoes Adicionais (infAdic)"},"entrega":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Entrega","description":"Dados do Local da Entrega (entrega)"},"versaoSB":{"description":"Versão do Software Básico (versaoSB)","type":"string"},"versaoDadosEnt":{"description":"Versão do leiaute (versaoDadosEnt)","type":"string"},"versao":{"description":"Versão (versao)","type":"string"},"id":{"description":"Chave de Acesso (Id)","type":"string"},"chCanc":{"description":"Chave de acesso do CF-e a ser cancelado (chCanc)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.Ide":{"description":"Grupo das informações de identificação do CF-e (ide)","type":"object","properties":{"cUF":{"format":"int32","description":"Código da UF do emitente do Documento Fiscal. Utilizar a Tabela do IBGE. (cUF)","type":"integer"},"cNF":{"description":"Código numérico que compõe a Chave de Acesso. Número aleatório gerado pelo emitente para cada NF-e. (cNF)","type":"string"},"mod":{"description":"Código do Modelo do documento fiscal (mod)","type":"string"},"nserieSAT":{"description":"Número de Série do SAT (nserieSAT)","type":"string"},"nCFe":{"description":"Número do Documento Fiscal (nNF)","type":"string"},"dEmi":{"format":"date-time","type":"string"},"proxydEmi":{"description":"Proxy para dEmi no formato AAAAMMDD (dEmi)","type":"string"},"hEmi":{"type":"string"},"proxyHEmi":{"description":"Proxy para hEmi no formato HHMMSS (hEmi)","type":"string"},"cDV":{"format":"int32","description":"Digito Verificador da Chave de Acesso da NF-e (cDV)","type":"integer"},"tpAmb":{"description":"Identificação do Ambiente (tpAmb)","enum":["Producao","Homologacao"],"type":"string"},"cnpj":{"description":"CNPJ Software House (CNPJ)","type":"string"},"signAC":{"description":"Assinatura do aplicativo comercial (signAC)","type":"string"},"assinaturaQRCODE":{"description":"Assinatura digital para uso em QRCODE(assinaturaQRCODE)","type":"string"},"numeroCaixa":{"description":"Número do Caixa (numeroCaixa)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.Emit":{"description":"Emitente (emit)","type":"object","properties":{"cnpj":{"description":"CNPJ do emitente (CNPJ)","type":"string"},"xNome":{"description":"Razão Social ou Nome do emitente (xNome)","type":"string"},"xFant":{"description":"Nome fantasia (xFant)","type":"string"},"enderEmit":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.EnderEmit","description":"Endereço do emitente (enderEmit)"},"ie":{"description":"Inscrição Estadual (IE)","type":"string"},"im":{"description":"Inscrição Municipal do Prestador de Serviço (IM)","type":"string"},"cRegTrib":{"description":"Código de Regime Tributário (CRT)\r\n\r\n 1 - Simples Nacional (National_Simple)\r\n 2 - Simples Nacional, excesso sublimite de receita bruta (National_Simple_Brute)\r\n 3 - Regime Normal (Normal_Regime)\r\n","enum":["SimplesNacional","SimplesNacionalExcessoSublimite","RegimeNormal"],"type":"string"},"cRegTribISSQN":{"description":"Regime Especial de Tributação do ISSQN (cRegTrib)","type":"string"},"indRatISSQN":{"description":"Indicador de Rateio do Desconto Sobre Subtotal (indRatISSQN)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.Dest":{"description":"Destinatario (dest)","type":"object","properties":{"cnpj":{"description":"CNPJ do Destinantario (CNPJ)","type":"string"},"cpf":{"description":"CPF do destinatário (CPF)","type":"string"},"xNome":{"description":"Razão Social ou nome do destinatário (xNome)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.Det":{"description":"Detalhamento do produto (det)","type":"object","properties":{"prod":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Prod","description":"Produto (prod)"},"imposto":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.Imposto","description":"Tributos incidentes no Produto ou Serviço (imposto)"},"nItem":{"format":"int32","description":"Item do Pedido de Compra (nItem)","type":"integer"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeTotal":{"description":"Grupo de Valores Totais (total)","type":"object","properties":{"icmsTot":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeICMSTot","description":"Grupo de Valores Totais referentes ao ICMS (ICMSTot)"},"issqNtot":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeISSQNTot","description":"Grupo de Valores Totais referentes ao ISSQN (ISSQNtot)"},"descAcrEntr":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.DescAcrEntr","description":"Grupo de valores de entrada de Desconto/Acréscimo sobre Subtotal (DescAcrEntr)"},"vCFe":{"format":"double","description":"Valor Total do CF-e (vCFe)","type":"number"},"vCFeLei12741":{"format":"double","description":"Valor dos Tributos Aproximado do CFe-SAT Lei12471/12 (vCFeLei12741)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.Pgto":{"description":"Grupo de Formas de Pagamento (pgto)","type":"object","properties":{"mp":{"description":"Grupo Detalhamento da Forma de Pagamento (MP)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.MP"}},"vTroco":{"format":"double","description":"Valor do troco (vTroco)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.InfAdic":{"description":"Informacoes Adicionais (infAdic)","type":"object","properties":{"infCpl":{"description":"Informações Complementares de interesse do Contribuinte (infCpl)","type":"string"},"obsFisco":{"description":"Informações Adicionais de Interesse do Fisco (obsFisco)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.ObsFisco"}}}},"DataTech.Services.Domain.Models.Cfe.xml.Entrega":{"description":"Dados do Local da Entrega (entrega)","type":"object","properties":{"uf":{"description":"Estado (UF)","type":"string"},"xLgr":{"description":"Logradouro do Endereco (xLgr)","type":"string"},"nro":{"description":"Número (nro)","type":"string"},"xCpl":{"description":"Complemento (xCpl)","type":"string"},"xBairro":{"description":"Bairro (xBairro)","type":"string"},"xMun":{"description":"Município (xMun)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.EnderEmit":{"type":"object","properties":{"cep":{"description":"Código do CEP (CEP)","type":"string"},"xLgr":{"description":"Logradouro do Endereco (xLgr)","type":"string"},"nro":{"description":"Número (nro)","type":"string"},"xCpl":{"description":"Complemento (xCpl)","type":"string"},"xBairro":{"description":"Bairro (xBairro)","type":"string"},"xMun":{"description":"Município (xMun)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.Prod":{"type":"object","properties":{"cProd":{"description":"Código do produto ou serviço (cProd)","type":"string"},"cEAN":{"description":"GTIN (Global Trade Item Number) do produto, \r\nantigo código EAN ou código de barras (cEAN)","type":"string"},"xProd":{"description":"Descrição do produto ou serviço (xProd)","type":"string"},"ncm":{"description":"Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM)","type":"string"},"cfop":{"format":"int32","description":"Código Fiscal de Operações e Prestações (CFOP)","type":"integer"},"uCom":{"description":"Unidade Comercial (uCom)","type":"string"},"qCom":{"format":"double","description":"Quantidade Comercial (qCom)","type":"number"},"vUnCom":{"format":"double","description":"Valor Unitário de Comercialização (vUnCom)","type":"number"},"vProd":{"format":"double","description":"Valor Bruto (vProd)","type":"number"},"indRegra":{"description":"Indicador da regra de cálculo utilizada para Valor Bruto dos Produtos e Serviços\r\n A - ArredondamentoT - Truncamento","type":"string"},"vDesc":{"format":"double","description":"Valor do Desconto (vDesc)","type":"number"},"vOutro":{"format":"double","description":"Outras despesas acessórias (vOutro)","type":"number"},"vItem":{"format":"double","description":"Valor Líquido (vItem)","type":"number"},"vRatDesc":{"format":"double","description":"Rateio desconto (vRatDesc)","type":"number"},"vRatAcr":{"format":"double","description":"Rateio acréscimo (vRatAcr)","type":"number"},"obsFiscoDet":{"description":"Observação fisco (obsFiscoDet)","type":"array","items":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.ObsFiscoDet"}}}},"DataTech.Services.Domain.Models.Cfe.xml.Imposto":{"description":"Tributos incidentes no Produto ou Serviço (imposto)","type":"object","properties":{"vItem12741":{"format":"double","description":"Valor aproximado total de tributos federais, estaduais e municipais. (vItem12741)","type":"number"},"icms":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeICMS","description":"Dados do ICMS Normal e ST (ICMS)"},"pis":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFePIS","description":"Grupo PIS (PIS)"},"cofins":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeCOFINS","description":"Grupo COFINS (COFINS)"},"cofinsst":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeCOFINSST","description":"Grupo COFINS Substituição Tributária (COFINSST)"},"pisst":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFePISST","description":"Grupo PIS Substituição Tributária (PISST)"},"issqn":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeISSQN","description":"Grupo Imposto Sobre Serviço de Qualquer Natureza (ISSQN)"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeICMSTot":{"description":"Grupo de Valores Totais referentes ao ICMS (ICMSTot)","type":"object","properties":{"vICMS":{"format":"double","description":"Valor total de ICMS (vICMS)","type":"number"},"vProd":{"format":"double","description":"Valor Total dos produtos e serviços (vProd)","type":"number"},"vDesc":{"format":"double","description":"Valor Total do Desconto (vDesc)","type":"number"},"vPIS":{"format":"double","description":"Valor do PIS (vPIS)","type":"number"},"vCOFINS":{"format":"double","description":"Valor do COFINS (vCOFINS)","type":"number"},"vPISST":{"format":"double","description":"Valor do PIS ST (vPISST)","type":"number"},"vCOFINSST":{"format":"double","description":"Valor do COFINS ST (vCOFINSST)","type":"number"},"vOutro":{"format":"double","description":"Outras Despesas acessórias (vOutro)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeISSQNTot":{"description":"Grupo de Valores Totais referentes ao ISSQN (ISSQNtot)","type":"object","properties":{"vBC":{"format":"double","description":"Base de Cálculo do ISSQN (vBC)","type":"number"},"vISS":{"format":"double","description":"Valor total de ISSQN (vISS)","type":"number"},"vPIS":{"format":"double","description":"Valor do PIS (vPIS)","type":"number"},"vCOFINS":{"format":"double","description":"Valor do COFINS (vCOFINS)","type":"number"},"vPISST":{"format":"double","description":"Valor do PIS ST (vPISST)","type":"number"},"vCOFINSST":{"format":"double","description":"Valor do COFINS ST (vCOFINSST)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.DescAcrEntr":{"description":"Grupo de valores de entrada de Desconto/Acréscimo sobre Subtotal (DescAcrEntr)","type":"object","properties":{"vDescSubtot":{"format":"double","description":"Valor de Entrada de Desconto sobre Subtotal","type":"number"},"vAcresSubtot":{"format":"double","description":"Valor de Entrada de Acréscimo sobre Subtotal","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.MP":{"description":"Grupo Detalhamento da Forma de Pagamento (MP)","type":"object","properties":{"cMP":{"description":"Código do meio de pagamento (cMP)","enum":["fpDinheiro","fpCheque","fpCartaoCredito","fpCartaoDebito","fpCreditoLoja","fpValeAlimentacao","fpValeRefeicao","fpValePresente","fpValeCombustivel","fpDuplicataMercantil","fpBoletoBancario","fpSemPagamento","fpOutro","fpDepositoBancario","fpPagamentoInstantaneoPIX","fpTransferenciabancaria","fpProgramadefidelidade"],"type":"string"},"vMP":{"format":"double","description":"Valor do meio de pagamento (vMP)","type":"number"},"cAdmc":{"description":"Credenciadora de cartão de débito ou crédito (cAmd)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.ObsFisco":{"description":"Informações Adicionais de Interesse do Fisco (obsFisco)","type":"object","properties":{"xTexto":{"description":"Texto (xTexto)","type":"string"},"xCampo":{"description":"Campo (xCampo)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.ObsFiscoDet":{"description":"Observação fisco (obsFiscoDet)","type":"object","properties":{"xTextoDet":{"description":"Texto (xTextoDet)","type":"string"},"xCampoDet":{"description":"Campo (xCampoDet)","type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeICMS":{"description":"Dados do ICMS Normal (ICMS)","type":"object","properties":{"tipo":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeICMSBase","description":"(ICMS00) - Grupo Tributação do ICMS= 00\r\n(ICMS40) - Grupo Tributação ICMS = 40, 41, 50\r\n(ICMS60) - Grupo Tributação ICMS = 60\r\n(ICMSSN102) - Grupo CRT=1 – Simples Nacional e CSOSN=102, 103, 300 ou 400\r\n(ICMSSN500) - Grupo CRT=1 – Simples Nacional e CSOSN=500\r\n(ICMSSN900) - Grupo CRT=1 – Simples Nacional e CSOSN=900"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFePIS":{"description":"Grupo PIS (PIS)","type":"object","properties":{"tipo":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFePISBase","description":"(PISAliq) - Grupo PIS tributado pela alíquota\r\n(PISNT) - Grupo PIS não tributado\r\n(PISQtde) - Grupo PIS quantidade\r\n(PISOutr) - Grupo PIS outros\r\n(PISSN) - Grupo PIS simples nacional"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeCOFINS":{"description":"Grupo COFINS (COFINS)","type":"object","properties":{"tipo":{"$ref":"#/definitions/DataTech.Services.Domain.Models.Cfe.xml.CFeCOFINSBase","description":"(COFINSAliq) - Grupo COFINS tributado pela alíquota\r\n(COFINSNT) - Grupo COFINS não tributado\r\n(COFINSQtde) - Grupo COFINS quantidade\r\n(COFINSOutr) - Grupo COFINS outros\r\n(COFINSSN) - Grupo COFINS simples nacional"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeCOFINSST":{"description":"Grupo COFINS Substituição Tributária (COFINSST)","type":"object","properties":{"vBC":{"format":"double","description":"Valor da Base de Cálculo da COFINS (vBC)","type":"number"},"pCOFINS":{"format":"double","description":"Alíquota da COFINS (em percentual) (pCOFINS)","type":"number"},"qBCProd":{"format":"double","description":"Quantidade Vendida (qBCProd)","type":"number"},"vAliqProd":{"format":"double","description":"Alíquota da COFINS (em reais) (vAliqProd)","type":"number"},"vCOFINS":{"format":"double","description":"Valor da COFINS (vCOFINS)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFePISST":{"description":"Grupo PIS Substituição Tributária (PISST)","type":"object","properties":{"vBC":{"format":"double","description":"Valor da Base de Cálculo do PIS (vBC)","type":"number"},"pPIS":{"format":"double","description":"Alíquota do PIS (em percentual) (pPIS)","type":"number"},"qBCProd":{"format":"double","description":"Quantidade Vendida (qBCProd)","type":"number"},"vAliqProd":{"format":"double","description":"Alíquota do PIS (em reais) (vAliqProd)","type":"number"},"vPIS":{"format":"double","description":"Valor do PIS (vPIS)","type":"number"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeISSQN":{"description":"Grupo Imposto Sobre Serviço de Qualquer Natureza (ISSQN)","type":"object","properties":{"vDeducISSQN":{"format":"double","description":"Valor dedução para redução da Base de Cálculo (vDeducISSQN)","type":"number"},"vBC":{"format":"double","description":"Valor da Base de Cálculo do ISSQN (vBC)","type":"number"},"vAliq":{"format":"double","description":"Alíquota do ISSQN (vAliq)","type":"number"},"vISSQN":{"format":"double","description":"Valor do ISSQN (vISSQN)","type":"number"},"cMunFG":{"format":"int64","description":"Código do Município do Fato Gerador do ISSQN (cMunFG)","type":"integer"},"cListServ":{"description":"Item da Lista de Serviços (cListServ)","type":"string"},"cServTribMun":{"description":"Código do serviço prestado dentro do município (cServTribMun)","type":"string"},"cNatOp":{"description":"Natureza de operação do ISSQN (cNatOp)","type":"string"},"indIncentivo":{"description":"Incentivo Fiscal do ISSQN (indIncFisc)","enum":["iiSim","iiNao"],"type":"string"}}},"DataTech.Services.Domain.Models.Cfe.xml.CFeICMSBase":{"type":"object","properties":{}},"DataTech.Services.Domain.Models.Cfe.xml.CFePISBase":{"type":"object","properties":{}},"DataTech.Services.Domain.Models.Cfe.xml.CFeCOFINSBase":{"type":"object","properties":{}}},"securityDefinitions":{"Authorization_Header":{"name":"Authorization","in":"header","type":"apiKey","description":"Autenticar usando o Cabeçalho HTTP Authorization com sua API Key"},"Authorization_QueryParam":{"name":"apikey","in":"query","type":"apiKey","description":"Autenticar usando o Parametro na URL, exemplo: \"/?apikey={APIKEY_TOKEN}\""}},"security":[{"Authorization_Header":[],"Authorization_QueryParam":[]}]} \ No newline at end of file diff --git a/openapi/contribuintes-v2.json b/openapi/contribuintes-v2.json new file mode 100644 index 0000000..4e387a9 --- /dev/null +++ b/openapi/contribuintes-v2.json @@ -0,0 +1,5136 @@ +{ + "openapi": "3.0.4", + "servers": [{ "url": "https://api.nfse.io", "description": "Produção" }], + "info": { + "title": "Empresas", + "description": "# Introdução\r\n\r\nSeja bem-vindo a documentação da API de Empresas!\r\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\r\n\r\n# Como usar a API?\r\nLogo a seguir você encontrará todos os recursos e métodos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\r\n\r\n# Autenticação\r\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API.\r\nPara isso você deve colocar sua chave de API no campo que se encontra no topo desta página para que os métodos funcionem corretamente.\r\nNo seu código de integração temos suporte para autenticação de diversas formas sendo eles:\r\nHTTP Header (Authorization ou X-NFEIO-APIKEY) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).", + "version": "v2" + }, + "paths": { + "/v2/companies": { + "post": { + "tags": [ + "Companies" + ], + "summary": "Criar uma Empresa", + "description": "### Informações adicionais\r\nUtilize esta requisição para criar novas empresas plataforma para processar Documentos Fiscais.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.", + "requestBody": { + "description": "Dados da Empresa a ser criada", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na criação da Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Companies" + ], + "summary": "Consultar todas as Empresas da Conta", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados das empresas vinculadas a conta.", + "parameters": [ + { + "name": "startingAfter", + "in": "query", + "description": "Id de início do contador (Default: Empty)", + "schema": { + "type": "string" + } + }, + { + "name": "endingBefore", + "in": "query", + "description": "Id final do contador (Default: Empty)", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Limite de resultados na página (Default: 10)", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta da Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompaniesResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Empresa não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}": { + "get": { + "tags": [ + "Companies" + ], + "summary": "Consultar uma Empresa pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta da Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Empresa não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "head": { + "tags": [ + "Companies" + ], + "summary": "Consultar se Empresa Existe pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta da Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Empresa não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Companies" + ], + "summary": "Alterar uma Empresa pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para alterar os dados de uma empresas pelo ID.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Dados da Empresa a ser alterada", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResource" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na alteração da Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Empresa não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Companies" + ], + "summary": "Excluir uma Empresa por ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para excluir uma empresas pelo ID, cuidado pois esse processo é irreversível.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na exclusão da Empresa" + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Empresa não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/certificates": { + "post": { + "tags": [ + "Companies Certificates" + ], + "summary": "Upload de um Certificado", + "description": "### Informações adicionais\r\nUtilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo __e-CNPJ A1__ ou __NFE A1__ em uma **Empresa** e vincula-lo para processamentos.\r\nO **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da empresa", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "File", + "Password" + ], + "type": "object", + "properties": { + "File": { + "type": "string", + "description": "Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12", + "format": "binary" + }, + "Password": { + "type": "string", + "description": "Senha do certificado ICP-Brasil" + } + } + }, + "encoding": { + "File": { + "style": "form" + }, + "Password": { + "style": "form" + } + } + }, + "application/form-data": { + "schema": { + "required": [ + "File", + "Password" + ], + "type": "object", + "properties": { + "File": { + "type": "string", + "description": "Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12", + "format": "binary" + }, + "Password": { + "type": "string", + "description": "Senha do certificado ICP-Brasil" + } + } + }, + "encoding": { + "File": { + "style": "form" + }, + "Password": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso no upload e vinculo com a Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificateMetadataResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Companies Certificates" + ], + "summary": "Consultar Certificado habilitado para empresa", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados do **Certificado da ICP-Brasil** habilitado para a empresa.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa relacionada ao certificado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificatesMetadataResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v1/companies/{company_id}/certificate": { + "post": { + "tags": [ + "Companies Certificates" + ], + "summary": "Upload de um Certificado", + "description": "### Informações adicionais\r\nUtilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo __e-CNPJ A1__ ou __NFE A1__ em uma **Empresa** e vincula-lo para processamentos.\r\nO **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da empresa", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "required": [ + "File", + "Password" + ], + "type": "object", + "properties": { + "File": { + "type": "string", + "description": "Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12", + "format": "binary" + }, + "Password": { + "type": "string", + "description": "Senha do certificado ICP-Brasil" + } + } + }, + "encoding": { + "File": { + "style": "form" + }, + "Password": { + "style": "form" + } + } + }, + "application/form-data": { + "schema": { + "required": [ + "File", + "Password" + ], + "type": "object", + "properties": { + "File": { + "type": "string", + "description": "Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12", + "format": "binary" + }, + "Password": { + "type": "string", + "description": "Senha do certificado ICP-Brasil" + } + } + }, + "encoding": { + "File": { + "style": "form" + }, + "Password": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso no upload e vinculo com a Empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificateMetadataResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "get": { + "tags": [ + "Companies Certificates" + ], + "summary": "Consultar Certificado habilitado para empresa", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados do **Certificado da ICP-Brasil** habilitado para a empresa.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa relacionada ao certificado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificatesMetadataResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/certificates/{certificate_thumbprint}": { + "get": { + "tags": [ + "Companies Certificates" + ], + "summary": "Consultar um Certificado por sua impressão digital", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de um **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__).", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa relacionada ao certificado", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "certificate_thumbprint", + "in": "path", + "description": "Impressão digital do certificado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificateMetadataResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Certificado não encontrado", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Companies Certificates" + ], + "summary": "Excluir um Certificado por sua impressão digital", + "description": "### Informações adicionais\r\nUtilize esta requisição para excluir o **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__) e desvincula-lo da **Empresa**.\r\n**ATENÇÃO pois esta requisição é irreversível**", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa relacionada ao certificado", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "certificate_thumbprint", + "in": "path", + "description": "Impressão digital do certificado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na exclusão e desvinculo com a Empresa" + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Certificado não encontrado", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v1/companies/{company_id}/certificate/{certificate_thumbprint}": { + "get": { + "tags": [ + "Companies Certificates" + ], + "summary": "Consultar um Certificado por sua impressão digital", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de um **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__).", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa relacionada ao certificado", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "certificate_thumbprint", + "in": "path", + "description": "Impressão digital do certificado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificateMetadataResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Certificado não encontrado", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Companies Certificates" + ], + "summary": "Excluir um Certificado por sua impressão digital", + "description": "### Informações adicionais\r\nUtilize esta requisição para excluir o **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__) e desvincula-lo da **Empresa**.\r\n**ATENÇÃO pois esta requisição é irreversível**", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa relacionada ao certificado", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "certificate_thumbprint", + "in": "path", + "description": "Impressão digital do certificado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na exclusão e desvinculo com a Empresa" + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Certificado não encontrado", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/municipaltaxes": { + "get": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Listar as Inscrições Municipais", + "description": "### Informações adicionais\r\nUtilize esta requisição para listar as inscrições municipais na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "startingAfter", + "in": "query", + "description": "Id de início do contador (Default: Empty)", + "schema": { + "type": "string" + } + }, + { + "name": "endingBefore", + "in": "query", + "description": "Id final do contador (Default: Empty)", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Limite de resultados na página (Default: 10)", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Sucesso na criação da Inscrição Municipal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.MunicipalTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "post": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Criar uma Inscrição Municipal", + "description": "### Informações adicionais\r\nUtilize esta requisição para criar novas inscrição municipais na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Dados da Inscrição Municipal a ser criada", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na criação da Inscrição Municipal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.MunicipalTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/municipaltaxes/{municipal_tax_id}": { + "get": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Consultar uma Inscrição Municipal pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "municipal_tax_id", + "in": "path", + "description": "ID da Inscrição Mnicipal que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta da Inscrição Municipal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.MunicipalTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Municipal não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Alterar uma Inscrição Municipal pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para alterar os dados de uma Inscrição Municipal pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "municipal_tax_id", + "in": "path", + "description": "ID da Inscrição Municipal que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Dados da Inscrição Municipal a ser alterada", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na alteração da Inscrição Municipal", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.MunicipalTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Municipal não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Excluir uma Inscrição Municipal pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para excluir uma Inscrição Municipal pelo ID, cuidado pois esse processo é irreversível.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "municipal_tax_id", + "in": "path", + "description": "ID da Inscrição Municipal que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na exclusão da Inscrição Municipal" + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Municipal não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/municipaltaxes/{municipal_tax_id}/updateprefecture": { + "patch": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Atualizar status da prefeitura para uma Inscrição Municipal pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para atualizar o status de uma prefeitura relacionada a uma Inscrição Municipal pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "municipal_tax_id", + "in": "path", + "description": "ID da Inscrição Municipal que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na atualização do status da prefeitura da Inscrição Municipal" + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Municipal não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/municipaltaxes/{municipal_tax_id}/series/{serie}": { + "get": { + "tags": [ + "Companies Municipal Taxes" + ], + "summary": "Consultar uma Serie pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Serie de RPS.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Municipal** representa os dados necessários sobre o cadastro municipal da empresa junto à prefeitura, exigidos para a emissão de notas fiscais de serviços (NFS-e) e para o cumprimento das obrigações tributárias no âmbito municipal.\r\n**Serie** representa a série do RPS (Recibo Provisório de Serviços) utilizada para a emissão de notas fiscais de serviços eletrônicas (NFS-e).", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "municipal_tax_id", + "in": "path", + "description": "ID da Inscrição Mnicipal que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "serie", + "in": "path", + "description": "Série do RPS que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta da Série", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.SerieResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Municipal não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/statetaxes": { + "get": { + "tags": [ + "Companies State Taxes" + ], + "summary": "Listar as Inscrições Estaduais", + "description": "### Informações adicionais\r\nUtilize esta requisição para listar as inscrições estaduais na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "startingAfter", + "in": "query", + "description": "Id de início do contador (Default: Empty)", + "schema": { + "type": "string" + } + }, + { + "name": "endingBefore", + "in": "query", + "description": "Id final do contador (Default: Empty)", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Limite de resultados na página (Default: 10)", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Sucesso na criação da Inscrição Estadual", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxesResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "post": { + "tags": [ + "Companies State Taxes" + ], + "summary": "Criar uma Inscrição Estadual", + "description": "### Informações adicionais\r\nUtilize esta requisição para criar novas inscrição estadual na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Dados da Inscrição Estadual a ser criada", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResource" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na criação da Inscrição Estadual", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/statetaxes/{state_tax_id}": { + "get": { + "tags": [ + "Companies State Taxes" + ], + "summary": "Consultar uma Inscrição Estadual pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state_tax_id", + "in": "path", + "description": "ID da Inscrição Estadual que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na consulta da Inscrição Estadual", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Estadual não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "put": { + "tags": [ + "Companies State Taxes" + ], + "summary": "Alterar uma Inscrição Estadual pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para alterar os dados de uma Inscrição Estadual pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state_tax_id", + "in": "path", + "description": "ID da Inscrição Estadual que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Dados da Inscrição Estadual a ser alterada", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResource" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na alteração da Inscrição Estadual", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxResource" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Estadual não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Companies State Taxes" + ], + "summary": "Excluir uma Inscrição Estadual pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para excluir uma Inscrição Estadual pelo ID, cuidado pois esse processo é irreversível.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state_tax_id", + "in": "path", + "description": "ID da Inscrição Estadual que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na exclusão da Inscrição Estadual" + }, + "400": { + "description": "Algum parametro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Estadual não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + } + } + } + }, + "/v2/companies/{company_id}/statetaxes/{state_tax_id}/switch-authorizer": { + "post": { + "tags": [ + "Companies State Taxes" + ], + "summary": "Alterar o ambiente de uma Inscrição Estadual pelo ID", + "description": "### Informações adicionais\r\nUtilize esta requisição para definir o ambiente de autorização das Notas Fiscais de uma Inscrição Estadual pelo ID.", + "parameters": [ + { + "name": "company_id", + "in": "path", + "description": "ID da Empresa", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state_tax_id", + "in": "path", + "description": "ID da Inscrição Estadual que deverá ser retornado", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "", + "content": { + "application/json;odata.metadata=minimal;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.streaming=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.streaming=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=minimal;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=full;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.metadata=none;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.streaming=true;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;odata.streaming=false;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;IEEE754Compatible=false": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/json;IEEE754Compatible=true": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "text/plain": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerResponse" + } + } + } + }, + "400": { + "description": "Algum parâmetro informado não é válido, verificar resposta", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "404": { + "description": "Inscrição Estadual não encontrada", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorsResource" + } + } + } + }, + "204": { + "description": "Sucesso na exclusão da Inscrição Estadual" + } + } + } + }, + "/v1/companies/{companyIdOrTaxNumber}": { + "get": { + "tags": [ + "Companies V1" + ], + "summary": "Obter os detalhes de uma empresa", + "parameters": [ + { + "name": "companyIdOrTaxNumber", + "in": "path", + "description": "ID da empresa ou Inscrição Federal (CNPJ)", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na requisição", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanySingleResourceV1" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido" + }, + "401": { + "description": "API Key da conta não é valida" + }, + "500": { + "description": "Erro no processamento" + } + } + } + }, + "/v1/companies": { + "get": { + "tags": [ + "Companies V1" + ], + "summary": "Obter os detalhes de todas as empresas da conta", + "parameters": [ + { + "name": "pageCount", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + } + }, + { + "name": "pageIndex", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sucesso na requisição", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyCollectionResourceV1" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido" + }, + "401": { + "description": "API Key da conta não é valida" + }, + "500": { + "description": "Erro no processamento" + } + } + }, + "post": { + "tags": [ + "Companies V1" + ], + "summary": "Criar uma empresa", + "requestBody": { + "description": "Dados da empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResourceV1" + } + } + } + }, + "responses": { + "201": { + "description": "Sucesso na criação da empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanySingleResourceV1" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido" + }, + "401": { + "description": "API Key da conta não é valida" + }, + "409": { + "description": "Já existe uma empresa com o CNPJ informado" + }, + "500": { + "description": "Erro no processamento" + } + } + } + }, + "/v1/companies/{companyId}": { + "put": { + "tags": [ + "Companies V1" + ], + "summary": "Atualizar uma empresa", + "parameters": [ + { + "name": "companyId", + "in": "path", + "description": "ID da empresa", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Dados da empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResourceV1" + } + } + } + }, + "responses": { + "200": { + "description": "Sucesso na atualização da empresa", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanySingleResourceV1" + } + } + } + }, + "400": { + "description": "Algum parametro informado não é válido" + }, + "401": { + "description": "API Key da conta não é valida" + }, + "500": { + "description": "Erro no processamento" + } + } + }, + "delete": { + "tags": [ + "Companies V1" + ], + "summary": "Deletar uma empresa", + "parameters": [ + { + "name": "companyId", + "in": "path", + "description": "ID da empresa", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Sucesso na deleção da empresa" + }, + "400": { + "description": "Algum parametro informado não é válido" + }, + "401": { + "description": "API Key da conta não é valida" + }, + "500": { + "description": "Erro no processamento" + } + } + } + } + }, + "components": { + "schemas": { + "DFeTech.TaxPayers.Domain.Entities.Address": { + "type": "object", + "properties": { + "state": { + "type": "string", + "nullable": true + }, + "city": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CityBase" + }, + "district": { + "type": "string", + "nullable": true + }, + "additionalInformation": { + "type": "string", + "nullable": true + }, + "streetPrefix": { + "type": "string", + "nullable": true + }, + "street": { + "type": "string", + "nullable": true + }, + "number": { + "type": "string", + "nullable": true + }, + "postalCode": { + "type": "string", + "nullable": true + }, + "country": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Domain.Entities.ApiEnvironment": { + "enum": [ + "Development", + "Production", + "Staging" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.CertificateStatus": { + "enum": [ + "None", + "Active", + "Inactive", + "Overdue", + "Pending" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.CityBase": { + "type": "object", + "properties": { + "code": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Domain.Entities.CityExtended": { + "type": "object", + "properties": { + "code": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "country": { + "type": "string", + "nullable": true + }, + "state": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Domain.Entities.CompanyFiscalStatus": { + "enum": [ + "None", + "Active", + "CityNotSupported", + "Pending", + "Inactive" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.EnvironmentType": { + "enum": [ + "None", + "Production", + "Test" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.FederalTaxDeterminationBy": { + "enum": [ + "NotInformed", + "Default", + "SimplesNacional" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.LegalNature": { + "enum": [ + "None", + "EmpresaPublica", + "SociedadeEconomiaMista", + "SociedadeAnonimaAberta", + "SociedadeAnonimaFechada", + "SociedadeEmpresariaLimitada", + "SociedadeEmpresariaEmNomeColetivo", + "SociedadeEmpresariaEmComanditaSimples", + "SociedadeEmpresariaEmComanditaporAcoes", + "SociedadeemContaParticipacao", + "Empresario", + "Cooperativa", + "ConsorcioSociedades", + "GrupoSociedades", + "SociedadeEstrangeiraNoBrasil", + "EmpresaBinacionalArgentinoBrasileira", + "EmpresaDomiciliadaExterior", + "ClubeFundoInvestimento", + "SociedadeSimplesPura", + "SociedadeSimplesLimitada", + "SociedadeSimplesEmNomeColetivo", + "SociedadeSimplesEmComanditaSimples", + "EmpresaBinacional", + "ConsorcioEmpregadores", + "ConsorcioSimples", + "EireliNaturezaEmpresaria", + "EireliNaturezaSimples", + "SociedadeUnipessoaldeAdvogados", + "CooperativaDeConsumo", + "EmpresaSimplesDeInovacao", + "InvestidorNaoResidente", + "ServicoNotarial", + "FundacaoPrivada", + "ServicoSocialAutonomo", + "CondominioEdilicio", + "ComissaoConciliacaoPrevia", + "EntidadeMediacaoArbitragem", + "PartidoPolitico", + "EntidadeSindical", + "EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras", + "FundacaoAssociacaoDomiciliadaExterior", + "OrganizacaoReligiosa", + "ComunidadeIndigena", + "FundoPrivado", + "OrgaoDirecaoNacionalPartidoPolitico", + "OrgaoDirecaoRegionalPartidoPolitico", + "OrgaoDirecaoLocalPartidoPolitico", + "ComiteFinanceiroDePartidoPolitico", + "FrentePlebiscitariaOuReferendaria", + "OrganizacaoSocial", + "DemaisCondominios", + "PlanoBeneficiosPrevidenciaComplementarFechada", + "AssociacaoPrivada", + "EmpresaIndividualImobiliaria", + "SeguradoEspecial", + "ContribuinteIndividual", + "CandidatoCargoPoliticoEletivo", + "Leiloeiro", + "ProdutorRural", + "OrganizacaoInternacional", + "RepresentacaoDiplomaticaEstrangeira", + "OutrasInstituicoesExtraterritoriais" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.MunicipalTaxDeterminationBy": { + "enum": [ + "NotInformed", + "Default", + "SimplesNacional" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.MunicipalTaxFiscalStatus": { + "enum": [ + "None", + "Active", + "CityNotSupported", + "Pending", + "Inactive" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.SecurityCredential": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "code": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime": { + "enum": [ + "Nenhum", + "MicroempresaMunicipal", + "Estimativa", + "SociedadeDeProfissionais", + "Cooperativa", + "MicroempreendedorIndividual", + "MicroempresarioEmpresaPequenoPorte", + "Automatico" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.StateCode": { + "enum": [ + "NA", + "RO", + "AC", + "AM", + "RR", + "PA", + "AP", + "TO", + "MA", + "PI", + "CE", + "RN", + "PB", + "PE", + "AL", + "SE", + "BA", + "MG", + "ES", + "RJ", + "SP", + "PR", + "SC", + "RS", + "MS", + "MT", + "GO", + "DF", + "EX" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.StateTaxProcessingAuthorizer": { + "enum": [ + "Normal", + "EPEC" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.StateTaxType": { + "enum": [ + "Default", + "NFe", + "NFCe" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.Status": { + "enum": [ + "None", + "Active", + "Inactive" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Domain.Entities.TaxRegime": { + "enum": [ + "None", + "LucroReal", + "LucroPresumido", + "SimplesNacional", + "SimplesNacionalExcessoSublimite", + "MicroempreendedorIndividual", + "Isento" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Resources.AddressResource": { + "required": [ + "city", + "country", + "district", + "number", + "postalCode", + "state", + "street" + ], + "type": "object", + "properties": { + "state": { + "minLength": 1, + "type": "string", + "description": "Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2." + }, + "city": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CityBaseResource" + }, + "district": { + "minLength": 1, + "type": "string", + "description": "Bairro do Endereço" + }, + "additionalInformation": { + "type": "string", + "description": "Complemento do Endereço, ex.: AP 2, BL A.", + "nullable": true + }, + "street": { + "minLength": 1, + "type": "string", + "description": "Logradouro do Endereço" + }, + "number": { + "minLength": 1, + "type": "string", + "description": "Número do Endereço. Usar S/N para \"sem número\"." + }, + "postalCode": { + "minLength": 1, + "type": "string", + "description": "Cód. Endereço Postal (CEP)" + }, + "country": { + "minLength": 1, + "type": "string", + "description": "País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3." + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CertificateMetadataResource": { + "type": "object", + "properties": { + "certificate": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificateMetadataResourceItem" + } + }, + "additionalProperties": false, + "description": "Certificado" + }, + "DFeTech.TaxPayers.Resources.CertificateMetadataResourceItem": { + "type": "object", + "properties": { + "taxPayerId": { + "type": "string", + "description": "Identificador do contribuinte", + "nullable": true + }, + "thumbprint": { + "type": "string", + "description": "A impressão digital do certificado", + "nullable": true + }, + "taxId": { + "type": "string", + "description": "Documento do contribuinte", + "nullable": true + }, + "subject": { + "type": "string", + "description": "Nome do certificado (subject distinguished name)", + "nullable": true + }, + "validUntil": { + "type": "string", + "description": "Data no horário local após o qual um certificado não é mais válido", + "format": "date-time" + }, + "modifiedOn": { + "type": "string", + "description": "Data de modificação", + "format": "date-time", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CertificateStatus" + } + }, + "additionalProperties": false, + "description": "Certificado" + }, + "DFeTech.TaxPayers.Resources.CertificatesMetadataResource": { + "type": "object", + "properties": { + "certificates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CertificateMetadataResourceItem" + }, + "description": "Certificado", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Certificado" + }, + "DFeTech.TaxPayers.Resources.CityBaseResource": { + "required": [ + "code", + "name" + ], + "type": "object", + "properties": { + "code": { + "minLength": 1, + "type": "string", + "description": "Cód. do Município, segundo o Tabela de Municípios do IBGE" + }, + "name": { + "minLength": 1, + "type": "string", + "description": "Nome do Município" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CompaniesResource": { + "type": "object", + "properties": { + "companies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResourceItem" + }, + "description": "Lista de Empresa", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Empresas" + }, + "DFeTech.TaxPayers.Resources.CompanyCertificateV1": { + "type": "object", + "properties": { + "thumbprint": { + "type": "string", + "description": "Thumbprint certificado", + "nullable": true + }, + "modifiedOn": { + "type": "string", + "description": "Certificado alterado em", + "format": "date-time", + "nullable": true + }, + "expiresOn": { + "type": "string", + "description": "Certificado expira em", + "format": "date-time", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CertificateStatus" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CompanyCollectionResourceV1": { + "type": "object", + "properties": { + "totalResults": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "totalPages": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "page": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "companies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResourceV1" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CompanyResource": { + "type": "object", + "properties": { + "company": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResourceItem" + } + }, + "additionalProperties": false, + "description": "Empresa" + }, + "DFeTech.TaxPayers.Resources.CompanyResourceItem": { + "required": [ + "address", + "federalTaxNumber", + "name", + "taxRegime" + ], + "type": "object", + "properties": { + "name": { + "minLength": 1, + "type": "string", + "description": "Razão Social" + }, + "accountId": { + "type": "string", + "description": "Identificador da conta", + "nullable": true + }, + "tradeName": { + "type": "string", + "description": "Nome Fantasia", + "nullable": true + }, + "federalTaxNumber": { + "type": "integer", + "description": "Número de Inscrição Federal (CNPJ)", + "format": "int64" + }, + "municipalTaxNumber": { + "type": "string", + "description": "Número da Inscrição Municipal", + "nullable": true + }, + "taxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.TaxRegime" + }, + "address": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.AddressResource" + }, + "id": { + "type": "string", + "description": "Identificador (gerado automaticamente)", + "nullable": true + }, + "stateTaxes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Lista de Inscrição Estadual", + "nullable": true + }, + "municipalTaxes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Lista de Inscrição Municipal", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.Status" + }, + "createdOn": { + "type": "string", + "description": "Data de criação", + "format": "date-time" + }, + "modifiedOn": { + "type": "string", + "description": "Data de modificação", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Dados da Empresa" + }, + "DFeTech.TaxPayers.Resources.CompanyResourceV1": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Identificação", + "nullable": true + }, + "name": { + "type": "string", + "description": "Nome ou Razão Social", + "nullable": true + }, + "tradeName": { + "type": "string", + "description": "Nome fantasia", + "nullable": true + }, + "federalTaxNumber": { + "type": "integer", + "description": "CNPJ ou CPF", + "format": "int64", + "nullable": true + }, + "email": { + "type": "string", + "description": "Email", + "nullable": true + }, + "address": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.Address" + }, + "openningDate": { + "type": "string", + "description": "Data abertura da empresa", + "format": "date-time", + "nullable": true + }, + "taxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.TaxRegime" + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "legalNature": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.LegalNature" + }, + "companyRegistryNumber": { + "type": "integer", + "description": "Número de Inscricação na Junta Comercial", + "format": "int64", + "nullable": true + }, + "regionalTaxNumber": { + "type": "integer", + "description": "Número de Inscricação na SEFAZ (IE)", + "format": "int64", + "nullable": true + }, + "municipalTaxNumber": { + "type": "string", + "description": "Número de Inscricação na Prefeitura (CCM)", + "nullable": true + }, + "rpsSerialNumber": { + "type": "string", + "description": "RPS número serie", + "nullable": true + }, + "rpsNumber": { + "type": "integer", + "description": "RPS número", + "format": "int64", + "nullable": true + }, + "lastRpsSent": { + "type": "integer", + "description": "RPS número", + "format": "int64", + "nullable": true + }, + "issRate": { + "type": "number", + "description": "Alíquota do ISS para Simples Nacional", + "format": "double", + "nullable": true + }, + "environment": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.ApiEnvironment" + }, + "fiscalStatus": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.MunicipalTaxFiscalStatus" + }, + "federalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.FederalTaxDeterminationBy" + }, + "municipalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.MunicipalTaxDeterminationBy" + }, + "loginName": { + "type": "string", + "description": "Login para acesso ao sistema", + "nullable": true + }, + "loginPassword": { + "type": "string", + "description": "Senha para acesso ao sistema", + "nullable": true + }, + "authIssueValue": { + "type": "string", + "description": "Código de autenticação gerado pela prefeitura", + "nullable": true + }, + "certificate": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyCertificateV1" + }, + "createdOn": { + "type": "string", + "description": "Data de criação", + "format": "date-time", + "nullable": true + }, + "modifiedOn": { + "type": "string", + "description": "Data da última modificação", + "format": "date-time", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.Status" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CompanySingleResourceV1": { + "type": "object", + "properties": { + "companies": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CompanyResourceV1" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CreateCompanyResource": { + "type": "object", + "properties": { + "company": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateCompanyResourceItem" + } + }, + "additionalProperties": false, + "description": "Dados para Criar Empresa" + }, + "DFeTech.TaxPayers.Resources.CreateCompanyResourceItem": { + "required": [ + "address", + "federalTaxNumber", + "name", + "taxRegime" + ], + "type": "object", + "properties": { + "name": { + "minLength": 1, + "type": "string", + "description": "Razão Social" + }, + "accountId": { + "type": "string", + "description": "Identificador da conta", + "nullable": true + }, + "tradeName": { + "type": "string", + "description": "Nome Fantasia", + "nullable": true + }, + "federalTaxNumber": { + "type": "integer", + "description": "Número de Inscrição Federal (CNPJ)", + "format": "int64" + }, + "municipalTaxNumber": { + "type": "string", + "description": "Número da Inscrição Municipal", + "nullable": true + }, + "taxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.TaxRegime" + }, + "address": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.AddressResource" + } + }, + "additionalProperties": false, + "description": "Criar Empresa" + }, + "DFeTech.TaxPayers.Resources.CreateMunicipalTaxResource": { + "type": "object", + "properties": { + "municipalTax": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateMunicipalTaxResourceItem" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CreateMunicipalTaxResourceItem": { + "type": "object", + "properties": { + "city": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CityExtended" + }, + "taxNumber": { + "type": "string", + "description": "Inscrição Municipal", + "nullable": true + }, + "environment": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.ApiEnvironment" + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "email": { + "type": "string", + "description": "Email", + "nullable": true + }, + "legalNature": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.LegalNature" + }, + "companyRegistryNumber": { + "type": "integer", + "description": "Registro da Empresa na Junta Comercial", + "format": "int64", + "nullable": true + }, + "regionalTaxNumber": { + "type": "integer", + "description": "Número Região", + "format": "int64", + "nullable": true + }, + "issRate": { + "type": "number", + "description": "ALíquota do ISS (%)", + "format": "double", + "nullable": true + }, + "federalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.FederalTaxDeterminationBy" + }, + "municipalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.MunicipalTaxDeterminationBy" + }, + "loginName": { + "type": "string", + "description": "Login para acesso ao sistema", + "nullable": true + }, + "loginPassword": { + "type": "string", + "description": "Senha para acesso ao sistema", + "nullable": true + }, + "authIssueValue": { + "type": "string", + "description": "Código de autenticação gerado pela prefeitura", + "nullable": true + }, + "rpsNumber": { + "type": "integer", + "description": "Número do RPS", + "format": "int64" + }, + "lastRpsSent": { + "type": "integer", + "description": "Último RPS enviado", + "format": "int64" + }, + "rpsSerialNumber": { + "type": "string", + "description": "Série do RPS", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CreateStateTaxProcessingDetailsResource": { + "type": "object", + "properties": { + "switchAuthorizerStrategy": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxProcessingSwitchAuthorizerStrategyResource" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CreateStateTaxResource": { + "type": "object", + "properties": { + "stateTax": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxResourceItem" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.CreateStateTaxResourceItem": { + "required": [ + "code", + "taxNumber", + "type" + ], + "type": "object", + "properties": { + "code": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateCode" + }, + "environmentType": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.EnvironmentType" + }, + "taxNumber": { + "minLength": 1, + "type": "string", + "description": "Inscrição Estadual" + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "serie": { + "type": "integer", + "description": "Serie para a emissão NFe", + "format": "int32", + "nullable": true + }, + "number": { + "type": "integer", + "description": "Número para a emissão NFe", + "format": "int64", + "nullable": true + }, + "securityCredential": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SecurityCredential" + }, + "type": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateTaxType" + }, + "processingDetails": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxProcessingDetailsResource" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.ErrorResource": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "description": "Código do erro", + "format": "int32", + "nullable": true, + "readOnly": true + }, + "message": { + "type": "string", + "description": "Mensagem contendo os detalhes do erro", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Erro" + }, + "DFeTech.TaxPayers.Resources.ErrorsResource": { + "type": "object", + "properties": { + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.ErrorResource" + }, + "description": "Lista de Erros", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false, + "description": "Lista de Erros" + }, + "DFeTech.TaxPayers.Resources.MunicipalTaxResource": { + "type": "object", + "properties": { + "municipalTax": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.MunicipalTaxResourceItem" + } + }, + "additionalProperties": false, + "description": "Inscrição Municipal" + }, + "DFeTech.TaxPayers.Resources.MunicipalTaxResourceItem": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Identificador (gerado automaticamente)", + "nullable": true + }, + "companyId": { + "type": "string", + "description": "Código da Empresa", + "nullable": true + }, + "accountId": { + "type": "string", + "description": "Código da Conta", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.Status" + }, + "city": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CityExtended" + }, + "taxNumber": { + "type": "string", + "description": "Inscrição Municipal", + "nullable": true + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "email": { + "type": "string", + "description": "Email", + "nullable": true + }, + "legalNature": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.LegalNature" + }, + "companyRegistryNumber": { + "type": "integer", + "description": "Registro da Empresa na Junta Comercial", + "format": "int64", + "nullable": true + }, + "regionalTaxNumber": { + "type": "integer", + "description": "Número Região", + "format": "int64", + "nullable": true + }, + "rpsSerialNumber": { + "type": "string", + "description": "Série do RPS", + "nullable": true + }, + "rpsNumber": { + "type": "integer", + "description": "Número do RPS", + "format": "int64" + }, + "lastRpsSent": { + "type": "integer", + "description": "Número do último RPS", + "format": "int64" + }, + "issRate": { + "type": "number", + "description": "ALíquota do ISS (%)", + "format": "double", + "nullable": true + }, + "environment": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.ApiEnvironment" + }, + "fiscalStatus": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CompanyFiscalStatus" + }, + "federalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.FederalTaxDeterminationBy" + }, + "municipalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.MunicipalTaxDeterminationBy" + }, + "loginName": { + "type": "string", + "description": "Login para acesso ao sistema", + "nullable": true + }, + "loginPassword": { + "type": "string", + "description": "Senha para acesso ao sistema", + "nullable": true + }, + "authIssueValue": { + "type": "string", + "description": "Código de autenticação gerado pela prefeitura", + "nullable": true + }, + "rpsSerialNumbers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Todas as séries para esta Inscrição Municipal", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Dados da Inscrição Municipal" + }, + "DFeTech.TaxPayers.Resources.SerieResource": { + "type": "object", + "properties": { + "serie": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.SerieResourceItem" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.SerieResourceItem": { + "type": "object", + "properties": { + "rpsNumber": { + "type": "integer", + "description": "Próximo número de RPS", + "format": "int64" + }, + "lastRpsSent": { + "type": "integer", + "description": "Último RPS enviado", + "format": "int64" + } + }, + "additionalProperties": false, + "description": "Dados da Serie" + }, + "DFeTech.TaxPayers.Resources.StateTaxProcessingAuthorizerResource": { + "enum": [ + "Normal", + "EPEC" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Resources.StateTaxProcessingSwitchAuthorizerStrategyResource": { + "enum": [ + "Manual", + "StateTaxAuthorityStatusUnavailable" + ], + "type": "string" + }, + "DFeTech.TaxPayers.Resources.StateTaxResource": { + "type": "object", + "properties": { + "stateTax": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxResourceItem" + } + }, + "additionalProperties": false, + "description": "Inscrição Estadual" + }, + "DFeTech.TaxPayers.Resources.StateTaxResourceItem": { + "required": [ + "code", + "taxNumber", + "type" + ], + "type": "object", + "properties": { + "code": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateCode" + }, + "environmentType": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.EnvironmentType" + }, + "taxNumber": { + "minLength": 1, + "type": "string", + "description": "Inscrição Estadual" + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "serie": { + "type": "integer", + "description": "Serie para a emissão NFe", + "format": "int32", + "nullable": true + }, + "number": { + "type": "integer", + "description": "Número para a emissão NFe", + "format": "int64", + "nullable": true + }, + "securityCredential": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SecurityCredential" + }, + "type": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateTaxType" + }, + "processingDetails": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxProcessingDetailsResource" + }, + "id": { + "type": "string", + "description": "Identificador (gerado automaticamente)", + "nullable": true + }, + "companyId": { + "type": "string", + "description": "Código da Empresa", + "nullable": true + }, + "accountId": { + "type": "string", + "description": "Código da Conta", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.Status" + }, + "series": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "description": "Todas as séries para esta Inscrição Estadual", + "nullable": true + }, + "createdOn": { + "type": "string", + "description": "Data de criação", + "format": "date-time" + }, + "modifiedOn": { + "type": "string", + "description": "Data de modificação", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Dados da Inscrição Estadual" + }, + "DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerRequest": { + "type": "object", + "properties": { + "authorizer": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxProcessingAuthorizerResource" + }, + "reason": { + "type": "string", + "description": "Motivo da contingência", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.StateTaxSwitchAuthorizerResponse": { + "type": "object", + "properties": { + "fromAuthorizer": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateTaxProcessingAuthorizer" + }, + "toAuthorizer": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateTaxProcessingAuthorizer" + }, + "reason": { + "type": "string", + "description": "Motivo da contingência", + "nullable": true + }, + "modifiedOn": { + "type": "string", + "description": "Data e hora da modificação", + "format": "date-time" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.StateTaxesResource": { + "type": "object", + "properties": { + "stateTaxes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.StateTaxResourceItem" + }, + "description": "Lista de Inscrições Estaduais", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Inscrições Estaduais" + }, + "DFeTech.TaxPayers.Resources.UpdateCompanyResource": { + "type": "object", + "properties": { + "company": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateCompanyResourceItem" + } + }, + "additionalProperties": false, + "description": "Dados para Alterar Empresa" + }, + "DFeTech.TaxPayers.Resources.UpdateCompanyResourceItem": { + "required": [ + "address", + "federalTaxNumber", + "name", + "taxRegime" + ], + "type": "object", + "properties": { + "name": { + "minLength": 1, + "type": "string", + "description": "Razão Social" + }, + "accountId": { + "type": "string", + "description": "Identificador da conta", + "nullable": true + }, + "tradeName": { + "type": "string", + "description": "Nome Fantasia", + "nullable": true + }, + "federalTaxNumber": { + "type": "integer", + "description": "Número de Inscrição Federal (CNPJ)", + "format": "int64" + }, + "municipalTaxNumber": { + "type": "string", + "description": "Número da Inscrição Municipal", + "nullable": true + }, + "taxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.TaxRegime" + }, + "address": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.AddressResource" + }, + "id": { + "type": "string", + "description": "Identificador (gerado automaticamente)", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Alterar Empresa" + }, + "DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResource": { + "type": "object", + "properties": { + "municipalTax": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResourceItem" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.UpdateMunicipalTaxResourceItem": { + "type": "object", + "properties": { + "city": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.CityExtended" + }, + "taxNumber": { + "type": "string", + "description": "Inscrição Municipal", + "nullable": true + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "email": { + "type": "string", + "description": "Email", + "nullable": true + }, + "legalNature": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.LegalNature" + }, + "companyRegistryNumber": { + "type": "integer", + "description": "Registro da Empresa na Junta Comercial", + "format": "int64", + "nullable": true + }, + "regionalTaxNumber": { + "type": "integer", + "description": "Número Região", + "format": "int64", + "nullable": true + }, + "rpsNumber": { + "type": "integer", + "description": "Número do RPS", + "format": "int64" + }, + "lastRpsSent": { + "type": "integer", + "description": "Número do último RPS", + "format": "int64" + }, + "issRate": { + "type": "number", + "description": "ALíquota do ISS (%)", + "format": "double", + "nullable": true + }, + "federalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.FederalTaxDeterminationBy" + }, + "municipalTaxDetermination": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.MunicipalTaxDeterminationBy" + }, + "loginName": { + "type": "string", + "description": "Login para acesso ao sistema", + "nullable": true + }, + "loginPassword": { + "type": "string", + "description": "Senha para acesso ao sistema", + "nullable": true + }, + "authIssueValue": { + "type": "string", + "description": "Código de autenticação gerado pela prefeitura", + "nullable": true + }, + "environment": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.ApiEnvironment" + }, + "rpsSerialNumber": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.UpdateStateTaxResource": { + "type": "object", + "properties": { + "stateTax": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.UpdateStateTaxResourceItem" + } + }, + "additionalProperties": false + }, + "DFeTech.TaxPayers.Resources.UpdateStateTaxResourceItem": { + "required": [ + "code", + "taxNumber", + "type" + ], + "type": "object", + "properties": { + "code": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateCode" + }, + "environmentType": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.EnvironmentType" + }, + "taxNumber": { + "minLength": 1, + "type": "string", + "description": "Inscrição Estadual" + }, + "specialTaxRegime": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SpecialTaxRegime" + }, + "serie": { + "type": "integer", + "description": "Serie para a emissão NFe", + "format": "int32", + "nullable": true + }, + "number": { + "type": "integer", + "description": "Número para a emissão NFe", + "format": "int64", + "nullable": true + }, + "securityCredential": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.SecurityCredential" + }, + "type": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Domain.Entities.StateTaxType" + }, + "processingDetails": { + "$ref": "#/components/schemas/DFeTech.TaxPayers.Resources.CreateStateTaxProcessingDetailsResource" + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.EdmContainerElementKind": { + "enum": [ + "None", + "EntitySet", + "ActionImport", + "FunctionImport", + "Singleton" + ], + "type": "string" + }, + "Microsoft.OData.Edm.EdmExpressionKind": { + "enum": [ + "None", + "BinaryConstant", + "BooleanConstant", + "DateTimeOffsetConstant", + "DecimalConstant", + "FloatingConstant", + "GuidConstant", + "IntegerConstant", + "StringConstant", + "DurationConstant", + "Null", + "Record", + "Collection", + "Path", + "If", + "Cast", + "IsOf", + "FunctionApplication", + "LabeledExpressionReference", + "Labeled", + "PropertyPath", + "NavigationPropertyPath", + "DateConstant", + "TimeOfDayConstant", + "EnumMember", + "AnnotationPath" + ], + "type": "string" + }, + "Microsoft.OData.Edm.EdmSchemaElementKind": { + "enum": [ + "None", + "TypeDefinition", + "Term", + "Action", + "EntityContainer", + "Function" + ], + "type": "string" + }, + "Microsoft.OData.Edm.EdmTypeKind": { + "enum": [ + "None", + "Primitive", + "Entity", + "Complex", + "Collection", + "EntityReference", + "Enum", + "TypeDefinition", + "Untyped", + "Path" + ], + "type": "string" + }, + "Microsoft.OData.Edm.IEdmEntityContainer": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "schemaElementKind": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.EdmSchemaElementKind" + }, + "namespace": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "elements": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmEntityContainerElement" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.IEdmEntityContainerElement": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "containerElementKind": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.EdmContainerElementKind" + }, + "container": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmEntityContainer" + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.IEdmExpression": { + "type": "object", + "properties": { + "expressionKind": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.EdmExpressionKind" + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.IEdmModel": { + "type": "object", + "properties": { + "schemaElements": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmSchemaElement" + }, + "nullable": true, + "readOnly": true + }, + "vocabularyAnnotations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.Vocabularies.IEdmVocabularyAnnotation" + }, + "nullable": true, + "readOnly": true + }, + "referencedModels": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmModel" + }, + "nullable": true, + "readOnly": true + }, + "declaredNamespaces": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "readOnly": true + }, + "directValueAnnotationsManager": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.Vocabularies.IEdmDirectValueAnnotationsManager" + }, + "entityContainer": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmEntityContainer" + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.IEdmSchemaElement": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "schemaElementKind": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.EdmSchemaElementKind" + }, + "namespace": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.IEdmType": { + "type": "object", + "properties": { + "typeKind": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.EdmTypeKind" + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.IEdmTypeReference": { + "type": "object", + "properties": { + "isNullable": { + "type": "boolean", + "readOnly": true + }, + "definition": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmType" + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.Vocabularies.IEdmDirectValueAnnotationsManager": { + "type": "object", + "additionalProperties": false + }, + "Microsoft.OData.Edm.Vocabularies.IEdmTerm": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "schemaElementKind": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.EdmSchemaElementKind" + }, + "namespace": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "type": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmTypeReference" + }, + "appliesTo": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "defaultValue": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.Edm.Vocabularies.IEdmVocabularyAnnotatable": { + "type": "object", + "additionalProperties": false + }, + "Microsoft.OData.Edm.Vocabularies.IEdmVocabularyAnnotation": { + "type": "object", + "properties": { + "qualifier": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "term": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.Vocabularies.IEdmTerm" + }, + "target": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.Vocabularies.IEdmVocabularyAnnotatable" + }, + "value": { + "$ref": "#/components/schemas/Microsoft.OData.Edm.IEdmExpression" + }, + "usesDefault": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.ODataEntitySetInfo": { + "type": "object", + "properties": { + "typeAnnotation": { + "$ref": "#/components/schemas/Microsoft.OData.ODataTypeAnnotation" + }, + "url": { + "type": "string", + "format": "uri", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.ODataFunctionImportInfo": { + "type": "object", + "properties": { + "typeAnnotation": { + "$ref": "#/components/schemas/Microsoft.OData.ODataTypeAnnotation" + }, + "url": { + "type": "string", + "format": "uri", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.ODataServiceDocument": { + "type": "object", + "properties": { + "typeAnnotation": { + "$ref": "#/components/schemas/Microsoft.OData.ODataTypeAnnotation" + }, + "entitySets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.ODataEntitySetInfo" + }, + "nullable": true + }, + "singletons": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.ODataSingletonInfo" + }, + "nullable": true + }, + "functionImports": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Microsoft.OData.ODataFunctionImportInfo" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.ODataSingletonInfo": { + "type": "object", + "properties": { + "typeAnnotation": { + "$ref": "#/components/schemas/Microsoft.OData.ODataTypeAnnotation" + }, + "url": { + "type": "string", + "format": "uri", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Microsoft.OData.ODataTypeAnnotation": { + "type": "object", + "properties": { + "typeName": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + } + }, + "securitySchemes": { + "Authorization_Header": { + "type": "apiKey", + "description": "Autenticar usando o cabeçalho HTTP", + "name": "Authorization", + "in": "header" + }, + "Authorization_QueryParam": { + "type": "apiKey", + "description": "Autenticar usando o parâmetro na URL", + "name": "apikey", + "in": "query" + }, + "Authorization_JwtBearer": { + "type": "http", + "description": "Autenticar usando o cabeçalho HTTP", + "scheme": "bearer", + "bearerFormat": "Json Web Token" + } + } + }, + "security": [ + { + "Authorization_Header": [], + "Authorization_QueryParam": [] + }, + { + "Authorization_JwtBearer": [] + } + ], + "tags": [ + { + "name": "Companies", + "description": "Utilize esta requisição para criar novas empresas plataforma para processar Documentos Fiscais. **Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais." + }, + { + "name": "Companies Certificates", + "description": "Utilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo __e-CNPJ A1__ ou __NFE A1__ em uma **Empresa** e vincula-lo para processamentos.\r\n\r\nO **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web." + }, + { + "name": "Companies State Taxes", + "description": "Está sessão é destinada às **Incrições Estaduais(IE)**. Uma **Incrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ.\r\n\r\nUtilizando as informações abaixo você pode criar novas IEs na empresa para processar **Documentos Fiscais**. Além disso, também é possível listar as IEs por empresa e consultar, alterar e exluir uma IE pelo ID da mesma." + } + ] +} \ No newline at end of file diff --git a/openapi/cpf-api.yaml b/openapi/cpf-api.yaml new file mode 100644 index 0000000..d6457d8 --- /dev/null +++ b/openapi/cpf-api.yaml @@ -0,0 +1,155 @@ +swagger: "2.0" +host: naturalperson.api.nfe.io +schemes: + - https +info: + title: Consulta de Pessoa Física + version: v1 + description: "# Introdução\nSeja bem-vindo a documentação da API de consulta de CPF!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra topo desta página para que os métodos funcionem corretamente.\nNo seu código e integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n\n" +tags: + - name: Consulta na Receita Federal + description: "Consulta de Situação Cadastral por coleta direta na página pública da Receita Federal. Indicada para volume alto e menor custo por consulta." + - name: Consulta Irrestrita + description: "Consulta de Situação Cadastral via base de dados irrestrita. Indicada para consultas críticas que exigem maior cobertura de campos como nome social." +paths: + /v1/naturalperson/status/{federalTaxNumber}/{birthDate}: + get: + tags: + - Consulta na Receita Federal + summary: Consulta de Situação Cadastral do CPF na Receita Federal + description: "Consulta a situação cadastral de um CPF por coleta direta na página pública da Receita Federal. Você precisará do APIKEY da Empresa." + operationId: V1NaturalpersonStatusByFederalTaxNumberByBirthDateGet + consumes: [] + produces: + - application/json + parameters: + - name: federalTaxNumber + in: path + description: CPF + required: true + type: string + - name: birthDate + in: path + description: Data de Nascimento aaaa-mm-dd + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + createdOn: + format: date-time + type: string + name: + type: string + federalTaxNumber: + type: string + birthOn: + format: date-time + type: string + status: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: CPF não encontrado ou data de nascimento divergente + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + "503": + description: Temporariamente indisponível + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v1/naturalperson/serpro/status/{federalTaxNumber}/{birthDate}: + get: + tags: + - Consulta Irrestrita + summary: Consulta de Situação Cadastral do CPF Irrestrita + description: "Consulta a situação cadastral de um CPF em base de dados irrestrita. Latência consistente e cobertura mais ampla de campos como nome social. Você precisará do APIKEY da Empresa." + operationId: V1NaturalpersonSerproStatusByFederalTaxNumberByBirthDateGet + consumes: [] + produces: + - application/json + parameters: + - name: federalTaxNumber + in: path + description: CPF + required: true + type: string + - name: birthDate + in: path + description: Data de Nascimento aaaa-mm-dd + required: true + type: string + responses: + "200": + description: Sucesso na requisição + schema: + type: object + properties: + createdOn: + format: date-time + type: string + name: + type: string + socialName: + type: string + federalTaxNumber: + type: string + birthOn: + format: date-time + type: string + status: + type: string + "400": + description: Algum parametro informado não é válido + schema: + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: CPF não encontrado + schema: + type: string + "500": + description: Erro no processamento + schema: + type: string + "503": + description: Temporariamente indisponível + schema: + type: string + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey +securityDefinitions: + Authorization_Header: + name: Authorization + in: header + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + Authorization_QueryParam: + name: apikey + in: query + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' diff --git a/openapi/nf-consumidor-v2.yaml b/openapi/nf-consumidor-v2.yaml new file mode 100644 index 0000000..2f63c37 --- /dev/null +++ b/openapi/nf-consumidor-v2.yaml @@ -0,0 +1,8862 @@ +openapi: 3.0.1 +info: + title: Nota Fiscal de Consumidor + description: "# Introducão\nSeja bem-vindo a documentação da API de Nota Fiscal de Consumidor!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra topo desta página para que os métodos funcionem corretamente.\nNo seu código e integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n\n" + version: v2 +servers: + - url: https://api.nfse.io +tags: + - name: Companies + description: | + Utilize esta requisição para criar novas empresas plataforma para processar Documentos Fiscais. **Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais. + - name: Companies Certificates + description: | + Utilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo **e-CNPJ A1** ou **NFE A1** em uma **Empresa** e vincula-lo para processamentos. + + O **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web. + - name: Companies State Taxes + description: | + Está sessão é destinada às **Incrições Estaduais(IE).** Uma **Incrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ. + + Utilizando as informações abaixo você pode criar novas IEs na empresa para processar **Documentos Fiscais.** Além disso, também é possível listar as IEs por empresa e consultar, alterar e exluir uma IE pelo ID da mesma. + - name: Consumer Invoices + description: "Nesta sessão estão disponíveis informações necessárias para emitir uma Nota Fiscal De Consumidor Eletrônica usando a nossa API. \n\nVocê também encontrará informações sobre consulta de uma nota fiscal por ID, consulta de uma lista de notas por empresa, consulta do PDF do Documento Auxiliar da Nota Fiscal Eletrônica(DANFE-NFCE) e consulta do XML da nota fiscal de consumidor eletrônica.\n" + - name: WebHooks + description: | + Eventos ocorrem a todo instante na plataforma durante os processamentos e são registrados criando notificações para os webhooks ativos e configurados para receber os eventos. + + Um **Webhook** é semelhante a uma assinatura em um sistema de publicação e assinatura que permite ao assinante indicar quando, como e onde as notificações de eventos devem ser despachadas. Um **Webhook** é registrado e gerenciado por Conta o que significa que cada Conta tem um conjunto separado de ganchos que podem ser acionados por eventos gerados através de ações executadas por esse Conta. Ou seja, a **Conta da Empresa A** não verá os WebHooks disparados por uma ação executada pelo usuário **Conta da Empresa B**. + + São identificados seguindo o padrão **Resource.EventAction**, sendo **Resource** o nome da entidade que gerou o evento e **EventAction** o nome do evento e ação criados. + + Esses tipos podem ser utilizados como filtro ao criar ou alterar um webhook, sendo que o filtro determina quais notificações de eventos e ação serão enviadas para um determinado webhook, ou seja, dependendo de quais filtros são vinculados ao webhook ele só receberá as notificações de evento e ação que correspondem a um ou mais desses filtros +paths: + /v2/companies: + get: + tags: + - Companies + summary: Consultar todas as Empresas da Conta + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados das empresas vinculadas a conta." + operationId: V2CompaniesGet + parameters: + - name: startingAfter + in: query + description: 'Id de início do contador (Default: Empty)' + schema: + type: string + - name: endingBefore + in: query + description: 'Id final do contador (Default: Empty)' + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + responses: + "200": + description: Sucesso na consulta da Empresa + content: + application/json: + schema: + type: object + properties: + companies: + type: array + description: Lista de Empresa + items: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresas + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - Companies + summary: Criar uma Empresa + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novas empresas plataforma para processar Documentos Fiscais.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais." + operationId: V2CompaniesPost + requestBody: + description: Dados da Empresa a ser criada + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Criar Empresa + text/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Criar Empresa + application/*+json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Criar Empresa + required: false + responses: + "200": + description: Sucesso na criação da Empresa + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresa + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + /v2/companies/{company_id}: + get: + tags: + - Companies + summary: Consultar uma Empresa pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID." + operationId: V2CompaniesByCompany_idGet + parameters: + - name: company_id + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta da Empresa + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresa + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + put: + tags: + - Companies + summary: Alterar uma Empresa pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados de uma empresas pelo ID." + operationId: V2CompaniesByCompany_idPut + parameters: + - name: company_id + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + requestBody: + description: Dados da Empresa a ser alterada + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Alterar Empresa + text/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Alterar Empresa + application/*+json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Alterar Empresa + required: false + responses: + "200": + description: Sucesso na alteração da Empresa + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresa + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + delete: + tags: + - Companies + summary: Excluir uma Empresa por ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir uma empresas pelo ID, cuidado pois esse processo é irreversível." + operationId: V2CompaniesByCompany_idDelete + parameters: + - name: company_id + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Empresa + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{company_id}/certificates: + get: + tags: + - Companies Certificates + summary: Consultar um Certificado por seu Status + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de um **Certificado da ICP-Brasil** através d0 **status do certificado** (__status__)." + operationId: V2CompaniesByCompany_idCertificatesGet + parameters: + - name: company_id + in: path + description: ID da Empresa relacionada ao certificado + required: true + schema: + type: string + - name: status + in: query + description: Status do certificado + schema: + type: string + enum: + - inactive + - overdue + - pending + - active + - none + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + type: object + properties: + certificates: + type: array + items: + type: object + properties: + subject: + type: string + description: Nome do certificado (subject distinguished name) + validUntil: + type: string + description: Data no horário local após o qual um certificado não é mais válido + format: date-time + thumbprint: + type: string + description: A impressão digital do certificado + federalTaxNumber: + type: string + description: CNPJ da Empresa + modifiedOn: + type: string + description: Data de modificação + format: date-time + status: + type: string + description: Status do certificado + enum: + - inactive + - overdue + - pending + - active + - none + description: Certificado + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - Companies Certificates + summary: Upload de um Certificado + description: "### Informações adicionais\r\n\r\nUtilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo __e-CNPJ A1__ ou __NFE A1__ em uma **Empresa** e vincula-lo para processamentos.\r\n\r\nO **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web." + operationId: V2CompaniesByCompany_idCertificatesPost + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + requestBody: + content: + multipart/form-data: + schema: + required: + - file + - password + type: object + properties: + file: + type: string + description: Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12 + format: binary + password: + type: string + description: Senha do certificado ICP-Brasil + application/form-data: + schema: + required: + - file + - password + type: object + properties: + file: + type: string + description: Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12 + format: binary + password: + type: string + description: Senha do certificado ICP-Brasil + required: true + responses: + "200": + description: Sucesso no upload e vinculo com a Empresa + content: + application/json: + schema: + type: object + properties: + certificate: + type: object + properties: + subject: + type: string + description: Nome do certificado (subject distinguished name) + validUntil: + type: string + description: Data no horário local após o qual um certificado não é mais válido + format: date-time + thumbprint: + type: string + description: A impressão digital do certificado + federalTaxNumber: + type: string + description: CNPJ da Empresa + modifiedOn: + type: string + description: Data de modificação + format: date-time + status: + type: string + description: Status do certificado + enum: + - inactive + - overdue + - pending + - active + - none + description: Certificado + description: Certificado + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{company_id}/certificates/{certificate_thumbprint}: + get: + tags: + - Companies Certificates + summary: Consultar um Certificado por sua impressão digital + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de um **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__)." + operationId: V2CompaniesByCompany_idCertificatesByCertificate_thumbprintGet + parameters: + - name: company_id + in: path + description: ID da Empresa relacionada ao certificado + required: true + schema: + type: string + - name: certificate_thumbprint + in: path + description: Impressão digital do certificado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + type: object + properties: + certificate: + type: object + properties: + subject: + type: string + description: Nome do certificado (subject distinguished name) + validUntil: + type: string + description: Data no horário local após o qual um certificado não é mais válido + format: date-time + thumbprint: + type: string + description: A impressão digital do certificado + federalTaxNumber: + type: string + description: CNPJ da Empresa + modifiedOn: + type: string + description: Data de modificação + format: date-time + status: + type: string + description: Status do certificado + enum: + - inactive + - overdue + - pending + - active + - none + description: Certificado + description: Certificado + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Certificado não encontrado + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + delete: + tags: + - Companies Certificates + summary: Excluir um Certificado por sua impressão digital + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir o **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__) e desvincula-lo da **Empresa**.\r\n\r\n**ATENÇÃO pois esta requisição é irreversível**" + operationId: V2CompaniesByCompany_idCertificatesByCertificate_thumbprintDelete + parameters: + - name: company_id + in: path + description: ID da Empresa relacionada ao certificado + required: true + schema: + type: string + - name: certificate_thumbprint + in: path + description: Impressão digital do certificado + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão e desvinculo com a Empresa + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Certificado não encontrado + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{company_id}/statetaxes: + get: + tags: + - Companies State Taxes + summary: Listar as Inscrições Estaduais + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para listar as inscrições estaduais na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesGet + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: startingAfter + in: query + description: 'Id de início do contador (Default: Empty)' + schema: + type: string + - name: endingBefore + in: query + description: 'Id final do contador (Default: Empty)' + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + responses: + "200": + description: Sucesso na criação da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTaxes: + type: array + description: Lista de Inscriçoes Estaduais + items: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - Companies State Taxes + summary: Criar uma Inscrição Estadual + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novas inscrição estadual na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesPost + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + requestBody: + description: Dados da Inscrição Estadual a ser criada + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Criar uma Inscrição Estadual + text/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Criar uma Inscrição Estadual + application/*+json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Criar uma Inscrição Estadual + required: false + responses: + "200": + description: Sucesso na criação da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + /v2/companies/{company_id}/statetaxes/{state_tax_id}: + get: + tags: + - Companies State Taxes + summary: Consultar uma Inscrição Estadual pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesByState_tax_idGet + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: state_tax_id + in: path + description: ID da Inscrição Estadual que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Inscrição Estadual não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + put: + tags: + - Companies State Taxes + summary: Alterar uma Inscrição Estadual pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados de uma Inscrição Estadual pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesByState_tax_idPut + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: state_tax_id + in: path + description: ID da Inscrição Estadual que deverá ser retornado + required: true + schema: + type: string + requestBody: + description: Dados da Inscrição Estadual a ser alterada + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Alterar uma Inscrição Estadual + text/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Alterar uma Inscrição Estadual + application/*+json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Alterar uma Inscrição Estadual + required: false + responses: + "200": + description: Sucesso na alteração da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Inscrição Estadual não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + delete: + tags: + - Companies State Taxes + summary: Excluir uma Inscrição Estadual pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir uma Inscrição Estadual pelo ID, cuidado pois esse processo é irreversível.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesByState_tax_idDelete + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: state_tax_id + in: path + description: ID da Inscrição Estadual que deverá ser retornado + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Inscrição Estadual + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Inscrição Estadual não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{companyId}/consumerinvoices: + get: + tags: + - Consumer Invoices + summary: Listar as Notas Fiscais Eletrônicas (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar uma lista de notas fiscais de consumidor eletrônica por empresa." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: environment + in: query + description: Ambiente das notas (Production/Test) + schema: + $ref: '#/components/schemas/EnvironmentType' + - name: startingAfter + in: query + description: 'Id da nota fiscal de início do contador (Default: Empty)' + schema: + type: string + - name: endingBefore + in: query + description: 'Id da nota fiscal final do contador (Default: Empty)' + schema: + type: string + - name: q + in: query + description: 'Buscar por parâmetros. ("Elasticsearch string query") Ex: (q=buyer.name:''EMPRESA LTDA'')' + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + default: 10 + responses: + "200": + description: Sucesso na consulta em lista + content: + application/json: + schema: + $ref: '#/components/schemas/ConsumerInvoicesResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + post: + tags: + - Consumer Invoices + summary: Emitir uma Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal de Consumidor Eletrônica (NFCE) para fila de emissão.\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante a emissão do documento fiscal.\r\nPara obter um retorno ao final do processo de emissão de uma Nota Fiscal Eletrônica (NFe), recomendamos\r\nutilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + requestBody: + description: Dados da nota fiscal de Consumidor a ser emitida + content: + application/json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + text/json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + application/*+json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + responses: + "200": + description: Sucesso ao enfileirar para emissão + content: + application/json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/statetaxes/{statetaxId}/consumerinvoices: + post: + tags: + - Consumer Invoices + summary: Emitir uma Nota Fiscal de Consumidor Eletrônica (NFCE) informando um StateTaxId + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal de Consumidor Eletrônica (NFCE) para fila de emissão, informando explicitamente qual Inscrição Estadual (StateTax) deve ser utilizada.\r\nUtilize este endpoint quando a empresa possui mais de uma Inscrição Estadual (StateTax) ativa, evitando a seleção automática da primeira IE cadastrada (paridade com a emissão de NF-e).\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo não garante a emissão do documento fiscal.\r\nPara obter um retorno ao final do processo de emissão de uma Nota Fiscal de Consumidor Eletrônica (NFCE), recomendamos utilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + - name: statetaxId + in: path + description: Inscrição Estadual (StateTax) ID + required: true + schema: + type: string + requestBody: + description: Dados da nota fiscal de Consumidor a ser emitida + content: + application/json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + text/json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + application/*+json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + responses: + "200": + description: Sucesso ao enfileirar para emissão + content: + application/json: + schema: + $ref: '#/components/schemas/ConsumerInvoiceRequest' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Inscrição Estadual (StateTax) informada não pertence à empresa ou empresa sem Inscrição Estadual configurada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/consumerinvoices/{invoiceId}: + get: + tags: + - Consumer Invoices + summary: Consultar por ID uma Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Nota Fiscal de Consumidor Eletrônica (NFCE) pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor Eletrônica que deverá ser retornada + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + $ref: '#/components/schemas/InvoiceResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + delete: + tags: + - Consumer Invoices + summary: Cancelar uma Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal de Consumidor Eletrônica (NFCE) para fila de cancelamento.\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante o cancelamento do documento fiscal.\r\nPara obter um retorno ao final do processo de cancelamento de uma Nota Fiscal Eletrônica (NFe),\r\nrecomendamos utilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor que deverá ser cancelada + required: true + schema: + type: string + - name: reason + in: query + description: Motivo do cancelamento + schema: + type: string + responses: + "204": + description: Sucesso ao enfileirar para cancelamento + content: + application/json: + schema: + $ref: '#/components/schemas/RequestCancellationResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/consumerinvoices/{invoiceId}/items: + get: + tags: + - Consumer Invoices + summary: Consultar os produtos por ID uma Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Nota Fiscal de Consumidor Eletrônica (NFCE) pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor Eletrônica que deverá ser retornada + required: true + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + default: 10 + - name: startingAfter + in: query + description: 'Índice de início do contador (Default: 0)' + schema: + type: integer + format: int32 + default: 0 + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + $ref: '#/components/schemas/InvoiceItemsResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + /v2/companies/{companyId}/consumerinvoices/{invoiceId}/events: + get: + tags: + - Consumer Invoices + summary: Consultar eventos por ID uma Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Nota Fiscal de Consumidor Eletrônica (NFCE) pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor Eletrônica que deverá ser retornada + required: true + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + default: 10 + - name: startingAfter + in: query + description: 'Índice de início do contador (Default: 0)' + schema: + type: integer + format: int32 + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + $ref: '#/components/schemas/InvoiceEventsResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + /v2/companies/{companyId}/consumerinvoices/{invoiceId}/pdf: + get: + tags: + - Consumer Invoices + summary: Consultar PDF do Documento Auxiliar da Nota Fiscal de Consumidor Eletrônica (DANFE-NFC-e) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar a URL para o Documento Auxiliar Nota Fiscal de Consumidor Eletrônica (DANFE-NFC-e)\r\nem formato de arquivo PDF." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor que deverá ser retornado + required: true + schema: + type: string + - name: force + in: query + schema: + type: boolean + default: false + responses: + "200": + description: Sucesso na consulta do DANFE-NFC-e + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/consumerinvoices/{invoiceId}/xml: + get: + tags: + - Consumer Invoices + summary: Consultar XML da Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma nota fiscal de Consumidor Eletrônica pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFCE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/consumerinvoices/{invoiceId}/xml/rejection: + get: + tags: + - Consumer Invoices + summary: Consultar XML de rejeição da Nota Fiscal de Consumidor Eletrônica (NFCE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar o motivo da rejeição de uma nota fiscal de Consumidor Eletrônica pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal de Consumidor que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFCE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal de Consumidor Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/consumerinvoices/disablement: + post: + tags: + - Consumer Invoices + summary: Inutilizar números de nota fiscal + description: "### Informações adicionais\r\nCaso seja um único número, utilizar o Número inicial e o Número final com o mesmo valor" + parameters: + - name: companyId + in: path + description: ID da Empresa + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DisablementResource' + text/json: + schema: + $ref: '#/components/schemas/DisablementResource' + application/*+json: + schema: + $ref: '#/components/schemas/DisablementResource' + responses: + "200": + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/DisablementResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/webhooks/eventTypes: + get: + tags: + - WebHooks + summary: Listar os Tipos de Eventos gerados pela plataforma + description: "### Informações adicionais\r\n\r\nEventos ocorrem a todo instante na plataforma durante os processamentos e são registrados\r\ncriando notificações para os webhooks ativos e configurados para receber os eventos.\r\n \r\nSão identificados seguindo o padrão **Resource.EventAction**,\r\nonde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\n\r\nEsse tipos podem ser utilizados como filtro ao criar ou alterar um webhook,\r\nsendo que o filtro determina quais notificações de eventos e ação serão enviadas\r\npara um determinado webhook, ou seja, dependendo de quais filtros são vinculados ao webhook\r\nele só receberá as notificações de evento e ação que correspondem a um ou mais desses filtros." + operationId: V2WebhooksEventTypesGet + responses: + "200": + description: Sucesso na consulta do tipos de eventos + content: + application/json: + schema: + type: object + properties: + eventTypes: + type: array + description: Lista de Evento + items: + type: object + properties: + id: + type: string + description: "Identificador do evento, seguem o padrão **Resource.EventAction**.\r\nOnde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\nAlguns exemplos **Invoice.Issued** ou **Blob.Updated**" + description: + type: string + description: Descrição para o recurso, evento e ação exemplicando quando e onde eles ocorrem dentro na plataforma. + description: Tipo de Evento + description: Tipos de Eventos + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v2/webhooks: + get: + tags: + - WebHooks + summary: Listar os Webhooks + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar uma lista de **Webhooks** cadastrados na Conta Autenticada." + operationId: V2WebhooksGet + responses: + "200": + description: Sucesso na consulta da lista + content: + application/json: + schema: + type: object + properties: + webHooks: + type: array + description: Lista de Web Hook + items: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Web Hooks + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - WebHooks + summary: Criar um Webhook + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novos **Webhooks** para receber as notificações de eventos ocorridos na plataforma.\r\n \r\nNa criação do **Webhook** a URL informada no cadastro deve ser responsiva, ou seja, deverá responder *(HTTP Status 200 OK)* a uma requisição *(HTTP POST)* que será feita para testar se a URL está operando como normalmente, caso contrario uma mensagem de erro será retornada.\r\n \r\nUm **Webhook** é semelhante a uma assinatura em um *sistema de publicação e assinatura*\r\nque permite ao assinante indicar *quando*, *como* e *onde* as notificações de eventos deve ser despachadas.\r\nUm **Webhook** é registrado e gerenciado por Conta o que significa que cada Conta tem um conjunto separado de ganchos\r\nque podem ser acionados por eventos gerados através de ações executadas por esse Conta.\r\nOu seja, a __Conta da *Empresa A*__ não verá os WebHooks disparados por uma ação executada pelo usuário __Conta da *Empresa B*__." + operationId: V2WebhooksPost + requestBody: + content: + application/json-patch+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + text/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + application/*+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + required: false + responses: + "201": + description: Sucesso na criação da webhook + content: + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Web Hook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + delete: + tags: + - WebHooks + summary: Excluir Todos os Webhooks existentes + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir todos os **Webhooks** cadastrados para a Conta Autenticada." + operationId: V2WebhooksDelete + responses: + "204": + description: Sucesso na exclusão dos WebHooks + content: {} + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/webhooks/{webhook_id}: + get: + tags: + - WebHooks + summary: Consultar um webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar um **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id**." + operationId: V2WebhooksByWebhook_idGet + parameters: + - name: webhook_id + in: path + description: ID do webhook a ser consultado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do webhook + content: + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Web Hook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + put: + tags: + - WebHooks + summary: Alterar um Webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados do **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id** especificado." + operationId: V2WebhooksByWebhook_idPut + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser atualizado + required: true + schema: + type: string + requestBody: + description: Dados para alterar o Webhook + content: + application/json-patch+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Dados para alterar um Web Hook + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Dados para alterar um Web Hook + text/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Dados para alterar um Web Hook + application/*+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Dados para alterar um Web Hook + required: false + responses: + "200": + description: Sucesso na atualização da Webhook + content: + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: string + description: "Tipo de mídia usado para serializar as notificações dos eventos que serão entregues.\r\nOs valores suportados são **json** e **form-urlencoded**, o padrão é **json**." + enum: + - json + - form-urlencoded + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: string + description: "Determina se as notificações são enviadas quando o webhook é acionado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + default: "1" + enum: + - active + - inactive + filters: + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + properties: {} + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados do Web Hook + description: Web Hook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + delete: + tags: + - WebHooks + summary: Excluir um Webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir o **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id** especificado.\r\nA exclusão do **Webhook** não exime o **Webhook** excluído de receber os notificações de eventos, já ocorridos na plataforma, que ainda estejam em processo de retentativa de envio dos gatilhos." + operationId: V2WebhooksByWebhook_idDelete + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser excluído + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Webhook + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/webhooks/{webhook_id}/pings: + put: + tags: + - WebHooks + summary: Criar notificação para Testar um webhook + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar uma notificação de teste (ping) em um **Webhook** já cadastrado.\r\n\r\nEsta ação irá criar um evento de notificação do tipo ping para o **Webhook** especificado, deste modo você poderá simular o recebimento de uma notificação de teste no **Webhook** cadastrado." + operationId: V2WebhooksByWebhook_idPingsPut + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser testado + required: true + schema: + type: string + responses: + "204": + description: Sucesso ao criar notificação de teste + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey +components: + schemas: + ActivityResource: + type: object + properties: + data: + description: Detalhes do Evento + nullable: true + type: + type: string + description: Nome do Evento gerado + nullable: true + sequence: + type: integer + description: Número sequencial do Evento + format: int32 + nullable: true + additionalProperties: false + AdditionResource: + type: object + properties: + code: + type: integer + description: Numero da adição (nAdicao) + format: int64 + nullable: true + manufacturer: + type: string + description: Código do fabricante estrangeiro (cFabricante) + nullable: true + amount: + type: number + description: Valor do desconto do item da DI – Adição (vDescDI) + format: double + nullable: true + drawback: + type: integer + description: Número do ato concessório de Drawback (nDraw) + format: int64 + nullable: true + additionalProperties: false + description: Adições (adi) + AdditionalInformationResource: + type: object + properties: + fisco: + type: string + description: Informações Adicionais de Interesse do Fisco (infAdFisco) + nullable: true + taxpayer: + type: string + description: Informações Complementares de interesse do Contribuinte (infCpl) + nullable: true + xmlAuthorized: + type: array + items: + type: integer + format: int64 + description: Informações Complementares de interesse do Contribuinte (infCpl) + nullable: true + effort: + type: string + nullable: true + order: + type: string + nullable: true + contract: + type: string + nullable: true + taxDocumentsReference: + type: array + items: + $ref: '#/components/schemas/TaxDocumentsReferenceResource' + description: Documentos Fiscais Referenciados (refECF) + nullable: true + advancePayment: + type: array + items: + $ref: '#/components/schemas/AdvancePaymentItemResource' + description: "Grupo de notas de antecipação de pagamento - Informado para abater as parcelas de antecipação de pagamento, conforme Art. 10. § 4º (gPagAntecipado)." + nullable: true + taxpayerComments: + type: array + items: + $ref: '#/components/schemas/TaxpayerCommentsResource' + description: Observações fiscais (obsCont) + nullable: true + referencedProcess: + type: array + items: + $ref: '#/components/schemas/ReferencedProcessResource' + description: Processos referenciados (procRef) + nullable: true + additionalProperties: false + AddressResource: + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + nullable: true + city: + $ref: '#/components/schemas/CityResource' + district: + type: string + description: Bairro do Endereço + nullable: true + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + nullable: true + street: + type: string + description: Logradouro do Endereço + nullable: true + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + nullable: true + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + nullable: true + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + nullable: true + phone: + type: string + description: Telefone + nullable: true + additionalProperties: false + description: Dados do Endereço + AuthorizationResource: + type: object + properties: + receiptOn: + type: string + format: date-time + nullable: true + accessKey: + type: string + nullable: true + message: + type: string + nullable: true + additionalProperties: false + BillResource: + type: object + properties: + number: + type: string + description: Número da Fatura (nFat) + nullable: true + originalAmount: + type: number + description: Valor Original da Fatura (vOrig) + format: double + nullable: true + discountAmount: + type: number + description: Valor do desconto (vDesc) + format: double + nullable: true + netAmount: + type: number + description: Valor Líquido da Fatura (vLiq) + format: double + nullable: true + additionalProperties: false + BillingResource: + type: object + properties: + bill: + $ref: '#/components/schemas/BillResource' + duplicates: + type: array + items: + $ref: '#/components/schemas/DuplicateResource' + description: Grupo Duplicata (dup) + nullable: true + additionalProperties: false + BuyerResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumberIndicator: + $ref: '#/components/schemas/ReceiverStateTaxIndicator' + tradeName: + type: string + description: Nome fantasia + nullable: true + taxRegime: + $ref: '#/components/schemas/TaxRegime' + stateTaxNumber: + type: string + description: Inscrição Estadual (IE) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo de endereço do Destinatário da NF-e" + CIDEResource: + type: object + properties: + bc: + type: number + description: BC da CIDE (qBCProd) + format: double + nullable: true + rate: + type: number + description: Valor da alíquota da CIDE (vAliqProd) + format: double + nullable: true + cideAmount: + type: number + description: Valor da CIDE (vCIDE) + format: double + nullable: true + additionalProperties: false + CardResource: + type: object + properties: + federalTaxNumber: + type: string + description: CNPJ da Credenciadora de cartão de crédito e/ou débito (CNPJ) + nullable: true + flag: + $ref: '#/components/schemas/FlagCard' + authorization: + type: string + description: Número de autorização da operação cartão de crédito e/ou débito (cAut) + nullable: true + integrationPaymentType: + $ref: '#/components/schemas/IntegrationPaymentType' + federalTaxNumberRecipient: + type: string + description: CNPJ do beneficiário do pagamento (CNPJReceb) + nullable: true + idPaymentTerminal: + type: string + description: Identificador do terminal de pagamento (idTermPag) + nullable: true + additionalProperties: false + CityResource: + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + nullable: true + name: + type: string + description: Nome do Município + nullable: true + additionalProperties: false + CofinsTaxResource: + type: object + properties: + cst: + type: string + description: Código de Situação Tributária da COFINS + nullable: true + baseTax: + type: number + description: Valor da Base de Cálculo da COFINS (vBC) + format: double + nullable: true + rate: + type: number + description: Alíquota da COFINS (em percentual) (pCOFINS) + format: double + nullable: true + amount: + type: number + description: Valor da COFINS (vCOFINS) + format: double + nullable: true + baseTaxProductQuantity: + type: number + description: Quantidade Vendida (qBCProd) + format: double + nullable: true + productRate: + type: number + description: Alíquota da COFINS (em reais) (vAliqProd) + format: double + nullable: true + additionalProperties: false + description: "Grupo do COFINS\r\n\r\nID: S01\r\nPai: M01\r\n\r\n Obs: Informar apenas um dos grupos S02, S03, S04 ou S04\r\n com base valor atribuído ao campo S06 – CST do COFINS\r\n" + ConsumerInvoiceRequest: + required: + - items + type: object + properties: + id: + type: string + description: Identificador único + nullable: true + payment: + type: array + items: + $ref: '#/components/schemas/PaymentResource' + description: Grupo de Formas de Pagamento (pag) + nullable: true + serie: + type: integer + description: Série do Documento Fiscal (serie) + format: int32 + nullable: true + number: + type: integer + description: Número do Documento Fiscal (nNF) + format: int64 + nullable: true + operationOn: + type: string + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55). Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: date-time + nullable: true + operationNature: + type: string + description: Descrição da Natureza da Operação (natOp) + nullable: true + operationType: + $ref: '#/components/schemas/OperationType' + destination: + $ref: '#/components/schemas/Destination' + printType: + $ref: '#/components/schemas/PrintType' + purposeType: + $ref: '#/components/schemas/PurposeType' + consumerType: + $ref: '#/components/schemas/ConsumerType' + presenceType: + $ref: '#/components/schemas/ConsumerPresenceType' + contingencyOn: + type: string + description: "Data e Hora da entrada em contingência (dhCont)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + format: date-time + nullable: true + contingencyJustification: + type: string + description: Justificativa da entrada em contingência (xJust) + nullable: true + consumptionCityCode: + $ref: '#/components/schemas/ConsumptionCityCode' + ibsConsumptionCityCode: + $ref: '#/components/schemas/IbsConsumptionCityCode' + debitType: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/DebitType' + creditType: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/CreditType' + governmentPurchase: + $ref: '#/components/schemas/GovernmentPurchaseResource' + buyer: + $ref: '#/components/schemas/BuyerResource' + transport: + description: "⚠️ Uso vedado na NFC-e (modelo 65): frete, transportador, veículo, reboque, vagão, balsa e volumes são rejeitados (rejeições 753–759 do MOC). Grupo aplicável à NF-e (modelo 55)." + $ref: '#/components/schemas/TransportInformationResource' + additionalInformation: + $ref: '#/components/schemas/AdditionalInformationResource' + items: + type: array + items: + $ref: '#/components/schemas/InvoiceItemResource' + description: Detalhamento de Produtos e Serviços (det) + totals: + $ref: '#/components/schemas/TotalResource' + billing: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/BillingResource' + issuer: + $ref: '#/components/schemas/IssuerFromRequestResource' + transactionIntermediate: + $ref: '#/components/schemas/IntermediateResource' + additionalProperties: false + description: Nota Fiscal de Consumidor Eletrônica (NFCe) + ConsumerInvoicesResource: + type: object + properties: + consumerInvoices: + type: array + items: + $ref: '#/components/schemas/InvoiceWithoutEventsResource' + description: Lista de Notas Fiscais de Consumidor Eletrônicas (NFC-e) + nullable: true + hasMore: + type: boolean + description: Identificador de possibilidade de mais itens. + additionalProperties: false + description: Notas Fiscais de Consumidor Eletrônicas (NFC-e) + ConsumerPresenceType: + enum: + - None + - Presence + - Internet + - Telephone + - Delivery + - OthersNonPresenceOperation + type: string + description: Indicador de Presença (indPres ) + ConsumerType: + enum: + - FinalConsumer + - Normal + type: string + description: Indica operação com Consumidor final (indFinal) + ContingencyDetails: + type: object + properties: + authorizer: + $ref: '#/components/schemas/StateTaxProcessingAuthorizer' + startedOn: + type: string + description: Data e hora do início da contingência + format: date-time + reason: + type: string + description: Justificativa da entrada em contingência + nullable: true + additionalProperties: false + DeliveryInformationResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumber: + type: string + description: Inscrição Estadual (IE) + nullable: true + additionalProperties: false + description: Identificação do Local de entrega (entrega) + Destination: + enum: + - None + - Internal_Operation + - Interstate_Operation + - International_Operation + type: string + description: Identificador de local de destino da operação (idDest) + DisablementResource: + type: object + properties: + environment: + $ref: '#/components/schemas/EnvironmentType' + serie: + type: integer + description: Série + format: int32 + state: + $ref: '#/components/schemas/StateCode' + beginNumber: + type: integer + description: Número inicial + format: int32 + lastNumber: + type: integer + description: Número final (usar o mesmo número inicial se for apenas um número) + format: int32 + reason: + type: string + description: Motivo da inutilização + nullable: true + additionalProperties: false + description: Dados para inutilizar números de nota fiscal + DocumentElectronicInvoiceResource: + type: object + properties: + accessKey: + type: string + description: Chave de Acesso (refNFe) + nullable: true + additionalProperties: false + DocumentInvoiceReferenceResource: + type: object + properties: + state: + type: number + description: Código da UF (cUF) + format: double + nullable: true + yearMonth: + type: string + description: Ano / Mês (AAMM) + nullable: true + federalTaxNumber: + type: string + description: CNPJ (CNPJ) + nullable: true + model: + type: string + description: Modelo (mod) + nullable: true + series: + type: string + description: Série (serie) + nullable: true + number: + type: string + description: Número (nNF) + nullable: true + additionalProperties: false + DuductionIndicator: + enum: + - NotDeduct + - Deduce + type: string + description: Indicador de intermediador/marketplace (indIntermed) + DuplicateResource: + type: object + properties: + number: + type: string + description: Número da Duplicata (nDup) + nullable: true + expirationOn: + type: string + description: Data de vencimento (dVenc) + format: date-time + nullable: true + amount: + type: number + description: Valor da duplicata (vDup) + format: double + nullable: true + additionalProperties: false + EconomicActivityResource: + type: object + properties: + type: + $ref: '#/components/schemas/EconomicActivityType' + code: + type: integer + description: Código da Atividade da Empresa + format: int32 + nullable: true + additionalProperties: false + EconomicActivityType: + enum: + - Main + - Secondary + type: string + EnvironmentType: + enum: + - None + - Production + - Test + type: string + ErrorResource: + type: object + properties: + code: + type: integer + format: int32 + nullable: true + message: + type: string + nullable: true + additionalProperties: false + ErrorsResource: + type: object + properties: + errors: + type: array + items: + $ref: '#/components/schemas/ErrorResource' + nullable: true + readOnly: true + additionalProperties: false + ExemptReason: + enum: + - Agriculture + - Others + - DevelopmentEntities + type: string + description: "Campo será preenchido quando o campo anterior estiver\r\npreenchido.Informar o motivo da desoneração:" + ExportDetailResource: + type: object + properties: + drawback: + type: string + description: Número do ato concessório de Drawback (nDraw) + nullable: true + hintInformation: + $ref: '#/components/schemas/ExportHintResource' + additionalProperties: false + ExportHintResource: + type: object + properties: + registryId: + type: string + description: Número do Registro de Exportação (nRE) + nullable: true + accessKey: + type: string + description: Chave de Acesso da NF-e recebida para exportação (chNFe) + nullable: true + quantity: + type: number + description: Quantidade do item realmente exportado (qExport) + format: double + nullable: true + additionalProperties: false + ExportResource: + type: object + properties: + state: + $ref: '#/components/schemas/StateCode' + office: + type: string + description: Descrição do Local de Embarque ou de transposição de fronteira (xLocExporta) + nullable: true + local: + type: string + description: Informações Complementares de interesse do Contribuinte (xLocDespacho) + nullable: true + additionalProperties: false + FileResource: + type: object + properties: + uri: + type: string + description: Endereço Absoluto URI para o arquivo + nullable: true + additionalProperties: false + description: Arquivo + FlagCard: + enum: + - None + - Visa + - Mastercard + - AmericanExpress + - Sorocred + - DinersClub + - Elo + - Hipercard + - Aura + - Cabal + - Alelo + - BanesCard + - CalCard + - Credz + - Discover + - GoodCard + - GreenCard + - Hiper + - JCB + - Mais + - MaxVan + - Policard + - RedeCompras + - Sodexo + - ValeCard + - Verocheque + - VR + - Ticket + - Other + type: string + FuelOriginResource: + type: object + properties: + indImport: + type: integer + description: Indicador de importação (indImport) + format: int32 + nullable: true + cUFOrig: + type: integer + description: Código da UF (cUFOrig) + format: int32 + nullable: true + pOrig: + type: number + description: Percentual originário para a UF (pOrig) + format: double + nullable: true + additionalProperties: false + FuelResource: + type: object + properties: + codeANP: + type: string + description: Código de produto da ANP (cProdANP) + nullable: true + percentageNG: + type: number + description: Percentual de Gás Natural para o produto GLP (cProdANP=210203001) (pMixGN) + format: double + nullable: true + descriptionANP: + type: string + description: Descrição do produto conforme ANP (descANP) + nullable: true + percentageGLP: + type: number + description: Percentual do GLP derivado do petróleo no produto GLP (cProdANP=210203001) (pGLP) + format: double + nullable: true + percentageNGn: + type: number + description: Percentual de Gás Natural Nacional – GLGNn para o produto GLP (cProdANP= 210203001) (pGNn) + format: double + nullable: true + percentageGNi: + type: number + description: Percentual de Gás Natural Importado – GLGNi para o produto GLP (cProdANP= 210203001) (pGNi) + format: double + nullable: true + startingAmount: + type: number + description: Valor de partida (cProdANP=210203001) (vPart) + format: double + nullable: true + codif: + type: string + description: Código de autorização / registro do CODIF (CODIF) + nullable: true + amountTemp: + type: number + description: Quantidade de combustível faturada à temperatura ambiente (qTemp) + format: double + nullable: true + stateBuyer: + type: string + description: Sigla da UF de consumo (UFCons) + nullable: true + cide: + $ref: '#/components/schemas/CIDEResource' + pump: + $ref: '#/components/schemas/PumpResource' + fuelOrigin: + $ref: '#/components/schemas/FuelOriginResource' + additionalProperties: false + ICMSTotalResource: + type: object + properties: + baseTax: + type: number + description: Base de Cálculo do ICMS (vBC) + format: double + nullable: true + icmsAmount: + type: number + description: Valor Total do ICMS (vICMS) + format: double + nullable: true + icmsExemptAmount: + type: number + description: Valor ICMS Total desonerado (vICMSDeson) + format: double + nullable: true + stCalculationBasisAmount: + type: number + description: Base de Cálculo do ICMS Substituição Tributária (vBCST) + format: double + nullable: true + stAmount: + type: number + description: Valor Total do ICMS ST (vST) + format: double + nullable: true + productAmount: + type: number + description: Valor Total dos produtos e serviços (vProd) + format: double + nullable: true + freightAmount: + type: number + description: Valor Total do Frete (vFrete) + format: double + nullable: true + insuranceAmount: + type: number + description: Valor Total do Seguro (vSeg) + format: double + nullable: true + discountAmount: + type: number + description: Valor Total do Desconto (vDesc) + format: double + nullable: true + iiAmount: + type: number + description: Valor Total do Imposto de Importação (vII) + format: double + nullable: true + ipiAmount: + type: number + description: Valor Total do IPI (vIPI) + format: double + nullable: true + pisAmount: + type: number + description: Valor do PIS (vPIS) + format: double + nullable: true + cofinsAmount: + type: number + description: Valor do COFINS (vCOFINS) + format: double + nullable: true + othersAmount: + type: number + description: Outras Despesas acessórias (vOutro) + format: double + nullable: true + invoiceAmount: + type: number + description: Valor Total da NF-e (vNF) + format: double + nullable: true + fcpufDestinationAmount: + type: number + description: Valor Total ICMS FCP UF Destino (vFCPUFDest) + format: double + nullable: true + icmsufDestinationAmount: + type: number + description: Valor Total ICMS Interestadual UF Destino (vICMSUFDest) + format: double + nullable: true + icmsufSenderAmount: + type: number + description: Valor Total ICMS Interestadual UF Remetente (vICMSUFRemet) + format: double + nullable: true + federalTaxesAmount: + type: number + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + format: double + nullable: true + fcpAmount: + type: number + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + format: double + nullable: true + fcpstAmount: + type: number + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (vFCPST) + format: double + nullable: true + fcpstRetAmount: + type: number + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (vFCPSTRet) + format: double + nullable: true + ipiDevolAmount: + type: number + description: Valor total do IPI devolvido (vIPIDevol) + format: double + nullable: true + qBCMono: + type: number + description: Valor total da quantidade tributada do ICMS monofásico próprio (qBCMono) + format: double + nullable: true + vICMSMono: + type: number + description: Valor total do ICMS monofásico próprio (vICMSMono) + format: double + nullable: true + qBCMonoReten: + type: number + description: Valor total da quantidade tributada do ICMS monofásico sujeito a retenção(qBCMonoReten) + format: double + nullable: true + vICMSMonoReten: + type: number + description: Valor total do ICMS monofásico sujeito a retenção (vICMSMonoReten) + format: double + nullable: true + qBCMonoRet: + type: number + description: Valor total da quantidade tributada do ICMS monofásico retido anteriormente(qBCMonoRet) + format: double + nullable: true + vICMSMonoRet: + type: number + description: Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet) + format: double + nullable: true + additionalProperties: false + description: "Manual Contribuinte v_5.00\r\nGrupo de Valores Totais referentes ao ICMS" + ICMSUFDestinationTaxResource: + type: object + properties: + vBCUFDest: + type: number + description: Valor da Base de Cálculo do ICMS na UF de destino (vBCUFDest) + format: double + nullable: true + pFCPUFDest: + type: number + description: Percentual adicional inserido na alíquota interna da UF de destino, relativo ao Fundo de Combate à Pobreza (FCP) naquela UF (pFCPUFDest) + format: double + nullable: true + pICMSUFDest: + type: number + description: Alíquota adotada nas operações internas na UF de destino para o produto / mercadoria (pICMSUFDest) + format: double + nullable: true + pICMSInter: + type: number + description: Alíquota interestadual das UF envolvidas (pICMSInter) + format: double + nullable: true + pICMSInterPart: + type: number + description: Percentual de ICMS Interestadual para a UF de destino (pICMSInterPart) + format: double + nullable: true + vFCPUFDest: + type: number + description: Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP) da UF de destino (vFCPUFDest + format: double + nullable: true + vICMSUFDest: + type: number + description: Valor do ICMS Interestadual para a UF de destino (vICMSUFDest) + format: double + nullable: true + vICMSUFRemet: + type: number + description: Valor do ICMS Interestadual para a UF do remetente (vICMSUFRemet) + format: double + nullable: true + vBCFCPUFDest: + type: number + description: Valor da BC FCP na UF de destino (vBCFCPUFDest) + format: double + nullable: true + additionalProperties: false + description: Grupo de Tributação do ICMS de Destino da UF + IITaxResource: + type: object + properties: + baseTax: + type: string + description: Valor BC do Imposto de Importação (vBC) + nullable: true + customsExpenditureAmount: + type: string + description: Valor despesas aduaneiras (vDespAdu) + nullable: true + amount: + type: number + description: Valor Imposto de Importação (vII) + format: double + nullable: true + iofAmount: + type: number + description: Valor Imposto sobre Operações Financeiras (vIOF) + format: double + nullable: true + vEnqCamb: + type: number + description: Valor dos encargos cambiais + format: double + nullable: true + additionalProperties: false + description: "Grupo do Imposto de Importação\r\n\r\nId: P01\r\nPai: O01" + IPITaxResource: + type: object + properties: + cst: + type: string + description: Código da situação tributária do IPI (CST) + nullable: true + classificationCode: + type: string + description: Código de Enquadramento Legal do IPI (cEnq) + nullable: true + classification: + type: string + description: "clEnq\r\nClasse de enquadramento do IPI para Cigarros e Bebidas (clEnq)" + nullable: true + producerCNPJ: + type: string + description: CNPJ do produtor da mercadoria, quando diferente do emitente. Somente para os casos de exportação direta ou indireta (CNPJProd) + nullable: true + stampCode: + type: string + description: Código do selo de controle IPI (cSelo) + nullable: true + stampQuantity: + type: number + description: Quantidade de selo de controle (qSelo) + format: double + nullable: true + base: + type: number + description: Valor da BC do IPI (vBC) + format: double + nullable: true + rate: + type: number + description: Alíquota do IPI (pIPI) + format: double + nullable: true + unitQuantity: + type: number + description: Quantidade total na unidade padrão para tributação (somente para os produtos tributados por unidade) (qUnid) + format: double + nullable: true + unitAmount: + type: number + description: Valor por Unidade Tributável (vUnid) + format: double + nullable: true + amount: + type: number + description: Valor IPI (vIPI) + format: double + nullable: true + additionalProperties: false + description: "\r\nGrupo do IPI\r\n\r\nInformar apenas quando o item for sujeito ao IPI\r\n\r\nID: O01\r\n\r\nPai: M01" + ISSQNTotalResource: + type: object + properties: + totalServiceNotTaxedICMS: + type: number + description: Valor Total Serv.Não Tributados p/ ICMS (vServ) + format: double + nullable: true + baseRateISS: + type: number + description: Base de Cálculo do ISS (vBC) + format: double + nullable: true + totalISS: + type: number + description: Valor Total do ISS (vISS) + format: double + nullable: true + valueServicePIS: + type: number + description: Valor do PIS sobre Serviços (vPIS) + format: double + nullable: true + valueServiceCOFINS: + type: number + description: Valor da COFINS sobre Serviços (vCOFINS) + format: double + nullable: true + provisionService: + type: string + description: Data Prestação Serviço (dCompet) + format: date-time + nullable: true + deductionReductionBC: + type: number + description: Valor Dedução para Redução da BC (vDeducao) + format: double + nullable: true + valueOtherRetention: + type: number + description: Valor Outras Retenções (vOutro) + format: double + nullable: true + discountUnconditional: + type: number + description: Valor Desconto Incondicionado (vDescIncond) + format: double + nullable: true + discountConditioning: + type: number + description: Valor Desconto Condicionado (vDescCond) + format: double + nullable: true + totalRetentionISS: + type: number + description: Valor Total Retenção ISS (vISSRet) + format: double + nullable: true + codeTaxRegime: + type: number + description: Código Regime Tributação (cRegTrib) + format: double + nullable: true + additionalProperties: false + IcmsTaxResource: + type: object + properties: + origin: + type: string + description: Origem da mercadoria (orig) + nullable: true + cst: + type: string + description: Tributação do ICMS (CST) + nullable: true + csosn: + type: string + description: "101- Tributada pelo Simples Nacional com permissão de crédito. (v.2.0) (CSOSN)\r\nCódigo de Situação da Operação – Simples Nacional" + nullable: true + baseTaxModality: + type: string + description: "Modalidade de determinação da BC do ICMS (modBC)\r\n\r\n Margem Valor Agregado (%) = 0\r\n Pauta (valor) = 1\r\n Preço Tabelado Máximo (valor) = 2\r\n Valor da Operação = 3\r\n" + nullable: true + baseTax: + type: number + description: Valor da BC do ICMS (vBC) + format: double + nullable: true + baseTaxSTModality: + type: string + description: Modalidade de determinação da BC do ICMS ST (modBCST) + nullable: true + baseTaxSTReduction: + type: string + description: "pRedBCST\r\nPercentual da Redução de BC do ICMS ST (pRedBCST)" + nullable: true + baseTaxST: + type: number + description: Valor da BC do ICMS ST (vBCST) + format: double + nullable: true + baseTaxReduction: + type: number + description: Percentual da Redução de BC (pRedBC) + format: double + nullable: true + stRate: + type: number + description: Alíquota do imposto do ICMS ST (pICMSST) + format: double + nullable: true + stAmount: + type: number + description: Valor do ICMS ST (vICMSST) + format: double + nullable: true + stMarginAmount: + type: number + description: "pMVAST\r\nPercentual da margem de valor Adicionado do ICMS ST (pMVAST)" + format: double + nullable: true + rate: + type: number + description: "pICMS\r\nAlíquota do imposto (pICMS)" + format: double + nullable: true + amount: + type: number + description: "Valor do ICMS (vICMS)\r\nO valor do ICMS desonerado será informado apenas nas operações:\r\na) com produtos beneficiados com a desoneração condicional do ICMS.\r\nb) destinadas à SUFRAMA, informando-se o valor que seria devido se não houvesse isenção.\r\nc) de venda a órgãos da administração pública direta e suas fundações e\r\nautarquias com isenção do ICMS. (NT 2011/004)" + format: double + nullable: true + percentual: + type: number + description: Percentual da Redução de BC (pICMS) + format: double + nullable: true + snCreditRate: + type: number + description: Alíquota aplicável de cálculo do crédito (Simples Nacional). (pCredSN) + format: double + nullable: true + snCreditAmount: + type: number + description: Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 Simples Nacional (vCredICMSSN) + format: double + nullable: true + stMarginAddedAmount: + type: string + description: Percentual da margem de valor Adicionado do ICMS ST (pMVAST) + nullable: true + stRetentionAmount: + type: string + description: Valor do ICMS ST retido (vICMSSTRet) + nullable: true + baseSTRetentionAmount: + type: string + description: Valor da BC do ICMS ST retido (vBCSTRet) + nullable: true + baseTaxOperationPercentual: + type: string + description: "Percentual da BC operação própria (pBCOp)\r\nPercentual para determinação do valor da Base de Cálculo da operação própria. (v2.0)" + nullable: true + ufst: + type: string + description: "UF para qual é devido o ICMS ST (UFST)\r\nSigla da UF para qual é devido o ICMS ST da operação. (v2.0)" + nullable: true + amountSTReason: + type: string + description: Motivo Desoneração ICMS + nullable: true + baseSNRetentionAmount: + type: string + description: Valor da BC do ICMS ST retido (vBCSTRet) + nullable: true + snRetentionAmount: + type: string + description: Valor do ICMS ST retido (vICMSSTRet) + nullable: true + amountOperation: + type: string + description: Valor do ICMS da Operação (vICMSOp) + nullable: true + percentualDeferment: + type: string + description: Percentual do Diferimento (pDif) + nullable: true + baseDeferred: + type: string + description: Valor do ICMS Diferido (vICMSDif) + nullable: true + exemptAmount: + type: number + description: Valor ICMS Desonerado + format: double + nullable: true + exemptReason: + $ref: '#/components/schemas/ExemptReason' + exemptAmountST: + type: number + description: Valor ICMS Desonerado + format: double + nullable: true + exemptReasonST: + $ref: '#/components/schemas/ExemptReason' + fcpRate: + type: number + description: Percentual do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCP) + format: double + nullable: true + fcpAmount: + type: number + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + format: double + nullable: true + fcpstRate: + type: number + description: Percentual do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (pFCPST) + format: double + nullable: true + fcpstAmount: + type: number + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (vFCPST) + format: double + nullable: true + fcpstRetRate: + type: number + description: Percentual do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (pFCPSTRet) + format: double + nullable: true + fcpstRetAmount: + type: number + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (vFCPSTRet) + format: double + nullable: true + baseTaxFCPSTAmount: + type: number + description: Informar o valor da Base de Cálculo do FCP (vBCFCPST) + format: double + nullable: true + substituteAmount: + type: number + description: 'Valor do ICMS próprio do Substituto (tag: vICMSSubstituto)' + format: double + nullable: true + stFinalConsumerRate: + type: number + description: "N26a - Alíquota suportada pelo Consumidor Final (pST)\r\nDeve ser informada a alíquota do cálculo do ICMS-ST, já incluso o FCP caso incida sobre a mercadoria" + format: double + nullable: true + effectiveBaseTaxReductionRate: + type: number + description: N34 - Percentual de redução da base de cálculo efetiva, caso estivesse submetida ao regime comum de tributação (pRedBCEfet) + format: double + nullable: true + effectiveBaseTaxAmount: + type: number + description: N35 - Valor da base de cálculo efetiva, caso estivesse submetida ao regime comum de tributação (vBCEfet) + format: double + nullable: true + effectiveRate: + type: number + description: N36 - Alíquota do ICMS efetiva, caso estivesse submetida ao regime comum de tributação (pICMSEFET) + format: double + nullable: true + effectiveAmount: + type: number + description: N37 - Valor do ICMS efetivo, caso estivesse submetida ao regime comum de tributação (vICMSEFET) + format: double + nullable: true + deductionIndicator: + $ref: '#/components/schemas/DuductionIndicator' + basisBenefitCode: + type: string + description: "Código de Benefício na UF para Redução da Base de Cálculo (cBenefRBC). Tamanho 8 ou 10, quando exigido pela UF (NT 2019.001)." + nullable: true + additionalProperties: false + description: "Grupo do ICMS da Operação própria e ST\r\n\r\nID: N01\r\nPAI: M01\r\n\r\n Obs: Informar apenas um dos grupos N02, N03, N04, N05, N06, N07, N08, N09, N10,\r\n N10a, N10b, N10c, N10d, N10e, N10f, N10g ou N10h com base no conteúdo informado na TAG Tributação do ICMS. (v2.0)\r\n" + ImportDeclarationResource: + type: object + properties: + code: + type: string + description: Número do Documento de Importação da DI/DSI/DA (nDI) + nullable: true + registeredOn: + type: string + description: Data de Registro da DI/DSI/DA (dDI) + format: date-time + nullable: true + customsClearanceName: + type: string + description: Local de desembaraço (xLocDesemb) + nullable: true + customsClearanceState: + $ref: '#/components/schemas/StateCode' + customsClearancedOn: + type: string + description: Data do Desembaraço Aduaneiro (dDesemb) + format: date-time + nullable: true + additions: + type: array + items: + $ref: '#/components/schemas/AdditionResource' + description: Adições (adi) + nullable: true + exporter: + type: string + description: Código do exportador (cExportador) + nullable: true + internationalTransport: + $ref: '#/components/schemas/InternationalTransportType' + intermediation: + $ref: '#/components/schemas/IntermediationType' + acquirerFederalTaxNumber: + type: string + description: CNPJ/CPF do adquirente ou do encomendante (CNPJ ou CPF) + nullable: true + stateThird: + type: string + description: Sigla da UF do adquirente ou do encomendante (UFTerceiro) + nullable: true + afrmmAmount: + type: number + description: Valor Adicional ao frete para renovação de marinha mercante (vAFRMM) + format: double + nullable: true + additionalProperties: false + description: Declaração Importação (DI) + IntegrationPaymentType: + enum: + - Integrated + - NotIntegrated + type: string + description: "1 - Pagamento integrado com o sistema de automação da empresa(Ex.: equipamento TEF, Comércio Eletrônico)\r\n2 - Pagamento não integrado com o sistema de automação da empresa(Ex.: equipamento POS);" + IntermediateResource: + type: object + properties: + federalTaxNumber: + type: integer + description: CNPJ do Intermediador da Transação (agenciador, plataforma de delivery, marketplace e similar) de serviços e de negócios. (CNPJ) + format: int64 + nullable: true + identifier: + type: string + description: Identificador cadastrado no intermediador (idCadIntTran) + nullable: true + additionalProperties: false + description: Grupo de Informações do Intermediador da Transação (infIntermed) + IntermediationType: + enum: + - None + - ByOwn + - ImportOnBehalf + - ByOrder + type: string + description: Tipo de Intermediação + InternationalTransportType: + enum: + - None + - Maritime + - River + - Lake + - Airline + - Postal + - Railway + - Highway + - Network + - Own + - Ficta + - Courier + - Handcarry + type: string + description: Tipo Transporte Internacional + InvoiceEventsResource: + type: object + properties: + events: + type: array + items: + $ref: '#/components/schemas/ActivityResource' + description: Lista de Eventos ocorridos na Nota Fiscal + nullable: true + hasMore: + type: boolean + description: Identificador de possibilidade de mais itens. + nullable: true + id: + type: string + description: Identificação + nullable: true + accountId: + type: string + description: Identificador da Conta + nullable: true + companyId: + type: string + description: Identificador da Empresa + nullable: true + additionalProperties: false + InvoiceEventsResourceBase: + type: object + properties: + events: + type: array + items: + $ref: '#/components/schemas/ActivityResource' + description: Lista de Eventos ocorridos na Nota Fiscal + nullable: true + hasMore: + type: boolean + description: Identificador de possibilidade de mais itens. + nullable: true + additionalProperties: false + InvoiceItemResource: + type: object + properties: + code: + type: string + description: Código do produto ou serviço (cProd) + nullable: true + codeGTIN: + type: string + description: "GTIN (Global Trade Item Number) do produto,\r\nantigo código EAN ou código de barras (cEAN)" + nullable: true + description: + type: string + description: Descrição do produto ou serviço (xProd) + nullable: true + ncm: + type: string + description: Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM) + nullable: true + nve: + type: array + items: + type: string + description: Nomenclatura de Valor aduaneiro e Estatístico (NVE) + nullable: true + extipi: + type: string + description: Código Exceção da Tabela de IPI + nullable: true + cfop: + type: integer + description: Código Fiscal de Operações e Prestações (CFOP) + format: int64 + nullable: true + unit: + type: string + description: Unidade Comercial (uCom) + nullable: true + quantity: + type: number + description: Quantidade Comercial (qCom) + format: double + nullable: true + unitAmount: + type: number + description: Valor Unitário de Comercialização (vUnCom) + format: double + nullable: true + totalAmount: + type: number + description: Valor Total Bruto dos Produtos ou Serviços (vProd) + format: double + nullable: true + codeTaxGTIN: + type: string + description: "GTIN (Global Trade Item Number) da unidade tributável,\r\nantigo código EAN ou código de barras (cEANTrib)" + nullable: true + unitTax: + type: string + description: Unidade Tributável (uTrib) + nullable: true + quantityTax: + type: number + description: Quantidade Tributável (qTrib) + format: double + nullable: true + taxUnitAmount: + type: number + description: Valor Unitário de tributação (vUnTrib) + format: double + nullable: true + freightAmount: + type: number + description: Valor Total do Frete (vFrete) + format: double + nullable: true + insuranceAmount: + type: number + description: Valor Total do Seguro (vSeg) + format: double + nullable: true + discountAmount: + type: number + description: Valor do Desconto (vDesc) + format: double + nullable: true + othersAmount: + type: number + description: Outras despesas acessórias (vOutro) + format: double + nullable: true + totalIndicator: + type: boolean + description: "Indica se valor do Item (vProd)\r\nentra no valor total da NF-e (vProd) (indTot)" + nullable: true + cest: + type: string + description: CEST - Código especificador da substituição tributária + nullable: true + tax: + $ref: '#/components/schemas/InvoiceItemTaxResource' + additionalInformation: + type: string + description: Informações Adicionais do Produto (infAdProd) + nullable: true + numberOrderBuy: + type: string + description: Número do pedido de compra (xPed) + nullable: true + itemNumberOrderBuy: + type: integer + description: Item do Pedido de Compra (nItemPed) + format: int32 + nullable: true + importControlSheetNumber: + type: string + description: Número de controle da FCI - Ficha de Conteúdo de Importação (nFCI) + nullable: true + fuelDetail: + $ref: '#/components/schemas/FuelResource' + benefit: + type: string + description: Código de Benefício Fiscal na UF aplicado ao item (cBenef) + nullable: true + importDeclarations: + type: array + items: + $ref: '#/components/schemas/ImportDeclarationResource' + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55). Declaração Importação (DI). Observação: o grupo de tributo II não é aceito na NFC-e (rejeição 743)." + nullable: true + exportDetails: + type: array + items: + $ref: '#/components/schemas/ExportDetailResource' + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55). Grupo de informações de exportação para o item (detExport)" + nullable: true + usedMovableAssetIndicator: + $ref: '#/components/schemas/UsedMovableAssetIndicator' + itemAmount: + type: number + description: Valor total do item (vItem). + format: double + nullable: true + vehicleDetail: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/VehicleDetailResource' + presumedCredit: + $ref: '#/components/schemas/PresumedCreditResource' + ibsZfmPresumedCreditClassification: + $ref: '#/components/schemas/IbsZfmPresumedCreditClassification' + referencedDFe: + $ref: '#/components/schemas/ReferencedDFeResource' + taxDetermination: + $ref: '#/components/schemas/TaxDeterminationResource' + additionalProperties: false + description: "Manual Contribuinte v_5.00\r\nGrupo do detalhamento de Produtos e Serviços da NF-e" + InvoiceItemTaxResource: + type: object + properties: + totalTax: + type: number + description: Valor aproximado total de tributos federais, estaduais e municipais (vTotTrib) + format: double + nullable: true + icms: + $ref: '#/components/schemas/IcmsTaxResource' + ipi: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/IPITaxResource' + ii: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/IITaxResource' + pis: + $ref: '#/components/schemas/PISTaxResource' + cofins: + $ref: '#/components/schemas/CofinsTaxResource' + icmsDestination: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/ICMSUFDestinationTaxResource' + IS: + $ref: '#/components/schemas/ISTaxResource' + IBSCBS: + $ref: '#/components/schemas/IBSCBSTaxResource' + competenceAdjustment: + $ref: '#/components/schemas/CompetenceAdjustmentResource' + additionalProperties: false + InvoiceItemsResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + companyId: + type: string + description: Identificador da Empresa + nullable: true + id: + type: string + description: Identificador da Nota Fiscal + nullable: true + items: + type: array + items: + $ref: '#/components/schemas/InvoiceItemResource' + description: Detalhamento de Produtos e Serviços (det) - Lista de Items da Nota Fiscal + nullable: true + hasMore: + type: boolean + description: Identifica se existem mais items a serem consultados + nullable: true + additionalProperties: false + InvoiceResource: + type: object + properties: + id: + type: string + description: Identificador único + nullable: true + serie: + type: integer + description: Série do Documento Fiscal (serie) + format: int32 + nullable: true + number: + type: integer + description: Número do Documento Fiscal (nNF) + format: int64 + nullable: true + status: + $ref: '#/components/schemas/InvoiceStatus' + authorization: + $ref: '#/components/schemas/AuthorizationResource' + contingencyDetails: + $ref: '#/components/schemas/ContingencyDetails' + operationNature: + type: string + description: Descrição da Natureza da Operação (natOp) + nullable: true + createdOn: + type: string + description: Data de criação + format: date-time + nullable: true + modifiedOn: + type: string + description: Data de modificação + format: date-time + nullable: true + operationOn: + type: string + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55). Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: date-time + nullable: true + operationType: + $ref: '#/components/schemas/OperationType' + environmentType: + $ref: '#/components/schemas/EnvironmentType' + purposeType: + $ref: '#/components/schemas/PurposeType' + issuer: + $ref: '#/components/schemas/IssuerResource' + buyer: + $ref: '#/components/schemas/BuyerResource' + totals: + $ref: '#/components/schemas/TotalResource' + transport: + description: "⚠️ Uso vedado na NFC-e (modelo 65): frete, transportador, veículo, reboque, vagão, balsa e volumes são rejeitados (rejeições 753–759 do MOC). Grupo aplicável à NF-e (modelo 55)." + $ref: '#/components/schemas/TransportInformationResource' + additionalInformation: + $ref: '#/components/schemas/AdditionalInformationResource' + export: + $ref: '#/components/schemas/ExportResource' + billing: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/BillingResource' + payment: + type: array + items: + $ref: '#/components/schemas/PaymentResource' + description: Grupo de Formas de Pagamento (pag) + nullable: true + transactionIntermediate: + $ref: '#/components/schemas/IntermediateResource' + delivery: + $ref: '#/components/schemas/DeliveryInformationResource' + withdrawal: + $ref: '#/components/schemas/WithdrawalInformationResource' + lastEvents: + $ref: '#/components/schemas/InvoiceEventsResourceBase' + additionalProperties: false + InvoiceStatus: + enum: + - None + - Created + - Processing + - Issued + - IssuedContingency + - Cancelled + - Disabled + - IssueDenied + - Error + type: string + InvoiceWithoutEventsResource: + type: object + properties: + id: + type: string + description: Identificador único + nullable: true + serie: + type: integer + description: Série do Documento Fiscal (serie) + format: int32 + nullable: true + number: + type: integer + description: Número do Documento Fiscal (nNF) + format: int64 + nullable: true + status: + $ref: '#/components/schemas/InvoiceStatus' + authorization: + $ref: '#/components/schemas/AuthorizationResource' + contingencyDetails: + $ref: '#/components/schemas/ContingencyDetails' + operationNature: + type: string + description: Descrição da Natureza da Operação (natOp) + nullable: true + createdOn: + type: string + description: Data de criação + format: date-time + nullable: true + modifiedOn: + type: string + description: Data de modificação + format: date-time + nullable: true + operationOn: + type: string + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55). Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: date-time + nullable: true + operationType: + $ref: '#/components/schemas/OperationType' + environmentType: + $ref: '#/components/schemas/EnvironmentType' + purposeType: + $ref: '#/components/schemas/PurposeType' + issuer: + $ref: '#/components/schemas/IssuerResource' + buyer: + $ref: '#/components/schemas/BuyerResource' + totals: + $ref: '#/components/schemas/TotalResource' + transport: + description: "⚠️ Uso vedado na NFC-e (modelo 65): frete, transportador, veículo, reboque, vagão, balsa e volumes são rejeitados (rejeições 753–759 do MOC). Grupo aplicável à NF-e (modelo 55)." + $ref: '#/components/schemas/TransportInformationResource' + additionalInformation: + $ref: '#/components/schemas/AdditionalInformationResource' + export: + $ref: '#/components/schemas/ExportResource' + billing: + description: "⚠️ Não se aplica à NFC-e (modelo 65) — campo/grupo exclusivo da NF-e (modelo 55)." + $ref: '#/components/schemas/BillingResource' + payment: + type: array + items: + $ref: '#/components/schemas/PaymentResource' + description: Grupo de Formas de Pagamento (pag) + nullable: true + transactionIntermediate: + $ref: '#/components/schemas/IntermediateResource' + delivery: + $ref: '#/components/schemas/DeliveryInformationResource' + withdrawal: + $ref: '#/components/schemas/WithdrawalInformationResource' + additionalProperties: false + IssuerFromRequestResource: + type: object + properties: + stStateTaxNumber: + type: string + description: IE do Substituto Tributário (IEST) + nullable: true + additionalProperties: false + IssuerResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + tradeName: + type: string + description: Nome Fantasia + nullable: true + openningDate: + type: string + description: Data abertura da empresa + format: date-time + nullable: true + taxRegime: + $ref: '#/components/schemas/TaxRegime' + specialTaxRegime: + $ref: '#/components/schemas/SpecialTaxRegime' + legalNature: + $ref: '#/components/schemas/LegalNature' + economicActivities: + type: array + items: + $ref: '#/components/schemas/EconomicActivityResource' + description: Atividades da Empresa (CNAE) + nullable: true + companyRegistryNumber: + type: integer + description: Número de Inscrição na Junta Comercial + format: int64 + nullable: true + regionalTaxNumber: + type: integer + description: Número de Inscrição na SEFAZ (IE) + format: int64 + nullable: true + regionalSTTaxNumber: + type: integer + description: Inscrição Estadual do Substituto Tributário (IEST) + format: int64 + nullable: true + municipalTaxNumber: + type: string + description: Número de Inscrição na Prefeitura (IM/CCM) + nullable: true + stStateTaxNumber: + type: string + description: IE do Substituto Tributário (IEST) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo de identificação do emitente da NF-e" + LegalNature: + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + OperationType: + enum: + - Outgoing + - Incoming + type: string + PISTaxResource: + type: object + properties: + cst: + type: string + description: Código de Situação Tributária do PIS (CST) + nullable: true + baseTax: + type: number + description: Valor da Base de Cálculo do PIS (vBC) + format: double + nullable: true + rate: + type: number + description: Alíquota do PIS (em percentual) (pPIS) + format: double + nullable: true + amount: + type: number + description: Valor do PIS (vPIS) + format: double + nullable: true + baseTaxProductQuantity: + type: number + description: Quantidade Vendida (qBCProd) + format: double + nullable: true + productRate: + type: number + description: Alíquota do PIS (em reais) (vAliqProd) + format: double + nullable: true + additionalProperties: false + description: Grupo do PIS + PaymentDetailResource: + type: object + properties: + method: + $ref: '#/components/schemas/PaymentMethod' + methodDescription: + type: string + description: Descrição do meio de pagamento (xPag) + nullable: true + paymentType: + $ref: '#/components/schemas/PaymentType' + amount: + type: number + description: Valor do Pagamento (vPag) + format: double + nullable: true + card: + $ref: '#/components/schemas/CardResource' + paymentDate: + type: string + description: Data do pagamento (dPag) + format: date-time + nullable: true + federalTaxNumberPag: + type: string + description: CNPJ transacional do pagamento (CNPJPag) + nullable: true + statePag: + type: string + description: UF do CNPJ do estabelecimento onde o pagamento foi processado/transacionado/recebido (UFPag) + nullable: true + additionalProperties: false + PaymentMethod: + enum: + - Cash + - Cheque + - CreditCard + - DebitCard + - StoreCredict + - FoodVouchers + - MealVouchers + - GiftVouchers + - FuelVouchers + - BankBill + - BankDeposit + - InstantPayment + - WireTransfer + - Cashback + - StaticInstantPayment + - StoreCredit + - ElectronicPaymentNotInformed + - WithoutPayment + - Others + type: string + PaymentResource: + type: object + properties: + paymentDetail: + type: array + items: + $ref: '#/components/schemas/PaymentDetailResource' + description: "YA01a - Grupo Detalhamento da Forma de Pagamento (detPag)\r\nVERSÃO 4.00" + nullable: true + payBack: + type: number + description: "Valor do troco (vTroco)\r\nVERSÃO 4.00" + format: double + nullable: true + additionalProperties: false + PaymentType: + enum: + - InCash + - Term + type: string + PersonType: + enum: + - Undefined + - NaturalPerson + - LegalEntity + - Company + - Customer + type: string + PrintType: + enum: + - None + - NFeNormalPortrait + - NFeNormalLandscape + - NFeSimplified + - DANFE_NFC_E + - DANFE_NFC_E_MSG_ELETRONICA + type: string + PumpResource: + type: object + properties: + spoutNumber: + type: integer + description: Número de identificação do bico utilizado no abastecimento (nBico) + format: int32 + nullable: true + number: + type: integer + description: Número de identificação da bomba ao qual o bico está interligado (nBomba) + format: int32 + nullable: true + tankNumber: + type: integer + description: Número de identificação do tanque ao qual o bico está interligado (nTanque) + format: int32 + nullable: true + beginningAmount: + type: number + description: Valor do Encerrante no início do abastecimento (vEncIni) + format: double + nullable: true + endAmount: + type: number + description: Valor do Encerrante no final do abastecimento (vEncFin) + format: double + nullable: true + percentageBio: + type: number + description: Percentual do índice de mistura do Biodiesel (B100) no Óleo Diesel B instituído pelo órgão regulamentador + format: double + nullable: true + additionalProperties: false + PurposeType: + enum: + - None + - Normal + - Complement + - Adjustment + - Devolution + type: string + ReboqueResource: + type: object + properties: + plate: + type: string + description: Placa do Veiculo (placa) + nullable: true + uf: + type: string + description: UF Veiculo Reboque (UF) + nullable: true + rntc: + type: string + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + nullable: true + wagon: + type: string + description: Identificação do Vagão (vagao) + nullable: true + ferry: + type: string + description: Identificação da Balsa (balsa) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo Reboque" + ReceiverStateTaxIndicator: + enum: + - None + - TaxPayer + - Exempt + - NonTaxPayer + type: string + ReferencedProcessResource: + type: object + properties: + identifierConcessory: + type: string + nullable: true + identifierOrigin: + type: integer + format: int32 + nullable: true + concessionActType: + type: integer + format: int32 + nullable: true + additionalProperties: false + RequestCancellationResource: + type: object + properties: + accountId: + type: string + nullable: true + companyId: + type: string + nullable: true + productInvoiceId: + type: string + nullable: true + reason: + type: string + nullable: true + additionalProperties: false + ShippingModality: + enum: + - ByIssuer + - ByReceiver + - ByThirdParties + - OwnBySender + - OwnByBuyer + - Free + type: string + SpecialTaxRegime: + enum: + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + - Automatico + type: string + description: Regime especial de tributação + StateCode: + enum: + - NA + - RO + - AC + - AM + - RR + - PA + - AP + - TO + - MA + - PI + - CE + - RN + - PB + - PE + - AL + - SE + - BA + - MG + - ES + - RJ + - SP + - PR + - SC + - RS + - MS + - MT + - GO + - DF + - EX + type: string + StateTaxProcessingAuthorizer: + enum: + - Normal + - EPEC + type: string + TaxCouponInformationResource: + type: object + properties: + modelDocumentFiscal: + type: string + description: Modelo de Documento Fiscal (mod) + nullable: true + orderECF: + type: string + description: Número de Ordem Sequencial do ECF (nECF) + nullable: true + orderCountOperation: + type: integer + description: Número do Contador de Ordem de Operação (nCOO) + format: int32 + nullable: true + additionalProperties: false + TaxDeterminationResource: + type: object + properties: + operationCode: + type: integer + description: Código interno para determinação de natureza de operação + format: int32 + nullable: true + issuerTaxProfile: + type: string + description: Perfil fiscal do vendedor (origem) - usado para o cálculo automático de impostos + nullable: true + buyerTaxProfile: + type: string + description: Perfil fiscal do comprador (destino) - usado para o cálculo automático de impostos + nullable: true + origin: + type: string + description: Origem da mercadoria + nullable: true + acquisitionPurpose: + type: string + description: Finalidade de aquisição - usado para o cálculo automático de impostos + nullable: true + additionalProperties: false + TaxDocumentsReferenceResource: + type: object + properties: + taxCouponInformation: + $ref: '#/components/schemas/TaxCouponInformationResource' + documentInvoiceReference: + $ref: '#/components/schemas/DocumentInvoiceReferenceResource' + documentElectronicInvoice: + $ref: '#/components/schemas/DocumentElectronicInvoiceResource' + additionalProperties: false + TaxRegime: + enum: + - None + - LucroReal + - LucroPresumido + - SimplesNacional + - SimplesNacionalExcessoSublimite + - MicroempreendedorIndividual + - Isento + type: string + description: Regime de tributação + TaxpayerCommentsResource: + type: object + properties: + field: + type: string + description: Campo (xCampo) + nullable: true + text: + type: string + description: Texto (xTexto) + nullable: true + additionalProperties: false + TotalResource: + type: object + properties: + icms: + $ref: '#/components/schemas/ICMSTotalResource' + issqn: + $ref: '#/components/schemas/ISSQNTotalResource' + withheldTaxes: + $ref: '#/components/schemas/TotalsWithholdings' + isTotals: + $ref: '#/components/schemas/ISTotalsResource' + ibsCbsTotals: + $ref: '#/components/schemas/IBSCBSTotalsResource' + totalInvoiceAmount: + type: number + description: Valor total da NF-e/NFC-e com IBS / CBS / IS (vNFTot) + format: double + nullable: true + additionalProperties: false + TransportGroupResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumber: + type: string + description: Inscrição Estadual do Transportador (IE) + nullable: true + transportRetention: + type: string + description: Grupo de Retenção do ICMS do transporte + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo Transportador" + TransportInformationResource: + type: object + properties: + freightModality: + $ref: '#/components/schemas/ShippingModality' + transportGroup: + $ref: '#/components/schemas/TransportGroupResource' + reboque: + $ref: '#/components/schemas/ReboqueResource' + volume: + $ref: '#/components/schemas/VolumeResource' + transportVehicle: + $ref: '#/components/schemas/TransportVehicleResource' + sealNumber: + type: string + description: Número dos Lacres + nullable: true + transpRate: + $ref: '#/components/schemas/TransportRateResource' + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo de Informações do Transporte da NF-e\r\nId: X01 Pai: A1" + TransportRateResource: + type: object + properties: + serviceAmount: + type: number + description: Valor do Serviço (vServ) + format: double + nullable: true + bcRetentionAmount: + type: number + description: BC da Retenção do ICMS (vBCRet) + format: double + nullable: true + icmsRetentionRate: + type: number + description: Alíquota da Retenção (pICMSRet) //Change to Rate + format: double + nullable: true + icmsRetentionAmount: + type: number + description: Valor do ICMS Retido (vICMSRet) + format: double + nullable: true + cfop: + type: integer + description: CFOP de Serviço de Transporte (CFOP) + format: int64 + nullable: true + cityGeneratorFactCode: + type: integer + description: Código do Municipio de ocorrencia do fato gerador do ICMS do Transporte (cMunFG) + format: int64 + nullable: true + additionalProperties: false + TransportVehicleResource: + type: object + properties: + plate: + type: string + description: Placa do Veiculo (placa) + nullable: true + state: + type: string + description: Sigla da UF (UF) + nullable: true + rntc: + type: string + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo Veiculo" + VolumeResource: + type: object + properties: + volumeQuantity: + type: integer + description: Quantidade de volumes transportados (qVol) + format: int32 + nullable: true + species: + type: string + description: Espécie dos volumes transportados (esp) + nullable: true + brand: + type: string + description: Marca dos Volumes Transportados (marca) + nullable: true + volumeNumeration: + type: string + description: Numeração dos Volumes Transportados (nVol) + nullable: true + netWeight: + type: number + description: Peso Liquido(em Kg) (pesoL) + format: double + nullable: true + grossWeight: + type: number + description: Peso Bruto(em Kg) (pesoB) + format: double + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nVolumes\r\nId:X26" + WithdrawalInformationResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumber: + type: string + description: Inscrição Estadual (IE) + nullable: true + additionalProperties: false + description: Identificação do Local de retirada (retirada) + AdvancePaymentItemResource: + type: "object" + properties: + accessKey: # Chave de Acesso da NF-e para antecipação de pagamento + type: "string" + nullable: true + additionalProperties: false + description: "Grupo de notas de antecipação de pagamento - Informado para abater as parcelas de antecipação de pagamento, conforme Art. 10. § 4º (gPagAntecipado)." + CBSTaxResource: + type: "object" + description: "Grupo de Informações da CBS" + properties: + rate: + type: "number" # Alíquota da CBS (em percentual) + nullable: true + description: "Alíquota da CBS (em percentual) (pCBS)" + format: "double" + deferment: + description: "Grupo de Informações do Diferimento (gDif)" + $ref: "#/components/schemas/DefermentTaxResource" + returnedAmount: + description: "Grupo de Informações da Devolução de Tributos (gDevTrib)" + $ref: "#/components/schemas/ReturnedTaxResource" + reduction: + description: "Grupo de informações da redução da alíquota (gRed)" + $ref: "#/components/schemas/ReductionTaxResource" + amount: + type: "number" + nullable: true # Valor total da CBS + description: "Valor total da CBS (vCBS)." + format: "double" + additionalProperties: false + CBSTotalsResource: + type: "object" + nullable: true + description: "Grupo total da CBS (gCBS)" + properties: + defermentAmount: + type: "number" + nullable: true # Valor total do diferimento + description: "Valor total do diferimento (vDif)" + format: "double" + returnedAmount: + type: "number" + nullable: true + description: "Valor total de devolução de tributos (vDevTrib)" + format: "double" + amount: + type: "number" + nullable: true # Valor total da CBS + description: "Valor total da CBS (vCBS)" + format: "double" + presumedCreditAmount: + type: "number" + nullable: true # Valor total do crédito presumido + description: "Valor total do crédito presumido (vCredPres)" + format: "double" + presumedCreditConditionalAmount: + type: "number" + nullable: true + description: "Valor total do crédito presumido em condição suspensiva. (vCredPresCondSus)" + format: "double" + additionalProperties: false + CompetenceAdjustmentResource: + type: "object" + description: "Ajuste de Competência (gAjusteCompet)" + properties: + assessmentPeriod: + type: "string" + nullable: true # Ano e mês referência do período de apuração + description: "Ano e mês referência do período de apuração (AAAA-MM) (competApur)" + ibsAmount: + type: "number" + nullable: true + description: "Valor de IBS referente ao ajuste de competência (vIBS)" + format: "double" + cbsAmount: + type: "number" + nullable: true # Valor de CBS referente ao ajuste de competência + description: "Valor de CBS referente ao ajuste de competência (vCBS)" + format: "double" + additionalProperties: false + ConsumptionCityCode: + type: "integer" + nullable: true + description: "Código do Município de ocorrência do fato gerador do IBS/CBS (cMunFGIBS). Informar o município de ocorrência do fato gerador do IBS/CBS. Este campo só é preenchido quando \"indPres = 5 (Operação presencial, fora do estabelecimento)\" e não incluir o endereço do destinatário (Grupo: E05) ou local de entrega (Grupo: G01)." + format: "int64" + CreditReversalResource: + type: "object" + description: "Estorno de Crédito (gEstornoCred)" + properties: + ibsReversalAmount: + type: "number" # Valor do IBS a ser estornado + nullable: true + description: "Valor do IBS a ser estornado (vIBSEstCred)" + format: "double" + cbsReversalAmount: + type: "number" + nullable: true + description: "Valor da CBS a ser estornada (vCBSEstCred)" + format: "double" + additionalProperties: false + CreditReversalTotalsResource: + type: "object" + description: "Estorno de Crédito (gEstornoCred)" + properties: + ibsReversalAmount: + type: "number" + nullable: true + description: "Valor do IBS a ser estornado (vIBSEstCred)" + format: "double" + cbsReversalAmount: + type: "number" + nullable: true + description: "Valor da CBS a ser estornada (vCBSEstCred)" + format: "double" + additionalProperties: false + CreditTransferTaxResource: + type: "object" + description: "Informações de Transferências de Crédito (gTransfCred)" + properties: + ibsAmount: + type: "number" # Valor de IBS a transferir + nullable: true + description: "Valor de IBS a transferir (vIBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor de CBS a transferir (vCBS)." + format: "double" + additionalProperties: false + CreditType: + type: "string" + nullable: true + description: | + Tipo de Nota de Crédito (tpNFCredito). + Valores possíveis: + - `FinesAndInterest`: Multa e juros + - `IbsPresumedCreditAppropriationZfm`: Apropriação de crédito presumido de IBS sobre o saldo devedor na ZFM + - `ReturnDeliveryRefusedOrNotFound`: Retorno por recusa na entrega ou não localização do destinatário + - `ValueReduction`: Redução de valores + - `TransferCreditSuccession`: Transferência de crédito na sucessão + enum: + - "FinesAndInterest" + - "IbsPresumedCreditAppropriationZfm" + - "ReturnDeliveryRefusedOrNotFound" + - "ValueReduction" + - "TransferCreditSuccession" + DebitType: + type: "string" + nullable: true + description: | + Tipo de Nota de Débito (tpNFDebito). + Valores possíveis: + - `TransferCreditsToCooperatives`: Transferência de créditos para cooperativas + - `CancelCreditsExemptImmuneSales`: Cancelamento de créditos por vendas isentas/imunes + - `UnprocessedInvoicesDebits`: Débitos de faturas não processadas no cálculo + - `FinesAndInterest`: Multas e juros + - `TransferInheritanceCredit`: Transferência de crédito de herança + - `AdvancePayment`: Pagamento antecipado + - `InventoryLoss`: Perda de estoque + - `SnDisqualification`: Desenquadramento do Simples Nacional + enum: + - "TransferCreditsToCooperatives" + - "CancelCreditsExemptImmuneSales" + - "UnprocessedInvoicesDebits" + - "FinesAndInterest" + - "TransferInheritanceCredit" + - "AdvancePayment" + - "InventoryLoss" + - "SnDisqualification" + DefermentTaxResource: + type: "object" + description: "Grupo de Informações do Diferimento" + properties: + rate: + type: "number" # Percentual do diferimento + nullable: true + description: "Percentual do diferimento" + format: "double" + amount: + type: "number" + nullable: true + description: "Valor do Diferimento" + format: "double" + additionalProperties: false + GovernmentPurchaseEntityType: + type: "string" + nullable: true + description: | + Tipo de ente governamental (tpEnteGov). Para administração pública direta e suas autarquias e fundações. + Valores possíveis: + - `Union`: União + - `State`: Estado + - `FederalDistrict`: Distrito Federal + - `Municipality`: Município + enum: + - "Union" + - "State" + - "FederalDistrict" + - "Municipality" + GovernmentPurchaseOperationType: + type: "string" + nullable: true + description: | + Tipo de operação com o ente governamental (tpOperGov). + Valores possíveis: + - `Supply`: Fornecimento + - `Payment`: Recebimento do pagamento + - `SupplyThenPay`: Fornecimento e pagamento simultâneo + - `PayForPastSupply`: Pagamento por fornecimento passado + - `SupplyAfterPay`: Fornecimento após pagamento + - `PayNowSupplyLater`: Pagamento agora, fornecimento depois + - `SupplyAndPayNow`: Fornecimento e pagamento agora + enum: + - "Supply" + - "Payment" + - "SupplyThenPay" + - "PayForPastSupply" + - "SupplyAfterPay" + - "PayNowSupplyLater" + - "SupplyAndPayNow" + GovernmentPurchaseResource: + type: "object" + description: "Grupo de Compras Governamentais (gCompraGov). Grupo opcional. Informar apenas para compras governamentais." + properties: + entityType: + $ref: "#/components/schemas/GovernmentPurchaseEntityType" # Tipo de ente governamental + rateReduction: + type: "number" + nullable: true + description: "Percentual de redução de alíquota em compra governamental (pRedutor). Conforme o art. 472/370 da LC 214/2025." + format: "double" + operationType: + $ref: "#/components/schemas/GovernmentPurchaseOperationType" + additionalProperties: false + GovernmentPurchaseTaxResource: + type: "object" + description: "Grupo de informações sobre a composição do valor do IBS e CBS nas compras governamentais. Informar apenas para compras governamentais." + properties: + stateRate: + type: "number" # Alíquota IBS UF em compras governamentais + nullable: true + description: "Alíquota IBS UF em compras governamentais (pAliqIBSUF)." + format: "double" + stateAmount: + type: "number" + nullable: true + description: "Valor IBS UF em compras governamentais (vTribIBSUF)." + format: "double" + municipalRate: + type: "number" # Alíquota IBS Município em compras governamentais + nullable: true + description: "Alíquota IBS Município em compras governamentais (pAliqIBSMun)." + format: "double" + municipalAmount: + type: "number" + nullable: true + description: "Valor IBS Município em compras governamentais (vTribIBSMun)." + format: "double" + cbsRate: + type: "number" # Alíquota CBS em compras governamentais + nullable: true + description: "Alíquota CBS em compras governamentais (pAliqCBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS em compras governamentais (vTribCBS)" + format: "double" + additionalProperties: false + IBSCBSTaxResource: + type: "object" + description: "Grupo de Informações do IBS e CBS" + properties: + situationCode: + type: "string" + nullable: true # Código de Situação Tributária do IBS/CBS + description: "Código de Situação Tributária do IBS/CBS (CST). Campo opcional. Se preenchido, será considerado; caso contrário, será definido com base no valor informado no campo `classCode`. Consulte a tabela de referência de `situationCode` (CST) disponível na nossa documentação funcional." + maxLength: 3 + classCode: + type: "string" + nullable: true + description: "Código de Classificação Tributária do IBS/CBS (cClassTrib). Consulte a tabela de referência [cClassTrib](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/tabelas-de-referencia/tabela-referencia-cst-classificacao-tributaria-ibs-cbs/) disponível na nossa documentação funcional." + maxLength: 6 + calculationMode: + type: "string" + nullable: true + description: | + Modo de cálculo do IBS/CBS. + Valores possíveis: + - `Manual`: Preenchimento manual dos campos de tributo. + - `OfficialService`: Utiliza o serviço oficial para calcular IBS/CBS. Quando ativo, apenas `situationCode` e `classCode` são necessários; os demais campos de tributo são ignorados na entrada e preenchidos pelo serviço. + enum: + - "Manual" + - "OfficialService" + default: "Manual" + donationIndicator: + type: "string" + nullable: true # Indica a natureza da operação de doação + description: "Indica a natureza da operação de doação, orientando a apuração e a geração de débitos ou estornos conforme o cenário (indDoacao). Informar quando for doação." + maxLength: 1 + basis: + type: "number" + nullable: true + description: "Base de cálculo antes de reduções para cálculo do tributo bruto. Este campo é opcional. Se enviado, será considerado; caso contrário, será calculado." + format: "double" + state: + $ref: "#/components/schemas/IBSStateTaxResource" + municipal: # Grupo de Informações do IBS para o município + $ref: "#/components/schemas/IBSMunicipalTaxResource" + ibsTotalAmount: + type: "number" + nullable: true + description: "Total do IBS (vIBSTot = vIBSUF + vIBSMun). Quando houver crédito presumido com o indicador \"IndDeduzCredPres=1\", o valor de vCredPres deve ser deduzido deste total." + format: "double" + cbs: + $ref: "#/components/schemas/CBSTaxResource" + regularTaxation: # Tributação regular hipotética + description: "Tributação regular hipotética caso condição resolutória/suspensiva não se aplique." + $ref: "#/components/schemas/RegularTaxationResource" + governmentPurchase: + description: "Grupo de informações sobre a composição do valor do IBS e CBS nas compras governamentais." + $ref: "#/components/schemas/GovernmentPurchaseTaxResource" + monophase: + description: "Grupo de Informações do IBS e CBS sobre transações monofásicas" + $ref: "#/components/schemas/MonophaseIBSCBSTaxResource" + creditTransfer: # Grupo de Informações sobre Transferências de Crédito + description: "Grupo de Informações sobre Transferências de Crédito" + $ref: "#/components/schemas/CreditTransferTaxResource" + operationalPresumedCredit: # Informações sobre o crédito presumido operacional + description: "Informações sobre o crédito presumido operacional (gCredPresOper)." + $ref: "#/components/schemas/OperationalPresumedCreditResource" + creditReversal: + description: "Estorno de Crédito (gEstornoCred). Observação: a obrigatoriedade ou vedação do preenchimento deste grupo está condicionada ao indicador “ind_gEstornoCred” da tabela de cClassTrib do IBS e da CBS." + $ref: "#/components/schemas/CreditReversalResource" + zfmPresumedCredit: + description: "Informações sobre o crédito presumido de IBS para fornecimentos da ZFM (gCredPresIBSZFM)." + $ref: "#/components/schemas/ZfmPresumedCreditResource" # Informações sobre o crédito presumido de IBS para fornecimentos da ZFM + additionalProperties: false + IBSCBSTotalsResource: + type: "object" + nullable: true + description: "Totais da NF-e com IBS e CBS. (IBSCBSTot)" + properties: + basis: + type: "number" + nullable: true # Valor total da Base de Cálculo do IBS e da CBS + description: "Valor total da Base de Cálculo do IBS e da CBS. (vBCIBSCBS)" + format: "double" + ibs: + description: "Grupo total do IBS (gIBS)" + $ref: "#/components/schemas/IBSTotalsResource" + cbs: + description: "Grupo total da CBS (gCBS)" + $ref: "#/components/schemas/CBSTotalsResource" + monophase: + description: "Grupo de totais da tributação monofásica." # Grupo de totais da tributação monofásica + $ref: "#/components/schemas/MonophaseTotalsResource" + creditReversal: + description: "Grupo total do Estorno de Crédito (gEstornoCred)" + $ref: "#/components/schemas/CreditReversalTotalsResource" + additionalProperties: false + IBSMunicipalTaxResource: + type: "object" + description: "Grupo de Informações do IBS para o município" + properties: + rate: + type: "number" # Alíquota IBS (Município) + nullable: true + description: "Alíquota IBS (Município) (%)." + format: "double" + deferment: + $ref: "#/components/schemas/DefermentTaxResource" + returnedAmount: + $ref: "#/components/schemas/ReturnedTaxResource" + reduction: + $ref: "#/components/schemas/ReductionTaxResource" + amount: + type: "number" + nullable: true # Valor do IBS do Município + description: "Valor do IBS do Município (vIBSMun)." + format: "double" + additionalProperties: false + IBSMunicipalTotalsResource: + type: "object" + nullable: true + description: "Informações do IBS do Município (gIBSMun)" + properties: + defermentAmount: + type: "number" + nullable: true # Valor total do diferimento + description: "Valor total do diferimento (vDif)" + format: "double" + returnedAmount: + type: "number" + nullable: true + description: "Valor total de devolução de tributos (vDevTrib)" + format: "double" + amount: + type: "number" + nullable: true # Valor total do IBS do Município + description: "Valor total do IBS do Município. (vIBSMun)" + format: "double" + additionalProperties: false + IBSStateTaxResource: + type: "object" + description: "Grupo de Informações do IBS para a UF" + properties: + rate: + type: "number" # Alíquota do IBS de competência das UF + nullable: true + description: "Alíquota do IBS de competência das UF (em percentual). Alíquota vigente do IBS da UF.Preencher de acordo com a tabela de alíquotas do IBS e CBS." + format: "double" + deferment: + $ref: "#/components/schemas/DefermentTaxResource" + returnedAmount: + $ref: "#/components/schemas/ReturnedTaxResource" + reduction: + $ref: "#/components/schemas/ReductionTaxResource" + amount: + type: "number" + nullable: true # Valor do IBS da UF + description: "Valor do IBS da UF (vIBSUF)." + format: "double" + additionalProperties: false + IBSStateTotalsResource: + type: "object" + nullable: true + description: "Informações do IBS da UF (gIBSUF)" + properties: + defermentAmount: + type: "number" + nullable: true # Valor total do diferimento + description: "Valor total do diferimento (vDif)" + format: "double" + returnedAmount: + type: "number" + nullable: true + description: "Valor total de devolução de tributos (vDevTrib)" + format: "double" + amount: + type: "number" + nullable: true # Valor total do IBS da UF + description: "Valor total do IBS da UF. (vIBSUF)" + format: "double" + additionalProperties: false + IBSTotalsResource: + type: "object" + nullable: true + description: "Grupo total do IBS (gIBS)" + properties: + state: + description: "Informações do IBS da UF." + $ref: "#/components/schemas/IBSStateTotalsResource" + municipal: + description: "Informações do IBS do Município." # Informações do IBS do Município + $ref: "#/components/schemas/IBSMunicipalTotalsResource" + totalAmount: + type: "number" + nullable: true + description: "Valor total do IBS (vIBS)" + format: "double" + presumedCreditAmount: + type: "number" + nullable: true + description: "Valor total do crédito presumido (vCredPres)" + format: "double" + presumedCreditConditionalAmount: + type: "number" + nullable: true + description: "Valor total do crédito presumido em condição suspensiva. (vCredPresCondSus)" + format: "double" + additionalProperties: false + ISTaxResource: + type: "object" + description: "Imposto Seletivo (IS). Informe quando o item estiver sujeito ao IS." + properties: + situationCode: + type: "string" # CST do Imposto Seletivo (IS) + nullable: true + description: "CST do Imposto Seletivo (IS). Código de Situação Tributária de 3 dígitos (CST). Consulte a tabela de referência." + classificationCode: + type: "string" + nullable: true + description: "Código de Classificação Tributária do IS (cClassTribIS), 6 dígitos. Consulte a tabela de referência." + basis: + type: "number" + nullable: true # Base de cálculo do IS + description: "Base de cálculo do IS (vBCIS). 15 posições, 13 inteiros e 2 decimais." + format: "double" + rate: + type: "number" + nullable: true + description: "Alíquota do IS em percentual (pIS). Até 4 casas decimais." + format: "double" + unitRate: + type: "number" + nullable: true # Alíquota específica por unidade + description: "Alíquota específica por unidade (pISEspec), em R$ por unidade tributável." + format: "double" + unit: + type: "string" + nullable: true + description: "Unidade tributável usada quando houver alíquota específica por unidade (uTrib)." + quantity: + type: "number" + nullable: true # Quantidade tributável + description: "Quantidade tributável usada quando houver alíquota específica por unidade (qTrib). Até 4 casas decimais." + format: "double" + amount: + type: "number" + nullable: true + description: "Valor do Imposto Seletivo (vIS). 15 posições, 13 inteiros e 2 decimais." + format: "double" + additionalProperties: false + ISTotalsResource: + type: "object" + nullable: true + description: "Grupo de totais do Imposto Seletivo. (ISTot)" + properties: + amount: + type: "number" # Total do imposto seletivo + nullable: true + description: "Total do imposto seletivo. (vIS)" + format: "double" + additionalProperties: false + IbsConsumptionCityCode: + type: "integer" + nullable: true + description: "Código do Município de ocorrência do fato gerador do IBS/CBS (cMunFGIBS). Informar o município de ocorrência do fato gerador do IBS/CBS. Este campo só é preenchido quando \"indPres = 5 (Operação presencial, fora do estabelecimento)\" e não incluir o endereço do destinatário (Grupo: E05) ou local de entrega (Grupo: G01)." + format: "int64" # Código do Município de ocorrência do fato gerador do IBS/CBS + IbsZfmPresumedCreditClassification: + type: "string" + nullable: true + description: | + Classificação para cálculo do crédito presumido de IBS para fornecimentos da ZFM (tpCredPresIBSZFM). + Valores possíveis: + - `NoPresumedCredit`: Sem Crédito Presumido + - `FinalConsumptionGoods`: Bens de consumo final (55%) + - `CapitalGoods`: Bens de capital (75%) + - `IntermediateGoods`: Bens intermediários (90,25%) + - `ItAndOtherGoods`: Bens de informática e outros definidos em legislação (100%) + enum: + - "NoPresumedCredit" + - "FinalConsumptionGoods" + - "CapitalGoods" + - "IntermediateGoods" + - "ItAndOtherGoods" + MonophaseCBSTotalsResource: + type: "object" + nullable: true + description: "Totais da CBS monofásica" + properties: + amount: + type: "number" + nullable: true # Total da CBS monofásica + description: "Total da CBS monofásica. (vCBSMono)" + format: "double" + withheldAmount: + type: "number" + nullable: true + description: "Total da CBS monofásica sujeita a retenção. (vCBSMonoReten)" + format: "double" + previouslyWithheldAmount: + type: "number" + nullable: true # Total da CBS monofásica retida anteriormente + description: "Total da CBS monofásica retida anteriormente. (vCBSMonoRet)" + format: "double" + additionalProperties: false + MonophaseDefermentTaxResource: + type: "object" + description: "Deferimento na tributação monofásica (para biocombustíveis)." + properties: + ibsRate: + type: "number" + nullable: true + description: "Percentual de diferimento do IBS monofásico (pDifIBS)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor do diferimento IBS monofásico (vIBSMonoDif)." + format: "double" + cbsRate: + type: "number" + nullable: true + description: "Percentual de diferimento do CBS monofásico (pDifCBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor do diferimento CBS monofásico (vCBSMonoDif)." + format: "double" + additionalProperties: false + MonophaseIBSCBSTaxResource: + type: "object" + description: "Grupo de Informações do IBS e CBS sobre transações monofásicas" + properties: + standart: + description: "Informações de tributação monofásica padrão para IBS/CBS (gMonofasicoPadrao)." + $ref: "#/components/schemas/MonophaseStandardTaxResource" + withholding: + description: "Tributação monofásica sujeita à retenção (gMonofasicoRetido)." + $ref: "#/components/schemas/MonophaseWithholdingTaxResource" + previouslyWithheld: + description: "Tributação monofásica previamente retida (gMonofasicoRetidoAnt)." + $ref: "#/components/schemas/MonophasePreviouslyWithheldTaxResource" + deferment: + description: "Deferimento na tributação monofásica (para biocombustíveis) (gMonofasicoDif)." + $ref: "#/components/schemas/MonophaseDefermentTaxResource" + ibsAmount: + type: "number" + nullable: true + description: "Total de IBS monofásico do item (vTotIBSMonoItem)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Total de CBS monofásico do item (vTotCBSMonoItem)." + format: "double" + additionalProperties: false + MonophaseIBSTotalsResource: + type: "object" + nullable: true + description: "Totais do IBS monofásico" + properties: + amount: + type: "number" + nullable: true # Total do IBS monofásico + description: "Total do IBS monofásico. (vIBSMono)" + format: "double" + withheldAmount: + type: "number" + nullable: true + description: "Total do IBS monofásico sujeito a retenção. (vIBSMonoReten)" + format: "double" + previouslyWithheldAmount: + type: "number" + nullable: true # Total do IBS monofásico retido anteriormente + description: "Total do IBS monofásico retido anteriormente. (vIBSMonoRet)" + format: "double" + additionalProperties: false + MonophasePreviouslyWithheldTaxResource: + type: "object" + description: "Tributação monofásica previamente retida." + properties: + quantityBasis: + type: "number" + nullable: true + description: "Quantidade base previamente retida (qBCMonoRet)." + format: "double" + ibsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem IBS previamente retida (adRemIBSRet)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor IBS previamente retido (vIBSMonoRet)." + format: "double" + cbsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem CBS previamente retida (adRemCBSRet)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS previamente retido (vCBSMonoRet)." + format: "double" + additionalProperties: false + MonophaseStandardTaxResource: + type: "object" + description: "Informações de tributação monofásica padrão para IBS/CBS." + properties: + quantityBasis: + type: "number" + nullable: true + description: "Quantidade base tributada na monofásica (qBCMono)." + format: "double" + ibsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem IBS (adRemIBS)." + format: "double" + cbsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem CBS (adRemCBS)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor IBS monofásico (vIBSMono)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS monofásico (vCBSMono)." + format: "double" + additionalProperties: false + MonophaseTotalsResource: + type: "object" + nullable: true + description: "Grupo de totais da tributação monofásica." + properties: + ibs: + description: "Totais do IBS monofásico" + $ref: "#/components/schemas/MonophaseIBSTotalsResource" # Totais do IBS monofásico + cbs: + description: "Totais da CBS monofásica" + $ref: "#/components/schemas/MonophaseCBSTotalsResource" + additionalProperties: false + MonophaseWithholdingTaxResource: + type: "object" + description: "Tributação monofásica sujeita à retenção." + properties: + quantityBasis: + type: "number" + nullable: true + description: "Quantidade base tributada na retenção monofásica (qBCMonoReten)." + format: "double" + ibsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem IBS retida (adRemIBSReten)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor IBS monofásico retido (vIBSMonoReten)." + format: "double" + cbsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem CBS retida (adRemCBSReten)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS monofásico retido (vCBSMonoReten)." + format: "double" + additionalProperties: false + OperationalPresumedCreditResource: + type: "object" + description: "Informações sobre o crédito presumido de IBS para fornecimentos (gCredPresOper)." + properties: + basis: + type: "number" + nullable: true + description: "Valor da Base de Cálculo do Crédito Presumido da Operação (vBC)" + format: "double" + classificationCode: + description: "Código de Classificação do Crédito Presumido (cCredPres)." + $ref: "#/components/schemas/PresumedCreditClassificationCode" + ibs: + description: "Grupo de Informações do Crédito Presumido referente ao IBS (gIBSCredPres)" + $ref: "#/components/schemas/PresumedCreditDetailsResource" + cbs: + description: "Grupo de Informações do Crédito Presumido referente a CBS (gCBSCredPres)" + $ref: "#/components/schemas/PresumedCreditDetailsResource" + additionalProperties: false + PresumedCreditClassificationCode: + type: "string" + nullable: true + enum: + - "RuralProducerNonTaxpayer" + - "TacPfTransportServiceNonTaxpayer" + - "RecyclingFromIndividual" + - "UsedMovableGoodsFromIndividualForResale" + - "OptionalRegimeForCooperative" + description: | + Código de Classificação do Crédito Presumido (cCredPres). + Valores possíveis: + - `RuralProducerNonTaxpayer`: Produtor rural não contribuinte + - `TacPfTransportServiceNonTaxpayer`: TAC Pessoa Física não contribuinte do serviço de transporte + - `RecyclingFromIndividual`: Reciclagem de pessoa física + - `UsedMovableGoodsFromIndividualForResale`: Bens móveis usados de pessoa física para revenda + - `OptionalRegimeForCooperative`: Regime opcional para cooperativa + PresumedCreditDetailsResource: + type: "object" + description: "Grupo de Informações do Crédito Presumido" + properties: + rate: + type: "number" + nullable: true + description: "Percentual do Crédito Presumido (pCredPres)" + format: "double" + amount: + type: "number" # Valor do Crédito Presumido + nullable: true + description: "Valor do Crédito Presumido (vCredPres)" + format: "double" + suspensiveConditionAmount: + type: "number" + nullable: true + description: "Valor do Crédito Presumido em condição suspensiva. (vCredPresCondSus)" + format: "double" + additionalProperties: false + PresumedCreditResource: + type: "object" + description: "Informações de Crédito Presumido por item (gCred). Preenchimento conforme exigência da UF (NT 2019.001)." + properties: + code: + type: "string" + nullable: true # Código do Benefício de Crédito Presumido na UF + description: "Código do Benefício de Crédito Presumido na UF (cCredPresumido). Use o mesmo código utilizado na EFD/declarações da UF. Tamanho 8 ou 10." + rate: + type: "number" + nullable: true + description: "Percentual do Crédito Presumido (pCredPresumido). Use fração: 0.04 = 4%. Até 4 casas decimais." + format: "double" + amount: + type: "number" + nullable: true # Valor do Crédito Presumido + description: "Valor do Crédito Presumido (vCredPresumido)." + format: "double" + additionalProperties: false + ReductionTaxResource: + type: "object" + description: "Grupo de informações da redução da alíquota" + properties: + rateReduction: + type: "number" + nullable: true + description: "Percentual da redução de alíquota" + format: "double" + effectiveRate: + type: "number" # Alíquota Efetiva que será aplicada a Base de Cálculo + nullable: true + description: "Alíquota Efetiva que será aplicada a Base de Cálculo (em percentual)" + format: "double" + additionalProperties: false + ReferencedDFeResource: + type: "object" + nullable: true + description: "Documento Fiscal Eletrônico Referenciado (DFeReferenciado). Grupo para referenciamento de itens de outro DF-e." + properties: + accessKey: + type: "string" + description: "Chave de acesso do DF-e referenciado (chaveAcesso)." + maxLength: 44 + minLength: 44 + pattern: "^[0-9]{44}$" + itemNumber: # Número do item do documento referenciado + type: "integer" + nullable: true + description: "Número do item do documento referenciado (nItem). Corresponde ao atributo “nItem” do elemento “det” do documentooriginal." + maximum: 999 + minimum: 1 + format: "int32" + required: + - "accessKey" + additionalProperties: false + RegularTaxationResource: + type: "object" + description: "Tributação regular hipotética caso condição resolutória/suspensiva não se aplique. Informar como a tributação seria aplicada se a condição resolutória/suspensiva não for atendida." + properties: + situationCode: + type: "string" + nullable: true # CST regular + description: "CST regular (CSTReg), 3 dígitos. Use tabela CST do IBS/CBS" + classCode: + type: "string" + nullable: true + description: "Classificação tributária regular (cClassTribReg), 6 dígitos. Use tabela cClassTrib" + stateEffectiveRate: + type: "number" + nullable: true # Alíquota efetiva IBS UF + description: "Alíquota efetiva IBS UF (pAliqEfetRegIBSUF)." + format: "double" + amount: + type: "number" + nullable: true + description: "IBS UF regular (vTribRegIBSUF)." + format: "double" + municipalEffectiveRate: + type: "number" + nullable: true # Alíquota efetiva IBS Município + description: "Alíquota efetiva IBS Município (pAliqEfetRegIBSMun)." + format: "double" + municipalAmount: + type: "number" + nullable: true + description: "IBS Município regular (vTribRegIBSMun)." + format: "double" + cbsEffectiveRate: + type: "number" + nullable: true # Alíquota efetiva CBS + description: "Alíquota efetiva CBS (pAliqEfetRegCBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "CBS regular (vTribRegCBS)." + format: "double" + additionalProperties: false + ReturnedTaxResource: + type: "object" + description: "Grupo de Informações da Devolução de Tributos" + properties: + amount: + type: "number" + nullable: true # Valor do tributo devolvido + description: "Valor do tributo devolvido (vDevTrib)" + format: "double" + additionalProperties: false + TotalsWithholdings: + type: "object" + nullable: true + description: "Grupo Retenções de Tributos (retTrib)" + properties: + pisAmount: + type: "number" + nullable: true # Valor Retido de PIS + description: "Valor Retido de PIS (vRetPIS)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + cofinsAmount: + type: "number" + nullable: true + description: "Valor Retido de COFINS (vRetCOFINS)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + csllAmount: # Valor Retido de CSLL + type: "number" + nullable: true + description: "Valor Retido de CSLL (vRetCSLL)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + irrfBasis: + type: "number" + nullable: true + description: "Base de Cálculo do IRRF (vBCIRRF)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + irrfAmount: # Valor Retido do IRRF + type: "number" + nullable: true + description: "Valor Retido do IRRF (vIRRF)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + socialSecutiryBasis: + type: "number" + nullable: true + description: "Base de Cálculo da Retenção da Previdência Social (vBCRetPrev)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + socialSecutiryAmount: # Valor da Retenção da Previdência Social + type: "number" + nullable: true + description: "Valor da Retenção da Previdência Social (vRetPrev)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + additionalProperties: false + UsedMovableAssetIndicator: # Indica fornecimento de bem móvel usado + type: "boolean" + nullable: false + description: "Indica fornecimento de bem móvel usado (indBemMovelUsado). true = bem usado; false = bem novo." + VehicleDetailResource: + type: "object" + description: "Detalhamento de Veículos novos (veicProd) - grupo J01" + properties: + operationType: + type: "integer" + nullable: true + description: | + Tipo da Operação (tpOp). + Valores possíveis: + - `0`: Outros + - `1`: Venda concessionária + - `2`: Faturamento direto para consumidor final + - `3`: Venda direta para grandes consumidores + format: "int32" + enum: [0, 1, 2, 3] + chassis: + type: "string" + nullable: true + description: "Chassi do veículo - VIN (chassi). 17 caracteres alfanuméricos" + minLength: 17 + maxLength: 17 + pattern: "^[A-Z0-9]+$" + colorCode: + type: "string" + nullable: true + description: "Cor do veículo - código de cada montadora (cCor)" + maxLength: 4 + colorDescription: + type: "string" + nullable: true + description: "Descrição da Cor (xCor)" + maxLength: 40 + enginePower: + type: "string" + nullable: true + description: "Potência máxima do motor em cavalo vapor - CV (pot)" + maxLength: 4 + engineDisplacement: + type: "string" + nullable: true + description: "Capacidade volumétrica do motor em centímetros cúbicos - CC (cilin)" + maxLength: 4 + netWeight: + type: "string" + nullable: true + description: "Peso Líquido (pesoL)" + maxLength: 9 + grossWeight: + type: "string" + nullable: true + description: "Peso Bruto (pesoB)" + maxLength: 9 + serialNumber: + type: "string" + nullable: true + description: "Serial - série (nSerie)" + maxLength: 9 + fuelType: + type: "string" + nullable: true + description: "Tipo de combustível - Tabela RENAVAM (tpComb). Ex: 01-Álcool; 02-Gasolina; 03-Diesel; 16-Álcool/Gas.; 17-Gas./Álcool/GNV; 18-Gasolina/Elétrico" + maxLength: 2 + engineNumber: + type: "string" + nullable: true + description: "Número do motor (nMotor)" + maxLength: 21 + maximumTractionCapacity: + type: "string" + nullable: true + description: "Capacidade Máxima de Tração em toneladas - 4 casas decimais (CMT)" + maxLength: 9 + wheelBase: + type: "string" + nullable: true + description: "Distância entre eixos (dist)" + maxLength: 4 + modelYear: + type: "integer" + nullable: true + description: "Ano Modelo de Fabricação (anoMod). Formato: 4 dígitos" + format: "int32" + manufactureYear: + type: "integer" + nullable: true + description: "Ano de Fabricação (anoFab). Formato: 4 dígitos" + format: "int32" + paintType: + type: "string" + nullable: true + description: "Tipo de pintura (tpPint)" + maxLength: 1 + vehicleType: + type: "string" + nullable: true + description: "Tipo de veículo - Tabela RENAVAM (tpVeic)" + maxLength: 2 + vehicleSpecies: + type: "integer" + nullable: true + description: "Espécie de veículo - Tabela RENAVAM (espVeic)" + format: "int32" + vinCondition: + type: "string" + nullable: true + description: | + Condição do VIN — chassi (VIN). + Valores possíveis: + - `R`: Remarcado (chassi regravado pelo DETRAN) + - `N`: Normal (chassi original de fábrica) + enum: ["R", "N"] + vehicleCondition: + type: "integer" + nullable: true + description: | + Condição do veículo (condVeic). + Valores possíveis: + - `1`: Acabado (veículo pronto para uso) + - `2`: Inacabado (veículo sem algum componente essencial) + - `3`: Semi-acabado (veículo parcialmente montado, ex: chassis-cabina) + format: "int32" + enum: [1, 2, 3] + brandModelCode: + type: "string" + nullable: true + description: "Código Marca Modelo - Tabela RENAVAM (cMod)" + maxLength: 6 + denatranColorCode: + type: "string" + nullable: true + description: "Código da Cor DENATRAN (cCorDENATRAN). 01-AMARELO; 02-AZUL; 03-BEGE; 04-BRANCA; 05-CINZA; 06-DOURADA; 07-GRENA; 08-LARANJA; 09-MARROM; 10-PRATA; 11-PRETA; 12-ROSA; 13-ROXA; 14-VERDE; 15-VERMELHA; 16-FANTASIA" + maxLength: 2 + seatingCapacity: + type: "integer" + nullable: true + description: "Quantidade máxima de passageiros sentados, inclusive motorista (lota)" + format: "int32" + restrictionType: + type: "integer" + nullable: true + description: | + Tipo de restrição sobre o veículo (tpRest). + Valores possíveis: + - `0`: Não há restrição (veículo livre para venda e transferência) + - `1`: Alienação Fiduciária (veículo dado como garantia em financiamento) + - `2`: Arrendamento Mercantil (veículo em contrato de leasing) + - `3`: Reserva de Domínio (vendedor mantém a propriedade até quitação total) + - `4`: Penhor de Veículos (veículo dado como garantia em empréstimo) + - `9`: Outras restrições + format: "int32" + enum: [0, 1, 2, 3, 4, 9] + additionalProperties: false + ZfmPresumedCreditResource: + type: "object" + description: "Informações sobre o crédito presumido de IBS para fornecimentos da ZFM (gCredPresIBSZFM)." + properties: + classificationCode: + description: "Tipo de crédito presumido (tpCredPresIBSZFM)." + $ref: "#/components/schemas/IbsZfmPresumedCreditClassification" # Tipo de crédito presumido + amount: + type: "number" + nullable: true + description: "Valor do crédito presumido ZFM (vCredPresIBSZFM). Obrigatório para notas de crédito com tpNFCredito = 02." + format: "double" + additionalProperties: false + securitySchemes: + Authorization_Header: + type: apiKey + description: Autenticar usando o cabeçalho HTTP + name: Authorization + in: header + Authorization_QueryParam: + type: apiKey + description: Autenticar usando o parâmetro na URL + name: apikey + in: query + Authorization_JwtBearer: + type: http + description: Autenticar usando o cabeçalho HTTP + scheme: bearer + bearerFormat: Json Web Token +security: + - Authorization_Header: [] + Authorization_QueryParam: [] + - Authorization_JwtBearer: [] +x-original-swagger-version: "2.0" diff --git a/openapi/nf-produto-v2.yaml b/openapi/nf-produto-v2.yaml new file mode 100644 index 0000000..b7b93b4 --- /dev/null +++ b/openapi/nf-produto-v2.yaml @@ -0,0 +1,8625 @@ +openapi: 3.0.1 +info: + title: Nota Fiscal de Produto + description: "# Introducão\nSeja bem-vindo a documentação da API de Nota Fiscal de Produto!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n\n\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e metódos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n\n\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra no topo desta página para que os métodos funcionem corretamente.\nNo seu código de integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n\n" + version: v2 +servers: + - url: https://api.nfse.io +tags: + - name: Companies + description: | + Utilize esta requisição para criar novas empresas plataforma para processar Documentos Fiscais. **Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais. + - name: Companies Certificates + description: | + Utilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo **e-CNPJ A1** ou **NFE A1** em uma **Empresa** e vincula-lo para processamentos. + + O **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web. + - name: Companies State Taxes + description: | + Está sessão é destinada às **Incrições Estaduais(IE).** Uma **Incrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ. + + Utilizando as informações abaixo você pode criar novas IEs na empresa para processar **Documentos Fiscais.** Além disso, também é possível listar as IEs por empresa e consultar, alterar e exluir uma IE pelo ID da mesma. + - name: Product Invoices + description: "Nesta sessão estão disponíveis informações necessárias para emitir uma Nota Fiscal Eletrônica usando a nossa API. \n\nVocê também encontrará informações sobre consulta de uma nota fiscal por ID, consulta de uma lista de notas por empresa, consulta do PDF do Documento Auxiliar da Nota Fiscal Eletrônica (DANFE) e consulta do XML da nota fiscal eletrônica.\n" + - name: WebHooks + description: | + Eventos ocorrem a todo instante na plataforma durante os processamentos e são registrados criando notificações para os webhooks ativos e configurados para receber os eventos. + + Um **Webhook** é semelhante a uma assinatura em um sistema de publicação e assinatura que permite ao assinante indicar quando, como e onde as notificações de eventos devem ser despachadas. Um **Webhook** é registrado e gerenciado por Conta o que significa que cada Conta tem um conjunto separado de ganchos que podem ser acionados por eventos gerados através de ações executadas por esse Conta. Ou seja, a **Conta da Empresa A** não verá os WebHooks disparados por uma ação executada pelo usuário **Conta da Empresa B**. + + São identificados seguindo o padrão **Resource.EventAction**, sendo **Resource** o nome da entidade que gerou o evento e **EventAction** o nome do evento e ação criados. + + Esses tipos podem ser utilizados como filtro ao criar ou alterar um webhook, sendo que o filtro determina quais notificações de eventos e ação serão enviadas para um determinado webhook, ou seja, dependendo de quais filtros são vinculados ao webhook ele só receberá as notificações de evento e ação que correspondem a um ou mais desses filtros +paths: + /v2/companies: + get: + tags: + - Companies + summary: Consultar todas as Empresas da Conta + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados das empresas vinculadas a conta." + operationId: V2CompaniesGet + parameters: + - name: startingAfter + in: query + description: 'Id de início do contador (Default: Empty)' + schema: + type: string + - name: endingBefore + in: query + description: 'Id final do contador (Default: Empty)' + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + responses: + "200": + description: Sucesso na consulta da Empresa + content: + application/json: + schema: + type: object + properties: + companies: + type: array + description: Lista de Empresa + items: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresas + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - Companies + summary: Criar uma Empresa + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novas empresas plataforma para processar Documentos Fiscais.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais." + operationId: V2CompaniesPost + requestBody: + description: Dados da Empresa a ser criada + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Criar Empresa + text/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Criar Empresa + application/*+json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Criar Empresa + required: false + responses: + "200": + description: Sucesso na criação da Empresa + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresa + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + /v2/companies/{company_id}: + get: + tags: + - Companies + summary: Consultar uma Empresa pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID." + operationId: V2CompaniesByCompany_idGet + parameters: + - name: company_id + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta da Empresa + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresa + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + put: + tags: + - Companies + summary: Alterar uma Empresa pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados de uma empresas pelo ID." + operationId: V2CompaniesByCompany_idPut + parameters: + - name: company_id + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + requestBody: + description: Dados da Empresa a ser alterada + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Alterar Empresa + text/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Alterar Empresa + application/*+json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Dados para Alterar Empresa + required: false + responses: + "200": + description: Sucesso na alteração da Empresa + content: + application/json: + schema: + type: object + properties: + company: + required: + - address + - federalTaxNumber + - name + - tradeName + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + stateTaxes: + type: array + description: Lista de Inscrição Estadual + items: + type: string + name: + type: string + description: Razão Social + accountId: + type: string + description: Identificador da conta + tradeName: + type: string + description: Nome Fantasia + federalTaxNumber: + type: integer + description: Número de Inscrição Federal (CNPJ) + format: int64 + taxRegime: + type: string + description: Regime Tributário + enum: + - isento + - microempreendedorIndividual + - simplesNacional + - lucroPresumido + - lucroReal + - none + address: + required: + - city + - country + - district + - number + - postalCode + - state + - street + type: object + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + required: + - code + - name + type: object + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + description: Cidade do Endereço + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + description: Endereço + description: Dados da Empresa + description: Empresa + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + delete: + tags: + - Companies + summary: Excluir uma Empresa por ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir uma empresas pelo ID, cuidado pois esse processo é irreversível." + operationId: V2CompaniesByCompany_idDelete + parameters: + - name: company_id + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Empresa + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Empresa não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{company_id}/certificates: + get: + tags: + - Companies Certificates + summary: Consultar um Certificado por seu Status + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de um **Certificado da ICP-Brasil** através d0 **status do certificado** (__status__)." + operationId: V2CompaniesByCompany_idCertificatesGet + parameters: + - name: company_id + in: path + description: ID da Empresa relacionada ao certificado + required: true + schema: + type: string + - name: status + in: query + description: Status do certificado + schema: + type: string + enum: + - inactive + - overdue + - pending + - active + - none + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + type: object + properties: + certificates: + type: array + items: + type: object + properties: + subject: + type: string + description: Nome do certificado (subject distinguished name) + validUntil: + type: string + description: Data no horário local após o qual um certificado não é mais válido + format: date-time + thumbprint: + type: string + description: A impressão digital do certificado + federalTaxNumber: + type: string + description: CNPJ da Empresa + modifiedOn: + type: string + description: Data de modificação + format: date-time + status: + type: string + description: Status do certificado + enum: + - inactive + - overdue + - pending + - active + - none + description: Certificado + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - Companies Certificates + summary: Upload de um Certificado + description: "### Informações adicionais\r\n\r\nUtilize esta requisição para fazer upload de um **Certificado da ICP-Brasil** do tipo __e-CNPJ A1__ ou __NFE A1__ em uma **Empresa** e vincula-lo para processamentos.\r\n\r\nO **Certificado da ICP-Brasil** funciona como uma identidade virtual, para empresas e pessoas, que permite a identificação segura e inequívoca do autor de uma mensagem ou transação feita em meios eletrônicos, como a web." + operationId: V2CompaniesByCompany_idCertificatesPost + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + requestBody: + content: + multipart/form-data: + schema: + required: + - file + - password + type: object + properties: + file: + type: string + description: Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12 + format: binary + password: + type: string + description: Senha do certificado ICP-Brasil + application/form-data: + schema: + required: + - file + - password + type: object + properties: + file: + type: string + description: Arquivo com certificado ICP-Brasil com extensão .pfx ou .p12 + format: binary + password: + type: string + description: Senha do certificado ICP-Brasil + required: true + responses: + "200": + description: Sucesso no upload e vinculo com a Empresa + content: + application/json: + schema: + type: object + properties: + certificate: + type: object + properties: + subject: + type: string + description: Nome do certificado (subject distinguished name) + validUntil: + type: string + description: Data no horário local após o qual um certificado não é mais válido + format: date-time + thumbprint: + type: string + description: A impressão digital do certificado + federalTaxNumber: + type: string + description: CNPJ da Empresa + modifiedOn: + type: string + description: Data de modificação + format: date-time + status: + type: string + description: Status do certificado + enum: + - inactive + - overdue + - pending + - active + - none + description: Certificado + description: Certificado + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{company_id}/certificates/{certificate_thumbprint}: + get: + tags: + - Companies Certificates + summary: Consultar um Certificado por sua impressão digital + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de um **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__)." + operationId: V2CompaniesByCompany_idCertificatesByCertificate_thumbprintGet + parameters: + - name: company_id + in: path + description: ID da Empresa relacionada ao certificado + required: true + schema: + type: string + - name: certificate_thumbprint + in: path + description: Impressão digital do certificado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + type: object + properties: + certificate: + type: object + properties: + subject: + type: string + description: Nome do certificado (subject distinguished name) + validUntil: + type: string + description: Data no horário local após o qual um certificado não é mais válido + format: date-time + thumbprint: + type: string + description: A impressão digital do certificado + federalTaxNumber: + type: string + description: CNPJ da Empresa + modifiedOn: + type: string + description: Data de modificação + format: date-time + status: + type: string + description: Status do certificado + enum: + - inactive + - overdue + - pending + - active + - none + description: Certificado + description: Certificado + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Certificado não encontrado + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + delete: + tags: + - Companies Certificates + summary: Excluir um Certificado por sua impressão digital + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir o **Certificado da ICP-Brasil** através da **impressão digital do certificado** (__thumbprint__) e desvincula-lo da **Empresa**.\r\n\r\n**ATENÇÃO pois esta requisição é irreversível**" + operationId: V2CompaniesByCompany_idCertificatesByCertificate_thumbprintDelete + parameters: + - name: company_id + in: path + description: ID da Empresa relacionada ao certificado + required: true + schema: + type: string + - name: certificate_thumbprint + in: path + description: Impressão digital do certificado + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão e desvinculo com a Empresa + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Certificado não encontrado + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{company_id}/statetaxes: + get: + tags: + - Companies State Taxes + summary: Listar as Inscrições Estaduais + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para listar as inscrições estaduais na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesGet + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: startingAfter + in: query + description: 'Id de início do contador (Default: Empty)' + schema: + type: string + - name: endingBefore + in: query + description: 'Id final do contador (Default: Empty)' + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + responses: + "200": + description: Sucesso na criação da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTaxes: + type: array + description: Lista de Inscriçoes Estaduais + items: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + post: + tags: + - Companies State Taxes + summary: Criar uma Inscrição Estadual + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novas inscrição estadual na empresa para processar __Documentos Fiscais__.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesPost + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + requestBody: + description: Dados da Inscrição Estadual a ser criada + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Criar uma Inscrição Estadual + text/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Criar uma Inscrição Estadual + application/*+json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Criar uma Inscrição Estadual + required: false + responses: + "200": + description: Sucesso na criação da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + /v2/companies/{company_id}/statetaxes/{state_tax_id}: + get: + tags: + - Companies State Taxes + summary: Consultar uma Inscrição Estadual pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar os dados de uma empresas pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesByState_tax_idGet + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: state_tax_id + in: path + description: ID da Inscrição Estadual que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Inscrição Estadual não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + put: + tags: + - Companies State Taxes + summary: Alterar uma Inscrição Estadual pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados de uma Inscrição Estadual pelo ID.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesByState_tax_idPut + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: state_tax_id + in: path + description: ID da Inscrição Estadual que deverá ser retornado + required: true + schema: + type: string + requestBody: + description: Dados da Inscrição Estadual a ser alterada + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Alterar uma Inscrição Estadual + text/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Alterar uma Inscrição Estadual + application/*+json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados para Alterar uma Inscrição Estadual + required: false + responses: + "200": + description: Sucesso na alteração da Inscrição Estadual + content: + application/json: + schema: + type: object + properties: + stateTax: + required: + - number + - serie + - taxNumber + type: object + properties: + companyId: + type: string + description: Código da Empresa + accountId: + type: string + description: Account Id + status: + type: string + description: Status no sistema + enum: + - inactive + - none + - active + series: + type: array + description: Todas as séries para esta Inscrição Estadual + items: + type: integer + format: int32 + createdOn: + type: string + description: Data de criação + format: date-time + modifiedOn: + type: string + description: Data de modificação + format: date-time + batchId: + type: integer + description: Número do Lote + format: int64 + id: + type: string + description: Identificador (gerado automaticamente) + code: + type: string + description: Código do Estado + enum: + - rO + - aC + - aM + - rR + - pA + - aP + - tO + - mA + - pI + - cE + - rN + - pB + - pE + - aL + - sE + - bA + - mG + - eS + - rJ + - sP + - pR + - sC + - rS + - mS + - mT + - gO + - dF + - eX + - nA + environmentType: + type: string + description: Ambiente + enum: + - none + - production + - test + taxNumber: + type: string + description: Inscrição Estadual + specialTaxRegime: + type: string + description: Tipo do regime especial de tributação + enum: + - automatico + - nenhum + - microempresaMunicipal + - estimativa + - sociedadeDeProfissionais + - cooperativa + - microempreendedorIndividual + - microempresarioEmpresaPequenoPorte + serie: + type: integer + description: Serie para a emissão NFe + format: int32 + number: + type: integer + description: Número para a emissão NFe + format: int64 + securityCredential: + type: object + properties: + id: + type: integer + description: Id do código de segurança do contribuinte + format: int32 + code: + type: string + description: Código de segurança do contribuinte + description: Código de segurança do contribuinte (necessário para emissão de NFCe) + type: + type: string + description: Tipo de emissão que será emitido | 0 - Default, 1 - NFe, 2 - NFCe + enum: + - default + - nFe + - nFCe + description: Dados da Inscrição Estadual + description: Dados da Inscrição Estadual + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Inscrição Estadual não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + x-codegen-request-body-name: body + delete: + tags: + - Companies State Taxes + summary: Excluir uma Inscrição Estadual pelo ID + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir uma Inscrição Estadual pelo ID, cuidado pois esse processo é irreversível.\r\n**Empresa** representa uma pessoa jurídica que precisa processar Documentos Fiscais.\r\n**Inscrição Estadual** representa os dados necessários sobre o cadastro Estadual (ICMS) que é preciso para processar Documentos Fiscais na SEFAZ." + operationId: V2CompaniesByCompany_idStatetaxesByState_tax_idDelete + parameters: + - name: company_id + in: path + description: ID da Empresa + required: true + schema: + type: string + - name: state_tax_id + in: path + description: ID da Inscrição Estadual que deverá ser retornado + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Inscrição Estadual + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Inscrição Estadual não encontrada + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - apiKey + - Authorization_QueryParam: + - apiKey + /v2/companies/{companyId}/productinvoices: + get: + tags: + - Product Invoices + summary: Listar as Notas Fiscais Eletrônicas (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar uma lista de notas fiscais eletrônicas por empresa." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: environment + in: query + description: Tipo de Ambiente é obrigatório (Production or Test) + required: true + schema: + $ref: '#/components/schemas/EnvironmentType' + - name: startingAfter + in: query + description: 'Id de início do contador (Default: Empty)' + schema: + type: string + - name: endingBefore + in: query + description: 'Id de fim do contador (Default: Empty)' + schema: + type: string + - name: q + in: query + description: "Buscar por parâmetros. (\"ElasticSearch string query\") Ex: (q=buyer.name:'EMPRESA LTDA'). Saiba mais\r\nem: https://nfe.io/docs/nota-fiscal-eletronica/integracao-api/consulta-elasticsearch" + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + default: 10 + responses: + "200": + description: Sucesso na consulta em lista + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoicesResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + post: + tags: + - Product Invoices + summary: Emitir uma Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal Eletrônica (NFE) para fila de emissão.\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante a emissão do documento fiscal.\r\nPara obter um retorno ao final do processo de emissão de uma Nota Fiscal Eletrônica (NFe), recomendamos\r\nutilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + requestBody: + description: Dados da nota fiscal a ser emitida + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + text/json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + application/*+json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + application/xml: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + text/xml: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + application/*+xml: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + responses: + "202": + description: Sucesso ao enfileirar para emissão + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}: + get: + tags: + - Product Invoices + summary: Consultar por ID uma Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Nota Fiscal Eletrônica (NFE) pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal Eletrônica que deverá ser retornada + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + $ref: '#/components/schemas/InvoiceResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + delete: + tags: + - Product Invoices + summary: Cancelar uma Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal Eletrônica (NFE) para fila de cancelamento.\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante o cancelamento do documento fiscal.\r\nPara obter um retorno ao final do processo de cancelamento de uma Nota Fiscal Eletrônica (NFe),\r\nrecomendamos utilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser cancelada + required: true + schema: + type: string + - name: reason + in: query + description: Motivo do cancelamento + schema: + type: string + responses: + "204": + description: Sucesso ao enfileirar para cancelamento + content: + application/json: + schema: + $ref: '#/components/schemas/RequestCancellationResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/items: + get: + tags: + - Product Invoices + summary: Consultar os produtos por ID uma Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Nota Fiscal Eletrônica (NFE) pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal Eletrônica que deverá ser retornada + required: true + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + default: 10 + - name: startingAfter + in: query + description: 'Índice de início do contador (Default: 0)' + schema: + type: integer + format: int32 + default: 0 + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + $ref: '#/components/schemas/InvoiceItemsResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/events: + get: + tags: + - Product Invoices + summary: Consultar eventos por ID uma Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma Nota Fiscal Eletrônica (NFE) pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal Eletrônica que deverá ser retornada + required: true + schema: + type: string + - name: limit + in: query + description: 'Limite de resultados na página (Default: 10)' + schema: + type: integer + format: int32 + default: 10 + - name: startingAfter + in: query + description: 'Índice de início do contador (Default: 0)' + schema: + type: integer + format: int32 + responses: + "200": + description: Sucesso na consulta + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceEventsResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/pdf: + get: + tags: + - Product Invoices + summary: Consultar PDF do Documento Auxiliar da Nota Fiscal Eletrônica (DANFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar a URL para o Documento Auxiliar Nota Fiscal Eletrônica (DANFE)\r\nem formato de arquivo PDF." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + - name: force + in: query + description: Força a geração do pdf independente do FlowStatus + schema: + type: boolean + default: false + responses: + "200": + description: Sucesso na consulta do DANFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/xml: + get: + tags: + - Product Invoices + summary: Consultar XML da Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados de uma nota fiscal Eletrônica pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/xml/rejection: + get: + tags: + - Product Invoices + summary: Consultar XML de rejeição da Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar o motivo da rejeição de uma nota fiscal Eletrônica pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/xml-rejection: + get: + tags: + - Product Invoices + summary: Consultar XML de rejeição da Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar o motivo da rejeição de uma nota fiscal Eletrônica pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/xml-epec: + get: + tags: + - Product Invoices + summary: Consultar XML da autorização em contingência (EPEC) + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/correctionletter: + put: + tags: + - Product Invoices + summary: Enviar uma carta de correção para Nota Fiscal Eletrônica (CC-e) + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma carta de correção na Nota Fiscal Eletrônica (NFE).\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante a execução do documento fiscal.\r\nPara obter um retorno ao final do processo de carta de correção de uma Nota Fiscal Eletrônica (NFe),\r\nrecomendamos utilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser cancelada + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/QueueEventResource' + text/json: + schema: + $ref: '#/components/schemas/QueueEventResource' + application/*+json: + schema: + $ref: '#/components/schemas/QueueEventResource' + application/xml: + schema: + $ref: '#/components/schemas/QueueEventResource' + text/xml: + schema: + $ref: '#/components/schemas/QueueEventResource' + application/*+xml: + schema: + $ref: '#/components/schemas/QueueEventResource' + responses: + "204": + description: Sucesso ao enfileirar para cancelamento + content: + application/json: + schema: + $ref: '#/components/schemas/RequestCancellationResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/correctionletter/pdf: + get: + tags: + - Product Invoices + summary: Consultar PDF do Documento Auxiliar da Nota Fiscal Eletrônica (DANFE) de Carta de Correção (CC-e) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar a URL para o Documento Auxiliar Nota Fiscal Eletrônica (DANFE)\r\nem formato de arquivo PDF." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do DANFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/correctionletter/xml: + get: + tags: + - Product Invoices + summary: Consultar XML da Carta de Correção Eletrônica (CC-e) + description: "### Informações adicionais\r\nUtilize esta requisição para consultar os dados da carta de correção de uma nota fiscal Eletrônica pelo ID." + parameters: + - name: companyId + in: path + description: ID da Empresa que deverá ser retornado + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser retornado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do XML da NFE + content: + application/json: + schema: + $ref: '#/components/schemas/FileResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/{invoiceId}/disablement: + post: + tags: + - Product Invoices + summary: Inutilizar uma Nota Fiscal Eletrônica (NFE) + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal Eletrônica (NFE) para fila de inutilização.\r\n**ATENÇÃO**: O processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante a inutilização do documento fiscal.\r\nPara obter um retorno ao final do processo de inutilização de uma Nota Fiscal Eletrônica (NFe),\r\nrecomendamos utilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + - name: invoiceId + in: path + description: ID da Nota Fiscal que deverá ser inutilizada + required: true + schema: + type: string + - name: reason + in: query + description: Motivo da inutilização + schema: + type: string + responses: + "204": + description: Sucesso ao enfileirar para inutilização + content: + application/json: + schema: + $ref: '#/components/schemas/RequestCancellationResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/productinvoices/disablement: + post: + tags: + - Product Invoices + summary: Inutilizar números de nota fiscal + description: "### Informações adicionais\r\nCaso seja um único número, utilizar o Número inicial e o Número final com o mesmo valor" + parameters: + - name: companyId + in: path + description: ID da Empresa + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DisablementResource' + text/json: + schema: + $ref: '#/components/schemas/DisablementResource' + application/*+json: + schema: + $ref: '#/components/schemas/DisablementResource' + application/xml: + schema: + $ref: '#/components/schemas/DisablementResource' + text/xml: + schema: + $ref: '#/components/schemas/DisablementResource' + application/*+xml: + schema: + $ref: '#/components/schemas/DisablementResource' + responses: + "200": + description: Sucesso + content: + application/json: + schema: + $ref: '#/components/schemas/DisablementResource' + "400": + description: Algum parâmetro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "404": + description: Nota Fiscal Eletrônica não encontrada + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/companies/{companyId}/statetaxes/{statetaxId}/productinvoices: + post: + tags: + - Product Invoices + summary: Emitir uma Nota Fiscal Eletrônica (NFE) Informando um StateTaxId + description: "### Informações adicionais\r\nUtilize esta requisição para enviar uma Nota Fiscal Eletrônica (NFE) para fila de emissão.\r\n**ATENÇÃO**: Cada processamento será feito de forma assíncrona, ou seja, o retorno positivo\r\nnão garante a emissão do documento fiscal.\r\nPara obter um retorno ao final do processo de emissão de uma Nota Fiscal Eletrônica (NFe), recomendamos\r\nutilizar os WebHooks." + parameters: + - name: companyId + in: path + description: Empresa ID + required: true + schema: + type: string + - name: statetaxId + in: path + description: Inscrição Estadual(StateTax) ID + required: true + schema: + type: string + requestBody: + description: Dados da nota fiscal a ser emitida + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + text/json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + application/*+json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + application/xml: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + text/xml: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + application/*+xml: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + responses: + "202": + description: Sucesso ao enfileirar para emissão + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceQueueIssueResource' + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "408": + description: Tempo limite de 60s excedido no enfileiramento + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + "500": + description: Erro no processamento + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + /v2/webhooks/eventtypes: + get: + tags: + - WebHooks + summary: Listar os Tipos de Eventos gerados pela plataforma + description: "### Informações adicionais\r\n\r\nEventos ocorrem a todo instante na plataforma durante os processamentos e são registrados\r\ncriando notificações para os webhooks ativos e configurados para receber os eventos.\r\n \r\nSão identificados seguindo o padrão **Resource.EventAction**,\r\nonde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\n\r\nEsse tipos podem ser utilizados como filtro ao criar ou alterar um webhook,\r\nsendo que o filtro determina quais notificações de eventos e ação serão enviadas\r\npara um determinado webhook, ou seja, dependendo de quais filtros são vinculados ao webhook\r\nele só receberá as notificações de evento e ação que correspondem a um ou mais desses filtros." + responses: + "200": + description: Sucesso na consulta do tipos de eventos + content: + application/json: + schema: + type: object + properties: + eventTypes: + type: array + description: Lista de Evento + items: + type: object + properties: + id: + type: string + description: "Identificador do evento, seguem o padrão **Resource.EventAction**.\r\nOnde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\nAlguns exemplos **Invoice.Issued** ou **Blob.Updated**" + description: + type: string + description: Descrição para o recurso, evento e ação exemplicando quando e onde eles ocorrem dentro na plataforma. + status: + type: integer + description: WebHook Filter Status + format: int32 + enum: + - 0 + - 1 + description: Tipo de Evento + description: Tipos de Eventos + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/webhooks: + get: + tags: + - WebHooks + summary: Listar os Webhooks + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar uma lista de **Webhooks** cadastrados na Conta Autenticada." + responses: + "200": + description: Sucesso na consulta da lista + content: + application/json: + schema: + type: object + properties: + webHooks: + type: array + description: Lista de Web Hook + items: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Web Hooks + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + post: + tags: + - WebHooks + summary: Criar um Webhook + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novos **Webhooks** para receber as notificações de eventos ocorridos na plataforma.\r\n \r\nNa criação do **Webhook** a URL informada no cadastro deve ser responsiva, ou seja, deverá responder *(HTTP Status 200 OK)* a uma requisição *(HTTP POST)* que será feita para testar se a URL está operando como normalmente, caso contrario uma mensagem de erro será retornada.\r\n \r\nUm **Webhook** é semelhante a uma assinatura em um *sistema de publicação e assinatura*\r\nque permite ao assinante indicar *quando*, *como* e *onde* as notificações de eventos deve ser despachadas.\r\nUm **Webhook** é registrado e gerenciado por Conta o que significa que cada Conta tem um conjunto separado de ganchos\r\nque podem ser acionados por eventos gerados através de ações executadas por esse Conta.\r\nOu seja, a **Conta da _Empresa A_** não verá os WebHooks disparados por uma ação executada pelo usuário **Conta da _Empresa B_**." + requestBody: + content: + application/json-patch+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + text/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + application/*+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: Dados para criar um Web Hook + description: Dados para criar um Web Hook + required: false + responses: + "201": + description: Sucesso na criação da webhook + content: + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Web Hook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + x-codegen-request-body-name: body + delete: + tags: + - WebHooks + summary: Excluir Todos os Webhooks existentes + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir todos os **Webhooks** cadastrados para a Conta Autenticada." + responses: + "204": + description: Sucesso na exclusão dos WebHooks + content: {} + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/webhooks/{webhook_id}: + get: + tags: + - WebHooks + summary: Consultar um webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar um **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id**." + operationId: RegistrationLookupAction + parameters: + - name: webhook_id + in: path + description: ID do webhook a ser consultado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do webhook + content: + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Web Hook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + put: + tags: + - WebHooks + summary: Alterar um Webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados do **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id** especificado." + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser atualizado + required: true + schema: + type: string + requestBody: + description: Dados para alterar o Webhook + content: + application/json-patch+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Dados para alterar um Web Hook + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Dados para alterar um Web Hook + text/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Dados para alterar um Web Hook + application/*+json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Dados para alterar um Web Hook + required: false + responses: + "200": + description: Sucesso na atualização da Webhook + content: + application/json: + schema: + type: object + properties: + webHook: + required: + - uri + type: object + properties: + id: + type: string + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + uri: + type: string + description: A URL onde as notificações dos eventos deverão entregues. + secret: + type: string + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + contentType: + type: integer + description: WebHook Media Type + format: int32 + enum: + - 0 + - 1 + insecureSsl: + type: boolean + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + status: + type: integer + description: WebHook Status + format: int32 + enum: + - 0 + - 1 + filters: + uniqueItems: true + type: array + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + items: + type: string + headers: + type: object + additionalProperties: + type: string + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + properties: + type: object + additionalProperties: + type: object + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + createdOn: + type: string + description: Data de criação do webhook + format: date-time + modifiedOn: + type: string + description: Data de modificação do webhook + format: date-time + description: WebHook (Notificação HTTP) + description: Web Hook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + x-codegen-request-body-name: body + delete: + tags: + - WebHooks + summary: Excluir um Webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir o **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id** especificado.\r\nA exclusão do **Webhook** não exime o **Webhook** excluído de receber os notificações de eventos, já ocorridos na plataforma, que ainda estejam em processo de retentativa de envio dos gatilhos." + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser excluído + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Webhook + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess + /v2/webhooks/{webhook_id}/pings: + put: + tags: + - WebHooks + summary: Criar notificação para Testar um webhook + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar uma notificação de teste (ping) em um **Webhook** já cadastrado.\r\n\r\nEsta ação irá criar um evento de notificação do tipo ping para o **Webhook** especificado, deste modo você poderá simular o recebimento de uma notificação de teste no **Webhook** cadastrado." + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser testado + required: true + schema: + type: string + responses: + "204": + description: Sucesso ao criar notificação de teste + content: {} + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + content: {} + "403": + description: Accesso proibido + content: {} + "404": + description: Webhook não encontrado + content: {} + "500": + description: Erro no processamento + content: + application/json: + schema: + type: object + properties: + errors: + type: array + description: Lista de Erros + items: + type: object + properties: + code: + type: integer + description: Código do erro + format: int32 + message: + type: string + description: Mensagem contendo os detalhes do erro + description: Erro + description: Lista de Erros + security: + - Authorization_Header: + - readAccess + - writeAccess + Authorization_QueryParam: + - readAccess + - writeAccess +components: + schemas: + ActivityResource: + type: object + properties: + data: + description: Detalhes do Evento + nullable: true + type: + type: string + description: Nome do Evento gerado + nullable: true + sequence: + type: integer + description: Número sequencial do Evento + format: int32 + nullable: true + additionalProperties: false + AdditionResource: + type: object + properties: + code: + type: integer + description: Numero da adição (nAdicao) + format: int64 + nullable: true + manufacturer: + type: string + description: Código do fabricante estrangeiro (cFabricante) + nullable: true + amount: + type: number + description: Valor do desconto do item da DI – Adição (vDescDI) + format: double + nullable: true + drawback: + type: integer + description: Número do ato concessório de Drawback (nDraw) + format: int64 + nullable: true + additionalProperties: false + description: Adições (adi) + AdditionalInformationResource: + type: object + properties: + fisco: + type: string + description: Informações Adicionais de Interesse do Fisco (infAdFisco) + nullable: true + taxpayer: + type: string + description: Informações Complementares de interesse do Contribuinte (infCpl) + nullable: true + xmlAuthorized: + type: array + items: + type: integer + format: int64 + description: Informações Complementares de interesse do Contribuinte (infCpl) + nullable: true + effort: + type: string + nullable: true + order: + type: string + nullable: true + contract: + type: string + nullable: true + taxDocumentsReference: + type: array + items: + $ref: '#/components/schemas/TaxDocumentsReferenceResource' + description: Documentos Fiscais Referenciados (refECF) + nullable: true + taxpayerComments: + type: array + items: + $ref: '#/components/schemas/TaxpayerCommentsResource' + description: Observações fiscais (obsCont) + nullable: true + referencedProcess: + type: array + items: + $ref: '#/components/schemas/ReferencedProcessResource' + description: Processos referenciados (procRef) + nullable: true + additionalProperties: false + AddressResource: + type: object + required: + - state + - city + - district + - street + - number + properties: + state: + type: string + description: 'Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2.' + city: + $ref: '#/components/schemas/CityResource' + district: + type: string + description: Bairro do Endereço + additionalInformation: + type: string + description: 'Complemento do Endereço, ex.: AP 2, BL A.' + nullable: true + street: + type: string + description: Logradouro do Endereço + number: + type: string + description: Número do Endereço. Usar S/N para "sem número". + postalCode: + type: string + description: Cód. Endereço Postal (CEP) + nullable: true + country: + type: string + description: 'País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3.' + nullable: true + phone: + type: string + description: Telefone + nullable: true + additionalProperties: false + description: Dados do Endereço + AuthorizationResource: + type: object + properties: + receiptOn: + type: string + format: date-time + nullable: true + accessKey: + type: string + nullable: true + message: + type: string + nullable: true + additionalProperties: false + BillResource: + type: object + properties: + number: + type: string + description: Número da Fatura (nFat) + nullable: true + originalAmount: + type: number + description: Valor Original da Fatura (vOrig) + format: double + nullable: true + discountAmount: + type: number + description: Valor do desconto (vDesc) + format: double + nullable: true + netAmount: + type: number + description: Valor Líquido da Fatura (vLiq) + format: double + nullable: true + additionalProperties: false + BillingResource: + type: object + properties: + bill: + $ref: '#/components/schemas/BillResource' + duplicates: + type: array + items: + $ref: '#/components/schemas/DuplicateResource' + description: Grupo Duplicata (dup) + nullable: true + additionalProperties: false + BuyerResource: + type: object + required: + - name + - federalTaxNumber + - address + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumberIndicator: + $ref: '#/components/schemas/ReceiverStateTaxIndicator' + tradeName: + type: string + description: Nome fantasia + nullable: true + taxRegime: + $ref: '#/components/schemas/TaxRegime' + stateTaxNumber: + type: string + description: Inscrição Estadual (IE) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo de endereço do Destinatário da NF-e" + CIDEResource: + type: object + properties: + bc: + type: number + description: BC da CIDE (qBCProd) + format: double + nullable: true + rate: + type: number + description: Valor da alíquota da CIDE (vAliqProd) + format: double + nullable: true + cideAmount: + type: number + description: Valor da CIDE (vCIDE) + format: double + nullable: true + additionalProperties: false + CardResource: + type: object + properties: + federalTaxNumber: + type: string + description: CNPJ da Credenciadora de cartão de crédito e/ou débito (CNPJ) + nullable: true + flag: + $ref: '#/components/schemas/FlagCard' + authorization: + type: string + description: Número de autorização da operação cartão de crédito e/ou débito (cAut) + nullable: true + integrationPaymentType: + $ref: '#/components/schemas/IntegrationPaymentType' + federalTaxNumberRecipient: + type: string + description: CNPJ do beneficiário do pagamento (CNPJReceb) + nullable: true + idPaymentTerminal: + type: string + description: Identificador do terminal de pagamento (idTermPag) + nullable: true + additionalProperties: false + CityResource: + type: object + required: + - code + - name + properties: + code: + type: string + description: Cód. do Município, segundo o Tabela de Municípios do IBGE + name: + type: string + description: Nome do Município + additionalProperties: false + CofinsTaxResource: + type: object + properties: + cst: + type: string + description: Código de Situação Tributária da COFINS + nullable: true + baseTax: + type: number + description: Valor da Base de Cálculo da COFINS (vBC) + format: double + nullable: true + rate: + type: number + description: Alíquota da COFINS (em percentual) (pCOFINS) + format: double + nullable: true + amount: + type: number + description: Valor da COFINS (vCOFINS) + format: double + nullable: true + baseTaxProductQuantity: + type: number + description: Quantidade Vendida (qBCProd) + format: double + nullable: true + productRate: + type: number + description: Alíquota da COFINS (em reais) (vAliqProd) + format: double + nullable: true + additionalProperties: false + description: "Grupo do COFINS\r\n\r\nID: S01\r\nPai: M01\r\n\r\n Obs: Informar apenas um dos grupos S02, S03, S04 ou S04\r\n com base valor atribuído ao campo S06 – CST do COFINS\r\n" + ConsumerPresenceType: + enum: + - None + - Presence + - Internet + - Telephone + - Delivery + - OthersNonPresenceOperation + type: string + description: | + Indicador de Presença do comprador no estabelecimento comercial no momento da operação (indPres). + Valores possíveis: + - `None` (0): Não se aplica (ex: nota fiscal complementar ou de ajuste) + - `Presence` (1): Operação presencial + - `Internet` (2): Operação não presencial, pela Internet + - `Telephone` (3): Operação não presencial, Teleatendimento + - `Delivery` (4): NFC-e em operação com entrega a domicílio + - `OthersNonPresenceOperation` (9): Outros, operação não presencial + ConsumerType: + enum: + - FinalConsumer + - Normal + type: string + description: | + Indica operação com Consumidor final (indFinal). + Valores possíveis: + - `Normal` (0): Não é consumidor final (revenda, industrialização etc.) — padrão para CNPJ + - `FinalConsumer` (1): Consumidor final — padrão para CPF/NIF + ContingencyDetails: + type: object + properties: + authorizer: + $ref: '#/components/schemas/StateTaxProcessingAuthorizer' + startedOn: + type: string + description: Data e hora do início da contingência + format: date-time + reason: + type: string + description: Justificativa da entrada em contingência + nullable: true + additionalProperties: false + DeliveryInformationResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumber: + type: string + description: Inscrição Estadual (IE) + nullable: true + additionalProperties: false + description: Identificação do Local de entrega (entrega) + Destination: + enum: + - None + - Internal_Operation + - Interstate_Operation + - International_Operation + type: string + description: | + Identificador de local de destino da operação (idDest). + Valores possíveis: + - `None` (0): Nenhum + - `Internal_Operation` (1): Operação interna (mesma UF) + - `Interstate_Operation` (2): Operação interestadual (UFs diferentes) + - `International_Operation` (3): Operação com o exterior + DisablementResource: + type: object + properties: + environment: + $ref: '#/components/schemas/EnvironmentType' + serie: + type: integer + description: Série + format: int32 + state: + $ref: '#/components/schemas/StateCode' + beginNumber: + type: integer + description: Número inicial + format: int32 + lastNumber: + type: integer + description: Número final (usar o mesmo número inicial se for apenas um número) + format: int32 + reason: + type: string + description: Motivo da inutilização + nullable: true + additionalProperties: false + description: Dados para inutilizar números de nota fiscal + DocumentElectronicInvoiceResource: + type: object + properties: + accessKey: + type: string + description: Chave de Acesso (refNFe) + nullable: true + additionalProperties: false + DocumentInvoiceReferenceResource: + type: object + properties: + state: + type: number + description: Código da UF (cUF) + format: double + nullable: true + yearMonth: + type: string + description: Ano / Mês (AAMM) + nullable: true + federalTaxNumber: + type: string + description: CNPJ (CNPJ) + nullable: true + model: + type: string + description: Modelo (mod) + nullable: true + series: + type: string + description: Série (serie) + nullable: true + number: + type: string + description: Número (nNF) + nullable: true + additionalProperties: false + DuductionIndicator: + enum: + - NotDeduct + - Deduce + type: string + description: | + Indicador de intermediador/marketplace na operação (indIntermed). + Valores possíveis: + - `NotDeduct` (0): Operação sem intermediador (em site ou plataforma própria) + - `Deduce` (1): Operação em site ou plataforma de terceiros (marketplace) + DuplicateResource: + type: object + properties: + number: + type: string + description: Número da Duplicata (nDup) + nullable: true + expirationOn: + type: string + description: Data de vencimento (dVenc) + format: date-time + nullable: true + amount: + type: number + description: Valor da duplicata (vDup) + format: double + nullable: true + additionalProperties: false + EconomicActivityResource: + type: object + properties: + type: + $ref: '#/components/schemas/EconomicActivityType' + code: + type: integer + description: Código da Atividade da Empresa + format: int32 + nullable: true + additionalProperties: false + EconomicActivityType: + enum: + - Main + - Secondary + type: string + description: | + Tipo da atividade econômica da empresa. + Valores possíveis: + - `Main`: Atividade principal (CNAE primário) + - `Secondary`: Atividade secundária (CNAE secundário) + EnvironmentType: + enum: + - None + - Production + - Test + type: string + description: | + Ambiente de processamento da nota fiscal (tpAmb). + Valores possíveis: + - `None` (0): Nenhum + - `Production` (1): Produção — emite nota com validade fiscal + - `Test` (2): Homologação — emite nota apenas para testes, sem validade fiscal + ErrorResource: + type: object + properties: + code: + type: integer + format: int32 + nullable: true + message: + type: string + nullable: true + additionalProperties: false + ErrorsResource: + type: object + properties: + errors: + type: array + items: + $ref: '#/components/schemas/ErrorResource' + nullable: true + readOnly: true + additionalProperties: false + ExemptReason: + enum: + - Agriculture + - Others + - DevelopmentEntities + type: string + description: | + Motivo da desoneração do ICMS (motDesICMS). + Valores possíveis: + - `Agriculture` (3): Uso na agropecuária + - `Others` (9): Outros + - `DevelopmentEntities` (12): Órgão de fomento e desenvolvimento agropecuário + ExportDetailResource: + type: object + properties: + drawback: + type: string + description: Número do ato concessório de Drawback (nDraw) + nullable: true + hintInformation: + $ref: '#/components/schemas/ExportHintResource' + additionalProperties: false + ExportHintResource: + type: object + properties: + registryId: + type: string + description: Número do Registro de Exportação (nRE) + nullable: true + accessKey: + type: string + description: Chave de Acesso da NF-e recebida para exportação (chNFe) + nullable: true + quantity: + type: number + description: Quantidade do item realmente exportado (qExport) + format: double + nullable: true + additionalProperties: false + ExportResource: + type: object + properties: + state: + $ref: '#/components/schemas/StateCode' + office: + type: string + description: Descrição do Local de Embarque ou de transposição de fronteira (xLocExporta) + nullable: true + local: + type: string + description: Informações Complementares de interesse do Contribuinte (xLocDespacho) + nullable: true + additionalProperties: false + FileResource: + type: object + properties: + uri: + type: string + description: Endereço Absoluto URI para o arquivo + nullable: true + additionalProperties: false + description: Arquivo + FlagCard: + enum: + - None + - Visa + - Mastercard + - AmericanExpress + - Sorocred + - DinersClub + - Elo + - Hipercard + - Aura + - Cabal + - Alelo + - BanesCard + - CalCard + - Credz + - Discover + - GoodCard + - GreenCard + - Hiper + - JCB + - Mais + - MaxVan + - Policard + - RedeCompras + - Sodexo + - ValeCard + - Verocheque + - VR + - Ticket + - Other + type: string + description: | + Bandeira da operadora de cartão de crédito/débito (tBand). + Valores possíveis: + - `None` (00): Nenhuma + - `Visa` (01): Visa + - `Mastercard` (02): Mastercard + - `AmericanExpress` (03): American Express + - `Sorocred` (04): Sorocred + - `DinersClub` (05): Diners Club + - `Elo` (06): Elo + - `Hipercard` (07): Hipercard + - `Aura` (08): Aura + - `Cabal` (09): Cabal + - `Alelo` (10): Alelo + - `BanesCard` (11): Banes Card + - `CalCard` (12): Cal Card + - `Credz` (13): Credz + - `Discover` (14): Discover + - `GoodCard` (15): Good Card + - `GreenCard` (16): Green Card + - `Hiper` (17): Hiper + - `JCB` (18): JCB + - `Mais` (19): Mais + - `MaxVan` (20): MaxVan + - `Policard` (21): Policard + - `RedeCompras` (22): RedeCompras + - `Sodexo` (23): Sodexo + - `ValeCard` (24): ValeCard + - `Verocheque` (25): Verocheque + - `VR` (26): VR + - `Ticket` (27): Ticket + - `Other` (99): Outros + FuelOriginResource: + type: object + properties: + indImport: + type: integer + description: Indicador de importação (indImport) + format: int32 + nullable: true + cUFOrig: + type: integer + description: Código da UF (cUFOrig) + format: int32 + nullable: true + pOrig: + type: number + description: Percentual originário para a UF (pOrig) + format: double + nullable: true + additionalProperties: false + VehicleDetailResource: + type: object + description: Detalhamento de Veículos novos (veicProd) - grupo J01 + properties: + operationType: + type: integer + description: "Tipo da Operação (tpOp). 0-Outros; 1-Venda concessionária; 2-Faturamento direto para consumidor final; 3-Venda direta para grandes consumidores" + format: int32 + enum: [0, 1, 2, 3] + nullable: true + chassis: + type: string + description: Chassi do veículo - VIN (chassi). 17 caracteres alfanuméricos + minLength: 17 + maxLength: 17 + pattern: "^[A-Z0-9]+$" + nullable: true + colorCode: + type: string + description: Cor do veículo - código de cada montadora (cCor) + maxLength: 4 + nullable: true + colorDescription: + type: string + description: Descrição da Cor (xCor) + maxLength: 40 + nullable: true + enginePower: + type: string + description: Potência máxima do motor em cavalo vapor - CV (pot) + maxLength: 4 + nullable: true + engineDisplacement: + type: string + description: Capacidade volumétrica do motor em centímetros cúbicos - CC (cilin) + maxLength: 4 + nullable: true + netWeight: + type: string + description: Peso Líquido (pesoL) + maxLength: 9 + nullable: true + grossWeight: + type: string + description: Peso Bruto (pesoB) + maxLength: 9 + nullable: true + serialNumber: + type: string + description: Serial - série (nSerie) + maxLength: 9 + nullable: true + fuelType: + type: string + description: "Tipo de combustível - Tabela RENAVAM (tpComb). Ex: 01-Álcool; 02-Gasolina; 03-Diesel; 16-Álcool/Gas.; 17-Gas./Álcool/GNV; 18-Gasolina/Elétrico" + maxLength: 2 + nullable: true + engineNumber: + type: string + description: Número do motor (nMotor) + maxLength: 21 + nullable: true + maximumTractionCapacity: + type: string + description: Capacidade Máxima de Tração em toneladas - 4 casas decimais (CMT) + maxLength: 9 + nullable: true + wheelBase: + type: string + description: Distância entre eixos (dist) + maxLength: 4 + nullable: true + modelYear: + type: integer + description: "Ano Modelo de Fabricação (anoMod). Formato: 4 dígitos" + format: int32 + nullable: true + manufactureYear: + type: integer + description: "Ano de Fabricação (anoFab). Formato: 4 dígitos" + format: int32 + nullable: true + paintType: + type: string + description: Tipo de pintura (tpPint) + maxLength: 1 + nullable: true + vehicleType: + type: string + description: Tipo de veículo - Tabela RENAVAM (tpVeic) + maxLength: 2 + nullable: true + vehicleSpecies: + type: integer + description: Espécie de veículo - Tabela RENAVAM (espVeic) + format: int32 + nullable: true + vinCondition: + type: string + description: Condição do VIN - chassi (VIN). R-Remarcado; N-Normal + enum: ["R", "N"] + nullable: true + vehicleCondition: + type: integer + description: Condição do veículo (condVeic). 1-Acabado; 2-Inacabado; 3-Semi-acabado + format: int32 + enum: [1, 2, 3] + nullable: true + brandModelCode: + type: string + description: Código Marca Modelo - Tabela RENAVAM (cMod) + maxLength: 6 + nullable: true + denatranColorCode: + type: string + description: Código da Cor DENATRAN (cCorDENATRAN). 01-AMARELO; 02-AZUL; 03-BEGE; 04-BRANCA; 05-CINZA; 06-DOURADA; 07-GRENA; 08-LARANJA; 09-MARROM; 10-PRATA; 11-PRETA; 12-ROSA; 13-ROXA; 14-VERDE; 15-VERMELHA; 16-FANTASIA + maxLength: 2 + nullable: true + seatingCapacity: + type: integer + description: Quantidade máxima de passageiros sentados, inclusive motorista (lota) + format: int32 + nullable: true + restrictionType: + type: integer + description: Restrição (tpRest). 0-Não há; 1-Alienação Fiduciária; 2-Arrendamento Mercantil; 3-Reserva de Domínio; 4-Penhor de Veículos; 9-Outras + format: int32 + enum: [0, 1, 2, 3, 4, 9] + nullable: true + additionalProperties: false + FuelResource: + type: object + properties: + codeANP: + type: string + description: Código de produto da ANP (cProdANP) + nullable: true + percentageNG: + type: number + description: Percentual de Gás Natural para o produto GLP (cProdANP=210203001) (pMixGN) + format: double + nullable: true + descriptionANP: + type: string + description: Descrição do produto conforme ANP (descANP) + nullable: true + percentageGLP: + type: number + description: Percentual do GLP derivado do petróleo no produto GLP (cProdANP=210203001) (pGLP) + format: double + nullable: true + percentageNGn: + type: number + description: Percentual de Gás Natural Nacional – GLGNn para o produto GLP (cProdANP= 210203001) (pGNn) + format: double + nullable: true + percentageGNi: + type: number + description: Percentual de Gás Natural Importado – GLGNi para o produto GLP (cProdANP= 210203001) (pGNi) + format: double + nullable: true + startingAmount: + type: number + description: Valor de partida (cProdANP=210203001) (vPart) + format: double + nullable: true + codif: + type: string + description: Código de autorização / registro do CODIF (CODIF) + nullable: true + amountTemp: + type: number + description: Quantidade de combustível faturada à temperatura ambiente (qTemp) + format: double + nullable: true + stateBuyer: + type: string + description: Sigla da UF de consumo (UFCons) + nullable: true + cide: + $ref: '#/components/schemas/CIDEResource' + pump: + $ref: '#/components/schemas/PumpResource' + fuelOrigin: + $ref: '#/components/schemas/FuelOriginResource' + additionalProperties: false + ICMSTotal: + type: object + properties: + baseTax: + type: number + description: Base de Cálculo do ICMS (vBC) + format: double + nullable: true + icmsAmount: + type: number + description: Valor Total do ICMS (vICMS) + format: double + nullable: true + icmsExemptAmount: + type: number + description: Valor ICMS Total desonerado (vICMSDeson) + format: double + nullable: true + stCalculationBasisAmount: + type: number + description: Base de Cálculo do ICMS Substituição Tributária (vBCST) + format: double + nullable: true + stAmount: + type: number + description: Valor Total do ICMS ST (vST) + format: double + nullable: true + productAmount: + type: number + description: Valor Total dos produtos e serviços (vProd) + format: double + freightAmount: + type: number + description: Valor Total do Frete (vFrete) + format: double + nullable: true + insuranceAmount: + type: number + description: Valor Total do Seguro (vSeg) + format: double + nullable: true + discountAmount: + type: number + description: Valor Total do Desconto (vDesc) + format: double + nullable: true + iiAmount: + type: number + description: Valor Total do Imposto de Importação (vII) + format: double + nullable: true + ipiAmount: + type: number + description: Valor Total do IPI (vIPI) + format: double + nullable: true + pisAmount: + type: number + description: Valor do PIS (vPIS) + format: double + nullable: true + cofinsAmount: + type: number + description: Valor do COFINS (vCOFINS) + format: double + nullable: true + othersAmount: + type: number + description: Outras Despesas acessórias (vOutro) + format: double + nullable: true + invoiceAmount: + type: number + description: Valor Total da NF-e (vNF) + format: double + fcpufDestinationAmount: + type: number + description: Valor Total ICMS FCP UF Destino + format: double + nullable: true + icmsufDestinationAmount: + type: number + description: Valor Total ICMS Interestadual UF Destino + format: double + nullable: true + icmsufSenderAmount: + type: number + description: Valor Total ICMS Interestadual UF Rem. + format: double + nullable: true + federalTaxesAmount: + type: number + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + format: double + fcpAmount: + type: number + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + format: double + nullable: true + fcpstAmount: + type: number + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido por substituição tributária. + format: double + nullable: true + fcpstRetAmount: + type: number + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido anteriormente por substituição tributária. + format: double + nullable: true + ipiDevolAmount: + type: number + description: Valor total do IPI devolvido (vIPIDevol) + format: double + nullable: true + qBCMono: + type: number + format: double + nullable: true + vICMSMono: + type: number + description: Valor total do ICMS monofásico próprio (vICMSMono). + format: double + nullable: true + qBCMonoReten: + type: number + description: Valor total da quantidade tributada do ICMS monofásico sujeito a retenção (qBCMonoReten). + format: double + nullable: true + vICMSMonoReten: + type: number + description: Valor total da quantidade tributada do ICMS monofásico retido anteriormente(vICMSMonoReten) + format: double + nullable: true + qBCMonoRet: + type: number + description: Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet) + format: double + nullable: true + vICMSMonoRet: + type: number + description: Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet) + format: double + nullable: true + additionalProperties: false + description: "Manual Contribuinte v_5.00\r\nGrupo de Valores Totais referentes ao ICMS" + ICMSTotalResource: + type: object + properties: + baseTax: + type: number + description: Base de Cálculo do ICMS (vBC) + format: double + nullable: true + icmsAmount: + type: number + description: Valor Total do ICMS (vICMS) + format: double + nullable: true + icmsExemptAmount: + type: number + description: Valor ICMS Total desonerado (vICMSDeson) + format: double + nullable: true + stCalculationBasisAmount: + type: number + description: Base de Cálculo do ICMS Substituição Tributária (vBCST) + format: double + nullable: true + stAmount: + type: number + description: Valor Total do ICMS ST (vST) + format: double + nullable: true + productAmount: + type: number + description: Valor Total dos produtos e serviços (vProd) + format: double + nullable: true + freightAmount: + type: number + description: Valor Total do Frete (vFrete) + format: double + nullable: true + insuranceAmount: + type: number + description: Valor Total do Seguro (vSeg) + format: double + nullable: true + discountAmount: + type: number + description: Valor Total do Desconto (vDesc) + format: double + nullable: true + iiAmount: + type: number + description: Valor Total do Imposto de Importação (vII) + format: double + nullable: true + ipiAmount: + type: number + description: Valor Total do IPI (vIPI) + format: double + nullable: true + pisAmount: + type: number + description: Valor do PIS (vPIS) + format: double + nullable: true + cofinsAmount: + type: number + description: Valor do COFINS (vCOFINS) + format: double + nullable: true + othersAmount: + type: number + description: Outras Despesas acessórias (vOutro) + format: double + nullable: true + invoiceAmount: + type: number + description: Valor Total da NF-e (vNF) + format: double + nullable: true + fcpufDestinationAmount: + type: number + description: Valor Total ICMS FCP UF Destino (vFCPUFDest) + format: double + nullable: true + icmsufDestinationAmount: + type: number + description: Valor Total ICMS Interestadual UF Destino (vICMSUFDest) + format: double + nullable: true + icmsufSenderAmount: + type: number + description: Valor Total ICMS Interestadual UF Remetente (vICMSUFRemet) + format: double + nullable: true + federalTaxesAmount: + type: number + description: Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib) + format: double + nullable: true + fcpAmount: + type: number + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + format: double + nullable: true + fcpstAmount: + type: number + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (vFCPST) + format: double + nullable: true + fcpstRetAmount: + type: number + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (vFCPSTRet) + format: double + nullable: true + ipiDevolAmount: + type: number + description: Valor total do IPI devolvido (vIPIDevol) + format: double + nullable: true + qBCMono: + type: number + description: Valor total da quantidade tributada do ICMS monofásico próprio (qBCMono) + format: double + nullable: true + vICMSMono: + type: number + description: Valor total do ICMS monofásico próprio (vICMSMono) + format: double + nullable: true + qBCMonoReten: + type: number + description: Valor total da quantidade tributada do ICMS monofásico sujeito a retenção(qBCMonoReten) + format: double + nullable: true + vICMSMonoReten: + type: number + description: Valor total do ICMS monofásico sujeito a retenção (vICMSMonoReten) + format: double + nullable: true + qBCMonoRet: + type: number + description: Valor total da quantidade tributada do ICMS monofásico retido anteriormente(qBCMonoRet) + format: double + nullable: true + vICMSMonoRet: + type: number + description: Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet) + format: double + nullable: true + additionalProperties: false + description: "Manual Contribuinte v_5.00\r\nGrupo de Valores Totais referentes ao ICMS" + ICMSUFDestinationTaxResource: + type: object + properties: + vBCUFDest: + type: number + description: Valor da Base de Cálculo do ICMS na UF de destino (vBCUFDest) + format: double + nullable: true + pFCPUFDest: + type: number + description: Percentual adicional inserido na alíquota interna da UF de destino, relativo ao Fundo de Combate à Pobreza (FCP) naquela UF (pFCPUFDest) + format: double + nullable: true + pICMSUFDest: + type: number + description: Alíquota adotada nas operações internas na UF de destino para o produto / mercadoria (pICMSUFDest) + format: double + nullable: true + pICMSInter: + type: number + description: Alíquota interestadual das UF envolvidas (pICMSInter) + format: double + nullable: true + pICMSInterPart: + type: number + description: Percentual de ICMS Interestadual para a UF de destino (pICMSInterPart) + format: double + nullable: true + vFCPUFDest: + type: number + description: Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP) da UF de destino (vFCPUFDest + format: double + nullable: true + vICMSUFDest: + type: number + description: Valor do ICMS Interestadual para a UF de destino (vICMSUFDest) + format: double + nullable: true + vICMSUFRemet: + type: number + description: Valor do ICMS Interestadual para a UF do remetente (vICMSUFRemet) + format: double + nullable: true + vBCFCPUFDest: + type: number + description: Valor da BC FCP na UF de destino (vBCFCPUFDest) + format: double + nullable: true + additionalProperties: false + description: Grupo de Tributação do ICMS de Destino da UF + IITaxResource: + type: object + properties: + baseTax: + type: string + description: Valor BC do Imposto de Importação (vBC) + nullable: true + customsExpenditureAmount: + type: string + description: Valor despesas aduaneiras (vDespAdu) + nullable: true + amount: + type: number + description: Valor Imposto de Importação (vII) + format: double + nullable: true + iofAmount: + type: number + description: Valor Imposto sobre Operações Financeiras (vIOF) + format: double + nullable: true + vEnqCamb: + type: number + description: Valor dos encargos cambiais + format: double + nullable: true + additionalProperties: false + description: "Grupo do Imposto de Importação\r\n\r\nId: P01\r\nPai: O01" + IPITaxResource: + type: object + properties: + cst: + type: string + description: Código da situação tributária do IPI (CST) + nullable: true + classificationCode: + type: string + description: Código de Enquadramento Legal do IPI (cEnq) + nullable: true + classification: + type: string + description: "clEnq\r\nClasse de enquadramento do IPI para Cigarros e Bebidas (clEnq)" + nullable: true + producerCNPJ: + type: string + description: CNPJ do produtor da mercadoria, quando diferente do emitente. Somente para os casos de exportação direta ou indireta (CNPJProd) + nullable: true + stampCode: + type: string + description: Código do selo de controle IPI (cSelo) + nullable: true + stampQuantity: + type: number + description: Quantidade de selo de controle (qSelo) + format: double + nullable: true + base: + type: number + description: Valor da BC do IPI (vBC) + format: double + nullable: true + rate: + type: number + description: Alíquota do IPI (pIPI) + format: double + nullable: true + unitQuantity: + type: number + description: Quantidade total na unidade padrão para tributação (somente para os produtos tributados por unidade) (qUnid) + format: double + nullable: true + unitAmount: + type: number + description: Valor por Unidade Tributável (vUnid) + format: double + nullable: true + amount: + type: number + description: Valor IPI (vIPI) + format: double + nullable: true + additionalProperties: false + description: "\r\nGrupo do IPI\r\n\r\nInformar apenas quando o item for sujeito ao IPI\r\n\r\nID: O01\r\n\r\nPai: M01" + ISSQNTotal: + type: object + properties: + totalServiceNotTaxedICMS: + type: number + description: Valor Total Serv.Não Tributados p/ ICMS + format: double + nullable: true + baseRateISS: + type: number + description: Base de Cálculo do ISS + format: double + nullable: true + totalISS: + type: number + description: Valor Total do ISS + format: double + nullable: true + valueServicePIS: + type: number + description: Valor do PIS sobre Serviços + format: double + nullable: true + valueServiceCOFINS: + type: number + description: Valor da COFINS sobre Serviços + format: double + nullable: true + provisionService: + type: string + description: Data Prestação Serviço + format: date-time + nullable: true + deductionReductionBC: + type: number + description: Valor Dedução para Redução da BC + format: double + nullable: true + valueOtherRetention: + type: number + description: Valor Outras Retenções + format: double + nullable: true + discountUnconditional: + type: number + description: Valor Desconto Incondicionado + format: double + nullable: true + discountConditioning: + type: number + description: Valor Desconto Condicionado + format: double + nullable: true + totalRetentionISS: + type: number + description: Valor Total Retenção ISS + format: double + nullable: true + codeTaxRegime: + type: number + description: Código Regime Tributação + format: double + nullable: true + additionalProperties: false + ISSQNTotalResource: + type: object + properties: + totalServiceNotTaxedICMS: + type: number + description: Valor Total Serv.Não Tributados p/ ICMS (vServ) + format: double + nullable: true + baseRateISS: + type: number + description: Base de Cálculo do ISS (vBC) + format: double + nullable: true + totalISS: + type: number + description: Valor Total do ISS (vISS) + format: double + nullable: true + valueServicePIS: + type: number + description: Valor do PIS sobre Serviços (vPIS) + format: double + nullable: true + valueServiceCOFINS: + type: number + description: Valor da COFINS sobre Serviços (vCOFINS) + format: double + nullable: true + provisionService: + type: string + description: Data Prestação Serviço (dCompet) + format: date-time + nullable: true + deductionReductionBC: + type: number + description: Valor Dedução para Redução da BC (vDeducao) + format: double + nullable: true + valueOtherRetention: + type: number + description: Valor Outras Retenções (vOutro) + format: double + nullable: true + discountUnconditional: + type: number + description: Valor Desconto Incondicionado (vDescIncond) + format: double + nullable: true + discountConditioning: + type: number + description: Valor Desconto Condicionado (vDescCond) + format: double + nullable: true + totalRetentionISS: + type: number + description: Valor Total Retenção ISS (vISSRet) + format: double + nullable: true + codeTaxRegime: + type: number + description: Código Regime Tributação (cRegTrib) + format: double + nullable: true + additionalProperties: false + IcmsTaxResource: + type: object + description: | + Grupo do ICMS da Operação própria e ST (ICMS). + **Regra de obrigatoriedade**: deve-se informar **exatamente um** entre `cst` (Regime Normal) ou `csosn` (Simples Nacional). A SEFAZ não aceita ambos preenchidos ou nenhum dos dois. + required: + - origin + properties: + origin: + type: string + description: Origem da mercadoria (orig) + cst: + type: string + description: Tributação do ICMS (CST) — obrigatório quando o emitente é do Regime Normal. Mutuamente exclusivo com `csosn`. + nullable: true + csosn: + type: string + description: "101- Tributada pelo Simples Nacional com permissão de crédito. (v.2.0) (CSOSN)\r\nCódigo de Situação da Operação – Simples Nacional" + nullable: true + baseTaxModality: + type: string + description: "Modalidade de determinação da BC do ICMS (modBC)\r\n\r\n Margem Valor Agregado (%) = 0\r\n Pauta (valor) = 1\r\n Preço Tabelado Máximo (valor) = 2\r\n Valor da Operação = 3\r\n" + nullable: true + baseTax: + type: number + description: Valor da BC do ICMS (vBC) + format: double + nullable: true + baseTaxSTModality: + type: string + description: Modalidade de determinação da BC do ICMS ST (modBCST) + nullable: true + baseTaxSTReduction: + type: string + description: "pRedBCST\r\nPercentual da Redução de BC do ICMS ST (pRedBCST)" + nullable: true + baseTaxST: + type: number + description: Valor da BC do ICMS ST (vBCST) + format: double + nullable: true + baseTaxReduction: + type: number + description: Percentual da Redução de BC (pRedBC) + format: double + nullable: true + stRate: + type: number + description: Alíquota do imposto do ICMS ST (pICMSST) + format: double + nullable: true + stAmount: + type: number + description: Valor do ICMS ST (vICMSST) + format: double + nullable: true + stMarginAmount: + type: number + description: "pMVAST\r\nPercentual da margem de valor Adicionado do ICMS ST (pMVAST)" + format: double + nullable: true + rate: + type: number + description: "pICMS\r\nAlíquota do imposto (pICMS)" + format: double + nullable: true + amount: + type: number + description: "Valor do ICMS (vICMS)\r\nO valor do ICMS desonerado será informado apenas nas operações:\r\na) com produtos beneficiados com a desoneração condicional do ICMS.\r\nb) destinadas à SUFRAMA, informando-se o valor que seria devido se não houvesse isenção.\r\nc) de venda a órgãos da administração pública direta e suas fundações e\r\nautarquias com isenção do ICMS. (NT 2011/004)" + format: double + nullable: true + percentual: + type: number + description: Percentual da Redução de BC (pICMS) + format: double + nullable: true + snCreditRate: + type: number + description: Alíquota aplicável de cálculo do crédito (Simples Nacional). (pCredSN) + format: double + nullable: true + snCreditAmount: + type: number + description: Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 Simples Nacional (vCredICMSSN) + format: double + nullable: true + stMarginAddedAmount: + type: string + description: Percentual da margem de valor Adicionado do ICMS ST (pMVAST) + nullable: true + stRetentionAmount: + type: string + description: Valor do ICMS ST retido (vICMSSTRet) + nullable: true + baseSTRetentionAmount: + type: string + description: Valor da BC do ICMS ST retido (vBCSTRet) + nullable: true + baseTaxOperationPercentual: + type: string + description: "Percentual da BC operação própria (pBCOp)\r\nPercentual para determinação do valor da Base de Cálculo da operação própria. (v2.0)" + nullable: true + ufst: + type: string + description: "UF para qual é devido o ICMS ST (UFST)\r\nSigla da UF para qual é devido o ICMS ST da operação. (v2.0)" + nullable: true + amountSTReason: + type: string + description: Motivo Desoneração ICMS + nullable: true + baseSNRetentionAmount: + type: string + description: Valor da BC do ICMS ST retido (vBCSTRet) + nullable: true + snRetentionAmount: + type: string + description: Valor do ICMS ST retido (vICMSSTRet) + nullable: true + amountOperation: + type: string + description: Valor do ICMS da Operação (vICMSOp) + nullable: true + percentualDeferment: + type: string + description: Percentual do Diferimento (pDif) + nullable: true + baseDeferred: + type: string + description: Valor do ICMS Diferido (vICMSDif) + nullable: true + exemptAmount: + type: number + description: Valor ICMS Desonerado + format: double + nullable: true + exemptReason: + $ref: '#/components/schemas/ExemptReason' + exemptAmountST: + type: number + description: Valor ICMS Desonerado + format: double + nullable: true + exemptReasonST: + $ref: '#/components/schemas/ExemptReason' + fcpRate: + type: number + description: Percentual do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCP) + format: double + nullable: true + fcpAmount: + type: number + description: Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) + format: double + nullable: true + fcpstRate: + type: number + description: Percentual do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (pFCPST) + format: double + nullable: true + fcpstAmount: + type: number + description: Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (vFCPST) + format: double + nullable: true + fcpstRetRate: + type: number + description: Percentual do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (pFCPSTRet) + format: double + nullable: true + fcpstRetAmount: + type: number + description: Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (vFCPSTRet) + format: double + nullable: true + baseTaxFCPSTAmount: + type: number + description: Informar o valor da Base de Cálculo do FCP (vBCFCPST) + format: double + nullable: true + substituteAmount: + type: number + description: 'Valor do ICMS próprio do Substituto (tag: vICMSSubstituto)' + format: double + nullable: true + stFinalConsumerRate: + type: number + description: "N26a - Alíquota suportada pelo Consumidor Final (pST)\r\nDeve ser informada a alíquota do cálculo do ICMS-ST, já incluso o FCP caso incida sobre a mercadoria" + format: double + nullable: true + effectiveBaseTaxReductionRate: + type: number + description: N34 - Percentual de redução da base de cálculo efetiva, caso estivesse submetida ao regime comum de tributação (pRedBCEfet) + format: double + nullable: true + effectiveBaseTaxAmount: + type: number + description: N35 - Valor da base de cálculo efetiva, caso estivesse submetida ao regime comum de tributação (vBCEfet) + format: double + nullable: true + effectiveRate: + type: number + description: N36 - Alíquota do ICMS efetiva, caso estivesse submetida ao regime comum de tributação (pICMSEFET) + format: double + nullable: true + effectiveAmount: + type: number + description: N37 - Valor do ICMS efetivo, caso estivesse submetida ao regime comum de tributação (vICMSEFET) + format: double + nullable: true + deductionIndicator: + $ref: '#/components/schemas/DuductionIndicator' + additionalProperties: false + ImportDeclarationResource: + type: object + properties: + code: + type: string + description: Número do Documento de Importação da DI/DSI/DA (nDI) + nullable: true + registeredOn: + type: string + description: Data de Registro da DI/DSI/DA (dDI) + format: date-time + nullable: true + customsClearanceName: + type: string + description: Local de desembaraço (xLocDesemb) + nullable: true + customsClearanceState: + $ref: '#/components/schemas/StateCode' + customsClearancedOn: + type: string + description: Data do Desembaraço Aduaneiro (dDesemb) + format: date-time + nullable: true + additions: + type: array + items: + $ref: '#/components/schemas/AdditionResource' + description: Adições (adi) + nullable: true + exporter: + type: string + description: Código do exportador (cExportador) + nullable: true + internationalTransport: + $ref: '#/components/schemas/InternationalTransportType' + intermediation: + $ref: '#/components/schemas/IntermediationType' + acquirerFederalTaxNumber: + type: string + description: CNPJ/CPF do adquirente ou do encomendante (CNPJ ou CPF) + nullable: true + stateThird: + type: string + description: Sigla da UF do adquirente ou do encomendante (UFTerceiro) + nullable: true + additionalProperties: false + description: Declaração Importação (DI) + IntegrationPaymentType: + enum: + - Integrated + - NotIntegrated + type: string + description: "1 - Pagamento integrado com o sistema de automação da empresa(Ex.: equipamento TEF, Comércio Eletrônico)\r\n2 - Pagamento não integrado com o sistema de automação da empresa(Ex.: equipamento POS);" + IntermediateResource: + type: object + properties: + federalTaxNumber: + type: integer + description: CNPJ do Intermediador da Transação (agenciador, plataforma de delivery, marketplace e similar) de serviços e de negócios. (CNPJ) + format: int64 + nullable: true + identifier: + type: string + description: Identificador cadastrado no intermediador (idCadIntTran) + nullable: true + additionalProperties: false + description: Grupo de Informações do Intermediador da Transação (infIntermed) + IntermediationType: + enum: + - None + - ByOwn + - ImportOnBehalf + - ByOrder + type: string + description: | + Tipo de Intermediação na operação de importação (tpIntermedio). + Valores possíveis: + - `None` (0): Nenhum + - `ByOwn` (1): Importação por conta própria + - `ImportOnBehalf` (2): Importação por conta e ordem + - `ByOrder` (3): Importação por encomenda + InternationalTransportType: + enum: + - None + - Maritime + - River + - Lake + - Airline + - Postal + - Railway + - Highway + - Network + - Own + - Ficta + - Courier + - Handcarry + type: string + description: | + Tipo de Transporte Internacional (tpViaTransp). + Valores possíveis: + - `None` (0): Nenhum + - `Maritime` (1): Marítima + - `River` (2): Fluvial + - `Lake` (3): Lacustre + - `Airline` (4): Aérea + - `Postal` (5): Postal + - `Railway` (6): Ferroviária + - `Highway` (7): Rodoviária + - `Network` (8): Conduto / Rede de Transmissão + - `Own` (9): Meios Próprios + - `Ficta` (10): Entrada / Saída ficta + - `Courier` (11): Courier + - `Handcarry` (12): Handcarry + InvoiceEventsResourceBase: + type: object + properties: + events: + type: array + items: + $ref: '#/components/schemas/ActivityResource' + description: Lista de Eventos ocorridos na Nota Fiscal + nullable: true + hasMore: + type: boolean + description: Identificador de possibilidade de mais itens. + nullable: true + additionalProperties: false + InvoiceItemResource: + type: object + required: + - code + - description + - ncm + - unit + - unitTax + - quantity + - unitAmount + - totalAmount + - tax + properties: + code: + type: string + description: Código do produto ou serviço (cProd) + codeGTIN: + type: string + description: "GTIN (Global Trade Item Number) do produto,\r\nantigo código EAN ou código de barras (cEAN)" + nullable: true + description: + type: string + description: Descrição do produto ou serviço (xProd) + ncm: + type: string + description: Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM) + nve: + type: array + items: + type: string + description: Nomenclatura de Valor aduaneiro e Estatístico (NVE) + nullable: true + extipi: + type: string + description: Código Exceção da Tabela de IPI + nullable: true + cfop: + type: integer + description: Código Fiscal de Operações e Prestações (CFOP) + format: int64 + nullable: true + unit: + type: string + description: Unidade Comercial (uCom) + quantity: + type: number + description: Quantidade Comercial (qCom) + format: double + unitAmount: + type: number + description: Valor Unitário de Comercialização (vUnCom) + format: double + totalAmount: + type: number + description: Valor Total Bruto dos Produtos ou Serviços (vProd) + format: double + codeTaxGTIN: + type: string + description: "GTIN (Global Trade Item Number) da unidade tributável,\r\nantigo código EAN ou código de barras (cEANTrib)" + nullable: true + unitTax: + type: string + description: Unidade Tributável (uTrib) + quantityTax: + type: number + description: Quantidade Tributável (qTrib) + format: double + nullable: true + taxUnitAmount: + type: number + description: Valor Unitário de tributação (vUnTrib) + format: double + nullable: true + freightAmount: + type: number + description: Valor Total do Frete (vFrete) + format: double + nullable: true + insuranceAmount: + type: number + description: Valor Total do Seguro (vSeg) + format: double + nullable: true + discountAmount: + type: number + description: Valor do Desconto (vDesc) + format: double + nullable: true + othersAmount: + type: number + description: Outras despesas acessórias (vOutro) + format: double + nullable: true + totalIndicator: + type: boolean + description: "Indica se valor do Item (vProd)\r\nentra no valor total da NF-e (vProd) (indTot)" + nullable: true + cest: + type: string + description: CEST - Código especificador da substituição tributária + nullable: true + tax: + $ref: '#/components/schemas/InvoiceItemTaxResource' + additionalInformation: + type: string + description: Informações Adicionais do Produto (infAdProd) + nullable: true + numberOrderBuy: + type: string + description: Número do pedido de compra (xPed) + nullable: true + itemNumberOrderBuy: + type: integer + description: Item do Pedido de Compra (nItemPed) + format: int32 + nullable: true + importControlSheetNumber: + type: string + description: Número de controle da FCI - Ficha de Conteúdo de Importação (nFCI) + nullable: true + vehicleDetail: + $ref: '#/components/schemas/VehicleDetailResource' + fuelDetail: + $ref: '#/components/schemas/FuelResource' + benefit: + type: string + description: Código de Benefício Fiscal na UF aplicado ao item (cBenef) + nullable: true + importDeclarations: + type: array + items: + $ref: '#/components/schemas/ImportDeclarationResource' + description: Declaração Importação (DI) + nullable: true + exportDetails: + type: array + items: + $ref: '#/components/schemas/ExportDetailResource' + description: Grupo de informações de exportação para o item (detExport) + nullable: true + taxDetermination: + $ref: '#/components/schemas/TaxDeterminationResource' + additionalProperties: false + description: "Manual Contribuinte v_5.00\r\nGrupo do detalhamento de Produtos e Serviços da NF-e" + InvoiceItemTaxResource: + type: object + required: + - icms + properties: + totalTax: + type: number + description: Valor aproximado total de tributos federais, estaduais e municipais (vTotTrib) + format: double + nullable: true + icms: + $ref: '#/components/schemas/IcmsTaxResource' + ipi: + $ref: '#/components/schemas/IPITaxResource' + ii: + $ref: '#/components/schemas/IITaxResource' + pis: + $ref: '#/components/schemas/PISTaxResource' + cofins: + $ref: '#/components/schemas/CofinsTaxResource' + icmsDestination: + $ref: '#/components/schemas/ICMSUFDestinationTaxResource' + additionalProperties: false + InvoiceItemsResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + companyId: + type: string + description: Identificador da Empresa + nullable: true + id: + type: string + description: Identificador da Nota Fiscal + nullable: true + items: + type: array + items: + $ref: '#/components/schemas/InvoiceItemResource' + description: Detalhamento de Produtos e Serviços (det) - Lista de Items da Nota Fiscal + nullable: true + hasMore: + type: boolean + description: Identifica se existem mais items a serem consultados + nullable: true + additionalProperties: false + InvoiceResource: + type: object + properties: + id: + type: string + description: Identificador único + nullable: true + serie: + type: integer + description: Série do Documento Fiscal (serie) + format: int32 + nullable: true + number: + type: integer + description: Número do Documento Fiscal (nNF) + format: int64 + nullable: true + status: + $ref: '#/components/schemas/InvoiceStatus' + authorization: + $ref: '#/components/schemas/AuthorizationResource' + contingencyDetails: + $ref: '#/components/schemas/ContingencyDetails' + operationNature: + type: string + description: Descrição da Natureza da Operação (natOp) + nullable: true + createdOn: + type: string + description: Data de criação + format: date-time + nullable: true + modifiedOn: + type: string + description: Data de modificação + format: date-time + nullable: true + operationOn: + type: string + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: date-time + nullable: true + operationType: + $ref: '#/components/schemas/OperationType' + environmentType: + $ref: '#/components/schemas/EnvironmentType' + purposeType: + $ref: '#/components/schemas/PurposeType' + issuer: + $ref: '#/components/schemas/IssuerResource' + buyer: + $ref: '#/components/schemas/BuyerResource' + totals: + $ref: '#/components/schemas/TotalResource' + transport: + $ref: '#/components/schemas/TransportInformationResource' + additionalInformation: + $ref: '#/components/schemas/AdditionalInformationResource' + export: + $ref: '#/components/schemas/ExportResource' + billing: + $ref: '#/components/schemas/BillingResource' + payment: + type: array + items: + $ref: '#/components/schemas/PaymentResource' + description: Grupo de Formas de Pagamento (pag) + nullable: true + transactionIntermediate: + $ref: '#/components/schemas/IntermediateResource' + delivery: + $ref: '#/components/schemas/DeliveryInformationResource' + withdrawal: + $ref: '#/components/schemas/WithdrawalInformationResource' + lastEvents: + $ref: '#/components/schemas/InvoiceEventsResourceBase' + additionalProperties: false + InvoiceStatus: + enum: + - None + - Created + - Processing + - Issued + - IssuedContingency + - Cancelled + - Disabled + - IssueDenied + - Error + type: string + description: | + Status atual da nota fiscal na plataforma. + Valores possíveis: + - `IssueDenied` (-2): Emissão denegada pela SEFAZ + - `Error` (-1): Erro de processamento + - `None` (0): Nenhum status definido + - `Created` (1): Criada (registrada na plataforma, ainda não enviada) + - `Processing` (2): Em processamento + - `Issued` (3): Emitida com sucesso (autorizada pela SEFAZ) + - `IssuedContingency` (4): Emitida em contingência (aguardando sincronização) + - `Cancelled` (5): Cancelada + - `Disabled` (6): Inutilizada + InvoiceWithoutEventsResource: + type: object + properties: + id: + type: string + description: Identificador único + nullable: true + serie: + type: integer + description: Série do Documento Fiscal (serie) + format: int32 + nullable: true + number: + type: integer + description: Número do Documento Fiscal (nNF) + format: int64 + nullable: true + status: + $ref: '#/components/schemas/InvoiceStatus' + authorization: + $ref: '#/components/schemas/AuthorizationResource' + contingencyDetails: + $ref: '#/components/schemas/ContingencyDetails' + operationNature: + type: string + description: Descrição da Natureza da Operação (natOp) + nullable: true + createdOn: + type: string + description: Data de criação + format: date-time + nullable: true + modifiedOn: + type: string + description: Data de modificação + format: date-time + nullable: true + operationOn: + type: string + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: date-time + nullable: true + operationType: + $ref: '#/components/schemas/OperationType' + environmentType: + $ref: '#/components/schemas/EnvironmentType' + purposeType: + $ref: '#/components/schemas/PurposeType' + issuer: + $ref: '#/components/schemas/IssuerResource' + buyer: + $ref: '#/components/schemas/BuyerResource' + totals: + $ref: '#/components/schemas/TotalResource' + transport: + $ref: '#/components/schemas/TransportInformationResource' + additionalInformation: + $ref: '#/components/schemas/AdditionalInformationResource' + export: + $ref: '#/components/schemas/ExportResource' + billing: + $ref: '#/components/schemas/BillingResource' + payment: + type: array + items: + $ref: '#/components/schemas/PaymentResource' + description: Grupo de Formas de Pagamento (pag) + nullable: true + transactionIntermediate: + $ref: '#/components/schemas/IntermediateResource' + delivery: + $ref: '#/components/schemas/DeliveryInformationResource' + withdrawal: + $ref: '#/components/schemas/WithdrawalInformationResource' + additionalProperties: false + IssuerFromRequestResource: + type: object + properties: + stStateTaxNumber: + type: string + description: IE do Substituto Tributário (IEST) + nullable: true + additionalProperties: false + IssuerResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + tradeName: + type: string + description: Nome Fantasia + nullable: true + openningDate: + type: string + description: Data abertura da empresa + format: date-time + nullable: true + taxRegime: + $ref: '#/components/schemas/TaxRegime' + specialTaxRegime: + $ref: '#/components/schemas/SpecialTaxRegime' + legalNature: + $ref: '#/components/schemas/LegalNature' + economicActivities: + type: array + items: + $ref: '#/components/schemas/EconomicActivityResource' + description: Atividades da Empresa (CNAE) + nullable: true + companyRegistryNumber: + type: integer + description: Número de Inscrição na Junta Comercial + format: int64 + nullable: true + regionalTaxNumber: + type: integer + description: Número de Inscrição na SEFAZ (IE) + format: int64 + nullable: true + regionalSTTaxNumber: + type: integer + description: Inscrição Estadual do Substituto Tributário (IEST) + format: int64 + nullable: true + municipalTaxNumber: + type: string + description: Número de Inscrição na Prefeitura (IM/CCM) + nullable: true + stStateTaxNumber: + type: string + description: IE do Substituto Tributário (IEST) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo de identificação do emitente da NF-e" + LegalNature: + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (não exaustivo, principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `SociedadeEmpresariaEmNomeColetivo`: Sociedade Empresária em Nome Coletivo + - `SociedadeEmpresariaEmComanditaSimples`: Sociedade Empresária em Comandita Simples + - `SociedadeEmpresariaEmComanditaporAcoes`: Sociedade Empresária em Comandita por Ações + - `SociedadeemContaParticipacao`: Sociedade em Conta de Participação + - `Empresario`: Empresário (Empresário Individual) + - `Cooperativa`: Cooperativa + - `ConsorcioSociedades`: Consórcio de Sociedades + - `GrupoSociedades`: Grupo de Sociedades + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + - `ClubeFundoInvestimento`: Clube/Fundo de Investimento + - `SociedadeSimplesPura`: Sociedade Simples Pura + - `SociedadeSimplesLimitada`: Sociedade Simples Limitada + - `SociedadeSimplesEmNomeColetivo`: Sociedade Simples em Nome Coletivo + - `SociedadeSimplesEmComanditaSimples`: Sociedade Simples em Comandita Simples + - `EmpresaBinacional`: Empresa Binacional + - `ConsorcioEmpregadores`: Consórcio de Empregadores + - `ConsorcioSimples`: Consórcio Simples + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `ServicoSocialAutonomo`: Serviço Social Autônomo + - `CondominioEdilicio`: Condomínio Edilício + - `ComissaoConciliacaoPrevia`: Comissão de Conciliação Prévia + - `EntidadeMediacaoArbitragem`: Entidade de Mediação e Arbitragem + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras`: Estabelecimento no Brasil de Fundação ou Associação Estrangeiras + - `FundacaoAssociacaoDomiciliadaExterior`: Fundação/Associação Domiciliada no Exterior + - `OrganizacaoReligiosa`: Organização Religiosa + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `AssociacaoPrivada`: Associação Privada + OperationType: + enum: + - Outgoing + - Incoming + type: string + description: | + Tipo da Operação fiscal (tpNF). + Valores possíveis: + - `Outgoing` (1): Saída — operação em que a mercadoria sai do estabelecimento (ex: venda) + - `Incoming` (0): Entrada — operação em que a mercadoria entra no estabelecimento (ex: devolução) + PISTaxResource: + type: object + properties: + cst: + type: string + description: Código de Situação Tributária do PIS (CST) + nullable: true + baseTax: + type: number + description: Valor da Base de Cálculo do PIS (vBC) + format: double + nullable: true + rate: + type: number + description: Alíquota do PIS (em percentual) (pPIS) + format: double + nullable: true + amount: + type: number + description: Valor do PIS (vPIS) + format: double + nullable: true + baseTaxProductQuantity: + type: number + description: Quantidade Vendida (qBCProd) + format: double + nullable: true + productRate: + type: number + description: Alíquota do PIS (em reais) (vAliqProd) + format: double + nullable: true + additionalProperties: false + description: Grupo do PIS + PaymentDetailResource: + type: object + required: + - method + properties: + method: + $ref: '#/components/schemas/PaymentMethod' + methodDescription: + type: string + description: Descrição do meio de pagamento (xPag) + nullable: true + paymentType: + $ref: '#/components/schemas/PaymentType' + amount: + type: number + description: Valor do Pagamento (vPag). Obrigatório para todos os meios exceto `method = WithoutPayment` (tPag=90), em que pode ser omitido. + format: double + nullable: true + card: + $ref: '#/components/schemas/CardResource' + paymentDate: + type: string + description: Data do pagamento (dPag) + format: date-time + nullable: true + federalTaxNumberPag: + type: string + description: CNPJ transacional do pagamento (CNPJPag) + nullable: true + statePag: + type: string + description: UF do CNPJ do estabelecimento onde o pagamento foi processado/transacionado/recebido (UFPag) + nullable: true + additionalProperties: false + PaymentMethod: + enum: + - Cash + - Cheque + - CreditCard + - DebitCard + - StoreCredict + - FoodVouchers + - MealVouchers + - GiftVouchers + - FuelVouchers + - BankBill + - BankDeposit + - InstantPayment + - WireTransfer + - Cashback + - WithoutPayment + - Others + type: string + description: | + Meio de pagamento (tPag). + Valores possíveis: + - `Cash` (01): Dinheiro + - `Cheque` (02): Cheque + - `CreditCard` (03): Cartão de Crédito + - `DebitCard` (04): Cartão de Débito + - `StoreCredict` (05): Crédito Loja + - `FoodVouchers` (10): Vale Alimentação + - `MealVouchers` (11): Vale Refeição + - `GiftVouchers` (12): Vale Presente + - `FuelVouchers` (13): Vale Combustível + - `BankBill` (15): Boleto Bancário + - `BankDeposit` (16): Depósito Bancário + - `InstantPayment` (17): Pagamento Instantâneo (PIX) Dinâmico + - `WireTransfer` (18): Transferência bancária, Carteira Digital + - `Cashback` (19): Programa de fidelidade, Cashback, Crédito Virtual + - `WithoutPayment` (90): Sem Pagamento + - `Others` (99): Outros + PaymentResource: + type: object + required: + - paymentDetail + properties: + paymentDetail: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/PaymentDetailResource' + description: "YA01a - Grupo Detalhamento da Forma de Pagamento (detPag)\r\nVERSÃO 4.00" + payBack: + type: number + description: "Valor do troco (vTroco)\r\nVERSÃO 4.00" + format: double + nullable: true + additionalProperties: false + PaymentType: + enum: + - InCash + - Term + type: string + description: | + Indicador da forma de pagamento (indPag). + Valores possíveis: + - `InCash` (0): À vista + - `Term` (1): A prazo + PersonType: + enum: + - Undefined + - NaturalPerson + - LegalEntity + - Company + - Customer + type: string + description: | + Tipo de pessoa. + Valores possíveis: + - `Undefined` (0): Indefinido + - `NaturalPerson` (2): Pessoa Física (CPF) + - `LegalEntity` (4): Pessoa Jurídica (CNPJ) + - `Company` (8): Prestador de serviço (uso interno — obsoleto) + - `Customer` (16): Cliente (uso interno — obsoleto) + PrintType: + enum: + - None + - NFeNormalPortrait + - NFeNormalLandscape + - NFeSimplified + - DANFE_NFC_E + - DANFE_NFC_E_MSG_ELETRONICA + type: string + description: | + Formato de impressão do DANFE (tpImp). + Valores possíveis: + - `None` (0): Sem geração de DANFE + - `NFeNormalPortrait` (1): DANFE Normal Retrato (NF-e) + - `NFeNormalLandscape` (2): DANFE Normal Paisagem (NF-e) + - `NFeSimplified` (3): DANFE Simplificado + - `DANFE_NFC_E` (4): DANFE NFC-e + - `DANFE_NFC_E_MSG_ELETRONICA` (5): DANFE NFC-e em mensagem eletrônica + ProductInvoiceEventsResource: + type: object + properties: + events: + type: array + items: + $ref: '#/components/schemas/ActivityResource' + description: Lista de Eventos ocorridos na Nota Fiscal + nullable: true + hasMore: + type: boolean + description: Identificador de possibilidade de mais itens. + nullable: true + id: + type: string + description: Identificação + nullable: true + accountId: + type: string + description: Identificador da Conta + nullable: true + companyId: + type: string + description: Identificador da Empresa + nullable: true + additionalProperties: false + ProductInvoiceQueueIssueResource: + type: object + required: + - items + - payment + - buyer + properties: + id: + type: string + description: Identificador único + nullable: true + payment: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/PaymentResource' + description: Grupo de Formas de Pagamento (pag). Pelo menos uma forma de pagamento é obrigatória. + serie: + type: integer + description: Série do Documento Fiscal (serie) + format: int32 + nullable: true + number: + type: integer + description: Número do Documento Fiscal (nNF) + format: int64 + nullable: true + operationOn: + type: string + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: date-time + nullable: true + operationNature: + type: string + description: Descrição da Natureza da Operação (natOp) + nullable: true + operationType: + $ref: '#/components/schemas/OperationType' + destination: + $ref: '#/components/schemas/Destination' + printType: + $ref: '#/components/schemas/PrintType' + purposeType: + $ref: '#/components/schemas/PurposeType' + consumerType: + $ref: '#/components/schemas/ConsumerType' + presenceType: + $ref: '#/components/schemas/ConsumerPresenceType' + contingencyOn: + type: string + description: "Data e Hora da entrada em contingência (dhCont)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + format: date-time + nullable: true + contingencyJustification: + type: string + description: Justificativa da entrada em contingência (xJust) + nullable: true + buyer: + $ref: '#/components/schemas/BuyerResource' + transport: + $ref: '#/components/schemas/TransportInformationResource' + additionalInformation: + $ref: '#/components/schemas/AdditionalInformationResource' + export: + $ref: '#/components/schemas/ExportResource' + items: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/InvoiceItemResource' + description: Detalhamento de Produtos e Serviços (det). Pelo menos um item é obrigatório. + billing: + $ref: '#/components/schemas/BillingResource' + issuer: + $ref: '#/components/schemas/IssuerFromRequestResource' + transactionIntermediate: + $ref: '#/components/schemas/IntermediateResource' + delivery: + $ref: '#/components/schemas/DeliveryInformationResource' + withdrawal: + $ref: '#/components/schemas/WithdrawalInformationResource' + totals: + $ref: '#/components/schemas/Total' + additionalProperties: false + description: Notas Fiscais Eletrônicas (NFe) + ProductInvoicesResource: + type: object + properties: + productInvoices: + type: array + items: + $ref: '#/components/schemas/InvoiceWithoutEventsResource' + description: Lista de Notas Fiscais Eletrônicas (NF-e) + nullable: true + hasMore: + type: boolean + description: Identificador de possibilidade de mais itens. + additionalProperties: false + description: Notas Fiscais Eletrônicas (NF-e) + PumpResource: + type: object + properties: + spoutNumber: + type: integer + description: Número de identificação do bico utilizado no abastecimento (nBico) + format: int32 + nullable: true + number: + type: integer + description: Número de identificação da bomba ao qual o bico está interligado (nBomba) + format: int32 + nullable: true + tankNumber: + type: integer + description: Número de identificação do tanque ao qual o bico está interligado (nTanque) + format: int32 + nullable: true + beginningAmount: + type: number + description: Valor do Encerrante no início do abastecimento (vEncIni) + format: double + nullable: true + endAmount: + type: number + description: Valor do Encerrante no final do abastecimento (vEncFin) + format: double + nullable: true + percentageBio: + type: number + description: Percentual do índice de mistura do Biodiesel (B100) no Óleo Diesel B instituído pelo órgão regulamentador + format: double + nullable: true + additionalProperties: false + PurposeType: + enum: + - None + - Normal + - Complement + - Adjustment + - Devolution + type: string + description: | + Finalidade da emissão da NF-e (finNFe). + Valores possíveis: + - `None` (0): Nenhum + - `Normal` (1): NF-e Normal (operação comum de venda/saída) + - `Complement` (2): NF-e Complementar (complementa valores de uma nota anterior) + - `Adjustment` (3): NF-e de Ajuste (regulariza divergências fiscais) + - `Devolution` (4): Devolução de mercadoria + QueueEventResource: + type: object + properties: + reason: + type: string + description: "Justificativa da carta de correção\r\nO Texto deve conter no mínimo 15 e no máximo 1.000 caracteres\r\n(os quais não poderão conter acentos e/ou caracteres especiais)" + nullable: true + additionalProperties: false + ReboqueResource: + type: object + properties: + plate: + type: string + description: Placa do Veiculo (placa) + nullable: true + uf: + type: string + description: UF Veiculo Reboque (UF) + nullable: true + rntc: + type: string + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + nullable: true + wagon: + type: string + description: Identificação do Vagão (vagao) + nullable: true + ferry: + type: string + description: Identificação da Balsa (balsa) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo Reboque" + ReceiverStateTaxIndicator: + enum: + - None + - TaxPayer + - Exempt + - NonTaxPayer + type: string + description: | + Indicador de Inscrição Estadual do destinatário (indIEDest). + Valores possíveis: + - `None` (0): Nenhum + - `TaxPayer` (1): Contribuinte ICMS (informar a IE do destinatário) + - `Exempt` (2): Contribuinte isento de Inscrição no cadastro de Contribuintes + - `NonTaxPayer` (9): Não Contribuinte (pode ou não possuir IE no Cadastro de Contribuintes do ICMS) + ReferencedProcessResource: + type: object + properties: + identifierConcessory: + type: string + nullable: true + identifierOrigin: + type: integer + format: int32 + nullable: true + concessionActType: + type: integer + format: int32 + nullable: true + additionalProperties: false + RequestCancellationResource: + type: object + properties: + accountId: + type: string + nullable: true + companyId: + type: string + nullable: true + productInvoiceId: + type: string + nullable: true + reason: + type: string + nullable: true + additionalProperties: false + ShippingModality: + enum: + - ByIssuer + - ByReceiver + - ByThirdParties + - OwnBySender + - OwnByBuyer + - Free + type: string + description: | + Modalidade do frete (modFrete). + Valores possíveis: + - `ByIssuer` (0): Contratação do Frete por conta do Remetente (CIF) + - `ByReceiver` (1): Contratação do Frete por conta do Destinatário (FOB) + - `ByThirdParties` (2): Contratação do Frete por conta de Terceiros + - `OwnBySender` (3): Transporte próprio por conta do Remetente + - `OwnByBuyer` (4): Transporte próprio por conta do Destinatário + - `Free` (9): Sem Ocorrência de transporte + SpecialTaxRegime: + enum: + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + - Automatico + type: string + description: | + Regime Especial de Tributação (indRegTrib) — aplicável principalmente a prestadores de serviços. + Valores possíveis: + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + - `Automatico`: Determinação automática pela API conforme o cadastro da empresa + StateCode: + enum: + - NA + - RO + - AC + - AM + - RR + - PA + - AP + - TO + - MA + - PI + - CE + - RN + - PB + - PE + - AL + - SE + - BA + - MG + - ES + - RJ + - SP + - PR + - SC + - RS + - MS + - MT + - GO + - DF + - EX + type: string + description: | + Sigla das Unidades Federativas (UF) do Brasil, incluindo casos especiais. + Valores possíveis: + - `NA`: Não Aplicável + - `RO`: Rondônia + - `AC`: Acre + - `AM`: Amazonas + - `RR`: Roraima + - `PA`: Pará + - `AP`: Amapá + - `TO`: Tocantins + - `MA`: Maranhão + - `PI`: Piauí + - `CE`: Ceará + - `RN`: Rio Grande do Norte + - `PB`: Paraíba + - `PE`: Pernambuco + - `AL`: Alagoas + - `SE`: Sergipe + - `BA`: Bahia + - `MG`: Minas Gerais + - `ES`: Espírito Santo + - `RJ`: Rio de Janeiro + - `SP`: São Paulo + - `PR`: Paraná + - `SC`: Santa Catarina + - `RS`: Rio Grande do Sul + - `MS`: Mato Grosso do Sul + - `MT`: Mato Grosso + - `GO`: Goiás + - `DF`: Distrito Federal + - `EX`: Exterior (operações com o exterior) + StateTaxProcessingAuthorizer: + enum: + - Normal + - EPEC + type: string + description: | + Autorizador SEFAZ responsável pelo processamento da nota fiscal. + Valores possíveis: + - `Normal`: Autorizador normal (SEFAZ da UF do emitente) + - `EPEC`: Evento Prévio de Emissão em Contingência (autorizador SVC para contingência) + TaxCouponInformationResource: + type: object + properties: + modelDocumentFiscal: + type: string + description: Modelo de Documento Fiscal (mod) + nullable: true + orderECF: + type: string + description: Número de Ordem Sequencial do ECF (nECF) + nullable: true + orderCountOperation: + type: integer + description: Número do Contador de Ordem de Operação (nCOO) + format: int32 + nullable: true + additionalProperties: false + TaxDeterminationResource: + type: object + properties: + operationCode: + type: integer + description: Código interno para determinação de natureza de operação + format: int32 + nullable: true + issuerTaxProfile: + type: string + description: Perfil fiscal do vendedor (origem) - usado para o cálculo automático de impostos + nullable: true + buyerTaxProfile: + type: string + description: Perfil fiscal do comprador (destino) - usado para o cálculo automático de impostos + nullable: true + origin: + type: string + description: Origem da mercadoria + nullable: true + acquisitionPurpose: + type: string + description: Finalidade de aquisição - usado para o cálculo automático de impostos + nullable: true + additionalProperties: false + TaxDocumentsReferenceResource: + type: object + properties: + taxCouponInformation: + $ref: '#/components/schemas/TaxCouponInformationResource' + documentInvoiceReference: + $ref: '#/components/schemas/DocumentInvoiceReferenceResource' + documentElectronicInvoice: + $ref: '#/components/schemas/DocumentElectronicInvoiceResource' + additionalProperties: false + TaxRegime: + enum: + - None + - LucroReal + - LucroPresumido + - SimplesNacional + - SimplesNacionalExcessoSublimite + - MicroempreendedorIndividual + - Isento + type: string + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `None`: Nenhum / Não informado + - `LucroReal`: Lucro Real (Regime Normal) + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `SimplesNacional`: Simples Nacional + - `SimplesNacionalExcessoSublimite`: Simples Nacional — excesso de sublimite de receita bruta + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `Isento`: Isento de tributação + TaxpayerCommentsResource: + type: object + properties: + field: + type: string + description: Campo (xCampo) + nullable: true + text: + type: string + description: Texto (xTexto) + nullable: true + additionalProperties: false + Total: + type: object + properties: + icms: + $ref: '#/components/schemas/ICMSTotal' + issqn: + $ref: '#/components/schemas/ISSQNTotal' + additionalProperties: false + TotalResource: + type: object + properties: + icms: + $ref: '#/components/schemas/ICMSTotalResource' + issqn: + $ref: '#/components/schemas/ISSQNTotalResource' + additionalProperties: false + TransportGroupResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumber: + type: string + description: Inscrição Estadual do Transportador (IE) + nullable: true + transportRetention: + type: string + description: Grupo de Retenção do ICMS do transporte + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo Transportador" + TransportInformationResource: + type: object + properties: + freightModality: + $ref: '#/components/schemas/ShippingModality' + transportGroup: + $ref: '#/components/schemas/TransportGroupResource' + reboque: + $ref: '#/components/schemas/ReboqueResource' + volume: + $ref: '#/components/schemas/VolumeResource' + transportVehicle: + $ref: '#/components/schemas/TransportVehicleResource' + sealNumber: + type: string + description: Número dos Lacres + nullable: true + transpRate: + $ref: '#/components/schemas/TransportRateResource' + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo de Informações do Transporte da NF-e\r\nId: X01 Pai: A1" + TransportRateResource: + type: object + properties: + serviceAmount: + type: number + description: Valor do Serviço (vServ) + format: double + nullable: true + bcRetentionAmount: + type: number + description: BC da Retenção do ICMS (vBCRet) + format: double + nullable: true + icmsRetentionRate: + type: number + description: Alíquota da Retenção (pICMSRet) //Change to Rate + format: double + nullable: true + icmsRetentionAmount: + type: number + description: Valor do ICMS Retido (vICMSRet) + format: double + nullable: true + cfop: + type: integer + description: CFOP de Serviço de Transporte (CFOP) + format: int64 + nullable: true + cityGeneratorFactCode: + type: integer + description: Código do Municipio de ocorrencia do fato gerador do ICMS do Transporte (cMunFG) + format: int64 + nullable: true + additionalProperties: false + TransportVehicleResource: + type: object + properties: + plate: + type: string + description: Placa do Veiculo (placa) + nullable: true + state: + type: string + description: Sigla da UF (UF) + nullable: true + rntc: + type: string + description: Registro Nacional de Transportador de Carga (ANTT) (RNTC) + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nGrupo Veiculo" + VolumeResource: + type: object + properties: + volumeQuantity: + type: integer + description: Quantidade de volumes transportados (qVol) + format: int32 + nullable: true + species: + type: string + description: Espécie dos volumes transportados (esp) + nullable: true + brand: + type: string + description: Marca dos Volumes Transportados (marca) + nullable: true + volumeNumeration: + type: string + description: Numeração dos Volumes Transportados (nVol) + nullable: true + netWeight: + type: number + description: Peso Liquido(em Kg) (pesoL) + format: double + nullable: true + grossWeight: + type: number + description: Peso Bruto(em Kg) (pesoB) + format: double + nullable: true + additionalProperties: false + description: "Manual_de_Orientação_Contribuinte_v_5.00\r\nVolumes\r\nId:X26" + WithdrawalInformationResource: + type: object + properties: + accountId: + type: string + description: Identificador da Conta + nullable: true + id: + type: string + description: Identificação + nullable: true + name: + type: string + description: Nome ou Razão Social (xNome) + nullable: true + federalTaxNumber: + type: integer + description: CNPJ ou CPF + format: int64 + nullable: true + email: + type: string + description: Email + nullable: true + address: + $ref: '#/components/schemas/AddressResource' + type: + $ref: '#/components/schemas/PersonType' + stateTaxNumber: + type: string + description: Inscrição Estadual (IE) + nullable: true + additionalProperties: false + description: Identificação do Local de retirada (retirada) + securitySchemes: + Authorization_Header: + type: apiKey + description: Autenticar usando o cabeçalho HTTP + name: Authorization + in: header + Authorization_QueryParam: + type: apiKey + description: Autenticar usando o parâmetro na URL + name: apikey + in: query + Authorization_JwtBearer: + type: http + description: Autenticar usando o cabeçalho HTTP + scheme: bearer + bearerFormat: Json Web Token +security: + - Authorization_Header: [] + Authorization_QueryParam: [] + - Authorization_JwtBearer: [] +x-original-swagger-version: "2.0" diff --git a/openapi/nf-servico-v1.yaml b/openapi/nf-servico-v1.yaml new file mode 100644 index 0000000..b9bf4c2 --- /dev/null +++ b/openapi/nf-servico-v1.yaml @@ -0,0 +1,8521 @@ +openapi: 3.0.0 +servers: + - url: https://api.nfe.io + description: Nota Fiscal de Serviço + - url: https://api.nfse.io + description: Webhooks +info: + title: Nota Fiscal de Serviço + version: v1 + description: "# Introdução\nSeja bem-vindo a documentação da API de Nota Fiscal de Serviço!\nNossa API foi criada utilizando o padrão REST que possibilita a integração de seu sistema ao nosso, sendo assim você também pode extender ou recriar as funcionalidades existentes na nossa plataforma, tudo isso consumindo a API que está documentada abaixo.\n# Como usar a API?\nLogo a seguir você encontrará todos os recursos e métodos suportados pela API, sendo que essa página possibilita que você teste os recursos e métodos diretamente através dela.\n# Autenticação\nVocê precisa de uma chave de API (API Key) para identificar a conta que está realizando solicitações para a API. \nPara isso você deve colocar sua chave de API no campo que se encontra topo desta página para que os métodos funcionem corretamente.\nNo seu código e integração temos suporte para autenticação de diversas formas sendo eles: \nHTTP Header (Authorization) ou HTTP Query String (api_key) nos dois modos passando o valor da sua chave de api (API Key).\n\n" +tags: + - name: Companies + description: | + :::warning Grupo em descontinuação + + Os endpoints deste grupo (`api.nfe.io/v1/companies/*`) fazem parte da **API legada de Nota Fiscal de Serviço v1** e estão em processo de descontinuação. + + A partir de agora, o gerenciamento de empresas é feito pela [**API de Contribuintes v2**](/docs/desenvolvedores/rest-api/contribuintes-v2), com a combinação de dois recursos: + + - **Empresa** ([API de Empresas v2](/docs/documentacao/gerenciamento-empresas/api-empresas)) + - **Inscrição Municipal** ([API de Inscrições Municipais v2](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais)) — necessária para emissão de NFS-e + + ::: + + ## Equivalência v1 → v2 + + | Endpoint v1 (descontinuado) | Endpoint v2 equivalente | + |---|---| + | `GET /v1/companies` — Listar empresas | [Consultar todas as Empresas da Conta](/docs/desenvolvedores/rest-api/contribuintes-v2/consultar-todas-as-empresas-da-conta) | + | `POST /v1/companies` — Criar empresa | [Criar uma Empresa](/docs/desenvolvedores/rest-api/contribuintes-v2/criar-uma-empresa) | + | `GET /v1/companies/{id}` — Consultar empresa | [Consultar uma Empresa pelo ID](/docs/desenvolvedores/rest-api/contribuintes-v2/consultar-uma-empresa-pelo-id) | + | `PUT /v1/companies/{id}` — Atualizar empresa | [Alterar uma Empresa pelo ID](/docs/desenvolvedores/rest-api/contribuintes-v2/alterar-uma-empresa-pelo-id) | + | `DELETE /v1/companies/{id}` — Excluir empresa | [Excluir uma Empresa por ID](/docs/desenvolvedores/rest-api/contribuintes-v2/excluir-uma-empresa-por-id) | + | `POST /v1/companies/{id}/certificate` — Upload de certificado | [Upload de um Certificado](/docs/desenvolvedores/rest-api/contribuintes-v2/upload-de-um-certificado) | + + > **Importante:** Para emitir NFS-e na nova API é preciso, além de criar a empresa, **vincular uma Inscrição Municipal**. Veja a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e o [guia de migração na release-note 2026.1](/docs/release-notes/2026-1-unificacao-api-contribuintes). +paths: + /v1/companies: + get: + tags: + - Companies + summary: Listar as empresas ativas de uma conta + description: | + :::warning Endpoint em descontinuação + + Este endpoint faz parte da API legada (`api.nfe.io/v1/companies`) e **está em processo de descontinuação**. + + A nova forma de gerenciar empresas combina **dois recursos** da API de Contribuintes v2: + + - **Empresa** — [API de Empresas (v2)](/docs/documentacao/gerenciamento-empresas/api-empresas) + - **Inscrição Municipal** — [API de Inscrições Municipais (v2)](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais) + + Consulte a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e a [release-note 2026.1 — Unificação da API de Contribuintes](/docs/release-notes/2026-1-unificacao-api-contribuintes) para o guia de migração completo. + + ::: + operationId: Companies_Get + parameters: + - name: pageCount + in: query + description: Items por página + required: false + schema: + type: integer + format: int32 + - name: pageIndex + in: query + description: Número da página + required: false + schema: + type: integer + format: int32 + responses: + "200": + description: Consulta realizada com sucesso + content: + application/json: + schema: + type: object + properties: + companies: + type: array + items: + required: + - name + - federalTaxNumber + - email + - address + - openningDate + - taxRegime + - legalNature + - municipalTaxNumber + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + rpsSerialNumber: + description: RPS número serie + type: string + rpsNumber: + format: int64 + description: RPS número + type: integer + issRate: + format: double + description: Alíquota do ISS para Simples Nacional + type: number + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + fiscalStatus: + description: Status no sistema + enum: + - CityNotSupported + - Pending + - Inactive + - None + - Active + type: string + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + certificate: + description: Certificado + type: object + properties: + thumbprint: + description: Thumbprint certificado + type: string + modifiedOn: + format: date-time + description: Certificado alterado em + type: string + expiresOn: + format: date-time + description: Certificado expira em + type: string + status: + description: Status do certificado + enum: + - Overdue + - Pending + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + totalResults: + format: int64 + type: integer + totalPages: + format: int32 + type: integer + page: + format: int32 + type: integer + "400": + description: Algum parametro informado não é válido, verificar resposta + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + post: + tags: + - Companies + summary: Criar uma empresa + description: | + :::warning Endpoint em descontinuação + + Este endpoint faz parte da API legada (`api.nfe.io/v1/companies`) e **está em processo de descontinuação**. + + A nova forma de gerenciar empresas combina **dois recursos** da API de Contribuintes v2: + + - **Empresa** — [API de Empresas (v2)](/docs/documentacao/gerenciamento-empresas/api-empresas) + - **Inscrição Municipal** — [API de Inscrições Municipais (v2)](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais) + + Consulte a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e a [release-note 2026.1 — Unificação da API de Contribuintes](/docs/release-notes/2026-1-unificacao-api-contribuintes) para o guia de migração completo. + + ::: + operationId: Companies_Post + requestBody: + description: Dados da empresa + required: true + content: + application/json: + schema: + required: + - name + - federalTaxNumber + - email + - address + - openningDate + - taxRegime + - legalNature + - municipalTaxNumber + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + rpsSerialNumber: + description: RPS número serie + type: string + rpsNumber: + format: int64 + description: RPS número + type: integer + issRate: + format: double + description: Alíquota do ISS para Simples Nacional + type: number + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + fiscalStatus: + description: Status no sistema + enum: + - CityNotSupported + - Pending + - Inactive + - None + - Active + type: string + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + certificate: + description: Certificado + type: object + properties: + thumbprint: + description: Thumbprint certificado + type: string + modifiedOn: + format: date-time + description: Certificado alterado em + type: string + expiresOn: + format: date-time + description: Certificado expira em + type: string + status: + description: Status do certificado + enum: + - Overdue + - Pending + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + responses: + "201": + description: Sucesso na criação da empresa + content: + application/json: + schema: + type: object + properties: + companies: + required: + - name + - federalTaxNumber + - email + - address + - openningDate + - taxRegime + - legalNature + - municipalTaxNumber + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + rpsSerialNumber: + description: RPS número serie + type: string + rpsNumber: + format: int64 + description: RPS número + type: integer + issRate: + format: double + description: Alíquota do ISS para Simples Nacional + type: number + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + fiscalStatus: + description: Status no sistema + enum: + - CityNotSupported + - Pending + - Inactive + - None + - Active + type: string + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + certificate: + description: Certificado + type: object + properties: + thumbprint: + description: Thumbprint certificado + type: string + modifiedOn: + format: date-time + description: Certificado alterado em + type: string + expiresOn: + format: date-time + description: Certificado expira em + type: string + status: + description: Status do certificado + enum: + - Overdue + - Pending + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "409": + description: Já existe uma empresa com o CNPJ informado + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id_or_tax_number}: + get: + tags: + - Companies + summary: Obter os detalhes de uma empresa + description: | + :::warning Endpoint em descontinuação + + Este endpoint faz parte da API legada (`api.nfe.io/v1/companies`) e **está em processo de descontinuação**. + + A nova forma de gerenciar empresas combina **dois recursos** da API de Contribuintes v2: + + - **Empresa** — [API de Empresas (v2)](/docs/documentacao/gerenciamento-empresas/api-empresas) + - **Inscrição Municipal** — [API de Inscrições Municipais (v2)](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais) + + Consulte a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e a [release-note 2026.1 — Unificação da API de Contribuintes](/docs/release-notes/2026-1-unificacao-api-contribuintes) para o guia de migração completo. + + ::: + operationId: Companies_idGet + parameters: + - name: company_id_or_tax_number + in: path + description: ID da empresa ou Inscrição Federal (CNPJ) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: object + properties: + companies: + required: + - name + - federalTaxNumber + - email + - address + - openningDate + - taxRegime + - legalNature + - municipalTaxNumber + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + rpsSerialNumber: + description: RPS número serie + type: string + rpsNumber: + format: int64 + description: RPS número + type: integer + issRate: + format: double + description: Alíquota do ISS para Simples Nacional + type: number + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + fiscalStatus: + description: Status no sistema + enum: + - CityNotSupported + - Pending + - Inactive + - None + - Active + type: string + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + certificate: + description: Certificado + type: object + properties: + thumbprint: + description: Thumbprint certificado + type: string + modifiedOn: + format: date-time + description: Certificado alterado em + type: string + expiresOn: + format: date-time + description: Certificado expira em + type: string + status: + description: Status do certificado + enum: + - Overdue + - Pending + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}: + put: + tags: + - Companies + summary: Atualizar uma empresa + description: | + :::warning Endpoint em descontinuação + + Este endpoint faz parte da API legada (`api.nfe.io/v1/companies`) e **está em processo de descontinuação**. + + A nova forma de gerenciar empresas combina **dois recursos** da API de Contribuintes v2: + + - **Empresa** — [API de Empresas (v2)](/docs/documentacao/gerenciamento-empresas/api-empresas) + - **Inscrição Municipal** — [API de Inscrições Municipais (v2)](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais) + + Consulte a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e a [release-note 2026.1 — Unificação da API de Contribuintes](/docs/release-notes/2026-1-unificacao-api-contribuintes) para o guia de migração completo. + + ::: + operationId: Companies_Put + requestBody: + description: Dados da empresa + required: true + content: + application/json: + schema: + required: + - name + - federalTaxNumber + - email + - address + - openningDate + - taxRegime + - legalNature + - municipalTaxNumber + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + rpsSerialNumber: + description: RPS número serie + type: string + rpsNumber: + format: int64 + description: RPS número + type: integer + issRate: + format: double + description: Alíquota do ISS para Simples Nacional + type: number + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + fiscalStatus: + description: Status no sistema + enum: + - CityNotSupported + - Pending + - Inactive + - None + - Active + type: string + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + certificate: + description: Certificado + type: object + properties: + thumbprint: + description: Thumbprint certificado + type: string + modifiedOn: + format: date-time + description: Certificado alterado em + type: string + expiresOn: + format: date-time + description: Certificado expira em + type: string + status: + description: Status do certificado + enum: + - Overdue + - Pending + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + responses: + "200": + description: Sucesso na atualização da empresa + content: + application/json: + schema: + type: object + properties: + companies: + required: + - name + - federalTaxNumber + - email + - address + - openningDate + - taxRegime + - legalNature + - municipalTaxNumber + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + rpsSerialNumber: + description: RPS número serie + type: string + rpsNumber: + format: int64 + description: RPS número + type: integer + issRate: + format: double + description: Alíquota do ISS para Simples Nacional + type: number + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + fiscalStatus: + description: Status no sistema + enum: + - CityNotSupported + - Pending + - Inactive + - None + - Active + type: string + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + certificate: + description: Certificado + type: object + properties: + thumbprint: + description: Thumbprint certificado + type: string + modifiedOn: + format: date-time + description: Certificado alterado em + type: string + expiresOn: + format: date-time + description: Certificado expira em + type: string + status: + description: Status do certificado + enum: + - Overdue + - Pending + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + delete: + tags: + - Companies + summary: Excluir uma empresa + description: | + :::warning Endpoint em descontinuação + + Este endpoint faz parte da API legada (`api.nfe.io/v1/companies`) e **está em processo de descontinuação**. + + A nova forma de gerenciar empresas combina **dois recursos** da API de Contribuintes v2: + + - **Empresa** — [API de Empresas (v2)](/docs/documentacao/gerenciamento-empresas/api-empresas) + - **Inscrição Municipal** — [API de Inscrições Municipais (v2)](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais) + + Consulte a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e a [release-note 2026.1 — Unificação da API de Contribuintes](/docs/release-notes/2026-1-unificacao-api-contribuintes) para o guia de migração completo. + + ::: + operationId: Companies_Delete + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + responses: + "200": + description: Sucesso na remoção da empresa + content: + application/json: + schema: + type: object + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "404": + description: empresa não foi encontrada + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/certificate: + post: + tags: + - Companies + summary: Upload do certificado digital da empresa usando o codificação multipart/form-data. + description: | + :::warning Endpoint em descontinuação + + Este endpoint faz parte da API legada (`api.nfe.io/v1/companies`) e **está em processo de descontinuação**. + + A nova forma de gerenciar empresas combina **dois recursos** da API de Contribuintes v2: + + - **Empresa** — [API de Empresas (v2)](/docs/documentacao/gerenciamento-empresas/api-empresas) + - **Inscrição Municipal** — [API de Inscrições Municipais (v2)](/docs/documentacao/gerenciamento-empresas/api-inscricoes-municipais) + + Consulte a [Visão Geral do Gerenciamento de Empresas](/docs/documentacao/gerenciamento-empresas/visao-geral) e a [release-note 2026.1 — Unificação da API de Contribuintes](/docs/release-notes/2026-1-unificacao-api-contribuintes) para o guia de migração completo. + + ::: + operationId: Companies_CertificateUpload + requestBody: + description: Arquivo do certificado digital com extensao PFX ou P12 + required: true + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + password: + type: string + responses: + "200": + description: Sucesso na atualização da certificado digital + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "404": + description: Empresa não foi encontrada + "415": + description: Nenhum arquivo foi encontrado na requisição + "500": + description: Erro no processamento + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/notifications: + get: + tags: + - ServiceInvoiceNotifications + summary: Listar as notificações de uma empresa + description: Utilize esta requisição para consultar uma lista das **Notificações** cadastradas na **Empresa**. + operationId: ServiceInvoiceNotifications_Get + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + responses: + "200": + description: Consulta realizada com sucesso + content: + application/json: + schema: + type: object + properties: + notifications: + type: array + items: + type: object + properties: + id: + description: Identificação + type: string + channel: + description: Canal de Notificação + enum: + - None + - Email + type: string + filters: + description: Filtro de Evento + type: array + items: + type: string + status: + description: Status no sistema + enum: + - Active + - Inactive + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido, verificar resposta + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/notifications/{notification_id}: + get: + tags: + - ServiceInvoiceNotifications + summary: Consultar uma notificação existente + description: Utilize esta requisição para consultar uma **Notificação** que esteja cadastrada e tenha o ID igual ao parametro **{notification_id}**. + operationId: ServiceInvoiceNotifications_idGet + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: notification_id + in: path + description: ID da notificação a ser consultado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: object + properties: + notification: + type: object + properties: + id: + description: Identificação + type: string + channel: + description: Canal de Notificação + enum: + - None + - Email + type: string + filters: + description: Filtro de Evento + type: array + items: + type: string + status: + description: Status no sistema + enum: + - Active + - Inactive + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + delete: + tags: + - ServiceInvoiceNotifications + summary: Excluir uma notificação + operationId: ServiceInvoiceNotifications_Delete + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: notification_id + in: path + description: ID da notificação + required: true + schema: + type: string + responses: + "200": + description: Sucesso na remoção da empresa + content: + application/json: + schema: + type: object + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "404": + description: empresa não foi encontrada + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/notifications/email: + post: + tags: + - ServiceInvoiceNotifications + summary: Criar notificação via Email da Nota Fiscal de Serviço (NFSE) + description: "Utilize esta requisição para definir se os Tomadores (Clientes) das Notas Fiscais de Serviço (NFSE)\r\ndevem ser notificados via email que a NFSE foi **emitida** ou **cancelada** com sucesso." + operationId: ServiceInvoiceNotifications_Post + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + requestBody: + description: Dados da notificação + required: true + content: + application/json: + schema: + description: Cria Notificação para Email + type: object + properties: + filters: + description: "Lista de filtros de evento sem distinção entre maiúsculas e minúsculas associado a esta notificação.\r\nOs filtros de evento são usados para determinar em quais eventos essa notificação será acionada.\r\nOs valores de filtros suportados pode ser consultados através do requisição na API de **Tipos de Eventos**." + type: array + items: + type: string + status: + description: "Determina se as notificações são enviadas quando o evento é gerado.\r\nDefinir como **Inactive** para não receber nenhuma nova notificação, sendo o padrão: **Active**\r\npara receber todas as notificações." + enum: + - Active + - Inactive + type: string + responses: + "201": + description: Sucesso na criação da empresa + content: + application/json: + schema: + type: object + properties: + notification: + type: object + properties: + id: + description: Identificação + type: string + channel: + description: Canal de Notificação + enum: + - None + - Email + type: string + filters: + description: Filtro de Evento + type: array + items: + type: string + status: + description: Status no sistema + enum: + - Active + - Inactive + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "409": + description: Já existe uma empresa com o CNPJ informado + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/eventTypes: + get: + tags: + - EventTypes + summary: Listar os Tipos de Eventos gerados pela plataforma + description: "Eventos ocorrem a todo instante na plataforma durante os processamentos e são registrados\r\ncriando notificações para os webhooks ativos e configurados para receber os eventos.\r\n \r\nSão identificados seguindo o padrão do nome do evento.\r\n\r\nEsse tipos podem ser utilizados como filtro ao criar ou alterar um webhook,\r\nsendo que o filtro determina quais notificações de eventos e ação serão enviadas\r\npara um determinado webhook, ou seja, dependendo de quais filtros são vinculados ao webhook\r\nele só receberá as notificações de evento e ação que correspondem a um ou mais desses filtros." + operationId: EventTypes_GetAll + responses: + "200": + description: Sucesso na consulta do tipos de eventos + content: + application/json: + schema: + description: Tipos de Eventos + type: object + properties: + eventTypes: + description: Lista de Evento + type: array + items: + description: "Eventos ocorrem a todo instante na plataforma durante os processamentos e são registrados\r\ncriando notificações para os webhooks ativos e configurados para receber os eventos." + type: object + properties: + id: + description: "Identificador do evento, seguem o padrão **Resource.EventAction**.\r\nOnde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\nAlguns exemplos **Invoice.Issued** ou **Blob.Updated**" + type: string + description: + description: Descrição para o recurso, evento e ação exemplicando quando e onde eles ocorrem dentro na plataforma. + type: string + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/legalpeople: + get: + tags: + - LegalPeople + summary: Listar as pessoas jurídicas ativas + operationId: LegalPeople_Get + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + required: + - name + - email + - address + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/legalpeople/{id}: + get: + tags: + - LegalPeople + summary: Obter os detalhes de uma pessoa jurídica + operationId: LegalPeople_idGet + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da pessoa juridica + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: object + properties: + legalPeople: + required: + - name + - email + - address + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + tradeName: + description: Nome fantasia + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/naturalpeople: + get: + tags: + - NaturalPeople + summary: Listar as pessoas físicas ativas + operationId: NaturalPeople_Get + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: object + properties: + naturalPeople: + type: array + items: + required: + - name + - email + - address + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome completo + type: string + federalTaxNumber: + format: int64 + description: CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + birthDate: + format: date-time + description: Data nascimento + type: string + idNumber: + description: Número do Registro Geral (RG) + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + totalResults: + format: int64 + type: integer + totalPages: + format: int32 + type: integer + page: + format: int32 + type: integer + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/naturalpeople/{id}: + get: + tags: + - NaturalPeople + summary: Obter os detalhes de uma pessoa física + operationId: NaturalPeople_idGet + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da pessoa física + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + required: + - name + - email + - address + type: object + properties: + id: + description: Identificação + type: string + name: + description: Nome completo + type: string + federalTaxNumber: + format: int64 + description: CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + birthDate: + format: date-time + description: Data nascimento + type: string + idNumber: + description: Número do Registro Geral (RG) + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices: + get: + tags: + - ServiceInvoices + summary: Listar as Notas Fiscais de Serviço (NFSE) + description: Você precisará do APIKEY da Empresa + operationId: ServiceInvoices_Get + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: pageCount + in: query + description: Items por página + required: false + schema: + type: integer + format: int32 + - name: pageIndex + in: query + description: Número da página + required: false + schema: + type: integer + format: int32 + - name: issuedBegin + in: query + description: Data de competência início + required: false + schema: + type: string + format: yyyy-MM-dd + - name: issuedEnd + in: query + description: Data de competência fim + required: false + schema: + type: string + format: yyyy-MM-dd + - name: createdBegin + in: query + description: Data de criação início + required: false + schema: + type: string + format: yyyy-MM-dd + - name: createdEnd + in: query + description: Data de criação fim + required: false + schema: + type: string + format: yyyy-MM-dd + - name: hasTotals + in: query + required: false + schema: + type: boolean + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: object + properties: + serviceInvoices: + type: array + items: + required: + - environment + type: object + properties: + id: + description: Identificação + type: string + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + flowStatus: + description: | + Status do processamento da NFS-e no fluxo de emissão. + Valores possíveis: + - `CancelFailed` (-2): Falha no cancelamento — tentativa de cancelar a NFS-e foi rejeitada + - `IssueFailed` (-1): Falha na emissão — a NFS-e não foi autorizada pela Prefeitura + - `Issued` (1): Emitida — autorizada pela Prefeitura + - `Cancelled` (2): Cancelada + - `PullFromCityHall` (3): Capturada da Prefeitura (sincronização de NFS-e já emitida fora da plataforma) + - `WaitingCalculateTaxes` (10): Aguardando cálculo de tributos + - `WaitingDefineRpsNumber` (11): Aguardando definição do número da RPS + - `WaitingSend` (12): Aguardando envio à Prefeitura + - `WaitingSendCancel` (13): Aguardando envio do cancelamento à Prefeitura + - `WaitingReturn` (14): Aguardando retorno da Prefeitura + - `WaitingDownload` (15): Aguardando download do XML/PDF + enum: + - CancelFailed + - IssueFailed + - Issued + - Cancelled + - PullFromCityHall + - WaitingCalculateTaxes + - WaitingDefineRpsNumber + - WaitingSend + - WaitingSendCancel + - WaitingReturn + - WaitingDownload + type: string + flowMessage: + description: Mensagem de processamento + type: string + provider: + description: Prestador dos serviços + type: object + properties: + tradeName: + description: Nome Fantasia + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + issRate: + format: double + description: Taxa da Aliquota do ISS (Simples Nacional) + type: number + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + borrower: + description: Tomador dos serviços + type: object + properties: + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + externalId: + description: Identificação única do cliente + type: string + batchNumber: + format: int64 + description: Número do lote da RPS + type: integer + batchCheckNumber: + description: Número do protocolo do lote da RPS + type: string + number: + format: int64 + description: Número do NFE + type: integer + checkCode: + description: Código de Verificação da NFE + type: string + status: + description: Status da NFE + enum: + - Error + - None + - Created + - Issued + - Cancelled + type: string + rpsType: + description: Tipo da RPS + enum: + - Rps + - RpsMista + - Cupom + type: string + rpsStatus: + description: Status da RPS + enum: + - Normal + - Canceled + - Lost + type: string + taxationType: + description: | + Tipo da tributação do ISSQN (TributacaoRPS). + Valores possíveis: + - `None`: Nenhuma + - `WithinCity`: Tributação dentro do mesmo município + - `OutsideCity`: Tributação fora do município + - `Export`: Exportação + - `Free`: Isento + - `Immune`: Imune + - `SuspendedCourtDecision`: Exigibilidade suspensa por decisão judicial + - `SuspendedAdministrativeProcedure`: Exigibilidade suspensa por procedimento administrativo + - `OutsideCityFree`: Tributação fora do município porém isento + - `OutsideCityImmune`: Tributação fora do município porém imune + - `OutsideCitySuspended`: Tributação fora do município porém suspensa + - `OutsideCitySuspendedAdministrativeProcedure`: Tributação fora do município, suspensa por procedimento administrativo + - `ObjectiveImune`: Tributação no município com indicação de imunidade objetiva + enum: + - None + - WithinCity + - OutsideCity + - Export + - Free + - Immune + - SuspendedCourtDecision + - SuspendedAdministrativeProcedure + - OutsideCityFree + - OutsideCityImmune + - OutsideCitySuspended + - OutsideCitySuspendedAdministrativeProcedure + - ObjectiveImune + type: string + issuedOn: + format: date-time + description: Data de emissão + type: string + cancelledOn: + format: date-time + description: Data de cancelamento + type: string + rpsSerialNumber: + description: Número de serie da RPS + type: string + rpsNumber: + format: int64 + description: Número da RPS + type: integer + cityServiceCode: + description: Código do servico prestado no Municipio + type: string + federalServiceCode: + description: Código do servico prestado federal + type: string + description: + description: Descrição do serviço no municipio + type: string + servicesAmount: + format: double + description: Valor do serviços + type: number + paidAmount: + format: double + description: Valor dos Serviços pago + type: number + paymentMethod: + description: Formas de pagamento + enum: + - None + - Cash + - Check + - CreditCard + - DebitCard + - StoreCredit + - FoodVoucher + - MealVoucher + - GiftCard + - FuelVoucher + - Others + type: string + deductionsAmount: + format: double + description: Valor de deduções + type: number + discountUnconditionedAmount: + format: double + description: Valor do desconto incondicionado + type: number + discountConditionedAmount: + format: double + description: Valor do desconto condicionado + type: number + baseTaxAmount: + format: double + description: Valor da base de calculo de impostos + type: number + issRate: + format: double + description: Aliquota do ISS + type: number + issTaxAmount: + format: double + description: Valor do ISS + type: number + irAmountWithheld: + format: double + description: Valor retido do Imposto de Renda (IR) + type: number + pisAmountWithheld: + format: double + description: Valor retido do PIS + type: number + cofinsAmountWithheld: + format: double + description: Valor retido do COFINS + type: number + csllAmountWithheld: + format: double + description: Valor retido do CSLL + type: number + inssAmountWithheld: + format: double + description: Valor retido do INSS + type: number + issAmountWithheld: + format: double + description: Valor retido do ISS + type: number + othersAmountWithheld: + format: double + description: Valor de outras retenções + type: number + amountWithheld: + format: double + description: Valor das retenções + type: number + amountNet: + format: double + description: Valor líquido + type: number + location: + description: Local da Prestação do Serviço + type: object + properties: + state: + description: Estado + type: string + country: + description: País + type: string + postalCode: + description: Código Postal + type: string + street: + description: Logradouro + type: string + number: + description: Número + type: string + district: + description: Bairro + type: string + AdditionalInformation: + description: Informações Adicionais (Complemento) + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + activityEvent: + description: Detalhes da atividade do evento + type: object + properties: + name: + description: Nome do evento + type: string + beginOn: + format: date-time + description: Data de início do evento + type: string + endOn: + format: date-time + description: Data do fim do evento + type: string + Code: + description: Código da atividade do evento + type: string + approximateTax: + description: Tributos aproximados + type: object + properties: + source: + description: Nome da fonte da taxa + type: string + version: + description: Versão da taxa baseado na fonte + type: string + totalRate: + format: double + description: Taxa dos tributos aproximados + type: number + additionalInformation: + description: Informações Adicionais + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + totalResults: + format: int64 + type: integer + totalPages: + format: int32 + type: integer + page: + format: int32 + type: integer + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + post: + tags: + - ServiceInvoices + summary: Emitir uma Nota Fiscal de Serviço (NFSE) + description: Você precisará do APIKEY da Empresa + operationId: ServiceInvoices_Post + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + requestBody: + description: Dados da nota fiscal de serviço + required: true + content: + application/json: + schema: + description: Emissão de nota fiscal de serviço + required: + - cityServiceCode + - description + - servicesAmount + type: object + properties: + borrower: + description: | + Tomador dos serviços. + + **Opcional**: o grupo `borrower` pode ser omitido. Quando informado, aplicam-se validações condicionais aos seus campos: + - `name`: se informado, no máximo 115 caracteres; + - `federalTaxNumber`: se informado (diferente de zero), deve ser um CNPJ/CPF válido e coerente com o `type` (`NaturalPerson` → CPF; `LegalEntity` → CNPJ). Para tomador no exterior (`address.country` ≠ `BRA`), não é validado; + - `phoneNumber`: se informado, entre 7 e 20 dígitos; + - `address`: opcional, mas se um endereço **brasileiro** for parcialmente preenchido, passam a ser obrigatórios `postalCode`, `street`, `city.code` (código IBGE de 7 dígitos), `city.name` e `state` (UF de 2 letras), que devem ser consistentes entre si. + required: [] + type: object + properties: + type: + description: | + Tipo do tomador dos serviços. + Valores possíveis: + - `Undefined`: Indefinido + - `NaturalPerson`: Pessoa Física (CPF) + - `LegalEntity`: Pessoa Jurídica (CNPJ) + enum: + - Undefined + - NaturalPerson + - LegalEntity + type: string + name: + description: Nome / Razão Social + type: string + maxLenght: 115 + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + maxLength: 14 + municipalTaxNumber: + description: Inscrição Municipal para Pessoas Jurídicas + type: string + maxLength: 12 + stateTaxNumber: + description: Inscrição Estadual (opcional, não se aplica a todos) + type: string + maxLength: 19 + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + caepf: + description: Cadastro de Atividade Econômica da Pessoa Física (CAEPF) + type: string + maxLength: 14 + phoneNumber: + description: Telefone + type: string + minLength: 7 + maxLenght: 20 + email: + description: Email + type: string + noTaxIdReason: + description: | + Justificativa para ausência de NIF (Número de Identificação Fiscal). + Valores possíveis: + - `NotInformedOriginal`: Não informado na nota de origem + - `Exempted`: Dispensado do NIF + - `NotRequired`: Não exigência do NIF + enum: + - NotInformedOriginal + - Exempted + - NotRequired + type: string + address: + description: Endereço + required: + - country + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + length: 3 + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + length: 9 + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + length: 7 + name: + description: Nome + type: string + state: + description: Estado + type: string + length: 2 + externalId: + description: Identificação única do cliente + type: string + cityServiceCode: + description: Código do serviço no municipio + type: string + federalServiceCode: + description: Código federal do servico (Item da lista de serviço LC 116) + type: string + cnaeCode: + description: Código CNAE (somente quando necessario na cidade) + type: string + nbsCode: + description: Código do NBS no municipio (somente quando necessario na cidade) + type: string + description: + description: Descrição dos serviços + type: string + servicesAmount: + format: double + description: Valor do serviços + type: number + rpsSerialNumber: + description: Número de Serie da RPS + type: string + issuedOn: + format: date-time + description: Data da emissão no formato YYYY-MM-DDTHH:MM:SS.SSSSSS-03:00 + type: string + rpsNumber: + format: int64 + description: Número da RPS + type: integer + taxationType: + description: | + Tipo da tributação do ISSQN (TributacaoRPS). + Valores possíveis: + - `None`: Nenhuma + - `WithinCity`: Tributação dentro do mesmo município + - `OutsideCity`: Tributação fora do município + - `Export`: Exportação + - `Free`: Isento + - `Immune`: Imune + - `SuspendedCourtDecision`: Exigibilidade suspensa por decisão judicial + - `SuspendedAdministrativeProcedure`: Exigibilidade suspensa por procedimento administrativo + - `OutsideCityFree`: Tributação fora do município porém isento + - `OutsideCityImmune`: Tributação fora do município porém imune + - `OutsideCitySuspended`: Tributação fora do município porém suspensa + - `OutsideCitySuspendedAdministrativeProcedure`: Tributação fora do município, suspensa por procedimento administrativo + - `ObjectiveImune`: Tributação no município com indicação de imunidade objetiva + enum: + - None + - WithinCity + - OutsideCity + - Export + - Free + - Immune + - SuspendedCourtDecision + - SuspendedAdministrativeProcedure + - OutsideCityFree + - OutsideCityImmune + - OutsideCitySuspended + - OutsideCitySuspendedAdministrativeProcedure + - ObjectiveImune + type: string + issRate: + format: double + description: Aliquota do ISS + type: number + issTaxAmount: + format: double + description: Valor do ISS + type: number + deductionsAmount: + format: double + description: Valor de deduções + type: number + discountUnconditionedAmount: + format: double + description: Valor do desconto incondicionado + type: number + discountConditionedAmount: + format: double + description: Valor do desconto condicionado + type: number + irAmountWithheld: + format: double + description: Valor retido do Imposto de Renda (IR) + type: number + pisAmountWithheld: + format: double + description: Valor retido do PIS + type: number + cofinsAmountWithheld: + format: double + description: Valor retido do COFINS + type: number + csllAmountWithheld: + format: double + description: Valor retido do CSLL + type: number + inssAmountWithheld: + format: double + description: Valor retido do INSS + type: number + issAmountWithheld: + format: double + description: Valor retido do ISS + type: number + othersAmountWithheld: + format: double + description: Valor de outras retenções + type: number + approximateTax: + description: Tributos aproximados + type: object + properties: + source: + description: Nome da fonte da taxa + type: string + version: + description: Versão da taxa baseado na fonte + type: string + totalRate: + format: double + description: Taxa dos tributos aproximados + type: number + additionalInformation: + description: Informações Adicionais + type: string + location: + description: Local da Prestação do Serviço + type: object + properties: + state: + description: Estado + type: string + country: + description: País + type: string + postalCode: + description: Código Postal + type: string + street: + description: Logradouro + type: string + number: + description: Número + type: string + district: + description: Bairro + type: string + AdditionalInformation: + description: Informações Adicionais (Complemento) + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + activityEvent: + description: Detalhes da atividade do evento + type: object + properties: + name: + description: Nome do evento + type: string + beginOn: + format: date-time + description: Data de início do evento + type: string + endOn: + format: date-time + description: Data do fim do evento + type: string + Code: + description: Código da atividade do evento + type: string + ncmCode: + description: Código NCM (Nomenclatura Comum do Mercosul) (NCM) + type: string + maxLength: 8 + paidAmount: + format: double + description: Valor dos Serviços pago (Valor Total Recebido) + type: number + accrualOn: + format: date + description: Data da competência da prestação do serviço no formato AAAA-MM-DD (Competencia). Se não for informado, o sistema utilizará a data do campo `issuedOn`. + type: string + cstPisCofins: + description: | + Código de Situação Tributária do PIS/COFINS (CST). + Valores: + - `00`: Nenhum + - `01`: Operação Tributável com Alíquota Básica + - `02`: Operação Tributável com Alíquota Diferenciada + - `03`: Operação Tributável com Alíquota por Unidade de Medida de Produto + - `04`: Operação Tributável monofásica - Revenda a Alíquota Zero + - `05`: Operação Tributável por Substituição Tributária + - `06`: Operação Tributável a Alíquota Zero + - `07`: Operação Tributável da Contribuição + - `08`: Operação sem Incidência da Contribuição + - `09`: Operação com Suspensão da Contribuição + enum: ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09"] + type: string + pisCofinsBaseTax: + format: double + description: Base de cálculo para o PIS e COFINS (vBCPisCofins) + type: number + pisRate: + format: double + description: Alíquota do PIS (pAliqPis). Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + type: number + pisAmount: + format: double + description: Valor do PIS (vPis). Campo utilizado para informar o valor do PIS, porém sem retenção. + type: number + cofinsRate: + format: double + description: Alíquota do COFINS (pAliqCofins). Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + type: number + cofinsAmount: + format: double + description: Valor do COFINS (vCofins). Campo utilizado para informar o valor do COFINS, porém sem retenção. + type: number + csllAmount: + format: double + description: Valor do CSLL (vCSLL). Campo utilizado para informar o valor do CSLL, porém sem retenção. + type: number + csllRate: + format: double + description: Alíquota do CSLL (pAliqCSLL) + type: number + inssRate: + format: double + description: Alíquota do INSS + type: number + ipiRate: + format: double + description: SP - Alíquota IPI (pAliqIPI). Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + type: number + ipiAmount: + format: double + description: SP - Valor IPI (vIPI). Se não for informado, o sistema realizará o cálculo automático. + type: number + immunityType: + description: | + Tipo de imunidade (tpImunidade) — usar apenas quando `taxationType = Immune`. + Valores possíveis: + - `Unspecified`: Imunidade (tipo não informado na nota de origem) + - `PublicEntitiesMutual`: Patrimônio, renda ou serviços, uns dos outros (CF88, Art 150, VI, a) + - `Temples`: Templos de qualquer culto (CF88, Art 150, VI, b) + - `PartiesUnionsEducationSocialNonprofit`: Patrimônio, renda ou serviços dos partidos políticos, inclusive suas fundações, das entidades sindicais dos trabalhadores, das instituições de educação e de assistência social, sem fins lucrativos (CF88, Art 150, VI, c) + - `BooksPressPaper`: Livros, jornais, periódicos e o papel destinado a sua impressão (CF88, Art 150, VI, d) + - `BrazilianMusicPhonograms`: Fonogramas e videofonogramas musicais produzidos no Brasil (CF88, Art 150, VI, e) + enum: [Unspecified, PublicEntitiesMutual, Temples, PartiesUnionsEducationSocialNonprofit, BooksPressPaper, BrazilianMusicPhonograms] + type: string + retentionType: + description: | + Tipo de retenção do ISSQN (tpRetISSQN). Define quem é o responsável pelo recolhimento do ISSQN. Se um valor for enviado na integração, ele será utilizado; caso contrário, o sistema aplicará a regra de cálculo automática. + Valores possíveis: + - `NotWithheld`: Não Retido — o prestador é o responsável pelo recolhimento. + - `WithheldByBuyer`: Retido pelo Tomador — a responsabilidade pelo recolhimento é transferida para o tomador. + - `WithheldByIntermediary`: Retido pelo Intermediário — a responsabilidade pelo recolhimento é transferida para o intermediário. + enum: [NotWithheld, WithheldByBuyer, WithheldByIntermediary] + default: NotWithheld + type: string + isEarlyInstallmentPayment: + description: Indica se é uma nota fiscal de pagamento parcelado antecipado, realizado antes do fornecimento do serviço. + type: boolean + intermediary: + description: | + Grupo de informações relativas ao intermediário do serviço (interm). Possui a mesma estrutura do `borrower`. + + **Opcional**: envie apenas quando houver intermediário na operação (por exemplo, quando a retenção do ISS é feita pelo intermediário). Quando informado, os campos básicos de identificação são `type`, `federalTaxNumber` (CNPJ/CPF/NIF) e `name`. + type: object + properties: + type: + description: | + Tipo do intermediário. + Valores possíveis: + - `Undefined`: Indefinido + - `NaturalPerson`: Pessoa Física (CPF) + - `LegalEntity`: Pessoa Jurídica (CNPJ) + enum: [Undefined, NaturalPerson, LegalEntity] + type: string + name: + description: Nome / Razão Social + type: string + maxLength: 115 + federalTaxNumber: + format: int64 + description: CNPJ, CPF ou NIF (Número de Identificação Fiscal) + type: integer + municipalTaxNumber: + description: Inscrição Municipal + type: string + maxLength: 12 + stateTaxNumber: + description: Inscrição Estadual (Opcional) + type: string + maxLength: 19 + taxRegime: + description: Tipo do Regime Tributário + enum: [Isento, MicroempreendedorIndividual, SimplesNacional, LucroPresumido, LucroReal] + type: string + caepf: + description: Cadastro de Atividade Econômica da Pessoa Física (CAEPF) + type: string + maxLength: 14 + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + noTaxIdReason: + description: | + Justificativa para ausência de NIF. + Valores possíveis: + - `NotInformedOriginal`: Não informado na nota de origem + - `Exempted`: Dispensado do NIF + - `NotRequired`: Não exigência do NIF + enum: [NotInformedOriginal, Exempted, NotRequired] + type: string + address: + description: Endereço + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF + type: string + recipient: + description: | + Destinatário final do serviço, quando diferente do tomador. Possui a mesma estrutura do `borrower`. + type: object + properties: + type: + description: | + Tipo do destinatário. + Valores possíveis: + - `Undefined`: Indefinido + - `NaturalPerson`: Pessoa Física (CPF) + - `LegalEntity`: Pessoa Jurídica (CNPJ) + enum: [Undefined, NaturalPerson, LegalEntity] + type: string + name: + description: Nome / Razão Social + type: string + maxLength: 115 + federalTaxNumber: + format: int64 + description: CNPJ, CPF ou NIF (Número de Identificação Fiscal) + type: integer + municipalTaxNumber: + description: Inscrição Municipal + type: string + maxLength: 12 + stateTaxNumber: + description: Inscrição Estadual (Opcional) + type: string + maxLength: 19 + taxRegime: + description: Tipo do Regime Tributário + enum: [Isento, MicroempreendedorIndividual, SimplesNacional, LucroPresumido, LucroReal] + type: string + caepf: + description: Cadastro de Atividade Econômica da Pessoa Física (CAEPF) + type: string + maxLength: 14 + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + noTaxIdReason: + description: | + Justificativa para ausência de NIF. + Valores possíveis: + - `NotInformedOriginal`: Não informado na nota de origem + - `Exempted`: Dispensado do NIF + - `NotRequired`: Não exigência do NIF + enum: [NotInformedOriginal, Exempted, NotRequired] + type: string + address: + description: Endereço + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF + type: string + referenceSubstitution: + description: Grupo de informações relativas à NFS-e a ser substituída (chSubstda). + type: object + properties: + id: + description: Identificador da NFS-e a ser substituída (chave de 44 dígitos). + type: string + pattern: '^[0-9]{44}$' + reason: + description: | + Motivo da substituição (cMotivo). + Valores possíveis: + - `SnOut`: Desenquadramento de NFS-e do Simples Nacional + - `SnIn`: Enquadramento de NFS-e no Simples Nacional + - `ImmunityAddRetro`: Inclusão Retroativa de Imunidade/Isenção para NFS-e + - `ImmunityRemoveRetro`: Exclusão Retroativa de Imunidade/Isenção para NFS-e + - `RejectionBuyerOrIntermediary`: Rejeição da NFS-e pelo tomador ou intermediário responsável pelo recolhimento + - `Other`: Outros + enum: [SnOut, SnIn, ImmunityAddRetro, ImmunityRemoveRetro, RejectionBuyerOrIntermediary, Other] + type: string + reasonText: + description: Descrição do motivo (xMotivo). Obrigatório quando `reason = Other`. + type: string + maxLength: 500 + lease: + description: Grupo de informações relativas a atividades de Locação, sublocação, arrendamento, direito de passagem ou permissão de uso, compartilhado ou não, de ferrovia, rodovia, postes, cabos, dutos e condutos de qualquer natureza. + type: object + properties: + category: + description: | + Categoria do serviço. + Valores possíveis: + - `Lease`: Locação + - `Sublease`: Sublocação + - `Leasehold`: Arrendamento + - `RightOfWay`: Direito de passagem + - `UsePermission`: Permissão de uso + enum: [Lease, Sublease, Leasehold, RightOfWay, UsePermission] + type: string + objectType: + description: | + Objeto da locação/sublocação/arrendamento/etc. + Valores possíveis: + - `Railway`: Ferrovia + - `Road`: Rodovia + - `Poles`: Postes + - `Cables`: Cabos + - `Pipelines`: Dutos + - `Conduits`: Condutos + enum: [Railway, Road, Poles, Cables, Pipelines, Conduits] + type: string + totalLength: + format: double + description: Comprimento total de ferrovia/rodovia/cabos/dutos/condutos (extensao). + type: number + polesCount: + format: int32 + description: Número total de postes (nPostes). + type: integer + minimum: 0 + construction: + description: Grupo de informações relativas a obras de construção civil e congêneres. Apenas uma das opções (`workId`, `cibCode` ou `siteAddress`) deve ser preenchida. + type: object + properties: + propertyFiscalRegistration: + description: 'Inscrição imobiliária fiscal (inscImobFisc), exemplos: SQL ou INCRA.' + type: string + maxLength: 60 + workId: + description: Identificação da obra (CNO/CEI) — cObra. + type: object + properties: + scheme: + description: | + Tipo de cadastro da obra. + Valores possíveis: + - `bra.cno`: Cadastro Nacional de Obras + - `bra.cei`: Cadastro Específico do INSS + enum: [bra.cno, bra.cei] + type: string + value: + description: Número da obra no cadastro selecionado. + type: string + maxLength: 30 + cibCode: + description: Código do Cadastro Imobiliário Brasileiro (cCIB). + type: string + maxLength: 30 + siteAddress: + description: Endereço da obra (nacional ou exterior). + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999) ou Código de Endereçamento Postal no exterior' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF (ou Estado, Província, Região no exterior) + type: string + encapsulationNumber: + description: | + Número do encapsulamento da obra (NumeroEncapsulamento). String numérica com 1 a 12 dígitos. + Atualmente utilizado apenas pelo serializador do município de São Paulo (Paulistana). Zeros à esquerda são preservados. + type: string + minLength: 1 + maxLength: 12 + pattern: '^[0-9]{1,12}$' + realEstate: + description: Grupo de informações de operações relacionadas a bens imóveis, exceto obras. Apenas uma das opções (`cibCode` ou `siteAddress`) deve ser preenchida. + type: object + properties: + propertyFiscalRegistration: + description: Inscrição imobiliária fiscal (inscImobFisc). + type: string + maxLength: 60 + cibCode: + description: Código do Cadastro Imobiliário Brasileiro (cCIB). + type: string + maxLength: 30 + siteAddress: + description: Endereço do imóvel (nacional ou exterior). + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999) ou Código de Endereçamento Postal no exterior' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF (ou Estado, Província, Região no exterior) + type: string + foreignTrade: + description: Grupo de informações sobre transações entre residentes ou domiciliados no Brasil com residentes ou domiciliados no exterior. + type: object + properties: + serviceMode: + description: | + Modo de prestação (mdPrestacao). + Valores possíveis: + - `Unknown`: Desconhecido + - `CrossBorder`: Transfronteiriço + - `ConsumptionInBrazil`: Consumo no Brasil + - `TemporaryPersonnel`: Movimento Temporário de Pessoas Físicas + - `ConsumptionAbroad`: Consumo no Exterior + enum: [Unknown, CrossBorder, ConsumptionInBrazil, TemporaryPersonnel, ConsumptionAbroad] + type: string + relationShip: + description: | + Vínculo entre as partes (vincPrest). + Valores possíveis: + - `NoLink`: Sem vínculo com o Tomador/Prestador + - `Controlled`: Controlada + - `Controller`: Controladora + - `Affiliate`: Coligada + - `HeadOffice`: Matriz + - `Branch`: Filial ou sucursal + - `OtherLink`: Outro vínculo + enum: [NoLink, Controlled, Controller, Affiliate, HeadOffice, Branch, OtherLink] + type: string + currency: + description: Moeda da transação (tabela de moedas do Banco Central do Brasil). + type: string + pattern: '^[0-9]+$' + serviceAmountInCurrency: + format: double + description: Valor do serviço na moeda informada em `currency`. + type: number + supportMechanismProvider: + description: | + Mecanismo de apoio/fomento utilizado pelo prestador (mecAFComexP). + Valores possíveis: + - `Unknown`: Desconhecido + - `None`: Nenhum + - `Acc`: ACC - Adiantamento sobre Contrato de Câmbio + - `Ace`: ACE - Adiantamento sobre Cambiais Entregues + - `BndesEximPostShipServices`: BNDES-Exim Pós-Embarque - Serviços + - `BndesEximPreShipServices`: BNDES-Exim Pré-Embarque - Serviços + - `Fge`: FGE - Fundo de Garantia à Exportação + - `ProexEqualization`: PROEX - Equalização + - `ProexFinancing`: PROEX - Financiamento + type: string + enum: [Unknown, None, Acc, Ace, BndesEximPostShipServices, BndesEximPreShipServices, Fge, ProexEqualization, ProexFinancing] + supportMechanismReceiver: + description: | + Mecanismo de apoio/fomento utilizado pelo tomador (mecAFComexT). + Valores possíveis: + - `Unknown`: Desconhecido + - `None`: Nenhum + - `PublicAdminAndInternationalRep`: Adm. Pública e Representação Internacional + - `LeasesMachineryShipsAircraft`: Aluguéis e Arrend. Mercantil de máquinas, equipamentos, embarcações e aeronaves + - `AircraftLeaseAirTransportPublic`: Arrendamento Mercantil de aeronave para empresa de transporte aéreo público + - `ExportAgentsCommission`: Comissão a agentes externos na exportação + - `StorageHandlingTransportAbroad`: Despesas de armazenagem, movimentação e transporte de carga no exterior + - `FifaEventsSubsidiary`: Eventos FIFA (subsidiária) + - `FifaEvents`: Eventos FIFA + - `FreightsVesselAircraftRentalsOthers`: Fretes, arrendamentos de embarcações ou aeronaves e outros + - `AeronauticalMaterial`: Material Aeronáutico + - `PromotionGoodsAbroad`: Promoção de Bens no Exterior + - `PromotionBrazilianTourism`: Promoção de Destinos Turísticos Brasileiros + - `PromotionBrazilAbroad`: Promoção do Brasil no Exterior + - `PromotionServicesAbroad`: Promoção de Serviços no Exterior + - `Recine`: RECINE + - `Recopa`: RECOPA + - `TrademarksPatentsCultivars`: Registro e Manutenção de marcas, patentes e cultivares + - `Reicomp`: REICOMP + - `Reidi`: REIDI + - `Repenec`: REPENEC + - `Repes`: REPES + - `Retaero`: RETAERO + - `Retid`: RETID + - `RoyaltiesTechnicalAssistance`: Royalties, Assistência Técnica, Científica e Assemelhados + - `ConformityAssessmentWto`: Serviços de avaliação da conformidade vinculados aos Acordos da OMC + - `Zpe`: ZPE + type: string + enum: [Unknown, None, PublicAdminAndInternationalRep, LeasesMachineryShipsAircraft, AircraftLeaseAirTransportPublic, ExportAgentsCommission, StorageHandlingTransportAbroad, FifaEventsSubsidiary, FifaEvents, FreightsVesselAircraftRentalsOthers, AeronauticalMaterial, PromotionGoodsAbroad, PromotionBrazilianTourism, PromotionBrazilAbroad, PromotionServicesAbroad, Recine, Recopa, TrademarksPatentsCultivars, Reicomp, Reidi, Repenec, Repes, Retaero, Retid, RoyaltiesTechnicalAssistance, ConformityAssessmentWto, Zpe] + temporaryGoods: + description: | + Vínculo à movimentação temporária de bens (movTempBens). + Valores possíveis: + - `Unknown`: Desconhecido + - `No`: Não + - `LinkedImportDeclaration`: Vinculada - Declaração de Importação + - `LinkedExportDeclaration`: Vinculada - Declaração de Exportação + enum: [Unknown, No, LinkedImportDeclaration, LinkedExportDeclaration] + type: string + importDeclaration: + description: Número da Declaração de Importação (DI/DSI/DA/DRI-E) averbado. + type: string + maxLength: 60 + exportRegistration: + description: Número do Registro de Exportação (RE) averbado. + type: string + maxLength: 60 + mdicDelivery: + description: Indicador de envio da NFS-e ao MDIC. + type: boolean + deduction: + description: | + Grupo de informações relativas aos valores para dedução/redução da base de cálculo do ISSQN (vDR). Aplicado SOMENTE à base de cálculo do ISSQN. Estrutura detalhada alinhada ao padrão da NFS-e Nacional. Quando preenchido, o sistema prioriza estes dados sobre o campo simples `deductionsAmount`. Apenas uma das opções (`rate`, `amount` ou `documents`) deve ser preenchida. + type: object + properties: + rate: + format: double + description: Percentual padrão de dedução/redução (pDR, %). + type: number + amount: + format: double + description: Valor monetário padrão de dedução/redução (vDR, R$). + type: number + documents: + description: Documentos que justificam cada item de dedução/redução (1..1000). + type: array + items: + type: object + required: [deductionType, issueDate, deductibleTotal, usedAmount] + properties: + nfseKey: + description: Chave de acesso da NFS-e nacional (50 dígitos). + type: string + pattern: '^[0-9]{50}$' + nfeKey: + description: Chave de acesso da NF-e de produto (44 dígitos). + type: string + pattern: '^[0-9]{44}$' + municipalNfse: + description: Referência a NFS-e municipal no padrão legado. + type: object + properties: + cityCode: + description: Código IBGE do município emissor. + type: string + number: + description: Número da NFS-e municipal. + type: string + verificationCode: + description: Código de verificação. + type: string + fiscalDocumentNumber: + description: Identificador de outro documento fiscal não eletrônico. + type: string + nonFiscalDocumentNumber: + description: 'Identificador de documento não fiscal (ex: nota de débito interna).' + type: string + deductionType: + description: | + Tipo da dedução/redução (tpDedRed). + Valores aceitos: + - `FoodAndBeverages` (1): Alimentação e bebidas/frigobar + - `Materials` (2): Materiais + - `ConsortiumPassThrough` (5): Repasse consorciado + - `HealthPlanPassThrough` (6): Repasse plano de saúde + - `Services` (7): Serviços + - `Subcontracting` (8): Subempreitada de mão de obra + - `Other` (99): Outras deduções — exige `otherDeductionDescription` + enum: [FoodAndBeverages, Materials, ConsortiumPassThrough, HealthPlanPassThrough, Services, Subcontracting, Other] + type: string + otherDeductionDescription: + description: Obrigatório quando `deductionType = Other`. + type: string + maxLength: 150 + issueDate: + format: date + description: Data de emissão do documento de origem (AAAA-MM-DD). + type: string + deductibleTotal: + format: double + description: Valor total dedutível/redutível no documento de origem. + type: number + usedAmount: + format: double + description: Valor efetivamente utilizado como dedução nesta NFS-e (≤ `deductibleTotal`). + type: number + supplier: + description: Fornecedor do documento (mesma estrutura do `borrower`). + type: object + properties: + type: + description: Tipo do fornecedor + enum: [Undefined, NaturalPerson, LegalEntity] + type: string + name: + description: Nome / Razão Social + type: string + maxLength: 115 + federalTaxNumber: + format: int64 + description: CNPJ, CPF ou NIF + type: integer + municipalTaxNumber: + description: Inscrição Municipal + type: string + maxLength: 12 + stateTaxNumber: + description: Inscrição Estadual (Opcional) + type: string + maxLength: 19 + taxRegime: + description: Tipo do Regime Tributário + enum: [Isento, MicroempreendedorIndividual, SimplesNacional, LucroPresumido, LucroReal] + type: string + caepf: + description: Cadastro de Atividade Econômica da Pessoa Física (CAEPF) + type: string + maxLength: 14 + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + noTaxIdReason: + description: | + Justificativa para ausência de NIF. + Valores possíveis: + - `NotInformedOriginal`: Não informado na nota de origem + - `Exempted`: Dispensado do NIF + - `NotRequired`: Não exigência do NIF + enum: [NotInformedOriginal, Exempted, NotRequired] + type: string + address: + description: Endereço + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF + type: string + benefit: + description: Benefício Municipal aplicado à base de cálculo do ISSQN (BM). Deve conter `id` e exatamente um entre `amount` ou `rate`. + type: object + required: [id] + properties: + id: + description: 'Identificador do benefício (nBM: IBGE[7] + tipo[2] + seq[5]).' + type: string + pattern: '^\d{14}$' + amount: + format: double + description: Redução da BC por valor (vRedBCBM, R$). + type: number + rate: + format: double + description: Redução da BC por percentual (pRedBCBM, %). + type: number + suspension: + description: Suspensão da exigibilidade do ISSQN (exigSusp). + type: object + required: [reason, processNumber] + properties: + reason: + description: | + Motivo da suspensão (tpSusp). + Valores possíveis: + - `Judicial`: Exigibilidade Suspensa por Decisão Judicial + - `Administrative`: Exigibilidade Suspensa por Processo Administrativo + enum: [Judicial, Administrative] + type: string + processNumber: + description: Número do processo (nProcesso). + type: string + maxLength: 30 + serviceAmountDetails: + description: 'Detalhes dos valores do serviço, incluindo encargos. (Versão 2.0 SP)' + type: object + properties: + initialChargedAmount: + format: double + description: Valor Inicial Cobrado (ValorInicialCobrado) — valor dos serviços antes de tributos, multa e juros. + type: number + finalChargedAmount: + format: double + description: Valor Final Cobrado (ValorFinalCobrado) — valor total cobrado pela prestação do serviço, incluindo todos os tributos. + type: number + fineAmount: + format: double + description: Valor da Multa (ValorMulta). + type: number + interestAmount: + format: double + description: Valor dos Juros (ValorJuros). + type: number + additionalInformationGroup: + description: | + Estrutura para envio de informações adicionais em campos específicos (ART/RRT, pedido, etc). Quando `additionalInformation` (texto simples) é preenchido, seu conteúdo é automaticamente copiado para `additionalInformationGroup.otherInformation`. + type: object + properties: + responsibilityDocumentIdentifier: + description: 'Identificador do documento de responsabilidade técnica (ART, RRT, etc.).' + type: string + referencedDocument: + description: Documento de referência relacionado ao serviço prestado. + type: string + order: + description: Número do pedido/ordem de compra/ordem de serviço. + type: string + items: + description: Grupo de itens do pedido/ordem de compra/ordem de serviço. + type: array + items: + type: object + properties: + item: + description: Item do pedido/ordem de compra/ordem de serviço. + type: string + otherInformation: + description: Outras informações complementares. + type: string + approximateTotals: + description: | + Totais aproximados dos tributos (Lei 12.741/2012) com detalhamento por esfera (totTrib). Granularidade maior que o campo `approximateTax`. Se ambos forem preenchidos, o sistema prioriza `approximateTotals`. Se nenhum for preenchido, o cálculo é realizado automaticamente e preenche o grupo `approximateTax`. + type: object + properties: + federal: + description: Tributos federais. + type: object + properties: + rate: + format: double + description: Percentual total aproximado dos tributos federais (%) (pTotTribFed). + type: number + minimum: 0 + amount: + format: double + description: Valor total aproximado dos tributos federais (R$) (vTotTribFed). + type: number + minimum: 0 + state: + description: Tributos estaduais. + type: object + properties: + rate: + format: double + description: Percentual total aproximado dos tributos estaduais (%). + type: number + minimum: 0 + amount: + format: double + description: Valor total aproximado dos tributos estaduais (R$). + type: number + minimum: 0 + municipal: + description: Tributos municipais. + type: object + properties: + rate: + format: double + description: Percentual total aproximado dos tributos municipais (%) (pTotTribMun). + type: number + minimum: 0 + amount: + format: double + description: Valor total aproximado dos tributos municipais (R$) (vTotTribMun). + type: number + minimum: 0 + rate: + format: double + description: Percentual total aproximado dos tributos (%). + type: number + minimum: 0 + amount: + format: double + description: Valor total aproximado dos tributos (R$). + type: number + minimum: 0 + ibsCbs: + description: | + Informações referentes ao IBS (Imposto sobre Bens e Serviços) e à CBS (Contribuição sobre Bens e Serviços), tributos introduzidos pela Reforma Tributária. (IBSCBS) + + **Campos obrigatórios:** `classCode` e `operationIndicator`. + type: object + required: [classCode, operationIndicator] + properties: + purpose: + description: | + Finalidade da emissão da NFS-e (finNFe). + Valores possíveis: + - `regular`: Regular + enum: [regular] + default: regular + type: string + destinationIndicator: + description: | + Relação entre destinatário e comprador/tomador indicado na NFS-e (indDest). Quando `DifferentFromBuyer`, o grupo `recipient` torna-se obrigatório. + Valores possíveis: + - `SameAsBuyer`: O destinatário é o mesmo que o comprador/tomador + - `DifferentFromBuyer`: O destinatário é diferente do comprador/tomador + enum: [SameAsBuyer, DifferentFromBuyer] + default: SameAsBuyer + type: string + basis: + format: double + description: Base de cálculo antes de reduções para cálculo do tributo bruto (vBC). + type: number + reimbursedResuppliedAmount: + format: double + description: Montante relativo a reembolso/repasse/ressarcimento não integrante da BC (vReembRepasse). + type: number + ibscbsDeductionReductionAmount: + format: double + description: Valor monetário (R$) total relativo aos valores de dedução e redução da Base de Cálculo do IBS e da CBS (vCalcDedRedIBSCBS). + type: number + isDonation: + description: Indica se a operação é uma doação (indDoacao). + type: boolean + nullable: true + personalUse: + description: | + Indicador de uso ou consumo pessoal do adquirente (indFinal). Crucial para regras tributárias específicas, como a não geração de crédito de IBS/CBS para o tomador. + type: boolean + nullable: true + operationIndicator: + description: | + Código que define a natureza e o local de incidência do IBS/CBS (cIndOp). Determina onde o imposto é devido — município do imóvel, estabelecimento do fornecedor, endereço do adquirente, local do evento, etc. + + A lista completa de valores pode ser consultada na Tabela de [operationIndicator](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/documentacao-layout-nfse-rtc/#tabela-de-operationindicator). + type: string + maxLength: 7 + operationType: + description: | + Tipo de Operação com Entes Governamentais ou outros serviços sobre bens imóveis (tpOper). + Valores possíveis: + - `SupplyFirstPayLater`: Fornecimento com pagamento posterior + - `PayForPastSupply`: Recebimento do pagamento com fornecimento já realizado + - `SupplyForPastPay`: Fornecimento com pagamento já realizado + - `PayFirstSupplyLater`: Recebimento do pagamento com fornecimento posterior + - `SupplyPayTogether`: Fornecimento e recebimento do pagamento concomitantes + enum: [SupplyFirstPayLater, PayForPastSupply, SupplyForPastPay, PayFirstSupplyLater, SupplyPayTogether] + type: string + situationCode: + description: | + Código de Situação Tributária do IBS/CBS. Opcional. Quando não preenchido, será derivado dos 3 primeiros caracteres de `classCode`. + + Lista completa em [situationCode](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/documentacao-layout-nfse-rtc/#tabela-de-situationcode). + type: string + classCode: + description: | + Código de Classificação Tributária do IBS/CBS (cClassTrib). + + Lista completa em [classCode](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/documentacao-layout-nfse-rtc/#tabela-de-classcode). + type: string + maxLength: 6 + relatedDocs: + description: Grupo de NFS-e referenciadas (gRefNFSe). + type: object + properties: + items: + description: Chaves de NFS-e referenciadas (refNFSe). + type: array + maxItems: 99 + items: + type: string + maxLength: 50 + leasedMovableAssets: + description: 'Grupo de informações relativas aos bens móveis objetos de locação (gLocBensMoveis). Admitido apenas quando `cTribNac = 99.04.01`.' + type: array + minItems: 0 + maxItems: 99 + items: + type: object + properties: + ncmCode: + description: Código NCM do bem móvel objeto da locação (cNCMBemMovel). + type: string + maxLength: 8 + description: + description: Descrição do bem móvel objeto da locação (xNCMBemMovel). + type: string + maxLength: 150 + quantity: + format: int32 + description: Quantidade do bem móvel objeto da locação (qtdNCMBemMovel). + type: integer + realEstate: + description: 'Operações relacionadas a bens imóveis dentro do IBS/CBS. Apenas uma das opções (`cibCode` ou `siteAddress`) deve ser preenchida.' + type: object + properties: + propertyFiscalRegistration: + description: Inscrição imobiliária fiscal (inscImobFisc). + type: string + maxLength: 60 + cibCode: + description: Código do Cadastro Imobiliário Brasileiro (cCIB). + type: string + maxLength: 30 + siteAddress: + description: Endereço do imóvel. + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999) ou Código de Endereçamento Postal no exterior' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF (ou Estado, Província, Região no exterior) + type: string + ibs: + description: 'Alíquotas e total do IBS por esfera subnacional (estadual + municipal).' + type: object + required: [totalAmount, state, municipal] + properties: + totalAmount: + format: double + description: 'Total do IBS (vIBSTot = vIBSUF + vIBSMun).' + type: number + state: + description: IBS na esfera estadual. + type: object + required: [rate, effectiveRate] + properties: + rate: + format: double + description: Alíquota IBS UF (%) (pAliqIBSUF). + type: number + rateReduction: + format: double + description: Redução de alíquota estadual (%). + type: number + default: 0 + effectiveRate: + format: double + description: 'pAliqEfetUF = rate × (1 − rateReduction). Se rateReduction ausente, usar rate.' + type: number + deferment: + description: Diferimento do IBS na esfera estadual. + type: object + properties: + rate: + format: double + description: Percentual de diferimento (pDif, %). + type: number + amount: + format: double + description: Valor do diferimento (vDif). + type: number + returnedAmount: + format: double + description: Valor de imposto devolvido/devolução (vDevTrib) na esfera estadual. + type: number + amount: + format: double + description: Valor do IBS da UF (vIBSUF). + type: number + municipal: + description: IBS na esfera municipal. + type: object + required: [rate, effectiveRate] + properties: + rate: + format: double + description: Alíquota IBS Município (%) (pAliqIBSMun). + type: number + rateReduction: + format: double + description: Redução de alíquota municipal (%). + type: number + default: 0 + effectiveRate: + format: double + description: 'pAliqEfetMun = rate × (1 − rateReduction). Se rateReduction ausente, usar rate.' + type: number + deferment: + description: Diferimento do IBS na esfera municipal. + type: object + properties: + rate: + format: double + description: Percentual de diferimento (pDif, %). + type: number + amount: + format: double + description: Valor do diferimento (vDif). + type: number + returnedAmount: + format: double + description: Valor de imposto devolvido/devolução (vDevTrib) na esfera municipal. + type: number + amount: + format: double + description: Valor do IBS do Município (vIBSMun). + type: number + cbs: + description: 'Alíquotas da CBS (esfera federal).' + type: object + required: [rate, effectiveRate] + properties: + rate: + format: double + description: Alíquota da CBS (%) (pAliqCBS). + type: number + rateReduction: + format: double + description: Redução de alíquota da CBS (%). + type: number + default: 0 + effectiveRate: + format: double + description: 'pAliqEfetCBS = rate × (1 − rateReduction). Se rateReduction ausente, usar rate.' + type: number + deferment: + description: Diferimento da CBS. + type: object + properties: + rate: + format: double + description: Percentual de diferimento (pDif, %). + type: number + amount: + format: double + description: Valor do diferimento (vDif). + type: number + returnedAmount: + format: double + description: Valor de imposto devolvido/devolução da CBS (vDevTrib). + type: number + amount: + format: double + description: Valor total da CBS (vCBS). + type: number + regularTaxation: + description: Tributação regular hipotética caso condição resolutória/suspensiva não se aplique. (tpGTribRegular) + type: object + properties: + situationCode: + description: CST regular (CSTReg), 3 dígitos. + type: string + classCode: + description: Classificação tributária regular (cClassTribReg), 6 dígitos. + type: string + ibs: + type: object + properties: + totalAmount: + format: double + description: Total do IBS regular (vIBSTotReg). + type: number + state: + type: object + properties: + effectiveRate: + format: double + description: Alíquota efetiva IBS UF (pAliqEfetRegIBSUF). + type: number + amount: + format: double + description: IBS UF regular (vTribRegIBSUF). + type: number + municipal: + type: object + properties: + effectiveRate: + format: double + description: Alíquota efetiva IBS Município (pAliqEfetRegIBSMun). + type: number + amount: + format: double + description: IBS Município regular (vTribRegIBSMun). + type: number + cbs: + type: object + properties: + effectiveRate: + format: double + description: Alíquota efetiva CBS (pAliqEfetRegCBS). + type: number + amount: + format: double + description: CBS regular (vTribRegCBS). + type: number + presumedCredits: + description: Créditos presumidos de IBS e CBS quando aplicáveis. + type: object + properties: + ibs: + type: object + properties: + code: + description: Código do crédito presumido IBS (cCredPres). + type: string + pattern: '^\d{2}$' + rate: + format: double + description: Percentual do crédito presumido IBS (pCredPres). + type: number + amount: + format: double + description: Valor do crédito presumido IBS (vCredPres). + type: number + conditionalAmount: + format: double + description: Valor do crédito presumido IBS sob condição suspensiva (vCredPresCondSus). + type: number + cbs: + type: object + properties: + code: + description: Código do crédito presumido CBS (cCredPres). + type: string + pattern: '^\d{2}$' + rate: + format: double + description: Percentual do crédito presumido CBS (pCredPres). + type: number + amount: + format: double + description: Valor do crédito presumido CBS (vCredPres). + type: number + conditionalAmount: + format: double + description: Valor do crédito presumido CBS sob condição suspensiva (vCredPresCondSus). + type: number + governmentPurchase: + description: Composição do valor de IBS e CBS em compras governamentais. + type: object + properties: + entityType: + description: | + Tipo do ente da compra governamental (tpEnteGov). + Valores possíveis: + - `Union`: União + - `State`: Estado + - `FederalDistrict`: Distrito Federal + - `Municipality`: Município + enum: [Union, State, FederalDistrict, Municipality] + type: string + operationType: + description: | + Tipo de Operação com Entes Governamentais (tpOperGov). + Valores possíveis: + - `SupplyFirstPayLater`: Fornecimento com pagamento posterior + - `PayForPastSupply`: Pagamento de fornecimento anterior + - `SupplyForPastPay`: Fornecimento com pagamento antecipado + - `SupplyPayTogether`: Fornecimento e pagamento concomitantes + enum: [SupplyFirstPayLater, PayForPastSupply, SupplyForPastPay, SupplyPayTogether] + type: string + ibs: + type: object + properties: + totalAmount: + format: double + description: Total do IBS em compras governamentais (vIBSTotGov). + type: number + state: + type: object + properties: + rate: + format: double + description: Alíquota IBS UF em compras governamentais (pAliqIBSUF). + type: number + amount: + format: double + description: Valor IBS UF em compras governamentais (vTribIBSUF). + type: number + municipal: + type: object + properties: + rate: + format: double + description: Alíquota IBS Município em compras governamentais (pAliqIBSMun). + type: number + amount: + format: double + description: Valor IBS Município em compras governamentais (vTribIBSMun). + type: number + cbs: + type: object + properties: + rate: + format: double + description: Alíquota CBS em compras governamentais (pAliqCBS). + type: number + amount: + format: double + description: Valor CBS em compras governamentais (vTribCBS). + type: number + creditTransfer: + description: Transferência de créditos de IBS e CBS. + type: object + properties: + ibsAmount: + format: double + description: Valor de IBS a transferir (vIBS). + type: number + cbsAmount: + format: double + description: Valor de CBS a transferir (vCBS). + type: number + thirdPartyReimbursements: + description: Valores de reembolso/repasse/ressarcimento já tributados e aqui referenciados. (tpGrupoReeRepRes) + type: object + properties: + documents: + description: Documentos que justificam a exclusão da BC de IBS/CBS/ISS (1..1000). + type: array + minItems: 1 + maxItems: 1000 + items: + type: object + required: [issueDate, accrualOn, reimbursementType, amount] + properties: + nfseKey: + description: Chave NFS-e (padrão nacional). + type: string + maxLength: 50 + nfeKey: + description: Chave NF-e (44 dígitos). + type: string + pattern: '^[0-9]{44}$' + cteKey: + description: Chave CT-e (44 dígitos). + type: string + pattern: '^[0-9]{44}$' + otherNationalDfe: + description: Outro DF-e presente no repositório nacional. + type: object + required: [dfeKey, dfeTypeText] + properties: + dfeKey: + description: Chave do DF-e (chDFE). + type: string + maxLength: 50 + dfeTypeText: + description: Tipo do DF-e (xTpDFE). + type: string + maxLength: 255 + dfeType: + description: Documento fiscal a que se refere a chaveDfe (tipoChaveDFE). + type: string + maxLength: 1 + otherFiscalDoc: + description: Documento fiscal que não está no repositório nacional (eletrônico ou não). + type: object + required: [issuerCityCode, fiscalDocNumber] + properties: + issuerCityCode: + description: Código IBGE do município emissor do documento fiscal. + type: string + fiscalDocNumber: + description: Número do documento fiscal. + type: string + maxLength: 255 + fiscalDocDescription: + description: Descrição do documento fiscal. + type: string + maxLength: 255 + otherDoc: + description: Documento não fiscal. + type: object + required: [docNumber, docDescription] + properties: + docNumber: + description: Número do documento. + type: string + maxLength: 255 + docDescription: + description: Descrição do documento. + type: string + maxLength: 255 + supplier: + description: Fornecedor/emitente do documento referenciado (mesma estrutura do `borrower`). + type: object + properties: + type: + description: Tipo do fornecedor + enum: [Undefined, NaturalPerson, LegalEntity] + type: string + name: + description: Nome / Razão Social + type: string + maxLength: 115 + federalTaxNumber: + format: int64 + description: CNPJ, CPF ou NIF + type: integer + municipalTaxNumber: + description: Inscrição Municipal + type: string + maxLength: 12 + stateTaxNumber: + description: Inscrição Estadual (Opcional) + type: string + maxLength: 19 + taxRegime: + description: Tipo do Regime Tributário + enum: [Isento, MicroempreendedorIndividual, SimplesNacional, LucroPresumido, LucroReal] + type: string + caepf: + description: Cadastro de Atividade Econômica da Pessoa Física (CAEPF) + type: string + maxLength: 14 + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + noTaxIdReason: + description: | + Justificativa para ausência de NIF. + Valores possíveis: + - `NotInformedOriginal`: Não informado na nota de origem + - `Exempted`: Dispensado do NIF + - `NotRequired`: Não exigência do NIF + enum: [NotInformedOriginal, Exempted, NotRequired] + type: string + address: + description: Endereço + type: object + properties: + country: + description: 'Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USA, ARG' + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10)' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado/UF + type: string + issueDate: + format: date + description: Data de emissão (AAAA-MM-DD). + type: string + accrualOn: + format: date + description: Data de competência (AAAA-MM-DD). + type: string + reimbursementType: + description: | + Motivo do reembolso/repasse/ressarcimento (tpReemb). + Valores possíveis: + - `RealEstateBrokerPassThrough`: Repasse de corretagem de imóveis + - `TravelAgencySupplierPassThrough`: Repasse de valores de fornecedores em agência de viagens + - `AdAgencyExternalProductionReimbursement`: Reembolso de produção externa em agência de publicidade + - `AdAgencyMediaReimbursement`: Reembolso de despesas com mídia em agência de publicidade + - `OtherReimbursement`: Outros reembolsos ou ressarcimentos + enum: [RealEstateBrokerPassThrough, TravelAgencySupplierPassThrough, AdAgencyExternalProductionReimbursement, AdAgencyMediaReimbursement, OtherReimbursement] + type: string + reimbursementTypeText: + description: Obrigatório quando `reimbursementType = OtherReimbursement` (xReembOutros). + type: string + maxLength: 150 + amount: + format: double + description: 'Valor considerado para exclusão da BC (total ou parcial, R$) (vReemb).' + type: number + responses: + "202": + description: Nota Fiscal de Serviços foi enviada com sucesso para fila de emissão + content: + application/json: + schema: + required: + - environment + type: object + properties: + id: + description: Identificação + type: string + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + flowStatus: + description: | + Status do processamento da NFS-e no fluxo de emissão. + Valores possíveis: + - `CancelFailed` (-2): Falha no cancelamento — tentativa de cancelar a NFS-e foi rejeitada + - `IssueFailed` (-1): Falha na emissão — a NFS-e não foi autorizada pela Prefeitura + - `Issued` (1): Emitida — autorizada pela Prefeitura + - `Cancelled` (2): Cancelada + - `PullFromCityHall` (3): Capturada da Prefeitura (sincronização de NFS-e já emitida fora da plataforma) + - `WaitingCalculateTaxes` (10): Aguardando cálculo de tributos + - `WaitingDefineRpsNumber` (11): Aguardando definição do número da RPS + - `WaitingSend` (12): Aguardando envio à Prefeitura + - `WaitingSendCancel` (13): Aguardando envio do cancelamento à Prefeitura + - `WaitingReturn` (14): Aguardando retorno da Prefeitura + - `WaitingDownload` (15): Aguardando download do XML/PDF + enum: + - CancelFailed + - IssueFailed + - Issued + - Cancelled + - PullFromCityHall + - WaitingCalculateTaxes + - WaitingDefineRpsNumber + - WaitingSend + - WaitingSendCancel + - WaitingReturn + - WaitingDownload + type: string + flowMessage: + description: Mensagem de processamento + type: string + provider: + description: Prestador dos serviços + type: object + properties: + tradeName: + description: Nome Fantasia + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + issRate: + format: double + description: Taxa da Aliquota do ISS (Simples Nacional) + type: number + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endere o + required: + - country + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + borrower: + description: Tomador dos serviços + type: object + properties: + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + address: + description: Endereço + required: + - country + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + externalId: + description: Identificação única do cliente + type: string + batchNumber: + format: int64 + description: Número do lote da RPS + type: integer + batchCheckNumber: + description: Número do protocolo do lote da RPS + type: string + number: + format: int64 + description: Número do NFE + type: integer + checkCode: + description: Código de Verificação da NFE + type: string + status: + description: Status da NFE + enum: + - Error + - None + - Created + - Issued + - Cancelled + type: string + rpsType: + description: Tipo da RPS + enum: + - Rps + - RpsMista + - Cupom + type: string + rpsStatus: + description: Status da RPS + enum: + - Normal + - Canceled + - Lost + type: string + taxationType: + description: | + Tipo da tributação do ISSQN (TributacaoRPS). + Valores possíveis: + - `None`: Nenhuma + - `WithinCity`: Tributação dentro do mesmo município + - `OutsideCity`: Tributação fora do município + - `Export`: Exportação + - `Free`: Isento + - `Immune`: Imune + - `SuspendedCourtDecision`: Exigibilidade suspensa por decisão judicial + - `SuspendedAdministrativeProcedure`: Exigibilidade suspensa por procedimento administrativo + - `OutsideCityFree`: Tributação fora do município porém isento + - `OutsideCityImmune`: Tributação fora do município porém imune + - `OutsideCitySuspended`: Tributação fora do município porém suspensa + - `OutsideCitySuspendedAdministrativeProcedure`: Tributação fora do município, suspensa por procedimento administrativo + - `ObjectiveImune`: Tributação no município com indicação de imunidade objetiva + enum: + - None + - WithinCity + - OutsideCity + - Export + - Free + - Immune + - SuspendedCourtDecision + - SuspendedAdministrativeProcedure + - OutsideCityFree + - OutsideCityImmune + - OutsideCitySuspended + - OutsideCitySuspendedAdministrativeProcedure + - ObjectiveImune + type: string + issuedOn: + format: date-time + description: Data de emissão + type: string + cancelledOn: + format: date-time + description: Data de cancelamento + type: string + rpsSerialNumber: + description: Número de serie da RPS + type: string + rpsNumber: + format: int64 + description: Número da RPS + type: integer + cityServiceCode: + description: Código do servico prestado no Municipio + type: string + federalServiceCode: + description: Código do servico prestado federal + type: string + description: + description: Descrição do serviço no municipio + type: string + servicesAmount: + format: double + description: Valor do serviços + type: number + deductionsAmount: + format: double + description: Valor de deduções + type: number + discountUnconditionedAmount: + format: double + description: Valor do desconto incondicionado + type: number + discountConditionedAmount: + format: double + description: Valor do desconto condicionado + type: number + baseTaxAmount: + format: double + description: Valor da base de calculo de impostos + type: number + issRate: + format: double + description: Aliquota do ISS + type: number + issTaxAmount: + format: double + description: Valor do ISS + type: number + irAmountWithheld: + format: double + description: Valor retido do Imposto de Renda (IR) + type: number + pisAmountWithheld: + format: double + description: Valor retido do PIS + type: number + cofinsAmountWithheld: + format: double + description: Valor retido do COFINS + type: number + csllAmountWithheld: + format: double + description: Valor retido do CSLL + type: number + inssAmountWithheld: + format: double + description: Valor retido do INSS + type: number + issAmountWithheld: + format: double + description: Valor retido do ISS + type: number + othersAmountWithheld: + format: double + description: Valor de outras retenções + type: number + amountWithheld: + format: double + description: Valor das retenções + type: number + amountNet: + format: double + description: Valor líquido + type: number + location: + description: Local da Prestação do Serviço + type: object + properties: + state: + description: Estado + type: string + country: + description: País + type: string + postalCode: + description: Código Postal + type: string + street: + description: Logradouro + type: string + number: + description: Número + type: string + district: + description: Bairro + type: string + AdditionalInformation: + description: Informações Adicionais (Complemento) + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + activityEvent: + description: Detalhes da atividade do evento + type: object + properties: + name: + description: Nome do evento + type: string + beginOn: + format: date-time + description: Data de início do evento + type: string + endOn: + format: date-time + description: Data do fim do evento + type: string + Code: + description: Código da atividade do evento + type: string + approximateTax: + description: Tributos aproximados + type: object + properties: + source: + description: Nome da fonte da taxa + type: string + version: + description: Versão da taxa baseado na fonte + type: string + totalRate: + format: double + description: Taxa dos tributos aproximados + type: number + additionalInformation: + description: Informações Adicionais + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "408": + description: Tempo de reposta do servidor excedeu o limite (60s) + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices/external/{id}: + get: + tags: + - ServiceInvoices + summary: Obter os detalhes de uma Nota Fiscal de Serviço (NFSE) através do ID externo (externalId) + description: Você precisará do API Key da Empresa + operationId: ServiceInvoices_idGet + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: externalId + in: path + description: ID externo da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + required: + - environment + type: object + properties: + id: + description: Identificação + type: string + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + flowStatus: + description: | + Status do processamento da NFS-e no fluxo de emissão. + Valores possíveis: + - `CancelFailed` (-2): Falha no cancelamento — tentativa de cancelar a NFS-e foi rejeitada + - `IssueFailed` (-1): Falha na emissão — a NFS-e não foi autorizada pela Prefeitura + - `Issued` (1): Emitida — autorizada pela Prefeitura + - `Cancelled` (2): Cancelada + - `PullFromCityHall` (3): Capturada da Prefeitura (sincronização de NFS-e já emitida fora da plataforma) + - `WaitingCalculateTaxes` (10): Aguardando cálculo de tributos + - `WaitingDefineRpsNumber` (11): Aguardando definição do número da RPS + - `WaitingSend` (12): Aguardando envio à Prefeitura + - `WaitingSendCancel` (13): Aguardando envio do cancelamento à Prefeitura + - `WaitingReturn` (14): Aguardando retorno da Prefeitura + - `WaitingDownload` (15): Aguardando download do XML/PDF + enum: + - CancelFailed + - IssueFailed + - Issued + - Cancelled + - PullFromCityHall + - WaitingCalculateTaxes + - WaitingDefineRpsNumber + - WaitingSend + - WaitingSendCancel + - WaitingReturn + - WaitingDownload + type: string + flowMessage: + description: Mensagem de processamento + type: string + provider: + description: Prestador dos serviços + type: object + properties: + tradeName: + description: Nome Fantasia + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + issRate: + format: double + description: Taxa da Aliquota do ISS (Simples Nacional) + type: number + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + borrower: + description: Tomador dos serviços + type: object + properties: + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + externalId: + description: Identificação única do cliente + type: string + batchNumber: + format: int64 + description: Número do lote da RPS + type: integer + batchCheckNumber: + description: Número do protocolo do lote da RPS + type: string + number: + format: int64 + description: Número do NFE + type: integer + checkCode: + description: Código de Verificação da NFE + type: string + status: + description: Status da NFE + enum: + - Error + - None + - Created + - Issued + - Cancelled + type: string + rpsType: + description: Tipo da RPS + enum: + - Rps + - RpsMista + - Cupom + type: string + rpsStatus: + description: Status da RPS + enum: + - Normal + - Canceled + - Lost + type: string + taxationType: + description: | + Tipo da tributação do ISSQN (TributacaoRPS). + Valores possíveis: + - `None`: Nenhuma + - `WithinCity`: Tributação dentro do mesmo município + - `OutsideCity`: Tributação fora do município + - `Export`: Exportação + - `Free`: Isento + - `Immune`: Imune + - `SuspendedCourtDecision`: Exigibilidade suspensa por decisão judicial + - `SuspendedAdministrativeProcedure`: Exigibilidade suspensa por procedimento administrativo + - `OutsideCityFree`: Tributação fora do município porém isento + - `OutsideCityImmune`: Tributação fora do município porém imune + - `OutsideCitySuspended`: Tributação fora do município porém suspensa + - `OutsideCitySuspendedAdministrativeProcedure`: Tributação fora do município, suspensa por procedimento administrativo + - `ObjectiveImune`: Tributação no município com indicação de imunidade objetiva + enum: + - None + - WithinCity + - OutsideCity + - Export + - Free + - Immune + - SuspendedCourtDecision + - SuspendedAdministrativeProcedure + - OutsideCityFree + - OutsideCityImmune + - OutsideCitySuspended + - OutsideCitySuspendedAdministrativeProcedure + - ObjectiveImune + type: string + issuedOn: + format: date-time + description: Data de emissão + type: string + cancelledOn: + format: date-time + description: Data de cancelamento + type: string + rpsSerialNumber: + description: Número de serie da RPS + type: string + rpsNumber: + format: int64 + description: Número da RPS + type: integer + cityServiceCode: + description: Código do servico prestado no Municipio + type: string + federalServiceCode: + description: Código do servico prestado federal + type: string + description: + description: Descrição do serviço no municipio + type: string + servicesAmount: + format: double + description: Valor do serviços + type: number + deductionsAmount: + format: double + description: Valor de deduções + type: number + discountUnconditionedAmount: + format: double + description: Valor do desconto incondicionado + type: number + discountConditionedAmount: + format: double + description: Valor do desconto condicionado + type: number + baseTaxAmount: + format: double + description: Valor da base de calculo de impostos + type: number + issRate: + format: double + description: Aliquota do ISS + type: number + issTaxAmount: + format: double + description: Valor do ISS + type: number + irAmountWithheld: + format: double + description: Valor retido do Imposto de Renda (IR) + type: number + pisAmountWithheld: + format: double + description: Valor retido do PIS + type: number + cofinsAmountWithheld: + format: double + description: Valor retido do COFINS + type: number + csllAmountWithheld: + format: double + description: Valor retido do CSLL + type: number + inssAmountWithheld: + format: double + description: Valor retido do INSS + type: number + issAmountWithheld: + format: double + description: Valor retido do ISS + type: number + othersAmountWithheld: + format: double + description: Valor de outras retenções + type: number + amountWithheld: + format: double + description: Valor das retenções + type: number + amountNet: + format: double + description: Valor líquido + type: number + location: + description: Local da Prestação do Serviço + type: object + properties: + state: + description: Estado + type: string + country: + description: País + type: string + postalCode: + description: Código Postal + type: string + street: + description: Logradouro + type: string + number: + description: Número + type: string + district: + description: Bairro + type: string + AdditionalInformation: + description: Informações Adicionais (Complemento) + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + activityEvent: + description: Detalhes da atividade do evento + type: object + properties: + name: + description: Nome do evento + type: string + beginOn: + format: date-time + description: Data de início do evento + type: string + endOn: + format: date-time + description: Data do fim do evento + type: string + Code: + description: Código da atividade do evento + type: string + approximateTax: + description: Tributos aproximados + type: object + properties: + source: + description: Nome da fonte da taxa + type: string + version: + description: Versão da taxa baseado na fonte + type: string + totalRate: + format: double + description: Taxa dos tributos aproximados + type: number + additionalInformation: + description: Informações Adicionais + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices/{id}: + get: + tags: + - ServiceInvoices + summary: Obter os detalhes de uma Nota Fiscal de Serviço (NFSE) + description: Você precisará do API Key da Empresa + operationId: ServiceInvoices_idGet + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + required: + - environment + type: object + properties: + id: + description: Identificação + type: string + environment: + description: | + Ambiente de processamento da nota fiscal. + Valores possíveis: + - `Development`: Desenvolvimento (uso interno/sandbox) + - `Production`: Produção — emite nota com validade fiscal + - `Staging`: Homologação — emite nota apenas para testes, sem validade fiscal + enum: + - Development + - Production + - Staging + type: string + flowStatus: + description: | + Status do processamento da NFS-e no fluxo de emissão. + Valores possíveis: + - `CancelFailed` (-2): Falha no cancelamento — tentativa de cancelar a NFS-e foi rejeitada + - `IssueFailed` (-1): Falha na emissão — a NFS-e não foi autorizada pela Prefeitura + - `Issued` (1): Emitida — autorizada pela Prefeitura + - `Cancelled` (2): Cancelada + - `PullFromCityHall` (3): Capturada da Prefeitura (sincronização de NFS-e já emitida fora da plataforma) + - `WaitingCalculateTaxes` (10): Aguardando cálculo de tributos + - `WaitingDefineRpsNumber` (11): Aguardando definição do número da RPS + - `WaitingSend` (12): Aguardando envio à Prefeitura + - `WaitingSendCancel` (13): Aguardando envio do cancelamento à Prefeitura + - `WaitingReturn` (14): Aguardando retorno da Prefeitura + - `WaitingDownload` (15): Aguardando download do XML/PDF + enum: + - CancelFailed + - IssueFailed + - Issued + - Cancelled + - PullFromCityHall + - WaitingCalculateTaxes + - WaitingDefineRpsNumber + - WaitingSend + - WaitingSendCancel + - WaitingReturn + - WaitingDownload + type: string + flowMessage: + description: Mensagem de processamento + type: string + provider: + description: Prestador dos serviços + type: object + properties: + tradeName: + description: Nome Fantasia + type: string + openningDate: + format: date-time + description: Data abertura da empresa + type: string + taxRegime: + description: | + Código de Regime Tributário (CRT) da empresa. + Valores possíveis: + - `Isento`: Isento de tributação + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido (Regime Normal) + - `LucroReal`: Lucro Real (Regime Normal) + enum: + - Isento + - MicroempreendedorIndividual + - SimplesNacional + - LucroPresumido + - LucroReal + type: string + specialTaxRegime: + description: | + Regime Especial de Tributação (indRegTrib) — aplicável a prestadores de serviços. + Valores possíveis: + - `Automatico`: Determinação automática pela API conforme cadastro da empresa + - `Nenhum`: Sem regime especial de tributação + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa fiscal + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `Cooperativa`: Cooperativa + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + enum: + - Automatico + - Nenhum + - MicroempresaMunicipal + - Estimativa + - SociedadeDeProfissionais + - Cooperativa + - MicroempreendedorIndividual + - MicroempresarioEmpresaPequenoPorte + type: string + legalNature: + description: | + Código da Natureza Jurídica da empresa, conforme tabela do IBGE. + Valores possíveis (principais): + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `CondominioEdilicio`: Condomínio Edilício + - `OrganizacaoReligiosa`: Organização Religiosa + - `AssociacaoPrivada`: Associação Privada + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + enum: + - EmpresaPublica + - SociedadeEconomiaMista + - SociedadeAnonimaAberta + - SociedadeAnonimaFechada + - SociedadeEmpresariaLimitada + - SociedadeEmpresariaEmNomeColetivo + - SociedadeEmpresariaEmComanditaSimples + - SociedadeEmpresariaEmComanditaporAcoes + - SociedadeemContaParticipacao + - Empresario + - Cooperativa + - ConsorcioSociedades + - GrupoSociedades + - EmpresaDomiciliadaExterior + - ClubeFundoInvestimento + - SociedadeSimplesPura + - SociedadeSimplesLimitada + - SociedadeSimplesEmNomeColetivo + - SociedadeSimplesEmComanditaSimples + - EmpresaBinacional + - ConsorcioEmpregadores + - ConsorcioSimples + - EireliNaturezaEmpresaria + - EireliNaturezaSimples + - ServicoNotarial + - FundacaoPrivada + - ServicoSocialAutonomo + - CondominioEdilicio + - ComissaoConciliacaoPrevia + - EntidadeMediacaoArbitragem + - PartidoPolitico + - EntidadeSindical + - EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras + - FundacaoAssociacaoDomiciliadaExterior + - OrganizacaoReligiosa + - ComunidadeIndigena + - FundoPrivado + - AssociacaoPrivada + type: string + economicActivities: + description: Atividades da Empresa + type: array + items: + type: object + properties: + type: + enum: + - Main + - Secondary + type: string + code: + format: int32 + type: integer + companyRegistryNumber: + format: int64 + description: Número de Inscrição na Junta Comercial + type: integer + regionalTaxNumber: + format: int64 + description: Número de Inscrição na SEFAZ (IE) + type: integer + municipalTaxNumber: + description: Número de Inscrição na Prefeitura (CCM) + type: string + issRate: + format: double + description: Taxa da Aliquota do ISS (Simples Nacional) + type: number + federalTaxDetermination: + description: Determinação de imposto federal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + municipalTaxDetermination: + description: Determinação de imposto municipal + enum: + - NotInformed + - Default + - SimplesNacional + type: string + loginName: + description: Nome de login + type: string + loginPassword: + description: Senha de login + type: string + authIssueValue: + description: Valor de emissão de autorização + type: string + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + borrower: + description: Tomador dos serviços + type: object + properties: + parentId: + type: string + id: + description: Identificação + type: string + name: + description: Nome ou Razão Social + type: string + federalTaxNumber: + format: int64 + description: CNPJ ou CPF + type: integer + phoneNumber: + description: Telefone + type: string + email: + description: Email + type: string + address: + description: Endereço + required: + - country + - street + - number + type: object + properties: + country: + description: "Sigla do País (padrão ISO 3166-1 mais em http://bit.ly/1OgCkxd)\r\nExemplo: BRA, USD, ARG" + type: string + postalCode: + description: 'CEP (Exemplo: 99999-999)' + type: string + street: + description: Logradouro + type: string + number: + description: 'Número (Exemplo: 185 ou S/N)' + type: string + additionalInformation: + description: 'Complemento (Exemplo: BLC A; APT 10' + type: string + district: + description: Bairro + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + state: + description: Estado + type: string + status: + description: Status no sistema + enum: + - Inactive + - None + - Active + type: string + type: + description: 'Tipo da pessoa: Jurídica ou Física' + enum: + - Undefined + - NaturalPerson + - LegalEntity + - LegalPerson + - Company + - Customer + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + externalId: + description: Identificação única do cliente + type: string + batchNumber: + format: int64 + description: Número do lote da RPS + type: integer + batchCheckNumber: + description: Número do protocolo do lote da RPS + type: string + number: + format: int64 + description: Número do NFE + type: integer + checkCode: + description: Código de Verificação da NFE + type: string + status: + description: Status da NFE + enum: + - Error + - None + - Created + - Issued + - Cancelled + type: string + rpsType: + description: Tipo da RPS + enum: + - Rps + - RpsMista + - Cupom + type: string + rpsStatus: + description: Status da RPS + enum: + - Normal + - Canceled + - Lost + type: string + taxationType: + description: | + Tipo da tributação do ISSQN (TributacaoRPS). + Valores possíveis: + - `None`: Nenhuma + - `WithinCity`: Tributação dentro do mesmo município + - `OutsideCity`: Tributação fora do município + - `Export`: Exportação + - `Free`: Isento + - `Immune`: Imune + - `SuspendedCourtDecision`: Exigibilidade suspensa por decisão judicial + - `SuspendedAdministrativeProcedure`: Exigibilidade suspensa por procedimento administrativo + - `OutsideCityFree`: Tributação fora do município porém isento + - `OutsideCityImmune`: Tributação fora do município porém imune + - `OutsideCitySuspended`: Tributação fora do município porém suspensa + - `OutsideCitySuspendedAdministrativeProcedure`: Tributação fora do município, suspensa por procedimento administrativo + - `ObjectiveImune`: Tributação no município com indicação de imunidade objetiva + enum: + - None + - WithinCity + - OutsideCity + - Export + - Free + - Immune + - SuspendedCourtDecision + - SuspendedAdministrativeProcedure + - OutsideCityFree + - OutsideCityImmune + - OutsideCitySuspended + - OutsideCitySuspendedAdministrativeProcedure + - ObjectiveImune + type: string + issuedOn: + format: date-time + description: Data de emissão + type: string + cancelledOn: + format: date-time + description: Data de cancelamento + type: string + rpsSerialNumber: + description: Número de serie da RPS + type: string + rpsNumber: + format: int64 + description: Número da RPS + type: integer + cityServiceCode: + description: Código do servico prestado no Municipio + type: string + federalServiceCode: + description: Código do servico prestado federal + type: string + description: + description: Descrição do serviço no municipio + type: string + servicesAmount: + format: double + description: Valor do serviços + type: number + deductionsAmount: + format: double + description: Valor de deduções + type: number + discountUnconditionedAmount: + format: double + description: Valor do desconto incondicionado + type: number + discountConditionedAmount: + format: double + description: Valor do desconto condicionado + type: number + baseTaxAmount: + format: double + description: Valor da base de calculo de impostos + type: number + issRate: + format: double + description: Aliquota do ISS + type: number + issTaxAmount: + format: double + description: Valor do ISS + type: number + irAmountWithheld: + format: double + description: Valor retido do Imposto de Renda (IR) + type: number + pisAmountWithheld: + format: double + description: Valor retido do PIS + type: number + cofinsAmountWithheld: + format: double + description: Valor retido do COFINS + type: number + csllAmountWithheld: + format: double + description: Valor retido do CSLL + type: number + inssAmountWithheld: + format: double + description: Valor retido do INSS + type: number + issAmountWithheld: + format: double + description: Valor retido do ISS + type: number + othersAmountWithheld: + format: double + description: Valor de outras retenções + type: number + amountWithheld: + format: double + description: Valor das retenções + type: number + amountNet: + format: double + description: Valor líquido + type: number + location: + description: Local da Prestação do Serviço + type: object + properties: + state: + description: Estado + type: string + country: + description: País + type: string + postalCode: + description: Código Postal + type: string + street: + description: Logradouro + type: string + number: + description: Número + type: string + district: + description: Bairro + type: string + AdditionalInformation: + description: Informações Adicionais (Complemento) + type: string + city: + description: Cidade + type: object + properties: + code: + description: Código do IBGE + type: string + name: + description: Nome + type: string + activityEvent: + description: Detalhes da atividade do evento + type: object + properties: + name: + description: Nome do evento + type: string + beginOn: + format: date-time + description: Data de início do evento + type: string + endOn: + format: date-time + description: Data do fim do evento + type: string + Code: + description: Código da atividade do evento + type: string + approximateTax: + description: Tributos aproximados + type: object + properties: + source: + description: Nome da fonte da taxa + type: string + version: + description: Versão da taxa baseado na fonte + type: string + totalRate: + format: double + description: Taxa dos tributos aproximados + type: number + additionalInformation: + description: Informações Adicionais + type: string + createdOn: + format: date-time + description: Data de criação + type: string + modifiedOn: + format: date-time + description: Data da última modificação + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + delete: + tags: + - ServiceInvoices + summary: Cancelar uma Nota Fiscal de Serviços (NFSE) + description: Você precisará do APIKEY da Empresa + operationId: ServiceInvoices_Delete + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Nota fiscal cancelada com sucesso + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "408": + description: Tempo de reposta do servidor excedeu o limite (60s) + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices/{id}/sendemail: + put: + tags: + - ServiceInvoices + summary: Enviar email para o Tomador com a Nota Fiscal de Serviço (NFSE) + description: Você precisará do APIKEY da Empresa + operationId: ServiceInvoices_SendEmail + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "408": + description: Tempo de reposta do servidor excedeu o limite (60s) + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices/{id}/pdf: + get: + tags: + - ServiceInvoices + summary: Download do PDF da Nota Fiscal de Serviço (NFSE) + description: Você precisará do APIKEY da Empresa + operationId: ServiceInvoices_GetDocumentPdf + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "404": + description: Não foi possivel o download + "408": + description: Tempo de reposta do servidor excedeu o limite (60s) + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices/{id}/xml: + get: + tags: + - ServiceInvoices + summary: Download do XML da Nota Fiscal de Serviço (NFSE) + description: Você precisará do APIKEY da Empresa + operationId: ServiceInvoices_GetDocumentXml + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "404": + description: Não foi possivel o download + "408": + description: Tempo de reposta do servidor excedeu o limite (60s) + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v1/companies/{company_id}/serviceinvoices/{id}/cancellation-xml: + get: + tags: + - ServiceInvoices + summary: Download do XML do evento de cancelamento da Nota Fiscal de Serviço (NFSE) + description: "Você precisará do APIKEY da Empresa.\r\nDisponível apenas para o ambiente Nacional (evento de cancelamento `e110001`). Provedores legados (ABRASF, Paulistana e demais padrões municipais) não possuem XML de evento de cancelamento próprio e retornam 404.\r\nQuando existem o XML enviado (request) e o XML do evento autorizado (retorno) pelo Ambiente Nacional, o retorno autorizado é priorizado." + operationId: ServiceInvoices_GetCancellationXml + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFSE) + required: true + schema: + type: string + responses: + "200": + description: Sucesso na requisição + content: + application/json: + schema: + type: string + "400": + description: Algum parametro informado não é válido + "401": + description: API Key da conta não é valida + "404": + description: Não há XML de evento de cancelamento para esta nota (provedor legado, ambiente não Nacional ou nota ainda não cancelada) + "500": + description: Erro no processamento + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v2/webhooks/eventtypes: + get: + tags: + - WebHooks + summary: Listar os Tipos de Eventos gerados pela plataforma + description: "### Informações adicionais\r\n\r\nEventos ocorrem a todo instante na plataforma durante os processamentos e são registrados\r\ncriando notificações para os webhooks ativos e configurados para receber os eventos.\r\n \r\nSão identificados seguindo o padrão **Resource.EventAction**,\r\nonde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\n\r\nEsse tipos podem ser utilizados como filtro ao criar ou alterar um webhook,\r\nsendo que o filtro determina quais notificações de eventos e ação serão enviadas\r\npara um determinado webhook, ou seja, dependendo de quais filtros são vinculados ao webhook\r\nele só receberá as notificações de evento e ação que correspondem a um ou mais desses filtros." + responses: + "200": + description: Sucesso na consulta do tipos de eventos + content: + application/json: + schema: + description: Tipos de Eventos + type: object + properties: + eventTypes: + description: Lista de Evento + type: array + items: + description: Tipo de Evento + type: object + properties: + id: + description: "Identificador do evento, seguem o padrão **Resource.EventAction**.\r\nOnde **Resource**: nome da entidade que gerou o evento;\r\n**EventAction**: nome do evento e ação criados.\r\nAlguns exemplos **Invoice.Issued** ou **Blob.Updated**" + type: string + description: + description: Descrição para o recurso, evento e ação exemplicando quando e onde eles ocorrem dentro na plataforma. + type: string + status: + format: int32 + description: WebHook Filter Status + enum: + - 0 + - 1 + type: integer + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v2/webhooks: + get: + tags: + - WebHooks + summary: Listar os Webhooks + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar uma lista de **Webhooks** cadastrados na Conta Autenticada." + responses: + "200": + description: Sucesso na consulta da lista + content: + application/json: + schema: + description: Web Hooks + type: object + properties: + webHooks: + description: Lista de Web Hook + type: array + items: + description: WebHook (Notificação HTTP) + required: + - uri + type: object + properties: + id: + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + type: string + uri: + description: A URL onde as notificações dos eventos deverão entregues. + type: string + secret: + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + type: string + contentType: + format: int32 + description: WebHook Media Type + enum: + - 0 + - 1 + type: integer + insecureSsl: + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + type: boolean + status: + format: int32 + description: WebHook Status + enum: + - 0 + - 1 + type: integer + filters: + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + uniqueItems: true + type: array + items: + type: string + headers: + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + type: object + additionalProperties: + type: string + properties: + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + type: object + additionalProperties: {} + createdOn: + format: date-time + description: Data de criação do webhook + type: string + modifiedOn: + format: date-time + description: Data de modificação do webhook + type: string + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + post: + tags: + - WebHooks + summary: Criar um Webhook + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar novos **Webhooks** para receber as notificações de eventos ocorridos na plataforma.\r\n \r\nNa criação do **Webhook** a URL informada no cadastro deve ser responsiva, ou seja, deverá responder *(HTTP Status 200 OK)* a uma requisição *(HTTP POST)* que será feita para testar se a URL está operando como normalmente, caso contrario uma mensagem de erro será retornada.\r\n \r\nUm **Webhook** é semelhante a uma assinatura em um *sistema de publicação e assinatura*\r\nque permite ao assinante indicar *quando*, *como* e *onde* as notificações de eventos deve ser despachadas.\r\nUm **Webhook** é registrado e gerenciado por Conta o que significa que cada Conta tem um conjunto separado de ganchos\r\nque podem ser acionados por eventos gerados através de ações executadas por esse Conta.\r\nOu seja, a **Conta da _Empresa A_** não verá os WebHooks disparados por uma ação executada pelo usuário **Conta da _Empresa B_**." + requestBody: + description: Dados para criar um Web Hook + content: + application/json: + schema: + description: Dados para criar um Web Hook + type: object + properties: + webHook: + description: Dados para criar um Web Hook + required: + - uri + type: object + properties: + uri: + description: A URL onde as notificações dos eventos deverão entregues. + type: string + secret: + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + type: string + contentType: + format: int32 + description: WebHook Media Type + enum: + - 0 + - 1 + type: integer + insecureSsl: + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + type: boolean + status: + format: int32 + description: WebHook Status + enum: + - 0 + - 1 + type: integer + filters: + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + uniqueItems: true + type: array + items: + type: string + headers: + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + type: object + additionalProperties: + type: string + properties: + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + type: object + additionalProperties: {} + createdOn: + format: date-time + description: Data de criação do webhook + type: string + modifiedOn: + format: date-time + description: Data de modificação do webhook + type: string + responses: + "201": + description: Sucesso na criação da webhook + content: + application/json: + schema: + description: Web Hook + type: object + properties: + webHook: + description: WebHook (Notificação HTTP) + required: + - uri + type: object + properties: + id: + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + type: string + uri: + description: A URL onde as notificações dos eventos deverão entregues. + type: string + secret: + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + type: string + contentType: + format: int32 + description: WebHook Media Type + enum: + - 0 + - 1 + type: integer + insecureSsl: + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + type: boolean + status: + format: int32 + description: WebHook Status + enum: + - 0 + - 1 + type: integer + filters: + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + uniqueItems: true + type: array + items: + type: string + headers: + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + type: object + additionalProperties: + type: string + properties: + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + type: object + additionalProperties: {} + createdOn: + format: date-time + description: Data de criação do webhook + type: string + modifiedOn: + format: date-time + description: Data de modificação do webhook + type: string + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Webhook não encontrado + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + delete: + tags: + - WebHooks + summary: Excluir Todos os Webhooks existentes + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir todos os **Webhooks** cadastrados para a Conta Autenticada." + responses: + "204": + description: Sucesso na exclusão dos WebHooks + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v2/webhooks/{webhook_id}: + get: + tags: + - WebHooks + summary: Consultar um webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para consultar um **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id**." + operationId: RegistrationLookupAction + parameters: + - name: webhook_id + in: path + description: ID do webhook a ser consultado + required: true + schema: + type: string + responses: + "200": + description: Sucesso na consulta do webhook + content: + application/json: + schema: + description: Web Hook + type: object + properties: + webHook: + description: WebHook (Notificação HTTP) + required: + - uri + type: object + properties: + id: + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + type: string + uri: + description: A URL onde as notificações dos eventos deverão entregues. + type: string + secret: + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + type: string + contentType: + format: int32 + description: WebHook Media Type + enum: + - 0 + - 1 + type: integer + insecureSsl: + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + type: boolean + status: + format: int32 + description: WebHook Status + enum: + - 0 + - 1 + type: integer + filters: + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + uniqueItems: true + type: array + items: + type: string + headers: + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + type: object + additionalProperties: + type: string + properties: + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + type: object + additionalProperties: {} + createdOn: + format: date-time + description: Data de criação do webhook + type: string + modifiedOn: + format: date-time + description: Data de modificação do webhook + type: string + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Webhook não encontrado + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + put: + tags: + - WebHooks + summary: Alterar um Webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para alterar os dados do **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id** especificado." + parameters: + - name: webhook_id + in: path + description: ID do webhook a ser consultado + required: true + schema: + type: string + requestBody: + description: Dados para alterar o Webhook + content: + application/json: + schema: + description: Dados para alterar um Web Hook + type: object + properties: + webHook: + description: WebHook (Notificação HTTP) + required: + - uri + type: object + properties: + id: + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + type: string + uri: + description: A URL onde as notificações dos eventos deverão entregues. + type: string + secret: + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + type: string + contentType: + format: int32 + description: WebHook Media Type + enum: + - 0 + - 1 + type: integer + insecureSsl: + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + type: boolean + status: + format: int32 + description: WebHook Status + enum: + - 0 + - 1 + type: integer + filters: + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + uniqueItems: true + type: array + items: + type: string + headers: + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + type: object + additionalProperties: + type: string + properties: + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + type: object + additionalProperties: {} + createdOn: + format: date-time + description: Data de criação do webhook + type: string + modifiedOn: + format: date-time + description: Data de modificação do webhook + type: string + responses: + "200": + description: Sucesso na atualização da Webhook + content: + application/json: + schema: + description: Web Hook + type: object + properties: + webHook: + description: WebHook (Notificação HTTP) + required: + - uri + type: object + properties: + id: + description: "ID exclusivo do WebHook. Este ID pode ser usado para se referir mais tarde ao WebHook no caso de\r\nprecisa ser atualizado ou excluído. O ID é, por padrão, na forma de um GUID." + type: string + uri: + description: A URL onde as notificações dos eventos deverão entregues. + type: string + secret: + description: "Segredo, contendo de 32 até 64 caracteres que será usado gerar o valor\r\ndo **HMAC-SHA1** em hexadecimal que será enviado no cabeçalho HTTP *X-Hub-Signature*.\r\nO HMAC-SHA1 será gerado baseado no bytes do corpo do evento de notificação que será enviado." + type: string + contentType: + format: int32 + description: WebHook Media Type + enum: + - 0 + - 1 + type: integer + insecureSsl: + description: "Determina se o certificado SSL do host da URL será verificado ao entregar as notificações dos eventos.\r\nDefina como **true** para pular a verificação do certificado SSL, sendo o padrão: **false**." + type: boolean + status: + format: int32 + description: WebHook Status + enum: + - 0 + - 1 + type: integer + filters: + description: "Lista de filtros sem distinção entre maiúsculas e minúsculas associado a este webhook. \r\nOs filtros são usados para determinar em quais notificações dos eventos esse WebHook será notificado. \r\nOs valores de filtros suportados pode ser consultados através do requisição do **Tipos de Eventos**." + uniqueItems: true + type: array + items: + type: string + headers: + description: Lista de cabeçalhos HTTP adicionais que serão enviados juntamente com as notificações dos eventos para o webhook. + type: object + additionalProperties: + type: string + properties: + description: "Lista de propriedades adicionais que não diferenciam maiúsculas de minúsculas que serão enviadas \r\njuntamente com as notificações dos eventos para o webhook como parte do corpo da entidade de solicitação HTTP." + type: object + additionalProperties: {} + createdOn: + format: date-time + description: Data de criação do webhook + type: string + modifiedOn: + format: date-time + description: Data de modificação do webhook + type: string + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Webhook não encontrado + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + delete: + tags: + - WebHooks + summary: Excluir um Webhook existente + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para excluir o **Webhook** que esteja cadastrado e tenha o ID igual ao parametro **webhook_id** especificado.\r\nA exclusão do **Webhook** não exime o **Webhook** excluído de receber os notificações de eventos, já ocorridos na plataforma, que ainda estejam em processo de retentativa de envio dos gatilhos." + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser excluído + required: true + schema: + type: string + responses: + "204": + description: Sucesso na exclusão da Webhook + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Webhook não encontrado + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] + /v2/webhooks/{webhook_id}/pings: + put: + tags: + - WebHooks + summary: Criar notificação para Testar um webhook + description: "### Informações adicionais\r\n \r\nUtilize esta requisição para criar uma notificação de teste (ping) em um **Webhook** já cadastrado.\r\n\r\nEsta ação irá criar um evento de notificação do tipo ping para o **Webhook** especificado, deste modo você poderá simular o recebimento de uma notificação de teste no **Webhook** cadastrado." + parameters: + - name: webhook_id + in: path + description: ID do Webhook a ser testado + required: true + schema: + type: string + responses: + "204": + description: Sucesso ao criar notificação de teste + "400": + description: Algum parametro informado não é válido, verificar resposta + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + "401": + description: Não autorizado, verificar o cabeçalho do HTTP Authorization + "403": + description: Accesso proibido + "404": + description: Webhook não encontrado + "500": + description: Erro no processamento + content: + application/json: + schema: + description: Lista de Erros + type: object + properties: + errors: + description: Lista de Erros + type: array + items: + description: Erro + type: object + properties: + code: + format: int32 + description: Código do erro + type: integer + message: + description: Mensagem contendo os detalhes do erro + type: string + security: + - Authorization_Header: [] + Authorization_QueryParam: [] +components: + securitySchemes: + Authorization_Header: + name: Authorization + in: header + type: apiKey + description: 'Autenticar usando o Cabeçalho HTTP Authorization com sua API Key' + Authorization_QueryParam: + name: apikey + in: query + type: apiKey + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' diff --git a/openapi/nfeio.yaml b/openapi/nfeio.yaml new file mode 100644 index 0000000..04af6a6 --- /dev/null +++ b/openapi/nfeio.yaml @@ -0,0 +1,630 @@ +openapi: 3.0.4 +info: + title: Batch Processor API + version: v1 +paths: + /api/notifications/zip: + post: + tags: + - Notification + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ZipRequest' + text/json: + schema: + $ref: '#/components/schemas/ZipRequest' + application/*+json: + schema: + $ref: '#/components/schemas/ZipRequest' + responses: + '200': + description: OK + '/api/notifications/{id}': + post: + tags: + - Notification + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: path + in: query + schema: + type: string + - name: outputType + in: query + schema: + $ref: '#/components/schemas/OutputType' + responses: + '200': + description: OK + /api/notifications/workflow/finished: + post: + tags: + - Notification + requestBody: + content: + application/json: + schema: + type: string + format: uuid + text/json: + schema: + type: string + format: uuid + application/*+json: + schema: + type: string + format: uuid + responses: + '200': + description: OK + /api/processing-jobs/resources/outputs: + get: + tags: + - ProcessingJobs + responses: + '200': + description: OK + content: + text/plain: + schema: + type: array + items: + $ref: '#/components/schemas/ResourceInfo' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ResourceInfo' + text/json: + schema: + type: array + items: + $ref: '#/components/schemas/ResourceInfo' + '401': + description: Unauthorized + content: + text/plain: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + text/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + /api/processing-jobs: + get: + tags: + - ProcessingJobs + parameters: + - name: PageSize + in: query + schema: + type: integer + format: int32 + - name: Direction + in: query + schema: + $ref: '#/components/schemas/SortDirection' + - name: Order + in: query + schema: + $ref: '#/components/schemas/SortOrder' + - name: Cursor.Value + in: query + schema: + type: string + format: uuid + - name: HasCursor + in: query + schema: + type: boolean + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/ProcessingBatchSummaryResponsePage' + application/json: + schema: + $ref: '#/components/schemas/ProcessingBatchSummaryResponsePage' + text/json: + schema: + $ref: '#/components/schemas/ProcessingBatchSummaryResponsePage' + '401': + description: Unauthorized + content: + text/plain: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + text/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + post: + tags: + - ProcessingJobs + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StartProcessingJobRequest' + text/json: + schema: + $ref: '#/components/schemas/StartProcessingJobRequest' + application/*+json: + schema: + $ref: '#/components/schemas/StartProcessingJobRequest' + responses: + '201': + description: Created + content: + text/plain: + schema: + $ref: '#/components/schemas/ProcessingBatchesResponse' + application/json: + schema: + $ref: '#/components/schemas/ProcessingBatchesResponse' + text/json: + schema: + $ref: '#/components/schemas/ProcessingBatchesResponse' + '400': + description: Bad Request + content: + text/plain: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + text/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + '/api/processing-jobs/{id}': + get: + tags: + - ProcessingJobs + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: status + in: query + schema: + type: array + items: + $ref: '#/components/schemas/StatusProcess' + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/ProcessingBatchDetailResponse' + application/json: + schema: + $ref: '#/components/schemas/ProcessingBatchDetailResponse' + text/json: + schema: + $ref: '#/components/schemas/ProcessingBatchDetailResponse' + '401': + description: Unauthorized + content: + text/plain: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + text/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + delete: + tags: + - ProcessingJobs + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: OK + content: + text/plain: + schema: + $ref: '#/components/schemas/ProcessingBatchDetailResponse' + application/json: + schema: + $ref: '#/components/schemas/ProcessingBatchDetailResponse' + text/json: + schema: + $ref: '#/components/schemas/ProcessingBatchDetailResponse' + '401': + description: Unauthorized + content: + text/plain: + schema: + $ref: '#/components/schemas/ProblemDetails' + application/json: + schema: + $ref: '#/components/schemas/ProblemDetails' + text/json: + schema: + $ref: '#/components/schemas/ProblemDetails' +components: + schemas: + BatchProcessResponse: + required: + - createdAt + type: object + properties: + input: + type: string + nullable: true + status: + type: string + nullable: true + statusReason: + type: string + nullable: true + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + nullable: true + outPuts: + type: array + items: + $ref: '#/components/schemas/OutPutResponse' + nullable: true + additionalProperties: false + Environment: + enum: + - Test + - Production + type: string + FileParsingOptionsRequest: + type: object + properties: + columnToParse: + type: integer + description: Coluna que está o input + format: int32 + example: 1 + parsingType: + $ref: '#/components/schemas/ParsingType' + additionalProperties: false + GuidPaginationCursor: + type: object + properties: + value: + type: string + format: uuid + additionalProperties: false + InputInfoRequest: + type: object + properties: + url: + type: string + description: Nome do processo + nullable: true + example: s3://bucket/input.json + parsingOptions: + $ref: '#/components/schemas/FileParsingOptionsRequest' + useCache: + type: boolean + description: Habilitar Cache + example: true + additionalProperties: false + InputsResponse: + type: object + properties: + totalInputs: + type: integer + format: int32 + outputs: + type: array + items: + type: string + nullable: true + additionalProperties: false + OutPutLinkResponse: + type: object + properties: + fileName: + type: string + nullable: true + url: + type: string + nullable: true + additionalProperties: false + OutPutResponse: + type: object + properties: + type: + type: string + nullable: true + status: + type: string + nullable: true + outPutLink: + $ref: '#/components/schemas/OutPutLinkResponse' + additionalProperties: false + OutputType: + enum: + - PDF + - XML + - Csv + type: string + ParsingType: + enum: + - Csv + - Xls + type: string + ProblemDetails: + type: object + properties: + type: + type: string + nullable: true + title: + type: string + nullable: true + status: + type: integer + format: int32 + nullable: true + detail: + type: string + nullable: true + instance: + type: string + nullable: true + additionalProperties: { } + ProcessingBatchDetailResponse: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + nullable: true + createdBy: + type: string + nullable: true + resourceName: + type: string + nullable: true + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + nullable: true + inputs: + $ref: '#/components/schemas/InputsResponse' + metrics: + $ref: '#/components/schemas/ProcessingMetricsResponse' + status: + type: string + nullable: true + stage: + type: string + nullable: true + batchProcesses: + type: array + items: + $ref: '#/components/schemas/BatchProcessResponse' + nullable: true + additionalProperties: false + ProcessingBatchSummaryResponse: + type: object + properties: + id: + type: string + format: uuid + parentId: + type: string + format: uuid + nullable: true + name: + type: string + nullable: true + createdBy: + type: string + nullable: true + resourceName: + type: string + nullable: true + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + nullable: true + metrics: + $ref: '#/components/schemas/ProcessingMetricsResponse' + inputs: + $ref: '#/components/schemas/InputsResponse' + status: + type: string + nullable: true + stage: + type: string + nullable: true + autoGenerated: + type: boolean + outPuts: + type: array + items: + $ref: '#/components/schemas/OutPutResponse' + nullable: true + additionalProperties: false + ProcessingBatchSummaryResponsePage: + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/ProcessingBatchSummaryResponse' + nullable: true + nextCursor: + $ref: '#/components/schemas/GuidPaginationCursor' + previousCursor: + $ref: '#/components/schemas/GuidPaginationCursor' + hasNext: + type: boolean + readOnly: true + hasPrevious: + type: boolean + readOnly: true + additionalProperties: false + ProcessingBatchesResponse: + type: object + properties: + id: + type: string + format: uuid + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + nullable: true + status: + type: string + nullable: true + additionalProperties: false + ProcessingMetricsResponse: + type: object + properties: + total: + type: integer + format: int32 + totalSuccess: + type: integer + format: int32 + totalError: + type: integer + format: int32 + additionalProperties: false + ResourceInfo: + type: object + properties: + id: + type: integer + format: int32 + name: + type: string + nullable: true + outputs: + type: array + items: + $ref: '#/components/schemas/OutputType' + nullable: true + additionalProperties: false + ResourceInfoRequest: + type: object + properties: + id: + type: integer + description: ID da fonte de dados + format: int32 + example: 1 + name: + type: string + description: Nome da fonte de dados + nullable: true + example: NFeSefaz + outputs: + type: array + items: + $ref: '#/components/schemas/OutputType' + description: Tipos de saidas + nullable: true + example: + - PDF + - XML + additionalProperties: false + SortDirection: + enum: + - Forward + - Backward + type: string + SortOrder: + enum: + - Asc + - Desc + type: string + StartProcessingJobRequest: + type: object + properties: + createdBy: + type: string + description: Quem criou a requisição + nullable: true + example: joao.souza + input: + $ref: '#/components/schemas/InputInfoRequest' + name: + type: string + description: Nome do processo + nullable: true + example: Processamento de Dados + resource: + $ref: '#/components/schemas/ResourceInfoRequest' + environment: + $ref: '#/components/schemas/Environment' + additionalProperties: false + StatusProcess: + enum: + - Pending + - Running + - Completed + - Duplicated + - Error + - PartialSuccess + - Succeed + type: string + ZipRequest: + type: object + properties: + id: + type: string + format: uuid + type: + $ref: '#/components/schemas/OutputType' + blobName: + type: string + nullable: true + additionalProperties: false + securitySchemes: + Authorization_Header: + type: apiKey + description: 'Chave de API no header: `Authorization: sua-chave`' + name: Authorization + in: header +security: + - Authorization_Header: [ ] \ No newline at end of file diff --git a/openapi/product-invoice-rtc-v1.yaml b/openapi/product-invoice-rtc-v1.yaml new file mode 100644 index 0000000..a5296e1 --- /dev/null +++ b/openapi/product-invoice-rtc-v1.yaml @@ -0,0 +1,5083 @@ +openapi: 3.0.1 +info: + title: API de Emissão de Nota Fiscal de Produto (NFe/NFCe) - RTC + version: v3 + description: | + ### Introdução + + API para emissão de Notas Fiscais de Produto (NFe/NFCe) de acordo com a legislação vigente e os padrões estabelecidos pelo Governo. + + ### Adequação de Leiaute + + Leiaute NFe/NFCe Reforma Tributária do Consumo - Modelo 55 e 65. + + Esta adequação de leiaute contempla até a Nota Técnica **NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS**. + + > **Atenção** + > _Sujeito a alterações mediante notas técnicas e processos de homologação._ +servers: + - url: https://api.nfse.io + description: Nota Fiscal de Produto/Consumidor (RTC). +tags: + - name: Nota Fiscal de Produto/Consumidor (RTC) + description: Operações relacionadas à Nota Fiscal Eletrônica de Produto + +paths: + /v2/companies/:companyId/productinvoices: + post: + tags: + - Nota Fiscal de Produto/Consumidor (RTC) + summary: Envio de dados para emissão de NF-e/NFC-e + description: Envia os dados para a criação e autorização de uma nova Nota Fiscal de Produto. + operationId: createProductInvoice + requestBody: + description: "Objeto JSON contendo todos os dados da NF-e, conforme o schema ProductInvoiceRequest." + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInvoiceRequest' + examples: + minimalWithIBSCBS: + summary: Exemplo Mínimo com IBS/CBS + value: + operationType: "Outgoing" + destination: "InternalOperation" + printType: "DANFE_NFC_E" + purposeType: "Normal" + consumerType: "FinalConsumer" + presenceType: "Internet" + buyer: + name: "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL" + federalTaxNumber: 11223344000155 + address: + state: "SC" + city: + code: "4205407" + name: "Florianópolis" + district: "Centro" + street: "Rua Teste" + number: "123" + postalCode: "88010000" + country: "BRA" + type: "LegalEntity" + stateTaxNumberIndicator: "TaxPayer" + stateTaxNumber: "123456789" + items: + - description: "NOTA FISCAL EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL" + ncm: "85171300" + cfop: 5102 + quantity: 1.0 + unitAmount: 150.00 + totalAmount: 150.0 + totalIndicator: true + tax: + icms: + origin: "0" + cst: "00" + pis: + cst: "01" + cofins: + cst: "01" + IBSCBS: + situationCode: "000" + classCode: "000001" + calculationMode: "OfficialService" + payment: + - paymentDetail: + - method: "Cash" + paymentType: "InCash" # Pagamento à vista + amount: 150.00 + intermediateWithDetailedIBSCBS: + summary: Exemplo Intermediário com IBS/CBS detalhado + value: + operationType: "Outgoing" + destination: "InterstateOperation" + printType: "NFeNormalPortrait" + purposeType: "Normal" + consumerType: "Normal" + presenceType: "Internet" + buyer: + name: "Empresa Exemplo Intermediario LTDA" + federalTaxNumber: 11223344000155 + address: + state: "RJ" + city: + code: "3304557" + name: "Rio de Janeiro" + district: "Centro" + street: "Avenida Rio Branco" + number: "1" + postalCode: "20090003" + country: "BRA" + type: "LegalEntity" + stateTaxNumberIndicator: "TaxPayer" + stateTaxNumber: "123456789" + items: + - description: "Produto Exemplo com IBS/CBS Detalhado" + ncm: "84713012" + cfop: 6102 + quantity: 2.0 + unitAmount: 750.00 + totalAmount: 1500.00 + totalIndicator: true + tax: + icms: + origin: "0" + cst: "00" + pis: + cst: "01" + cofins: + cst: "01" + IBSCBS: + situationCode: "101" + classCode: "RT0001" + basis: 1500.00 + state: # IBS Estadual + rate: 8.5 + amount: 127.50 + municipal: # IBS Municipal + rate: 2.0 + amount: 30.00 + cbs: # CBS + rate: 10.5 + amount: 157.50 + totals: + icms: + productAmount: 1500.00 + invoiceAmount: 1500.00 + ibsCbsTotals: + basis: 1500.00 + ibs: + state: { amount: 127.50 } + municipal: { amount: 30.00 } + totalAmount: 157.50 + cbs: + amount: 157.50 + totalInvoiceAmount: 1657.50 + payment: + - paymentDetail: + - method: "InstantPayment" # Pagamento Instantâneo PIX + paymentType: "InCash" + amount: 1500.00 + intermediateWithTaxDetermination: + summary: Exemplo Intermediário com taxDetermination + value: + operationType: "Outgoing" + destination: "InterstateOperation" + printType: "NFeNormalPortrait" + purposeType: "Normal" + consumerType: "Normal" + presenceType: "Internet" + buyer: + name: "Empresa Exemplo com Tax Determination" + federalTaxNumber: 55443322000111 + address: + state: "SP" + city: + code: "3550308" + name: "São Paulo" + district: "Itaim Bibi" + street: "Avenida Brigadeiro Faria Lima" + number: "2000" + postalCode: "01452002" + country: "BRA" + type: "LegalEntity" + stateTaxNumberIndicator: "TaxPayer" + stateTaxNumber: "987654321" + items: + - description: "Produto com cálculo automático de imposto" + ncm: "90064000" + quantity: 5.0 + unitAmount: 300.00 + totalAmount: 1500.00 + totalIndicator: true + taxDetermination: + operationCode: 121 + issuerTaxProfile: "retail" + buyerTaxProfile: "final_consumer_non_icms_contributor" + origin: "0" + acquisitionPurpose: null + tax: + IBSCBS: # Grupo de Informações do IBS e CBS + situationCode: "000" # Código de Situação Tributária do IBS/CBS + classCode: "000001" # Código de Classificação Tributária do IBS/CBS + calculationMode: "OfficialService" + full: + summary: Exemplo Completo (Exaustivo) + value: + id: "nfe-exemplo-completo-12345" + payment: + - paymentDetail: + - method: "CreditCard" + methodDescription: "Cartão de Crédito Master" + paymentType: "Term" + amount: 1500.5 + card: + federalTaxNumber: "12345678000199" + flag: "Mastercard" + authorization: "ABC123456" + integrationPaymentType: "Integrated" + federalTaxNumberRecipient: "98765432000100" # CNPJ do beneficiário do pagamento + idPaymentTerminal: "TERM-PDV-001" + paymentDate: "2025-10-28T10:00:00-03:00" + federalTaxNumberPag: "11223344000155" + statePag: "SP" + - method: "InstantPayment" + methodDescription: "PIX" + paymentType: "InCash" + amount: 523.5 + card: null # Grupo de Cartões + paymentDate: "2025-10-29T11:30:00-03:00" + federalTaxNumberPag: "111222333000144" + statePag: "RJ" + payBack: 0.0 + serie: 1 + number: 987654 + operationOn: "2025-10-28T10:00:00-03:00" + expectedDeliveryOn: "2025-10-30" + operationNature: "Venda de Mercadoria c/ Reforma Tributaria" + operationType: "Outgoing" + destination: "InterstateOperation" + consumptionCityCode: 3550308 + ibsConsumptionCityCode: 3550308 + printType: "NFeNormalPortrait" + purposeType: "Normal" # Finalidade da emissão + debitType: "FinesAndInterest" + creditType: "IbsPresumedCreditAppropriationZfm" + consumerType: "Normal" + presenceType: "Internet" + contingencyOn: "2025-10-28T09:00:00-03:00" + contingencyJustification: "Problemas tecnicos no SEFAZ de origem." + governmentPurchase: + entityType: "state" + rateReduction: 15.5 + operationType: "supply" + buyer: + accountId: "ACC-BUYER-789" + id: "BUYER-001" + name: "Empresa Compradora Exemplo LTDA" + federalTaxNumber: 11223344000155 + email: "compras@comprador.com" + address: + state: "RJ" + city: + code: "3304557" + name: "Rio de Janeiro" + district: "Centro" + additionalInformation: "Sala 1001" + street: "Avenida Rio Branco" + number: "1" + postalCode: "20090003" + country: "BRA" + phone: "21987654321" + type: "LegalEntity" + stateTaxNumberIndicator: "TaxPayer" + tradeName: "Comprador Exemplo" + taxRegime: "LucroReal" + stateTaxNumber: "123456789" + transport: + freightModality: "ByThirdParties" + transportGroup: + accountId: "ACC-TRANSP-456" + id: "TRANSP-001" + name: "Transportadora Veloz S.A." + federalTaxNumber: 55667788000199 + email: "contato@transportadora.com" + address: + state: "SP" + city: + code: "3550308" + name: "São Paulo" + district: "Vila Olimpia" + additionalInformation: "Andar 5" + street: "Rua Funchal" + number: "500" + postalCode: "04551060" + country: "BRA" + phone: "11912345678" + type: "LegalEntity" + stateTaxNumber: "987654321" + transportRetention: null + reboque: + plate: "REB1A23" + uf: "SP" + rntc: "12345678" + wagon: "WAG-001" + ferry: "BAL-001" + volume: + volumeQuantity: 10 + species: "Caixa (CX)" + brand: "MARCA-EXEMPLO" + volumeNumeration: "001-010" + netWeight: 1000.5 + grossWeight: 1100.75 + transportVehicle: + plate: "VEI4B56" + state: "SP" + rntc: "87654321" + sealNumber: "LACRE-98765" + transpRate: + serviceAmount: 350.0 + bcRetentionAmount: 350.0 + icmsRetentionRate: 12.0 + icmsRetentionAmount: 42.0 + cfop: 5352 + cityGeneratorFactCode: 3550308 + additionalInformation: + fisco: "Informacoes de interesse do Fisco (Reforma Tributaria)." + taxpayer: "Informacoes complementares do contribuinte." + xmlAuthorized: [12345678901, 98765432109] + effort: "Safra 2025" + order: "Pedido 123" + contract: "Contrato 456" + taxDocumentsReference: + - documentElectronicInvoice: + accessKey: "41251012345678000199550010009876541234567890" + advancePayment: + - accessKey: "41251012345678000199550010001112221234567890" + taxpayerComments: + - field: "MeuCampoCustom" + text: "Observacao fiscal do meu campo" + - field: "OutroCampo" + text: "Outra observacao" + referencedProcess: + - identifierConcessory: "PROC-JUD-123" + identifierOrigin: 1 + concessionActType: 1 + export: + state: "SP" + office: "Porto de Santos" + local: "Armazem 1 - Alfandega" + items: + - code: "PROD-EXAUSTIVO-001" + codeGTIN: "7891234567890" + description: "Produto de Exemplo Exaustivo com todos os impostos" + ncm: "84713012" + nve: ["AA01", "BB02"] + extipi: "01" + cfop: 5102 + unit: "UN" + quantity: 10.0 + unitAmount: 200.0 + totalAmount: 2000.0 + codeTaxGTIN: "7891234567890" + unitTax: "UN" + quantityTax: 10.0 + taxUnitAmount: 200.0 + freightAmount: 10.0 + insuranceAmount: 5.0 + discountAmount: 15.0 + othersAmount: 2.0 + totalIndicator: true + usedMovableAssetIndicator: false + itemAmount: 2002.0 # Valor total do item + cest: "0100100" + benefit: "RS051500" + tax: + totalTax: 450.5 + icms: + origin: "0" + cst: "00" + csosn: null + baseTaxModality: "3" + baseTax: 2002.0 + baseTaxSTModality: "4" + baseTaxSTReduction: "10.0" + baseTaxST: 2200.0 + baseTaxReduction: 0.0 + basisBenefitCode: "BENEF-ICMS-01" + stRate: 18.0 + stAmount: 396.0 + stMarginAmount: 10.0 + rate: 18.0 + amount: 360.36 + percentual: null + snCreditRate: 0.0 + snCreditAmount: 0.0 + stMarginAddedAmount: "10.0" + stRetentionAmount: "396.0" + baseSTRetentionAmount: "2200.0" + baseTaxOperationPercentual: "100.0" + ufst: "RJ" + amountSTReason: "Valor desonerado ST" + baseSNRetentionAmount: "0.0" + snRetentionAmount: "0.0" + amountOperation: "360.36" + percentualDeferment: "0.0" + baseDeferred: "0.0" + exemptAmount: 0.0 + exemptReason: "Others" + exemptAmountST: 0.0 + exemptReasonST: "Others" + fcpRate: 2.0 + fcpAmount: 40.04 + fcpstRate: 2.0 + fcpstAmount: 44.0 + fcpstRetRate: 2.0 + fcpstRetAmount: 44.0 + baseTaxFCPSTAmount: 2200.0 + substituteAmount: 360.36 + stFinalConsumerRate: 20.0 + effectiveBaseTaxReductionRate: 0.0 + effectiveBaseTaxAmount: 2002.0 + effectiveRate: 18.0 + effectiveAmount: 360.36 + deductionIndicator: "NotDeduct" + ipi: + cst: "50" + classificationCode: "999" + classification: "CL-01" + producerCNPJ: "44556677000188" + stampCode: "SELO-IPI-123" + stampQuantity: 10.0 + base: 2002.0 + rate: 10.0 + unitQuantity: 10.0 + unitAmount: 20.0 + amount: 200.2 + ii: + baseTax: "2002.00" + customsExpenditureAmount: "100.00" + amount: 120.0 + iofAmount: 20.0 + vEnqCamb: 5.0 + pis: + cst: "01" + baseTax: 2002.0 + rate: 1.65 + amount: 33.03 + baseTaxProductQuantity: 10.0 + productRate: 3.303 + cofins: + cst: "01" + baseTax: 2002.0 + rate: 7.6 + amount: 152.15 + baseTaxProductQuantity: 10.0 + productRate: 15.215 + icmsDestination: + vBCUFDest: 2002.0 + pFCPUFDest: 2.0 + pICMSUFDest: 18.0 + pICMSInter: 12.0 + pICMSInterPart: 60.0 + vFCPUFDest: 40.04 + vICMSUFDest: 72.07 + vICMSUFRemet: 48.05 + vBCFCPUFDest: 2002.0 + IS: + situationCode: "101" + classificationCode: "IS0001" + basis: 2002.0 + rate: 5.0 + unitRate: null + unit: null + quantity: null + amount: 100.1 + IBSCBS: + situationCode: "101" + classCode: "RT0001" + donationIndicator: "0" + basis: 2002.0 + state: + rate: 10.0 + deferment: { rate: 1.0, amount: 20.02 } + returnedAmount: { amount: 10.0 } + reduction: { rateReduction: 0.5, effectiveRate: 9.5 } + amount: 190.19 + municipal: + rate: 5.0 + deferment: { rate: 0.5, amount: 10.01 } + returnedAmount: { amount: 5.0 } + reduction: { rateReduction: 0.2, effectiveRate: 4.8 } + amount: 96.1 + ibsTotalAmount: 286.29 + cbs: + rate: 12.0 + deferment: { rate: 1.0, amount: 24.02 } + returnedAmount: { amount: 12.0 } + reduction: { rateReduction: 0.1, effectiveRate: 10.8 } + amount: 216.22 + regularTaxation: + situationCode: "101" + classCode: "RT0001" + stateEffectiveRate: 10.0 + amount: 200.2 + municipalEffectiveRate: 5.0 + municipalAmount: 100.1 + cbsEffectiveRate: 12.0 + cbsAmount: 240.24 + governmentPurchase: + stateRate: 8.0 + stateAmount: 160.16 + municipalRate: 4.0 + municipalAmount: 80.08 + cbsRate: 10.0 + cbsAmount: 200.2 + monophase: + standart: + quantityBasis: 10.0 + ibsAdRemRate: 15.0 + cbsAdRemRate: 25.0 + ibsAmount: 150.0 + cbsAmount: 250.0 + withholding: + quantityBasis: 5.0 + ibsAdRemRate: 10.0 + ibsAmount: 50.0 + cbsAdRemRate: 20.0 + cbsAmount: 100.0 + previouslyWithheld: + quantityBasis: 3.0 + ibsAdRemRate: 5.0 + ibsAmount: 15.0 + cbsAdRemRate: 10.0 + cbsAmount: 30.0 + deferment: + ibsRate: 50.0 + ibsAmount: 75.0 + cbsRate: 50.0 + cbsAmount: 125.0 + ibsAmount: 140.0 + cbsAmount: 255.0 + creditTransfer: + ibsAmount: 50.0 + cbsAmount: 30.0 + operationalPresumedCredit: # Crédito presumido operacional + basis: 1000.0 + classificationCode: "RuralProducerNonTaxpayer" + ibs: { rate: 10.0, amount: 100.0, suspensiveConditionAmount: 10.0 } + cbs: { rate: 5.0, amount: 50.0, suspensiveConditionAmount: 5.0 } + creditReversal: + ibsReversalAmount: 2.0 # Valor do IBS a ser estornado + cbsReversalAmount: 1.0 + zfmPresumedCredit: + classificationCode: "IntermediateGoods" + amount: 123.45 + competenceAdjustment: + assessmentPeriod: "2025-09" + ibsAmount: 5.0 + cbsAmount: 3.0 # Valor de CBS referente ao ajuste de competência + additionalInformation: "Informacao adicional do item." + numberOrderBuy: "PED-COMPRA-555" # Número do pedido de compra + itemNumberOrderBuy: 1 + importControlSheetNumber: "FCI-12345678-ABCD" + vehicleDetail: + operationType: 1 # 1-Venda concessionária + chassis: "9BWZZZ377VT004251" + colorCode: "001" + colorDescription: "PRETO" + enginePower: "150" + engineDisplacement: "1998" + netWeight: "1250.000" + grossWeight: "1500.000" + serialNumber: "123456789" + fuelType: "16" # 16-Álcool/Gasolina + engineNumber: "MOTOR123456789" + maximumTractionCapacity: "0.0000" + wheelBase: "2649" + modelYear: 2026 + manufactureYear: 2025 + paintType: "S" # Sólida + vehicleType: "06" # Automóvel + vehicleSpecies: 1 # Passageiro + vinCondition: "N" # N-Normal + vehicleCondition: 1 # 1-Acabado + brandModelCode: "025104" + denatranColorCode: "11" # 11-PRETA + seatingCapacity: 5 + restrictionType: 0 # 0-Não há + fuelDetail: + codeANP: "210203001" + percentageNG: 50.0 + descriptionANP: "GLP" + percentageGLP: 40.0 # Percentual de GLP derivado do petróleo + percentageNGn: 30.0 + percentageGNi: 20.0 + startingAmount: 100.0 + codif: "CODIF-123" + amountTemp: 10.0 + stateBuyer: "RJ" + cide: { bc: 10.0, rate: 5.0, cideAmount: 0.5 } + pump: { spoutNumber: 1, number: 1, tankNumber: 1, beginningAmount: 1000.0, endAmount: 1010.0, percentageBio: 10.0 } + fuelOrigin: { indImport: 1, cUFOrig: 35, pOrig: 10.0 } + presumedCredit: { code: "BENEF-001", rate: 4.0, amount: 80.08 } + ibsZfmPresumedCreditClassification: "ItAndOtherGoods" + importDeclarations: + - code: "DI-123456" + registeredOn: "2025-10-01T10:00:00-03:00" + customsClearanceName: "Porto de Santos" + customsClearanceState: "SP" + customsClearancedOn: "2025-10-15T10:00:00-03:00" + additions: + - { code: 1, manufacturer: "FAB-CHINA-XYZ", amount: 10.0, drawback: 12345 } + exporter: "EXP-US-99" + internationalTransport: "Maritime" + intermediation: "ByOrder" + acquirerFederalTaxNumber: "11223344000155" + stateThird: "RJ" + exportDetails: + - drawback: "DB-98765" + hintInformation: { registryId: "RE-555444", accessKey: "41251012345678000199550010003334441234567890", quantity: 10.0 } + referencedDFe: + accessKey: "35251098765432000199550010000001231000001234" + itemNumber: 1 + taxDetermination: + operationCode: 120 + issuerTaxProfile: "industry" + buyerTaxProfile: "final_consumer_non_icms_contributor" + origin: "0" + acquisitionPurpose: "43" + purchaseInformation: + commitmentNote: "NE-2025-12345" + purchaseOrder: "PO-2025-67890" + contractNumber: "CT-2025-ABCDE" + totals: + icms: + baseTax: 2002.0 + icmsAmount: 360.36 + icmsExemptAmount: 0.0 + stCalculationBasisAmount: 2200.0 + stAmount: 396.0 + productAmount: 2000.0 + freightAmount: 10.0 + insuranceAmount: 5.0 + discountAmount: 15.0 + iiAmount: 120.0 + ipiAmount: 200.2 + pisAmount: 33.03 + cofinsAmount: 152.15 + othersAmount: 2.0 + invoiceAmount: 2023.5 + fcpufDestinationAmount: 40.04 + icmsufDestinationAmount: 72.07 + icmsufSenderAmount: 48.05 + federalTaxesAmount: 450.5 + fcpAmount: 40.04 + fcpstAmount: 44.0 + fcpstRetAmount: 44.0 + ipiDevolAmount: 0.0 + qBCMono: 10.0 + vICMSMono: 150.0 + qBCMonoReten: 5.0 + vICMSMonoReten: 50.0 + qBCMonoRet: 3.0 + vICMSMonoRet: 15.0 + issqn: + totalServiceNotTaxedICMS: 0.0 + baseRateISS: 0.0 + totalISS: 0.0 + valueServicePIS: 0.0 + valueServiceCOFINS: 0.0 + provisionService: "2025-10-28T10:00:00-03:00" + deductionReductionBC: 0.0 + valueOtherRetention: 0.0 + discountUnconditional: 0.0 + discountConditioning: 0.0 + totalRetentionISS: 0.0 + codeTaxRegime: 1.0 + withheldTaxes: + pisAmount: 10.0 # Valor Retido de PIS + cofinsAmount: 50.0 + csllAmount: 20.0 + irrfBasis: 1000.0 + irrfAmount: 150.0 + socialSecutiryBasis: 1000.0 + socialSecutiryAmount: 110.0 + isTotals: + amount: 100.1 + ibsCbsTotals: + basis: 2002.0 + ibs: + state: { defermentAmount: 20.02, returnedAmount: 10.0, amount: 190.19 } + municipal: { defermentAmount: 10.01, returnedAmount: 5.0, amount: 96.1 } + totalAmount: 286.29 + presumedCreditAmount: 100.0 + presumedCreditConditionalAmount: 10.0 + cbs: + defermentAmount: 24.02 + returnedAmount: 12.0 + amount: 216.22 + presumedCreditAmount: 50.0 + presumedCreditConditionalAmount: 5.0 + monophase: + ibs: { amount: 150.0, withheldAmount: 50.0, previouslyWithheldAmount: 15.0 } # Totais de IBS monofásico + cbs: { amount: 250.0, withheldAmount: 100.0, previouslyWithheldAmount: 30.0 } # Totais de CBS monofásico + totalInvoiceAmount: 2675.04 + billing: + bill: + number: "FAT-987654" + originalAmount: 2000.0 + discountAmount: 15.0 + netAmount: 1985.0 + duplicates: + - { number: "DUP-001", expirationOn: "2025-11-28T00:00:00Z", amount: 1000.0 } + - { number: "DUP-002", expirationOn: "2025-12-28T00:00:00Z", amount: 985.0 } + issuer: + stStateTaxNumber: "9876543210" + transactionIntermediate: + federalTaxNumber: 77889900000144 # CNPJ do Intermediador da Transação + identifier: "Marketplace-ID-555" + delivery: + accountId: "ACC-DELIV-111" + id: "DELIV-001" + name: "Local de Entrega Ltda" + federalTaxNumber: 22334455000166 + email: "entrega@local.com" + address: + state: "MG" + city: { code: "3106200", name: "Belo Horizonte" } + district: "Savassi" + additionalInformation: "Loja B" + street: "Avenida Cristovão Colombo" + number: "300" + postalCode: "30140150" + country: "BRA" + phone: "31911223344" + type: "LegalEntity" + stateTaxNumber: "111222333" + withdrawal: + accountId: "ACC-WITHDR-222" + id: "WITHDR-001" + name: "Local de Retirada Ltda" + federalTaxNumber: 33445566000177 + email: "retirada@local.com" + address: + state: "PR" + city: { code: "4106902", name: "Curitiba" } + district: "Centro Cívico" + additionalInformation: "Galpão 3" + street: "Avenida Cândido de Abreu" + number: "100" + postalCode: "80530000" + country: "BRA" + phone: "41955667788" + type: "LegalEntity" + stateTaxNumber: "444555666" + responses: + '201': + description: NF-e criada com sucesso (aguardando processamento/autorização). + content: + application/json: + schema: + $ref: '#/components/schemas/InvoiceResource' + '400': + description: Erro de validação (Bad Request). O corpo da requisição está inválido. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorsResource' + '500': + description: Erro interno do servidor. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResource' +components: + schemas: + ProductInvoiceRequest: + title: "Nota Fiscal de Produto (NFe) Schema" + description: "Schema para validar o objeto ProductInvoiceRequest da API" + type: "object" + required: + - items + - payment + properties: + id: + type: "string" + nullable: true + description: "Identificador único" + payment: + type: "array" + items: + $ref: "#/components/schemas/PaymentResource" + description: "Grupo de Formas de Pagamento (pag)" + serie: + type: "integer" + nullable: true + description: "Série do Documento Fiscal (serie)" + format: "int32" + number: + type: "integer" + nullable: true + description: "Número do Documento Fiscal (nNF)" + format: "int64" + operationOn: + type: "string" + nullable: true + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD.\r\n" + format: "date-time" + expectedDeliveryOn: + type: "string" + nullable: true + description: "Data da previsão de entrega ou disponibilização do bem (dPrevEntrega). Formato: “AAAA-MM-DD”. Observação: Não informar este campo para a NFC-e." + format: "date" + operationNature: + type: "string" + nullable: true + description: "Descrição da Natureza da Operação (natOp)" + operationType: + description: "Tipo do Documento Fiscal (tpNF)" + $ref: "#/components/schemas/OperationType" + destination: + description: "Identificador de Local de destino da operação (idDest)" + $ref: "#/components/schemas/Destination" + consumptionCityCode: + description: "Código do Município de Ocorrência do Fato Gerador (cMunFG)" + $ref: "#/components/schemas/ConsumptionCityCode" + ibsConsumptionCityCode: + description: "Município de ocorrência do fato gerador do IBS/CBS (cMunFGIBS)" + $ref: "#/components/schemas/IbsConsumptionCityCode" + printType: + description: "Formato de impressão do DANFE (tpImp)" + $ref: "#/components/schemas/PrintType" + purposeType: + description: "Finalidade da emissão da NF-e (finNFe)" + $ref: "#/components/schemas/PurposeType" + debitType: + description: "Tipo de Nota de Débito (tpNFDebito)" + $ref: "#/components/schemas/DebitType" + creditType: + $ref: "#/components/schemas/CreditType" + consumerType: + description: "Indica operação com Consumidor final (indFinal)" + $ref: "#/components/schemas/ConsumerType" + presenceType: + description: "Indicador de presença do comprador no estabelecimento (indPres)" + $ref: "#/components/schemas/ConsumerPresenceType" + contingencyOn: + type: "string" + nullable: true + description: "Data e Hora da entrada em contingência (dhCont)\r\n\r\n Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD\r\n" + format: "date-time" + contingencyJustification: + type: "string" + nullable: true + description: "Justificativa da entrada em contingência (xJust)" + governmentPurchase: + description: "Grupo de Compras Governamentais (gCompraGov)" + $ref: "#/components/schemas/GovernmentPurchaseResource" + buyer: + description: "Identificação do Destinatário (dest)" + $ref: "#/components/schemas/BuyerResource" + transport: + description: "Grupo de Informações do Transporte da NF-e (transp)" + $ref: "#/components/schemas/TransportInformationResource" + additionalInformation: + description: "Informações adicionais da NF-e (infAdic)" + $ref: "#/components/schemas/AdditionalInformationResource" + export: + description: "Informações de exportação (exporta)" + $ref: "#/components/schemas/ExportResource" + items: + type: "array" + minItems: 1 + items: + $ref: "#/components/schemas/InvoiceItemResource" + description: "Detalhamento de Produtos e Serviços (det). Pelo menos um item é obrigatório." + totals: + description: "Grupo de Valores Totais da NF-e (total)" + $ref: "#/components/schemas/Total" + billing: + $ref: "#/components/schemas/BillingResource" + issuerTaxSubstitute: + description: "IE do Substituto Tributário da UF de destino da mercadoria, quando houver a retenção do ICMS ST para a UF de destino. (IEST)" + $ref: "#/components/schemas/IssuerFromRequestResource" + transactionIntermediate: + description: "Grupo de Informações do Intermediador da Transação (infIntermed)" + $ref: "#/components/schemas/IntermediateResource" + delivery: + description: "Identificação do Local de entrega (entrega)" + $ref: "#/components/schemas/DeliveryInformationResource" + withdrawal: + description: "Identificação do Local de retirada (retirada)" + $ref: "#/components/schemas/WithdrawalInformationResource" + purchaseInformation: + $ref: "#/components/schemas/PurchaseInformationResource" + additionalProperties: false + ActivityResource: + type: "object" + properties: + data: + description: "Detalhes do Evento" + nullable: true + type: # Nome do Evento gerado + type: "string" + nullable: true + description: "Nome do Evento gerado" + sequence: + type: "integer" + nullable: true + description: "Número sequencial do Evento" + format: "int32" + additionalProperties: false + AdditionResource: + type: "object" + properties: + code: + type: "integer" # Numero da adição + nullable: true + description: "Numero da adição (nAdicao)" + format: "int64" + manufacturer: + type: "string" + nullable: true + description: "Código do fabricante estrangeiro (cFabricante)" + amount: + type: "number" + nullable: true # Valor do desconto do item da DI – Adição + description: "Valor do desconto do item da DI – Adição (vDescDI)" + format: "double" + drawback: + type: "integer" + nullable: true + description: "Número do ato concessório de Drawback (nDraw)" + format: "int64" + additionalProperties: false + description: "Adições (adi)" + AdditionalInformationResource: + type: "object" + properties: + fisco: + type: "string" # Informações Adicionais de Interesse do Fisco + nullable: true + description: "Informações Adicionais de Interesse do Fisco (infAdFisco)" + taxpayer: + type: "string" + nullable: true + description: "Informações Complementares de interesse do Contribuinte (infCpl)" + xmlAuthorized: + type: "array" + nullable: true + items: + type: "integer" + format: "int64" + description: "Pessoas autorizadas para o download do XML da NF-e (autXML). CNPJ ou CPF das pessoas autorizadas. Máximo de 10 autorizações." + effort: + type: "string" + nullable: true # Esforço + description: "Esforço (xCampo)" + order: + type: "string" + nullable: true + description: "Pedido (xCampo)" + contract: + type: "string" + nullable: true + description: "Contrato (xCampo)" + taxDocumentsReference: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/TaxDocumentsReferenceResource" + description: "Documentos Fiscais Referenciados (refECF)" + advancePayment: # Grupo de notas de antecipação de pagamento + type: "array" + nullable: true + items: + $ref: "#/components/schemas/AdvancePaymentItemResource" + description: "Grupo de notas de antecipação de pagamento - Informado para abater as parcelas de antecipação de pagamento, conforme Art. 10. § 4º (gPagAntecipado)." + taxpayerComments: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/TaxpayerCommentsResource" + description: "Observações fiscais (obsCont)" + referencedProcess: # Processos referenciados + type: "array" + nullable: true + items: + $ref: "#/components/schemas/ReferencedProcessResource" + description: "Processos referenciados (procRef)" + additionalProperties: false + AddressResource: + type: "object" + required: + - state + - city + - district + - street + - number + properties: + state: + type: "string" # Estado + description: "Estado, ex.: SP, RJ, AC, padrão ISO 3166-2 ALFA 2." + city: + description: "Cidade do Endereço (cMun)" + $ref: "#/components/schemas/CityResource" + district: + type: "string" + description: "Bairro do Endereço (xBairro)" + additionalInformation: + type: "string" + nullable: true + description: "Complemento do Endereço, ex.: AP 2, BL A. (xCpl)" + street: + type: "string" + description: "Logradouro do Endereço (xLgr)" + number: # Número do Endereço + type: "string" + description: "Número do Endereço. Usar S/N para \"sem número\". (nro)" + postalCode: + type: "string" + nullable: true + description: "Cód. Endereço Postal (CEP)" + country: + type: "string" # País + nullable: true + description: "País, ex.: BRA, ARG, USA, padrão ISO 3166-1 ALFA-3. (xPais). Opcional — se omitido, assume BRA." + default: "BRA" + phone: + type: "string" + nullable: true + description: "Telefone (fone)" + additionalProperties: false + description: "Dados do Endereço" + AdvancePaymentItemResource: + type: "object" + properties: + accessKey: # Chave de Acesso da NF-e para antecipação de pagamento + type: "string" + nullable: true + additionalProperties: false + description: "Grupo de notas de antecipação de pagamento - Informado para abater as parcelas de antecipação de pagamento, conforme Art. 10. § 4º (gPagAntecipado)." + AuthorizationResource: + type: "object" + properties: + receiptOn: + type: "string" + nullable: true # Data e hora do recebimento + description: "Data e hora do recebimento (dhRecbto)" + format: "date-time" + accessKey: + type: "string" + nullable: true + description: "Chave de Acesso da NF-e (chNFe)" + message: + type: "string" + nullable: true # Mensagem da SEFAZ + description: + type: string + description: "Mensagem da SEFAZ (xMotivo)" + additionalProperties: false + BillResource: + type: "object" + properties: + number: + type: "string" # Número da Fatura + nullable: true + description: "Número da Fatura (nFat)" + originalAmount: + type: "number" + nullable: true + description: "Valor Original da Fatura (vOrig)" + format: "double" + discountAmount: + type: "number" + nullable: true # Valor do desconto + description: "Valor do desconto (vDesc)" + format: "double" + netAmount: + type: "number" + nullable: true + description: "Valor Líquido da Fatura (vLiq)" + format: "double" + additionalProperties: false + BillingResource: + type: "object" + properties: + bill: + description: "Grupo Fatura (fat)" + $ref: "#/components/schemas/BillResource" + duplicates: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/DuplicateResource" + description: "Grupo Duplicata (dup)" + additionalProperties: false # Grupo Cobrança (cobr) + BuyerResource: + type: "object" + required: + - name + - federalTaxNumber + - address + properties: + accountId: + type: "string" + nullable: true + description: "Identificador da Conta" + id: + type: "string" + nullable: true + description: "Identificação" + name: + type: "string" + description: "Nome ou Razão Social (xNome)" + federalTaxNumber: + type: "integer" # O valor padrão de consumerType é determinado com base neste campo. Se for um CNPJ, o padrão será "Normal"; se for um CPF, será "FinalConsumer". + description: "CNPJ ou CPF (CNPJ/CPF)" + format: "int64" + email: + type: "string" + nullable: true # Email — opcional pelo leiaute SEFAZ + description: "Email (email)" + address: + description: "Dados do Endereço (enderDest)" + $ref: "#/components/schemas/AddressResource" + type: + description: "Tipo da pessoa (indIEDest)" + $ref: "#/components/schemas/PersonType" + stateTaxNumberIndicator: + description: "Indicador Inscrição Estadual (indIEDest)" + $ref: "#/components/schemas/ReceiverStateTaxIndicator" + tradeName: + type: "string" # Nome fantasia + nullable: true + description: "Nome fantasia (xFant)" + taxRegime: + description: "Regime de tributação (CRT)" + $ref: "#/components/schemas/TaxRegime" + stateTaxNumber: + type: "string" + nullable: true # Inscrição Estadual + description: "Inscrição Estadual (IE)" + additionalProperties: false + description: "Identificação do Destinatário da Nota Fiscal eletrônica - Grupo Obrigatório para a NF-e (modelo 55) e opcional para NFC-e (modelo 65)." + CBSTaxResource: + type: "object" + description: "Grupo de Informações da CBS" + properties: + rate: + type: "number" # Alíquota da CBS (em percentual) + nullable: true + description: "Alíquota da CBS (em percentual) (pCBS)" + format: "double" + deferment: + description: "Grupo de Informações do Diferimento (gDif)" + $ref: "#/components/schemas/DefermentTaxResource" + returnedAmount: + description: "Grupo de Informações da Devolução de Tributos (gDevTrib)" + $ref: "#/components/schemas/ReturnedTaxResource" + reduction: + description: "Grupo de informações da redução da alíquota (gRed)" + $ref: "#/components/schemas/ReductionTaxResource" + amount: + type: "number" + nullable: true # Valor total da CBS + description: "Valor total da CBS (vCBS)." + format: "double" + additionalProperties: false + CIDEResource: + type: "object" + properties: + bc: + type: "number" # BC da CIDE + nullable: true + description: "BC da CIDE (qBCProd)" + format: "double" + rate: + type: "number" + nullable: true + description: "Valor da alíquota da CIDE (vAliqProd)" + format: "double" + cideAmount: + type: "number" # Valor da CIDE + nullable: true + description: "Valor da CIDE (vCIDE)" + format: "double" + additionalProperties: false + CardResource: + type: "object" + properties: + federalTaxNumber: + type: "string" # CNPJ da Credenciadora de cartão de crédito e/ou débito + nullable: true + description: "CNPJ da Credenciadora de cartão de crédito e/ou débito (CNPJ)" + flag: + description: "Bandeira da operadora de cartão de crédito e/ou débito (tBand)" + $ref: "#/components/schemas/FlagCard" + authorization: + type: "string" + nullable: true # Número de autorização da operação cartão de crédito e/ou débito + description: "Número de autorização da operação cartão de crédito e/ou débito (cAut)" + integrationPaymentType: + description: "Tipo de Integração para pagamento (tpIntegra)" + $ref: "#/components/schemas/IntegrationPaymentType" + federalTaxNumberRecipient: + type: "string" # CNPJ do beneficiário do pagamento + nullable: true + idPaymentTerminal: + type: "string" + nullable: true + additionalProperties: false + CityResource: + type: "object" + required: + - code + - name + properties: + code: + type: "string" # Cód. do Município + description: "Cód. do Município, segundo o Tabela de Municípios do IBGE (cMun)" + name: + type: "string" + description: "Nome do Município (xMun)" + additionalProperties: false + CofinsTaxResource: + type: "object" + required: + - cst + properties: + cst: + type: "string" # Código de Situação Tributária da COFINS + description: "Código de Situação Tributária da COFINS (CST)" + baseTax: + type: "number" + nullable: true + description: "Valor da Base de Cálculo da COFINS (vBC)" + format: "double" + rate: + type: "number" + nullable: true # Alíquota da COFINS (em percentual) + description: "Alíquota da COFINS (em percentual) (pCOFINS)" + format: "double" + amount: + type: "number" + nullable: true + description: "Valor da COFINS (vCOFINS)" + format: "double" + baseTaxProductQuantity: + type: "number" + nullable: true # Quantidade Vendida + description: "Quantidade Vendida (qBCProd)" + format: "double" + productRate: + type: "number" + nullable: true + description: "Alíquota da COFINS (em reais) (vAliqProd)" + format: "double" + additionalProperties: false + description: "Grupo do COFINS\r\n\r\nID: S01\r\nPai: M01\r\n\r\n Obs: Informar apenas um dos grupos S02, S03, S04 ou S04\r\n com base valor atribuído ao campo S06 – CST do COFINS\r\n" + CompetenceAdjustmentResource: + type: "object" + description: "Ajuste de Competência (gAjusteCompet)" + properties: + assessmentPeriod: + type: "string" + nullable: true # Ano e mês referência do período de apuração + description: "Ano e mês referência do período de apuração (AAAA-MM) (competApur)" + ibsAmount: + type: "number" + nullable: true + description: "Valor de IBS referente ao ajuste de competência (vIBS)" + format: "double" + cbsAmount: + type: "number" + nullable: true # Valor de CBS referente ao ajuste de competência + description: "Valor de CBS referente ao ajuste de competência (vCBS)" + format: "double" + additionalProperties: false + ConsumerPresenceType: + type: "string" + description: | + Indicador de Presença (indPres). + Valores possíveis: + - `None`: Não se aplica (ex: nota complementar ou de ajuste) + - `Presence`: Operação presencial + - `Internet`: Operação não presencial, pela Internet + - `Telephone`: Operação não presencial, Teleatendimento + - `Delivery`: NFC-e em operação com entrega a domicílio + - `OthersNonPresenceOperation`: Operação não presencial, outros + enum: + - "None" + - "Presence" + - "Internet" + - "Telephone" + - "Delivery" + - "OthersNonPresenceOperation" + default: "Internet" + ConsumerType: + type: "string" + description: | + Indica operação com Consumidor final (indFinal). O valor padrão é determinado pelo `federalTaxNumber` do `buyer`: `Normal` para CNPJ, `FinalConsumer` para CPF. + Valores possíveis: + - `FinalConsumer`: Consumidor final + - `Normal`: Operação normal + enum: + - "FinalConsumer" + - "Normal" + default: "Normal" # O valor padrão é "Normal" para CNPJ e "FinalConsumer" para CPF. + + ConsumptionCityCode: + type: "integer" + nullable: true + description: "Código do Município de ocorrência do fato gerador do IBS/CBS (cMunFGIBS). Informar o município de ocorrência do fato gerador do IBS/CBS. Este campo só é preenchido quando \"indPres = 5 (Operação presencial, fora do estabelecimento)\" e não incluir o endereço do destinatário (Grupo: E05) ou local de entrega (Grupo: G01)." + format: "int64" + ContingencyDetails: + type: "object" + properties: + authorizer: + $ref: "#/components/schemas/StateTaxProcessingAuthorizer" + startedOn: + type: "string" + description: "Data e hora do início da contingência" + format: "date-time" + reason: + type: "string" # Justificativa da entrada em contingência + nullable: true + description: "Justificativa da entrada em contingência" + additionalProperties: false + CreditReversalResource: + type: "object" + description: "Estorno de Crédito (gEstornoCred)" + properties: + ibsReversalAmount: + type: "number" # Valor do IBS a ser estornado + nullable: true + description: "Valor do IBS a ser estornado (vIBSEstCred)" + format: "double" + cbsReversalAmount: + type: "number" + nullable: true + description: "Valor da CBS a ser estornada (vCBSEstCred)" + format: "double" + additionalProperties: false + CreditReversalTotalsResource: + type: "object" + description: "Estorno de Crédito (gEstornoCred)" + properties: + ibsReversalAmount: + type: "number" + nullable: true + description: "Valor do IBS a ser estornado (vIBSEstCred)" + format: "double" + cbsReversalAmount: + type: "number" + nullable: true + description: "Valor da CBS a ser estornada (vCBSEstCred)" + format: "double" + additionalProperties: false + CreditTransferTaxResource: + type: "object" + description: "Informações de Transferências de Crédito (gTransfCred)" + properties: + ibsAmount: + type: "number" # Valor de IBS a transferir + nullable: true + description: "Valor de IBS a transferir (vIBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor de CBS a transferir (vCBS)." + format: "double" + additionalProperties: false + CreditType: + type: "string" + nullable: true + description: | + Tipo de Nota de Crédito (tpNFCredito). + Valores possíveis: + - `FinesAndInterest`: Multa e juros + - `IbsPresumedCreditAppropriationZfm`: Apropriação de crédito presumido de IBS sobre o saldo devedor na ZFM + - `ReturnDeliveryRefusedOrNotFound`: Retorno por recusa na entrega ou não localização do destinatário + - `ValueReduction`: Redução de valores + - `TransferCreditSuccession`: Transferência de crédito na sucessão + enum: + - "FinesAndInterest" + - "IbsPresumedCreditAppropriationZfm" + - "ReturnDeliveryRefusedOrNotFound" + - "ValueReduction" + - "TransferCreditSuccession" + DebitType: + type: "string" + nullable: true + description: | + Tipo de Nota de Débito (tpNFDebito). + Valores possíveis: + - `TransferCreditsToCooperatives`: Transferência de créditos para cooperativas + - `CancelCreditsExemptImmuneSales`: Cancelamento de créditos por vendas isentas/imunes + - `UnprocessedInvoicesDebits`: Débitos de faturas não processadas no cálculo + - `FinesAndInterest`: Multas e juros + - `TransferInheritanceCredit`: Transferência de crédito de herança + - `AdvancePayment`: Pagamento antecipado + - `InventoryLoss`: Perda de estoque + - `SnDisqualification`: Desenquadramento do Simples Nacional + enum: + - "TransferCreditsToCooperatives" + - "CancelCreditsExemptImmuneSales" + - "UnprocessedInvoicesDebits" + - "FinesAndInterest" + - "TransferInheritanceCredit" + - "AdvancePayment" + - "InventoryLoss" + - "SnDisqualification" + DefermentTaxResource: + type: "object" + description: "Grupo de Informações do Diferimento" + properties: + rate: + type: "number" # Percentual do diferimento + nullable: true + description: "Percentual do diferimento" + format: "double" + amount: + type: "number" + nullable: true + description: "Valor do Diferimento" + format: "double" + additionalProperties: false + DeliveryInformationResource: + type: "object" + properties: + accountId: + type: "string" + nullable: true + description: "Identificador da Conta" + id: + type: "string" + nullable: true + description: "Identificação" + name: + type: "string" + nullable: true + description: "Nome ou Razão Social (xNome)" + federalTaxNumber: + type: "integer" + nullable: true # CNPJ ou CPF + description: "CNPJ ou CPF" + format: "int64" + email: + type: "string" + nullable: true + description: "Email" + address: + $ref: "#/components/schemas/AddressResource" + type: + $ref: "#/components/schemas/PersonType" + stateTaxNumber: + type: "string" # Inscrição Estadual + nullable: true + description: "Inscrição Estadual (IE)" + additionalProperties: false + description: "Identificação do Local de entrega (entrega)" + Destination: + type: "string" + enum: + - "None" + - "InternalOperation" + - "InterstateOperation" + - "InternationalOperation" + default: "InternalOperation" # Operação interna + description: | + Identificador de local de destino da operação (idDest). + Valores possíveis: + - `None`: Não definido + - `InternalOperation`: Operação interna + - `InterstateOperation`: Operação interestadual + - `InternationalOperation`: Operação com o exterior + DisablementResource: + type: "object" + properties: + environment: + $ref: "#/components/schemas/EnvironmentType" + serie: + type: "integer" # Série + description: "Série" + format: "int32" + state: + $ref: "#/components/schemas/StateCode" + beginNumber: + type: "integer" + description: "Número inicial" + format: "int32" + lastNumber: + type: "integer" # Número final + description: "Número final (usar o mesmo número inicial se for apenas um número)" + format: "int32" + reason: + type: "string" + nullable: true + description: "Motivo da inutilização" + additionalProperties: false + description: "Dados para inutilizar números de nota fiscal" + DocumentElectronicInvoiceResource: + type: "object" + properties: + accessKey: + type: "string" # Chave de Acesso + nullable: true + description: "Chave de Acesso (refNFe)" + additionalProperties: false + DocumentInvoiceReferenceResource: + type: "object" + properties: + state: + type: "number" # Código da UF + nullable: true + description: "Código da UF (cUF)" + format: "double" + yearMonth: + type: "string" + nullable: true + description: "Ano / Mês (AAMM)" + federalTaxNumber: + type: "string" + nullable: true # CNPJ + description: "CNPJ (CNPJ)" + model: + type: "string" + nullable: true + description: "Modelo (mod)" + series: + type: "string" + nullable: true + description: "Série (serie)" + number: + type: "string" + nullable: true # Número + description: "Número (nNF)" + additionalProperties: false + DuductionIndicator: + type: "string" + enum: + - "NotDeduct" + - "Deduce" + description: | + Indicador de dedução do ICMS desonerado do valor total da NF-e (indDeducao). + Valores possíveis: + - `NotDeduct`: O valor do ICMS desonerado (vICMSDeson) não deduz do valor total da NF-e + - `Deduce`: O valor do ICMS desonerado (vICMSDeson) deduz do valor total da NF-e + DuplicateResource: + type: "object" + properties: + number: + type: "string" + nullable: true + description: "Número da Duplicata (nDup)" + expirationOn: + type: "string" + nullable: true # Data de vencimento + description: "Data de vencimento (dVenc)" + format: "date-time" + amount: + type: "number" + nullable: true + description: "Valor da duplicata (vDup)" + format: "double" + additionalProperties: false + EconomicActivityResource: + type: "object" + properties: + type: + $ref: "#/components/schemas/EconomicActivityType" + code: + type: "integer" # Código da Atividade da Empresa + nullable: true + description: "Código da Atividade da Empresa" + format: "int32" + additionalProperties: false + EconomicActivityType: + type: "string" + enum: + - "Main" + - "Secondary" + description: | + Tipo de Atividade Econômica. + Valores possíveis: + - `Main`: Principal + - `Secondary`: Secundária + EnvironmentType: + type: "string" + description: | + Tipo de Ambiente (tpAmb). + Valores possíveis: + - `None`: Não definido + - `Production`: Produção + - `Test`: Homologação (Teste) + enum: + - "None" + - "Production" + - "Test" + ErrorResource: + type: "object" + properties: + code: + type: "integer" + nullable: true + format: "int32" + message: + type: "string" + nullable: true + additionalProperties: false + ErrorsResource: + type: "object" + properties: + errors: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/ErrorResource" + readOnly: true + additionalProperties: false + ExemptReason: + type: "string" + enum: + - "Agriculture" + - "Others" + - "DevelopmentEntities" + description: | + Motivo da desoneração. Campo será preenchido quando o campo anterior estiver preenchido. + Valores possíveis: + - `Agriculture`: Produtos agropecuários + - `Others`: Outros + - `DevelopmentEntities`: Órgãos de fomento e desenvolvimento + ExportDetailResource: + type: "object" + properties: + drawback: + type: "string" + nullable: true + description: "Número do ato concessório de Drawback (nDraw)" + hintInformation: + $ref: "#/components/schemas/ExportHintResource" # Informações de exportação + additionalProperties: false + ExportHintResource: + type: "object" + properties: + registryId: + type: "string" + nullable: true + description: "Número do Registro de Exportação (nRE)" + accessKey: + type: "string" # Chave de Acesso da NF-e recebida para exportação + nullable: true + description: "Chave de Acesso da NF-e recebida para exportação (chNFe)" + quantity: + type: "number" + nullable: true + description: "Quantidade do item realmente exportado (qExport)" + format: "double" + additionalProperties: false + ExportResource: + type: "object" + properties: + state: + $ref: "#/components/schemas/StateCode" # Sigla da UF + office: + type: "string" + nullable: true + description: "Descrição do Local de Embarque ou de transposição de fronteira (xLocExporta)" + local: + type: "string" + nullable: true + description: "Informações Complementares de interesse do Contribuinte (xLocDespacho)" + additionalProperties: false + FileResource: + type: "object" + properties: + uri: + type: "string" + nullable: true + description: "Endereço Absoluto URI para o arquivo" + additionalProperties: false # Arquivo + description: "Arquivo" + FlagCard: + type: "string" + enum: + - "None" + - "Visa" + - "Mastercard" + - "AmericanExpress" + - "Sorocred" + - "DinersClub" + - "Elo" + - "Hipercard" + - "Aura" + - "Cabal" + - "Alelo" + - "BanesCard" + - "CalCard" + - "Credz" + - "Discover" + - "GoodCard" + - "GreenCard" + - "Hiper" + - "JCB" + - "Mais" + - "MaxVan" + - "Policard" + - "RedeCompras" + - "Sodexo" + - "ValeCard" + - "Verocheque" + - "VR" + - "Ticket" + - "Other" + description: | + Bandeira da operadora de cartão de crédito e/ou débito (tBand). + Valores possíveis: + - `None`: Não definido + - `Visa`: Visa + - `Mastercard`: Mastercard + - `AmericanExpress`: American Express + - `Sorocred`: Sorocred + - `DinersClub`: Diners Club + - `Elo`: Elo + - `Hipercard`: Hipercard + - `Aura`: Aura + - `Cabal`: Cabal + - `Alelo`: Alelo + - `BanesCard`: Banescard + - `CalCard`: Calcard + - `Credz`: Credz + - `Discover`: Discover + - `GoodCard`: Good Card + - `GreenCard`: Green Card + - `Hiper`: Hiper + - `JCB`: JCB + - `Mais`: Mais + - `MaxVan`: Maxvan + - `Policard`: Policard + - `RedeCompras`: Rede Compras + - `Sodexo`: Sodexo + - `ValeCard`: ValeCard + - `Verocheque`: Verocheque + - `VR`: VR + - `Ticket`: Ticket + - `Other`: Outros + FuelOriginResource: + type: "object" + properties: + indImport: + type: "integer" + nullable: true + description: "Indicador de importação (indImport)" + format: "int32" + cUFOrig: + type: "integer" # Código da UF + nullable: true + description: "Código da UF (cUFOrig)" + format: "int32" + pOrig: + type: "number" + nullable: true + description: "Percentual originário para a UF (pOrig)" + format: "double" + additionalProperties: false + VehicleDetailResource: + type: "object" + description: "Detalhamento de Veículos novos (veicProd) - grupo J01" + properties: + operationType: + type: "integer" + nullable: true + description: | + Tipo da Operação (tpOp). + Valores possíveis: + - `0`: Outros + - `1`: Venda concessionária + - `2`: Faturamento direto para consumidor final + - `3`: Venda direta para grandes consumidores + format: "int32" + enum: [0, 1, 2, 3] + chassis: + type: "string" + nullable: true + description: "Chassi do veículo - VIN (chassi). 17 caracteres alfanuméricos" + minLength: 17 + maxLength: 17 + pattern: "^[A-Z0-9]+$" + colorCode: + type: "string" + nullable: true + description: "Cor do veículo - código de cada montadora (cCor)" + maxLength: 4 + colorDescription: + type: "string" + nullable: true + description: "Descrição da Cor (xCor)" + maxLength: 40 + enginePower: + type: "string" + nullable: true + description: "Potência máxima do motor em cavalo vapor - CV (pot)" + maxLength: 4 + engineDisplacement: + type: "string" + nullable: true + description: "Capacidade volumétrica do motor em centímetros cúbicos - CC (cilin)" + maxLength: 4 + netWeight: + type: "string" + nullable: true + description: "Peso Líquido (pesoL)" + maxLength: 9 + grossWeight: + type: "string" + nullable: true + description: "Peso Bruto (pesoB)" + maxLength: 9 + serialNumber: + type: "string" + nullable: true + description: "Serial - série (nSerie)" + maxLength: 9 + fuelType: + type: "string" + nullable: true + description: "Tipo de combustível - Tabela RENAVAM (tpComb). Ex: 01-Álcool; 02-Gasolina; 03-Diesel; 16-Álcool/Gas.; 17-Gas./Álcool/GNV; 18-Gasolina/Elétrico" + maxLength: 2 + engineNumber: + type: "string" + nullable: true + description: "Número do motor (nMotor)" + maxLength: 21 + maximumTractionCapacity: + type: "string" + nullable: true + description: "Capacidade Máxima de Tração em toneladas - 4 casas decimais (CMT)" + maxLength: 9 + wheelBase: + type: "string" + nullable: true + description: "Distância entre eixos (dist)" + maxLength: 4 + modelYear: + type: "integer" + nullable: true + description: "Ano Modelo de Fabricação (anoMod). Formato: 4 dígitos" + format: "int32" + manufactureYear: + type: "integer" + nullable: true + description: "Ano de Fabricação (anoFab). Formato: 4 dígitos" + format: "int32" + paintType: + type: "string" + nullable: true + description: "Tipo de pintura (tpPint)" + maxLength: 1 + vehicleType: + type: "string" + nullable: true + description: "Tipo de veículo - Tabela RENAVAM (tpVeic)" + maxLength: 2 + vehicleSpecies: + type: "integer" + nullable: true + description: "Espécie de veículo - Tabela RENAVAM (espVeic)" + format: "int32" + vinCondition: + type: "string" + nullable: true + description: | + Condição do VIN — chassi (VIN). + Valores possíveis: + - `R`: Remarcado (chassi regravado pelo DETRAN) + - `N`: Normal (chassi original de fábrica) + enum: ["R", "N"] + vehicleCondition: + type: "integer" + nullable: true + description: | + Condição do veículo (condVeic). + Valores possíveis: + - `1`: Acabado (veículo pronto para uso) + - `2`: Inacabado (veículo sem algum componente essencial) + - `3`: Semi-acabado (veículo parcialmente montado, ex: chassis-cabina) + format: "int32" + enum: [1, 2, 3] + brandModelCode: + type: "string" + nullable: true + description: "Código Marca Modelo - Tabela RENAVAM (cMod)" + maxLength: 6 + denatranColorCode: + type: "string" + nullable: true + description: "Código da Cor DENATRAN (cCorDENATRAN). 01-AMARELO; 02-AZUL; 03-BEGE; 04-BRANCA; 05-CINZA; 06-DOURADA; 07-GRENA; 08-LARANJA; 09-MARROM; 10-PRATA; 11-PRETA; 12-ROSA; 13-ROXA; 14-VERDE; 15-VERMELHA; 16-FANTASIA" + maxLength: 2 + seatingCapacity: + type: "integer" + nullable: true + description: "Quantidade máxima de passageiros sentados, inclusive motorista (lota)" + format: "int32" + restrictionType: + type: "integer" + nullable: true + description: | + Tipo de restrição sobre o veículo (tpRest). + Valores possíveis: + - `0`: Não há restrição (veículo livre para venda e transferência) + - `1`: Alienação Fiduciária (veículo dado como garantia em financiamento) + - `2`: Arrendamento Mercantil (veículo em contrato de leasing) + - `3`: Reserva de Domínio (vendedor mantém a propriedade até quitação total) + - `4`: Penhor de Veículos (veículo dado como garantia em empréstimo) + - `9`: Outras restrições + format: "int32" + enum: [0, 1, 2, 3, 4, 9] + additionalProperties: false + FuelResource: + type: "object" + properties: + codeANP: + type: "string" # Código de produto da ANP + nullable: true + description: "Código de produto da ANP (cProdANP)" + percentageNG: + type: "number" + nullable: true + description: "Percentual de Gás Natural para o produto GLP (cProdANP=210203001) (pMixGN)" + format: "double" + descriptionANP: + type: "string" + nullable: true # Descrição do produto conforme ANP + description: "Descrição do produto conforme ANP (descANP)" + percentageGLP: + type: "number" + nullable: true + description: "Percentual do GLP derivado do petróleo no produto GLP (cProdANP=210203001) (pGLP)" + format: "double" + percentageNGn: + type: "number" + nullable: true # Percentual de Gás Natural Nacional + description: "Percentual de Gás Natural Nacional – GLGNn para o produto GLP (cProdANP= 210203001) (pGNn)" + format: "double" + percentageGNi: + type: "number" + nullable: true + description: "Percentual \r\nde Gás Natural Importado – GLGNi para o produto GLP (cProdANP= 210203001) (pGNi)" + format: "double" + startingAmount: + type: "number" + nullable: true # Valor de partida + description: "Valor de partida (cProdANP=210203001) (vPart)" + format: "double" + codif: + type: "string" + nullable: true + description: "Código de autorização / registro do CODIF (CODIF)" + amountTemp: + type: "number" + nullable: true # Quantidade de combustível faturada à temperatura ambiente + description: "Quantidade de combustível faturada à temperatura ambiente (qTemp)" + format: "double" + stateBuyer: + type: "string" + nullable: true + description: "Sigla da UF de consumo (UFCons)" + cide: + $ref: "#/components/schemas/CIDEResource" + pump: + $ref: "#/components/schemas/PumpResource" + fuelOrigin: + $ref: "#/components/schemas/FuelOriginResource" + additionalProperties: false + GovernmentPurchaseEntityType: + type: "string" + nullable: true + description: | + Tipo de ente governamental (tpEnteGov). Para administração pública direta e suas autarquias e fundações. + Valores possíveis: + - `Union`: União + - `State`: Estado + - `FederalDistrict`: Distrito Federal + - `Municipality`: Município + enum: + - "Union" + - "State" + - "FederalDistrict" + - "Municipality" + GovernmentPurchaseOperationType: + type: "string" + nullable: true + description: | + Tipo de operação com o ente governamental (tpOperGov). + Valores possíveis: + - `Supply`: Fornecimento + - `Payment`: Recebimento do pagamento + - `SupplyThenPay`: Fornecimento e pagamento simultâneo + - `PayForPastSupply`: Pagamento por fornecimento passado + - `SupplyAfterPay`: Fornecimento após pagamento + - `PayNowSupplyLater`: Pagamento agora, fornecimento depois + - `SupplyAndPayNow`: Fornecimento e pagamento agora + enum: + - "Supply" + - "Payment" + - "SupplyThenPay" + - "PayForPastSupply" + - "SupplyAfterPay" + - "PayNowSupplyLater" + - "SupplyAndPayNow" + GovernmentPurchaseResource: + type: "object" + description: "Grupo de Compras Governamentais (gCompraGov). Grupo opcional. Informar apenas para compras governamentais." + properties: + entityType: + $ref: "#/components/schemas/GovernmentPurchaseEntityType" # Tipo de ente governamental + rateReduction: + type: "number" + nullable: true + description: "Percentual de redução de alíquota em compra governamental (pRedutor). Conforme o art. 472/370 da LC 214/2025." + format: "double" + operationType: + $ref: "#/components/schemas/GovernmentPurchaseOperationType" + additionalProperties: false + GovernmentPurchaseTaxResource: + type: "object" + description: "Grupo de informações sobre a composição do valor do IBS e CBS nas compras governamentais. Informar apenas para compras governamentais." + properties: + stateRate: + type: "number" # Alíquota IBS UF em compras governamentais + nullable: true + description: "Alíquota IBS UF em compras governamentais (pAliqIBSUF)." + format: "double" + stateAmount: + type: "number" + nullable: true + description: "Valor IBS UF em compras governamentais (vTribIBSUF)." + format: "double" + municipalRate: + type: "number" # Alíquota IBS Município em compras governamentais + nullable: true + description: "Alíquota IBS Município em compras governamentais (pAliqIBSMun)." + format: "double" + municipalAmount: + type: "number" + nullable: true + description: "Valor IBS Município em compras governamentais (vTribIBSMun)." + format: "double" + cbsRate: + type: "number" # Alíquota CBS em compras governamentais + nullable: true + description: "Alíquota CBS em compras governamentais (pAliqCBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS em compras governamentais (vTribCBS)" + format: "double" + additionalProperties: false + IBSCBSTaxResource: + type: "object" + description: "Grupo de Informações do IBS e CBS" + properties: + situationCode: + type: "string" + nullable: true # Código de Situação Tributária do IBS/CBS + description: "Código de Situação Tributária do IBS/CBS (CST). Campo opcional. Se preenchido, será considerado; caso contrário, será definido com base no valor informado no campo `classCode`. Consulte a tabela de referência de `situationCode` (CST) disponível na nossa documentação funcional." + maxLength: 3 + classCode: + type: "string" + nullable: true + description: "Código de Classificação Tributária do IBS/CBS (cClassTrib). Consulte a tabela de referência [cClassTrib](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/tabelas-de-referencia/tabela-referencia-cst-classificacao-tributaria-ibs-cbs/) disponível na nossa documentação funcional." + maxLength: 6 + calculationMode: + type: "string" + nullable: true + description: | + Modo de cálculo do IBS/CBS. + Valores possíveis: + - `Manual`: Preenchimento manual dos campos de tributo. + - `OfficialService`: Utiliza o serviço oficial para calcular IBS/CBS. Quando ativo, apenas `situationCode` e `classCode` são necessários; os demais campos de tributo são ignorados na entrada e preenchidos pelo serviço. + enum: + - "Manual" + - "OfficialService" + default: "Manual" + donationIndicator: + type: "string" + nullable: true # Indica a natureza da operação de doação + description: "Indica a natureza da operação de doação, orientando a apuração e a geração de débitos ou estornos conforme o cenário (indDoacao). Informar quando for doação." + maxLength: 1 + basis: + type: "number" + nullable: true + description: "Base de cálculo antes de reduções para cálculo do tributo bruto. Este campo é opcional. Se enviado, será considerado; caso contrário, será calculado." + format: "double" + state: + $ref: "#/components/schemas/IBSStateTaxResource" + municipal: # Grupo de Informações do IBS para o município + $ref: "#/components/schemas/IBSMunicipalTaxResource" + ibsTotalAmount: + type: "number" + nullable: true + description: "Total do IBS (vIBSTot = vIBSUF + vIBSMun). Quando houver crédito presumido com o indicador \"IndDeduzCredPres=1\", o valor de vCredPres deve ser deduzido deste total." + format: "double" + cbs: + $ref: "#/components/schemas/CBSTaxResource" + regularTaxation: # Tributação regular hipotética + description: "Tributação regular hipotética caso condição resolutória/suspensiva não se aplique." + $ref: "#/components/schemas/RegularTaxationResource" + governmentPurchase: + description: "Grupo de informações sobre a composição do valor do IBS e CBS nas compras governamentais." + $ref: "#/components/schemas/GovernmentPurchaseTaxResource" + monophase: + description: "Grupo de Informações do IBS e CBS sobre transações monofásicas" + $ref: "#/components/schemas/MonophaseIBSCBSTaxResource" + creditTransfer: # Grupo de Informações sobre Transferências de Crédito + description: "Grupo de Informações sobre Transferências de Crédito" + $ref: "#/components/schemas/CreditTransferTaxResource" + operationalPresumedCredit: # Informações sobre o crédito presumido operacional + description: "Informações sobre o crédito presumido operacional (gCredPresOper)." + $ref: "#/components/schemas/OperationalPresumedCreditResource" + creditReversal: + description: "Estorno de Crédito (gEstornoCred). Observação: a obrigatoriedade ou vedação do preenchimento deste grupo está condicionada ao indicador “ind_gEstornoCred” da tabela de cClassTrib do IBS e da CBS." + $ref: "#/components/schemas/CreditReversalResource" + zfmPresumedCredit: + description: "Informações sobre o crédito presumido de IBS para fornecimentos da ZFM (gCredPresIBSZFM)." + $ref: "#/components/schemas/ZfmPresumedCreditResource" # Informações sobre o crédito presumido de IBS para fornecimentos da ZFM + additionalProperties: false + ICMSTotal: + type: "object" + properties: + baseTax: + type: "number" + nullable: true + description: "Base de Cálculo do ICMS (vBC)" + format: "double" + icmsAmount: + type: "number" + nullable: true + description: "Valor Total do ICMS (vICMS)" + format: "double" + icmsExemptAmount: + type: "number" + nullable: true + description: "Valor ICMS Total desonerado (vICMSDeson)" + format: "double" + stCalculationBasisAmount: + type: "number" + nullable: true + description: "Base de Cálculo do ICMS Substituição Tributária (vBCST)" + format: "double" + stAmount: + type: "number" + nullable: true + description: "Valor Total do ICMS ST (vST)" + format: "double" + productAmount: + type: "number" + description: "Valor Total dos produtos e serviços (vProd)" # Valor Total dos produtos e serviços + format: "double" + freightAmount: + type: "number" + nullable: true + description: "Valor Total do Frete (vFrete)" + format: "double" + insuranceAmount: + type: "number" + nullable: true # Valor Total do Seguro + description: "Valor Total do Seguro (vSeg)" + format: "double" + discountAmount: + type: "number" + nullable: true + description: "Valor Total do Desconto (vDesc)" + format: "double" + iiAmount: + type: "number" + nullable: true + description: "Valor Total do Imposto de Importação (vII)" + format: "double" + ipiAmount: + type: "number" + nullable: true + description: "Valor Total do IPI (vIPI)" + format: "double" + pisAmount: + type: "number" + nullable: true + description: "Valor do PIS (vPIS)" + format: "double" + cofinsAmount: + type: "number" + nullable: true + description: "Valor do COFINS (vCOFINS)" + format: "double" + othersAmount: + type: "number" + nullable: true + description: "Outras Despesas acessórias (vOutro)" + format: "double" + invoiceAmount: + type: "number" + description: "Valor Total da NF-e (vNF)" # Valor Total da NF-e + format: "double" + fcpufDestinationAmount: + type: "number" + nullable: true + description: "Valor Total ICMS FCP UF Destino" + format: "double" + icmsufDestinationAmount: + type: "number" + nullable: true + description: "Valor Total ICMS Interestadual UF Destino" + format: "double" + icmsufSenderAmount: + type: "number" + nullable: true + description: "Valor Total ICMS Interestadual UF Rem." + format: "double" + federalTaxesAmount: + type: "number" + description: "Valor aproximado total de tributos federais, estaduais e municipais. (vTotTrib)" + format: "double" + fcpAmount: + type: "number" + nullable: true + description: "Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP)" + format: "double" + fcpstAmount: + type: "number" + nullable: true + description: "Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCPST) retido por substituição tributária." + format: "double" + fcpstRetAmount: + type: "number" + nullable: true + description: "Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP) retido anteriormente por substituição tributária." + format: "double" + ipiDevolAmount: + type: "number" + nullable: true + description: "Valor total do IPI devolvido (vIPIDevol)" + format: "double" + qBCMono: + type: "number" + nullable: true # Valor total da quantidade tributada do ICMS monofásico próprio + format: "double" + vICMSMono: + type: "number" + nullable: true + description: "Valor total do ICMS monofásico próprio (vICMSMono)." + format: "double" + qBCMonoReten: + type: "number" + nullable: true # Valor total da quantidade tributada do ICMS monofásico sujeito a retenção + description: "Valor total da quantidade tributada do ICMS monofásico sujeito a retenção (qBCMonoReten)." + format: "double" + vICMSMonoReten: + type: "number" + nullable: true + description: "Valor total da quantidade tributada do ICMS monofásico retido anteriormente(vICMSMonoReten)" + format: "double" + qBCMonoRet: + type: "number" + nullable: true # Valor total do ICMS monofásico retido anteriormente + description: "Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet)" + format: "double" + vICMSMonoRet: + type: "number" + nullable: true + description: "Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet)" + format: "double" + additionalProperties: false + description: "Grupo de Valores Totais referentes ao ICMS" + ICMSTotalResource: + type: "object" + properties: + baseTax: + type: "number" + nullable: true + description: "Base de Cálculo do ICMS (vBC)" + format: "double" + icmsAmount: + type: "number" + nullable: true + description: "Valor Total do ICMS (vICMS)" + format: "double" + icmsExemptAmount: + type: "number" + nullable: true + description: "Valor ICMS Total desonerado (vICMSDeson)" + format: "double" + stCalculationBasisAmount: + type: "number" + nullable: true + description: "Base de Cálculo do ICMS Substituição Tributária (vBCST)" + format: "double" + stAmount: + type: "number" + nullable: true + description: "Valor Total do ICMS ST (vST)" + format: "double" + productAmount: + type: "number" + nullable: true + description: "Valor Total dos produtos e serviços (vProd)" + format: "double" + freightAmount: + type: "number" + nullable: true + description: "Valor Total do Frete (vFrete)" + format: "double" + insuranceAmount: + type: "number" + nullable: true # Valor Total do Seguro + description: "Valor Total do Seguro (vSeg)" + format: "double" + discountAmount: + type: "number" + nullable: true + description: "Valor Total do Desconto (vDesc)" + format: "double" + iiAmount: + type: "number" + nullable: true + description: "Valor Total do Imposto de Importação (vII)" + format: "double" + ipiAmount: + type: "number" + nullable: true + description: "Valor Total do IPI (vIPI)" + format: "double" + pisAmount: + type: "number" + nullable: true + description: "Valor do PIS (vPIS)" + format: "double" + cofinsAmount: + type: "number" + nullable: true + description: "Valor do COFINS (vCOFINS)" + format: "double" + othersAmount: + type: "number" + nullable: true + description: "Outras Despesas acessórias (vOutro)" + format: "double" + invoiceAmount: + type: "number" + nullable: true + description: "Valor Total da NF-e (vNF)" + format: "double" + fcpufDestinationAmount: + type: "number" + nullable: true + description: "Valor Total ICMS FCP UF Destino (vFCPUFDest)" + format: "double" + icmsufDestinationAmount: + type: "number" + nullable: true + description: "Valor Total ICMS Interestadual UF Destino (vICMSUFDest)" + format: "double" + icmsufSenderAmount: + type: "number" + nullable: true + description: "Valor Total ICMS Interestadual UF Remetente (vICMSUFRemet)" + format: "double" + federalTaxesAmount: + type: "number" + nullable: true # Valor aproximado total de tributos federais, estaduais e municipais + description: "Valor aproximado total de tributos federais, estaduais e municipais.\r\n(vTotTrib)" + format: "double" + fcpAmount: + type: "number" + nullable: true + description: "Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP)" + format: "double" + fcpstAmount: + type: "number" + nullable: true + description: "Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCPST) retido por substituição tributária." + format: "double" + fcpstRetAmount: + type: "number" + nullable: true + description: "Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (vFCPSTRet)" + format: "double" + ipiDevolAmount: + type: "number" + nullable: true + description: "Valor total do IPI devolvido (vIPIDevol)" + format: "double" + qBCMono: + type: "number" + nullable: true # Valor total da quantidade tributada do ICMS monofásico próprio + description: "Valor total da quantidade tributada do ICMS monofásico próprio (qBCMono)" + format: "double" + vICMSMono: + type: "number" + nullable: true + description: "Valor total do ICMS monofásico próprio (vICMSMono)." + format: "double" + qBCMonoReten: + type: "number" + nullable: true # Valor total da quantidade tributada do ICMS monofásico sujeito a retenção + description: "Valor total da quantidade tributada do ICMS monofásico sujeito a retenção (qBCMonoReten)." + format: "double" + vICMSMonoReten: + type: "number" + nullable: true + description: "Valor total da quantidade tributada do ICMS monofásico retido anteriormente(vICMSMonoReten)" + format: "double" + qBCMonoRet: + type: "number" + nullable: true # Valor total da quantidade tributada do ICMS monofásico retido anteriormente + description: "Valor total da quantidade tributada do ICMS monofásico retido anteriormente(qBCMonoRet)" + format: "double" + vICMSMonoRet: + type: "number" + nullable: true + description: "Valor total do ICMS monofásico retido anteriormente (vICMSMonoRet)" + format: "double" + additionalProperties: false + description: "Grupo de Valores Totais referentes ao ICMS" + ICMSUFDestinationTaxResource: + type: "object" + properties: + vBCUFDest: + type: "number" + nullable: true # Valor da Base de Cálculo do ICMS na UF de destino + description: "Valor da Base de Cálculo do ICMS na UF de destino (vBCUFDest)" + format: "double" + pFCPUFDest: + type: "number" + nullable: true + description: "Percentual adicional inserido na alíquota interna da UF de destino, relativo ao Fundo de Combate à Pobreza (FCP) naquela UF (pFCPUFDest)" + format: "double" + pICMSUFDest: + type: "number" + nullable: true # Alíquota adotada nas operações internas na UF de destino para o produto / mercadoria + description: "Alíquota adotada nas operações internas na UF de destino para o produto / mercadoria (pICMSUFDest)" + format: "double" + pICMSInter: + type: "number" + nullable: true + description: "Alíquota interestadual das UF envolvidas (pICMSInter)" + format: "double" + pICMSInterPart: + type: "number" + nullable: true # Percentual de ICMS Interestadual para a UF de destino + description: "Percentual de ICMS Interestadual para a UF de destino (pICMSInterPart)" + format: "double" + vFCPUFDest: + type: "number" + nullable: true + description: "Valor do ICMS relativo ao Fundo de Combate à Pobreza (FCP) da UF de destino (vFCPUFDest" + format: "double" + vICMSUFDest: + type: "number" + nullable: true # Valor do ICMS Interestadual para a UF de destino + description: "Valor do ICMS \r\nInterestadual para a UF de destino (vICMSUFDest)" + format: "double" + vICMSUFRemet: + type: "number" + nullable: true + description: "Valor do ICMS Interestadual para a UF do remetente (vICMSUFRemet)" + format: "double" + vBCFCPUFDest: + type: "number" + nullable: true # Valor da BC FCP na UF de destino + description: "Valor da BC FCP na UF de destino (vBCFCPUFDest)" + format: "double" + additionalProperties: false + description: "Grupo de Tributação do ICMS de Destino da UF" + IBSMunicipalTaxResource: + type: "object" + description: "Grupo de Informações do IBS para o município" + properties: + rate: + type: "number" # Alíquota IBS (Município) + nullable: true + description: "Alíquota IBS (Município) (%)." + format: "double" + deferment: + $ref: "#/components/schemas/DefermentTaxResource" + returnedAmount: + $ref: "#/components/schemas/ReturnedTaxResource" + reduction: + $ref: "#/components/schemas/ReductionTaxResource" + amount: + type: "number" + nullable: true # Valor do IBS do Município + description: "Valor do IBS do Município (vIBSMun)." + format: "double" + additionalProperties: false + IBSStateTaxResource: + type: "object" + description: "Grupo de Informações do IBS para a UF" + properties: + rate: + type: "number" # Alíquota do IBS de competência das UF + nullable: true + description: "Alíquota do IBS de competência das UF (em percentual). Alíquota vigente do IBS da UF.Preencher de acordo com a tabela de alíquotas do IBS e CBS." + format: "double" + deferment: + $ref: "#/components/schemas/DefermentTaxResource" + returnedAmount: + $ref: "#/components/schemas/ReturnedTaxResource" + reduction: + $ref: "#/components/schemas/ReductionTaxResource" + amount: + type: "number" + nullable: true # Valor do IBS da UF + description: "Valor do IBS da UF (vIBSUF)." + format: "double" + additionalProperties: false + IITaxResource: + type: "object" + properties: + baseTax: + type: "string" # Valor BC do Imposto de Importação + nullable: true + description: "Valor BC do Imposto de Importação (vBC)" + customsExpenditureAmount: + type: "string" + nullable: true + description: "Valor despesas aduaneiras (vDespAdu)" + amount: + type: "number" + nullable: true + description: "Valor Imposto de Importação (vII)" + format: "double" + iofAmount: + type: "number" + nullable: true # Valor Imposto sobre Operações Financeiras + description: "Valor Imposto sobre Operações Financeiras (vIOF)" + format: "double" + vEnqCamb: + type: "number" + nullable: true + description: "Valor dos encargos cambiais" + format: "double" + additionalProperties: false + description: "Grupo do Imposto de Importação\r\n\r\nId: P01\r\nPai: O01" + IPITaxResource: + type: "object" + properties: + cst: + type: "string" + nullable: true # Código da situação tributária do IPI + description: "Código da situação tributária do IPI (CST)" + classificationCode: + type: "string" + nullable: true + description: "Código de Enquadramento Legal do IPI (cEnq)" + classification: + type: "string" + nullable: true + description: "Classe de enquadramento do IPI para Cigarros e Bebidas (clEnq)" + producerCNPJ: + type: "string" # CNPJ do produtor da mercadoria + nullable: true + description: "CNPJ do produtor da mercadoria, quando diferente do emitente. Somente para os casos de exportação direta ou indireta (CNPJProd)" + stampCode: + type: "string" + nullable: true + description: "Código do selo de controle IPI (cSelo)" + stampQuantity: + type: "number" + nullable: true # Quantidade de selo de controle + description: "Quantidade de selo de controle (qSelo)" + format: "double" + base: + type: "number" + nullable: true + description: "Valor da BC do IPI (vBC)" + format: "double" + rate: + type: "number" + nullable: true # Alíquota do IPI + description: "Alíquota do IPI (pIPI)" + format: "double" + unitQuantity: + type: "number" + nullable: true + description: "Quantidade total na unidade padrão para tributação (somente para os produtos tributados por unidade) (qUnid)" + format: "double" + unitAmount: + type: "number" + nullable: true # Valor por Unidade Tributável + description: "Valor por Unidade Tributável (vUnid)" + format: "double" + amount: + type: "number" + nullable: true + description: "Valor IPI (vIPI)" + format: "double" + additionalProperties: false + description: "\r\nGrupo do IPI\r\n\r\nInformar apenas quando \r\no item for sujeito ao IPI\r\n\r\nID: O01\r\n\r\nPai: M01" + ISSQNTotal: + type: "object" + properties: + totalServiceNotTaxedICMS: + type: "number" + nullable: true # Valor Total Serv.Não Tributados p/ ICMS + description: "Valor Total Serv.Não Tributados p/ ICMS (vServ)" + format: "double" + baseRateISS: + type: "number" + nullable: true + description: "Base de Cálculo do ISS (vBC)" + format: "double" + totalISS: + type: "number" + nullable: true # Valor Total do ISS + description: "Valor Total do ISS (vISS)" + format: "double" + valueServicePIS: + type: "number" + nullable: true + description: "Valor do PIS sobre Serviços (vPIS)" + format: "double" + valueServiceCOFINS: + type: "number" + nullable: true # Valor da COFINS sobre Serviços + description: "Valor da COFINS sobre Serviços (vCOFINS)" + format: "double" + provisionService: + type: "string" + nullable: true + description: "Data Prestação Serviço (dCompet)" + format: "date-time" + deductionReductionBC: + type: "number" + nullable: true # Valor Dedução para Redução da BC + description: "Valor Dedução para Redução da BC (vDeducao)" + format: "double" + valueOtherRetention: + type: "number" + nullable: true + description: "Valor Outras Retenções (vOutro)" + format: "double" + discountUnconditional: + type: "number" + nullable: true # Valor Desconto Incondicionado + description: "Valor Desconto Incondicionado (vDescIncond)" + format: "double" + discountConditioning: + type: "number" + nullable: true + description: "Valor Desconto Condicionado (vDescCond)" + format: "double" + totalRetentionISS: + type: "number" + nullable: true # Valor Total Retenção ISS + description: "Valor Total Retenção ISS (vISSRet)" + format: "double" + codeTaxRegime: + type: "number" + nullable: true + description: "Código Regime Tributação (cRegTrib)" + format: "double" + additionalProperties: false + ISSQNTotalResource: + type: "object" + properties: + totalServiceNotTaxedICMS: + type: "number" + nullable: true # Valor Total Serv.Não Tributados p/ ICMS + description: "Valor Total Serv.Não Tributados p/ ICMS (vServ)" + format: "double" + baseRateISS: + type: "number" + nullable: true + description: "Base de Cálculo do ISS (vBC)" + format: "double" + totalISS: + type: "number" + nullable: true # Valor Total do ISS + description: "Valor Total do ISS (vISS)" + format: "double" + valueServicePIS: + type: "number" + nullable: true + description: "Valor do PIS sobre Serviços (vPIS)" + format: "double" + valueServiceCOFINS: + type: "number" + nullable: true # Valor da COFINS sobre Serviços + description: "Valor da COFINS sobre Serviços (vCOFINS)" + format: "double" + provisionService: + type: "string" + nullable: true + description: "Data Prestação Serviço (dCompet)" + format: "date-time" + deductionReductionBC: + type: "number" + nullable: true # Valor Dedução para Redução da BC + description: "Valor Dedução para Redução da BC (vDeducao)" + format: "double" + valueOtherRetention: + type: "number" + nullable: true + description: "Valor Outras Retenções (vOutro)" + format: "double" + discountUnconditional: + type: "number" + nullable: true # Valor Desconto Incondicionado + description: "Valor Desconto Incondicionado (vDescIncond)" + format: "double" + discountConditioning: + type: "number" + nullable: true + description: "Valor Desconto Condicionado (vDescCond)" + format: "double" + totalRetentionISS: + type: "number" + nullable: true # Valor Total Retenção ISS + description: "Valor Total Retenção ISS (vISSRet)" + format: "double" + codeTaxRegime: + type: "number" + nullable: true + description: "Código Regime Tributação (cRegTrib)" + format: "double" + additionalProperties: false + ISTaxResource: + type: "object" + description: "Imposto Seletivo (IS). Informe quando o item estiver sujeito ao IS." + properties: + situationCode: + type: "string" # CST do Imposto Seletivo (IS) + nullable: true + description: "CST do Imposto Seletivo (IS). Código de Situação Tributária de 3 dígitos (CST). Consulte a tabela de referência." + classificationCode: + type: "string" + nullable: true + description: "Código de Classificação Tributária do IS (cClassTribIS), 6 dígitos. Consulte a tabela de referência." + basis: + type: "number" + nullable: true # Base de cálculo do IS + description: "Base de cálculo do IS (vBCIS). 15 posições, 13 inteiros e 2 decimais." + format: "double" + rate: + type: "number" + nullable: true + description: "Alíquota do IS em percentual (pIS). Até 4 casas decimais." + format: "double" + unitRate: + type: "number" + nullable: true # Alíquota específica por unidade + description: "Alíquota específica por unidade (pISEspec), em R$ por unidade tributável." + format: "double" + unit: + type: "string" + nullable: true + description: "Unidade tributável usada quando houver alíquota específica por unidade (uTrib)." + quantity: + type: "number" + nullable: true # Quantidade tributável + description: "Quantidade tributável usada quando houver alíquota específica por unidade (qTrib). Até 4 casas decimais." + format: "double" + amount: + type: "number" + nullable: true + description: "Valor do Imposto Seletivo (vIS). 15 posições, 13 inteiros e 2 decimais." + format: "double" + additionalProperties: false + IbsConsumptionCityCode: + type: "integer" + nullable: true + description: "Código do Município de ocorrência do fato gerador do IBS/CBS (cMunFGIBS). Informar o município de ocorrência do fato gerador do IBS/CBS. Este campo só é preenchido quando \"indPres = 5 (Operação presencial, fora do estabelecimento)\" e não incluir o endereço do destinatário (Grupo: E05) ou local de entrega (Grupo: G01)." + format: "int64" # Código do Município de ocorrência do fato gerador do IBS/CBS + IbsZfmPresumedCreditClassification: + type: "string" + nullable: true + description: | + Classificação para cálculo do crédito presumido de IBS para fornecimentos da ZFM (tpCredPresIBSZFM). + Valores possíveis: + - `NoPresumedCredit`: Sem Crédito Presumido + - `FinalConsumptionGoods`: Bens de consumo final (55%) + - `CapitalGoods`: Bens de capital (75%) + - `IntermediateGoods`: Bens intermediários (90,25%) + - `ItAndOtherGoods`: Bens de informática e outros definidos em legislação (100%) + enum: + - "NoPresumedCredit" + - "FinalConsumptionGoods" + - "CapitalGoods" + - "IntermediateGoods" + - "ItAndOtherGoods" + IcmsTaxResource: # Grupo do ICMS da Operação própria e ST (ICMS) + type: "object" + description: | + Grupo do ICMS da Operação própria e ST (ICMS). + **Regra de obrigatoriedade**: deve-se informar **exatamente um** entre `cst` (Regime Normal) ou `csosn` (Simples Nacional). A SEFAZ não aceita ambos preenchidos ou nenhum dos dois. + required: + - origin + properties: + origin: + type: "string" + description: "Origem da mercadoria (orig).\n0 - Nacional, exceto as indicadas nos códigos 3, 4, 5 e 8;\n1 - Estrangeira - Importação direta, exceto a indicada no código 6;\n2 - Estrangeira - Adquirida no mercado interno, exceto a indicada no código 7;\n3 - Nacional, mercadoria ou bem com Conteúdo de Importação superior a 40% e inferior ou igual a 70%;\n4 - Nacional, cuja produção tenha sido feita em conformidade com os processos produtivos básicos de que tratam as legislações citadas nos Ajustes;\n5 - Nacional, mercadoria ou bem com Conteúdo de Importação inferior ou igual a 40%;\n6 - Estrangeira - Importação direta, sem similar nacional, constante em lista da CAMEX e gás natural;\n7 - Estrangeira - Adquirida no mercado interno, sem similar nacional, constante lista CAMEX e gás natural;\n8 - Nacional, mercadoria ou bem com Conteúdo de Importação superior a 70%;" + cst: + type: "string" + nullable: true + description: "Tributação do ICMS (CST) — obrigatório quando o emitente é do Regime Normal. Mutuamente exclusivo com `csosn`." + csosn: + type: "string" + nullable: true # Código de Situação da Operação – Simples Nacional + description: "101- Tributada pelo Simples Nacional com permissão de crédito (v.2.0) (CSOSN). Código de Situação da Operação – Simples Nacional" + baseTaxModality: + type: "string" + nullable: true + description: "Modalidade de determinação da BC do ICMS (modBC).\nMargem Valor Agregado (%) = 0\nPauta (valor) = 1\nPreço Tabelado Máximo (valor) = 2\nValor da Operação = 3" + baseTax: + type: "number" + nullable: true # Valor da BC do ICMS + description: "Valor da BC do ICMS (vBC)" + format: "double" + baseTaxSTModality: + type: "string" + nullable: true + description: "Modalidade de determinação da BC do ICMS ST (modBCST)" + baseTaxSTReduction: + type: "string" + nullable: true # Percentual da Redução de BC do ICMS ST + description: "Percentual da Redução de BC do ICMS ST (pRedBCST)" + baseTaxST: + type: "number" + nullable: true + description: "Valor da BC do ICMS ST (vBCST)" + format: "double" + baseTaxReduction: + type: "number" + nullable: true # Percentual da Redução de BC + description: "Percentual da Redução de BC (pRedBC)" + format: "double" + basisBenefitCode: + type: "string" + nullable: true + description: "Código de Benefício na UF para Redução da Base de Cálculo (cBenefRBC). Tamanho 8 ou 10, quando exigido pela UF (NT 2019.001). Código de Benefício Fiscal utilizado pelo Estado, aplicado ao item quando houver RBC. Observação: Deve ser utilizado o mesmo código utilizado na EFD e demais declarações nos Estados que o exigem. (Incluído na NT 2019.001)" + stRate: + type: "number" + nullable: true # Alíquota do imposto do ICMS ST + description: "Alíquota do imposto do ICMS ST (pICMSST)" + format: "double" + stAmount: + type: "number" + nullable: true + description: "Valor do ICMS ST (vICMSST)" + format: "double" + stMarginAmount: + type: "number" + nullable: true # Percentual da margem de valor Adicionado do ICMS ST + description: "Percentual da margem de valor Adicionado do ICMS ST (pMVAST)" + format: "double" + rate: + type: "number" + nullable: true + description: "Alíquota do imposto (pICMS)" + format: "double" + amount: + type: "number" + nullable: true # Valor do ICMS + description: "Valor do ICMS (vICMS). O valor do ICMS desonerado será informado apenas nas operações:\na) com produtos beneficiados com a desoneração condicional do ICMS.\nb) destinadas à SUFRAMA, informando-se o valor que seria devido se não houvesse isenção.\nc) de venda a órgãos da administração pública direta e suas fundações e autarquias com isenção do ICMS. (NT 2011/004)" + format: "double" + percentual: + type: "number" + nullable: true + description: "Percentual da Redução de BC (pICMS)" + format: "double" + snCreditRate: + type: "number" + nullable: true # Alíquota aplicável de cálculo do crédito (Simples Nacional) + description: "Alíquota aplicável de cálculo do crédito (Simples Nacional) (pCredSN)." + format: "double" + snCreditAmount: + type: "number" + nullable: true + description: "Valor crédito do ICMS que pode ser aproveitado nos termos do art. 23 da LC 123 Simples Nacional (vCredICMSSN)" + format: "double" + stMarginAddedAmount: + type: "string" + nullable: true # Percentual da margem de valor Adicionado do ICMS ST + description: "Percentual da margem de valor Adicionado do ICMS ST (pMVAST)" + stRetentionAmount: + type: "string" + nullable: true + description: "Valor do ICMS ST retido (vICMSSTRet)" + baseSTRetentionAmount: + type: "string" + nullable: true # Valor da BC do ICMS ST retido + description: "Valor da BC do ICMS ST retido (vBCSTRet)" + baseTaxOperationPercentual: + type: "string" + nullable: true + description: "Percentual da BC operação própria (pBCOp). Percentual para determinação do valor da Base de Cálculo da operação própria (v2.0)" + ufst: + type: "string" + nullable: true # UF para qual é devido o ICMS ST + description: "UF para qual é devido o ICMS ST (UFST). Sigla da UF para qual é devido o ICMS ST da operação (v2.0)" + amountSTReason: + type: "string" + nullable: true + description: "Motivo Desoneração ICMS (motDesICMS)" + baseSNRetentionAmount: + type: "string" + nullable: true # Valor da BC do ICMS ST retido + description: "Valor da BC do ICMS ST retido (vBCSTRet)" + snRetentionAmount: + type: "string" + nullable: true + description: "Valor do ICMS ST retido (vICMSSTRet)" + amountOperation: + type: "string" + nullable: true # Valor do ICMS da Operação + description: "Valor do ICMS da Operação (vICMSOp)" + percentualDeferment: + type: "string" + nullable: true + description: "Percentual do Diferimento (pDif)" + baseDeferred: + type: "string" + nullable: true # Valor do ICMS Diferido + description: "Valor do ICMS Diferido (vICMSDif)" + exemptAmount: + type: "number" + nullable: true + description: "Valor ICMS Desonerado (vICMSDeson)" + format: "double" + exemptReason: + description: "Motivo da desoneração do ICMS (motDesICMS)" + $ref: "#/components/schemas/ExemptReason" + exemptAmountST: # Valor ICMS Desonerado + type: "number" + nullable: true + description: "Valor ICMS Desonerado (vICMSSTDeson)" + format: "double" + exemptReasonST: + description: "Motivo da desoneração do ICMS ST (motDesICMSST)" + $ref: "#/components/schemas/ExemptReason" + fcpRate: + type: "number" + nullable: true # Percentual do FCP + description: "Percentual do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (pFCP)" + format: "double" + fcpAmount: + type: "number" + nullable: true + description: "Valor Total do FCP - Valor do ICMS relativo ao Fundo de Combate à Pobreza (vFCP)" + format: "double" + fcpstRate: + type: "number" + nullable: true # Percentual do FCP retido por ST + description: "Percentual do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (pFCPST)" + format: "double" + fcpstAmount: + type: "number" + nullable: true + description: "Valor Total do FCP retido por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido por substituição tributária (vFCPST)" + format: "double" + fcpstRetRate: + type: "number" + nullable: true # Percentual do FCP retido por anteriormente por ST + description: "Percentual do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (pFCPSTRet)" + format: "double" + fcpstRetAmount: + type: "number" + nullable: true + description: "Valor Total do FCP retido por anteriormente por ST - Valor do ICMS relativo ao Fundo de Combate à Pobreza retido anteriormente por substituição tributária (vFCPSTRet)" + format: "double" + baseTaxFCPSTAmount: + type: "number" + nullable: true # Informar o valor da Base de Cálculo do FCP + description: "Informar o valor da Base de Cálculo do FCP (vBCFCPST)" + format: "double" + substituteAmount: + type: "number" + nullable: true + description: "Valor do ICMS próprio do Substituto (tag: vICMSSubstituto)" + format: "double" + stFinalConsumerRate: + type: "number" + nullable: true # Alíquota suportada pelo Consumidor Final + description: "N26a - Alíquota suportada pelo Consumidor Final (pST). Deve ser informada a alíquota do cálculo do ICMS-ST, já incluso o FCP caso incida sobre a mercadoria" + format: "double" + effectiveBaseTaxReductionRate: + type: "number" + nullable: true + description: "N34 - Percentual de redução da base de cálculo efetiva, caso estivesse submetida ao regime comum de tributação (pRedBCEfet)" + format: "double" + effectiveBaseTaxAmount: + type: "number" + nullable: true # Valor da base de cálculo efetiva + description: "N35 - Valor da base de cálculo efetiva, caso estivesse submetida ao regime comum de tributação (vBCEfet)" + format: "double" + effectiveRate: + type: "number" + nullable: true + description: "N36 - Alíquota do ICMS efetiva, caso estivesse submetida ao regime comum de tributação (pICMSEFET)" + format: "double" + effectiveAmount: + type: "number" + nullable: true # Valor do ICMS efetivo + description: "N37 - Valor do ICMS efetivo, caso estivesse submetida ao regime comum de tributação (vICMSEFET)" + format: "double" + deductionIndicator: + description: "Indicador de dedução do ICMS desonerado (indDeducao)" + $ref: "#/components/schemas/DuductionIndicator" + additionalProperties: false + ImportDeclarationResource: + type: "object" + properties: + code: + type: "string" + nullable: true # Número do Documento de Importação da DI/DSI/DA + description: "Número do Documento de Importação da DI/DSI/DA (nDI)" + registeredOn: + type: "string" + nullable: true + description: "Data de Registro da DI/DSI/DA (dDI)" + format: "date-time" + customsClearanceName: + type: "string" + nullable: true # Local de desembaraço + description: "Local de desembaraço (xLocDesemb)" + customsClearanceState: + description: "Sigla da UF onde ocorreu o Desembaraço Aduaneiro (UFDesemb)" + $ref: "#/components/schemas/StateCode" + customsClearancedOn: + type: "string" + nullable: true + description: "Data do Desembaraço Aduaneiro (dDesemb)" + format: "date-time" + additions: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/AdditionResource" + description: "Adições (adi)" + exporter: # Código do exportador + type: "string" + nullable: true + description: "Código do exportador (cExportador)" + internationalTransport: + description: "Via de transporte internacional informada na Declaração de Importação (DI) (tpViaTransp)" + $ref: "#/components/schemas/InternationalTransportType" + afrmmAmount: + type: "number" + nullable: true + description: "Valor Adicional ao frete para renovação de marinha mercante (vAFRMM)" + format: "double" + intermediation: + description: "Forma de importação quanto a intermediação (tpIntermedio)" + $ref: "#/components/schemas/IntermediationType" + acquirerFederalTaxNumber: + type: "string" # CNPJ/CPF do adquirente ou do encomendante + nullable: true + description: "CNPJ/CPF do adquirente ou do encomendante (CNPJ ou CPF)" + stateThird: + type: "string" + nullable: true + description: "Sigla da UF do adquirente ou do encomendante (UFTerceiro)" + additionalProperties: false + description: "Declaração Importação (DI)" + IntegrationPaymentType: + type: "string" + enum: + - "Integrated" + - "NotIntegrated" + description: | + Tipo de Integração para pagamento (tpIntegra). + Valores possíveis: + - `Integrated`: 1 - Pagamento integrado com o sistema de automação da empresa (ex: equipamento TEF, Comércio Eletrônico) + - `NotIntegrated`: 2 - Pagamento não integrado com o sistema de automação da empresa (ex: equipamento POS) + IntermediateResource: + type: "object" + properties: + federalTaxNumber: + type: "integer" + nullable: true + description: "CNPJ do Intermediador da Transação (agenciador, plataforma de delivery, marketplace e similar) de serviços e de negócios (CNPJ)." + format: "int64" + identifier: + type: "string" # Identificador cadastrado no intermediador + nullable: true + description: "Identificador cadastrado no intermediador (idCadIntTran)" + additionalProperties: false + description: "Grupo de Informações do Intermediador da Transação (infIntermed)" + IntermediationType: + type: "string" + enum: + - "None" + - "ByOwn" + - "ImportOnBehalf" + - "ByOrder" + description: | + Forma de importação quanto a intermediação (tpIntermedio). + Valores possíveis: + - `None`: Não definido + - `ByOwn`: Importação por conta própria + - `ImportOnBehalf`: Importação por conta e ordem de terceiro + - `ByOrder`: Importação por encomenda + InternationalTransportType: + type: "string" + description: | + Via de transporte internacional (tpViaTransp). + Valores possíveis: + - `None`: Não definido + - `Maritime`: Marítima + - `River`: Fluvial + - `Lake`: Lacustre + - `Airline`: Aérea + - `Postal`: Postal + - `Railway`: Ferroviária + - `Highway`: Rodoviária + - `Network`: Conduto / Rede Transmissão + - `Own`: Meios Próprios + - `Ficta`: Entrada / Saída ficta + - `Courier`: Serviço de Courrier + - `Handcarry`: Em mãos + enum: + - "None" + - "Maritime" + - "River" + - "Lake" + - "Airline" + - "Postal" + - "Railway" + - "Highway" + - "Network" + - "Own" + - "Ficta" + - "Courier" + - "Handcarry" + InvoiceEventsResource: + type: "object" + properties: + events: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/ActivityResource" + description: "Lista de Eventos ocorridos na Nota Fiscal" + hasMore: # Identificador de possibilidade de mais itens + type: "boolean" + nullable: true + description: "Identificador de possibilidade de mais itens." + id: + type: "string" + nullable: true + description: "Identificação" + accountId: + type: "string" + nullable: true # Identificador da Conta + description: "Identificador da Conta" + companyId: + type: "string" + nullable: true + description: "Identificador da Empresa" + additionalProperties: false + InvoiceEventsResourceBase: + type: "object" + properties: + events: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/ActivityResource" + description: "Lista de Eventos ocorridos na Nota Fiscal" + hasMore: # Identificador de possibilidade de mais itens + type: "boolean" + nullable: true + description: "Identificador de possibilidade de mais itens." + additionalProperties: false + InvoiceItemResource: + type: "object" + required: + - code + - description + - ncm + - unit + - unitTax + - quantity + - unitAmount + - totalAmount + - tax + properties: + code: + type: "string" + description: "Código do produto ou serviço (cProd)" + codeGTIN: + type: "string" + nullable: true + description: "GTIN (Global Trade Item Number) do produto, antigo código EAN ou código de barras (cEAN)" + description: + type: "string" + description: "Descrição do produto ou serviço (xProd)" + ncm: + type: "string" + description: "Código NCM com 8 dígitos ou 2 dígitos (gênero) (NCM)" + nve: + type: "array" + nullable: true # Nomenclatura de Valor Aduaneiro e Estatístico + items: + type: "string" + description: "Nomenclatura de Valor Aduaneiro e Estatístico (NVE)" + extipi: + type: "string" + nullable: true + description: "Código Exceção da Tabela de IPI (EXTIPI)" + cfop: + type: "integer" + nullable: true # Código Fiscal de Operações e Prestações + description: "Código Fiscal de Operações e Prestações (CFOP)" + format: "int64" + unit: + type: "string" + description: "Unidade Comercial (uCom)" + quantity: + type: "number" + description: "Quantidade Comercial (qCom)" + format: "double" + unitAmount: + type: "number" + description: "Valor Unitário de Comercialização (vUnCom)" + format: "double" + totalAmount: + type: "number" + description: "Valor Total Bruto dos Produtos ou Serviços (vProd)" + format: "double" + codeTaxGTIN: + type: "string" + nullable: true + description: "GTIN (Global Trade Item Number) da unidade tributável, antigo código EAN ou código de barras (cEANTrib)" + unitTax: + type: "string" + description: "Unidade Tributável (uTrib)" + quantityTax: + type: "number" + nullable: true + description: "Quantidade Tributável (qTrib)" + format: "double" + taxUnitAmount: + type: "number" + nullable: true # Valor Unitário de tributação + description: "Valor Unitário de tributação (vUnTrib)" + format: "double" + freightAmount: + type: "number" + nullable: true + description: "Valor Total do Frete (vFrete)" + format: "double" + insuranceAmount: + type: "number" + nullable: true # Valor Total do Seguro + description: "Valor Total do Seguro (vSeg)" + format: "double" + discountAmount: + type: "number" + nullable: true + description: "Valor do Desconto (vDesc)" + format: "double" + othersAmount: + type: "number" + nullable: true # Outras despesas acessórias + description: "Outras despesas acessórias (vOutro)" + format: "double" + totalIndicator: + type: "boolean" + nullable: true + description: "Indica se valor do Item (vProd) entra no valor total da NF-e (vProd) (indTot)" + default: true # Mantido o default anterior + usedMovableAssetIndicator: + description: "Indica fornecimento de bem móvel usado (indBemMovelUsado)" + $ref: "#/components/schemas/UsedMovableAssetIndicator" + cest: + type: "string" # CEST - Código especificador da substituição tributária + nullable: true + description: "CEST - Código especificador da substituição tributária (CEST)" + tax: + description: "Tributos incidentes no Produto ou Serviço (imposto)" + $ref: "#/components/schemas/InvoiceItemTaxResource" + additionalInformation: + type: "string" + nullable: true + description: "Informações Adicionais do Produto (infAdProd)" + itemAmount: + type: "number" + nullable: true # Valor total do item + description: "Valor total do item (vItem)." + format: "double" + maximum: 99999999999.99 + minimum: 0 + numberOrderBuy: + type: "string" + nullable: true + description: "Número do pedido de compra (xPed)" + itemNumberOrderBuy: + type: "integer" + nullable: true # Item do Pedido de Compra + description: "Item do Pedido de Compra (nItemPed)" + format: "int32" + importControlSheetNumber: + type: "string" + nullable: true + description: "Número de controle da FCI - Ficha de Conteúdo de Importação (nFCI)" + vehicleDetail: + description: | + Detalhamento de Veículos novos (veicProd). Preencher exclusivamente quando o item da nota fiscal é um veículo 0 km. + **Mutuamente exclusivo** com `fuelDetail` e `medicineDetail` — cada item da nota pode conter no máximo um grupo de produto específico. + $ref: "#/components/schemas/VehicleDetailResource" + fuelDetail: + description: "Detalhamento de Combustível (comb)" + $ref: "#/components/schemas/FuelResource" # Detalhamento de Combustível + benefit: + type: "string" + nullable: true + description: "Código de Benefício Fiscal na UF aplicado ao item (cBenef)" + presumedCredit: + description: "Informações de Crédito Presumido por item (gCred)" + $ref: "#/components/schemas/PresumedCreditResource" + ibsZfmPresumedCreditClassification: + description: "Classificação conforme percentuais definidos no art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido (tpCredPresIBSZFM)" # Classificação conforme percentuais definidos no art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido + $ref: "#/components/schemas/IbsZfmPresumedCreditClassification" + importDeclarations: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/ImportDeclarationResource" + description: "Declaração Importação (DI)" + exportDetails: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/ExportDetailResource" + description: "Grupo de informações de exportação para o item (detExport)" + referencedDFe: # Documento Fiscal Eletrônico Referenciado + $ref: "#/components/schemas/ReferencedDFeResource" + taxDetermination: + description: "Grupo de informações fiscais para o cálculo automático de impostos (infFiscal). Se este grupo for preenchido, o grupo `tax.IBSCBS` será calculado automaticamente. Se não for preenchido, o cálculo automático do grupo `tax.IBSCBS` torna-se opcional." + $ref: "#/components/schemas/TaxDeterminationResource" + additionalProperties: false + description: "Grupo do detalhamento de Produtos e Serviços da NF-e\r\n" + InvoiceItemTaxResource: + type: "object" + required: + - icms + properties: + totalTax: + type: "number" + nullable: true # Valor aproximado total de tributos federais, estaduais e municipais — opcional (calculado automaticamente quando não informado) + description: "Valor aproximado total de tributos federais, estaduais e municipais (vTotTrib)" + format: "double" + icms: + description: "Grupo do ICMS da Operação própria e ST (ICMS)" + $ref: "#/components/schemas/IcmsTaxResource" + ipi: + description: "Grupo do IPI (IPI)" + $ref: "#/components/schemas/IPITaxResource" + ii: + description: "Grupo do Imposto de Importação (II)" + $ref: "#/components/schemas/IITaxResource" + pis: + description: "Grupo do PIS (PIS)" + $ref: "#/components/schemas/PISTaxResource" + cofins: + description: "Grupo do COFINS (COFINS)" + $ref: "#/components/schemas/CofinsTaxResource" + icmsDestination: + description: "Grupo de Tributação do ICMS de Destino da UF (ICMSUFDest)" # Grupo de Tributação do ICMS de Destino da UF + $ref: "#/components/schemas/ICMSUFDestinationTaxResource" + IS: + description: "Imposto Seletivo (IS)" + $ref: "#/components/schemas/ISTaxResource" + IBSCBS: + description: "Grupo de Informações do IBS e CBS" + $ref: "#/components/schemas/IBSCBSTaxResource" + competenceAdjustment: # Ajuste de Competência (gAjusteCompet) + $ref: "#/components/schemas/CompetenceAdjustmentResource" + description: "Ajuste de Competência (gAjusteCompet)" + additionalProperties: false + InvoiceItemsResource: + type: "object" + properties: + accountId: + type: "string" + nullable: true + description: "Identificador da Conta" + companyId: + type: "string" + nullable: true + description: "Identificador da Empresa" + id: + type: "string" + nullable: true + description: "Identificador da Nota Fiscal" + items: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/InvoiceItemResource" + description: "Detalhamento de Produtos e Serviços (det) - Lista de Items da Nota Fiscal" + hasMore: + type: "boolean" + nullable: true + description: "Identifica se existem mais items a serem consultados" + additionalProperties: false + InvoiceResource: + type: "object" + properties: + id: + type: "string" + nullable: true + description: "Identificador único" + serie: + type: "integer" + nullable: true + description: "Série do Documento Fiscal (serie)" + format: "int32" + number: + type: "integer" + nullable: true + description: "Número do Documento Fiscal (nNF)" + format: "int64" + status: + description: "Status da NF-e (cStat)" + $ref: "#/components/schemas/InvoiceStatus" + authorization: + description: "Informações do Protocolo de Autorização (protNFe)" + $ref: "#/components/schemas/AuthorizationResource" + contingencyDetails: + description: "Detalhes da contingência (dhCont)" + $ref: "#/components/schemas/ContingencyDetails" + operationNature: + type: "string" + nullable: true + description: "Descrição da Natureza da Operação (natOp)" + createdOn: + type: "string" + nullable: true + description: "Data de criação" + format: "date-time" + modifiedOn: + type: "string" + nullable: true + description: "Data de modificação" + format: "date-time" + operationOn: + type: "string" + nullable: true + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt). Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD." + format: "date-time" + operationType: + description: "Tipo do Documento Fiscal (tpNF)" + $ref: "#/components/schemas/OperationType" + environmentType: + description: "Tipo de Ambiente (tpAmb)" + $ref: "#/components/schemas/EnvironmentType" + purposeType: + description: "Finalidade da emissão da NF-e (finNFe)" + $ref: "#/components/schemas/PurposeType" + issuer: + description: "Identificação do Emitente (emit)" + $ref: "#/components/schemas/IssuerResource" + buyer: + description: "Identificação do Destinatário (dest)" + $ref: "#/components/schemas/BuyerResource" + totals: + description: "Grupo de Valores Totais da NF-e (total)" + $ref: "#/components/schemas/TotalResource" + transport: + description: "Grupo de Informações do Transporte da NF-e (transp)" + $ref: "#/components/schemas/TransportInformationResource" + additionalInformation: + description: "Informações adicionais da NF-e (infAdic)" + $ref: "#/components/schemas/AdditionalInformationResource" + export: + description: "Informações de exportação (exporta)" + $ref: "#/components/schemas/ExportResource" + billing: + description: "Grupo Cobrança (cobr)" + $ref: "#/components/schemas/BillingResource" + payment: + type: "array" + items: + $ref: "#/components/schemas/PaymentResource" + description: "Grupo de Formas de Pagamento (pag)" + transactionIntermediate: + description: "Grupo de Informações do Intermediador da Transação (infIntermed)" + $ref: "#/components/schemas/IntermediateResource" + delivery: + description: "Identificação do Local de entrega (entrega)" + $ref: "#/components/schemas/DeliveryInformationResource" + withdrawal: + description: "Identificação do Local de retirada (retirada)" + $ref: "#/components/schemas/WithdrawalInformationResource" + lastEvents: + description: "Últimos eventos da NF-e (eventos)" + $ref: "#/components/schemas/InvoiceEventsResourceBase" + additionalProperties: false + InvoiceStatus: + type: "string" + enum: + - "None" + - "Created" + - "Processing" + - "Issued" + - "IssuedContingency" + - "Cancelled" + - "Disabled" + - "IssueDenied" + - "Error" + description: | + Status da NF-e. + Valores possíveis: + - `None`: Não definido + - `Created`: Criada + - `Processing`: Processando + - `Issued`: Emitida + - `IssuedContingency`: Emitida em Contingência + - `Cancelled`: Cancelada + - `Disabled`: Inutilizada + - `IssueDenied`: Emissão Denegada + - `Error`: Erro + InvoiceWithoutEventsResource: + type: "object" + properties: + id: + type: "string" + nullable: true + description: "Identificador único" + serie: + type: "integer" + nullable: true + description: "Série do Documento Fiscal (serie)" + format: "int32" + number: + type: "integer" + nullable: true + description: "Número do Documento Fiscal (nNF)" + format: "int64" + status: + description: "Status da NF-e (cStat)" + $ref: "#/components/schemas/InvoiceStatus" + authorization: + description: "Informações do Protocolo de Autorização (protNFe)" + $ref: "#/components/schemas/AuthorizationResource" + contingencyDetails: + description: "Detalhes da contingência (dhCont)" + $ref: "#/components/schemas/ContingencyDetails" + operationNature: + type: "string" + nullable: true + description: "Descrição da Natureza da Operação (natOp)" + createdOn: + type: "string" + nullable: true + description: "Data de criação" + format: "date-time" + modifiedOn: + type: "string" + nullable: true + description: "Data de modificação" + format: "date-time" + operationOn: + type: "string" + nullable: true + description: "Data e Hora de Saída ou da Entrada da Mercadoria/Produto (dhSaiEnt). Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD." + format: "date-time" + operationType: + description: "Tipo do Documento Fiscal (tpNF)" + $ref: "#/components/schemas/OperationType" + environmentType: + description: "Tipo de Ambiente (tpAmb)" + $ref: "#/components/schemas/EnvironmentType" + purposeType: + description: "Finalidade da emissão da NF-e (finNFe)" + $ref: "#/components/schemas/PurposeType" + issuer: + description: "Identificação do Emitente (emit)" + $ref: "#/components/schemas/IssuerResource" + buyer: + description: "Identificação do Destinatário (dest)" + $ref: "#/components/schemas/BuyerResource" + totals: + description: "Grupo de Valores Totais da NF-e (total)" + $ref: "#/components/schemas/TotalResource" + transport: + description: "Grupo de Informações do Transporte da NF-e (transp)" + $ref: "#/components/schemas/TransportInformationResource" + additionalInformation: + description: "Informações adicionais da NF-e (infAdic)" + $ref: "#/components/schemas/AdditionalInformationResource" + export: + description: "Informações de exportação (exporta)" + $ref: "#/components/schemas/ExportResource" + billing: + description: "Grupo Cobrança (cobr)" + $ref: "#/components/schemas/BillingResource" + payment: + type: "array" + items: + $ref: "#/components/schemas/PaymentResource" + description: "Grupo de Formas de Pagamento (pag)" + transactionIntermediate: + description: "Grupo de Informações do Intermediador da Transação (infIntermed)" + $ref: "#/components/schemas/IntermediateResource" + delivery: + description: "Identificação do Local de entrega (entrega)" + $ref: "#/components/schemas/DeliveryInformationResource" + withdrawal: + description: "Identificação do Local de retirada (retirada)" + $ref: "#/components/schemas/WithdrawalInformationResource" + additionalProperties: false + IssuerFromRequestResource: + type: "object" + properties: + stStateTaxNumber: + type: "string" # IE do Substituto Tributário da UF de destino da mercadoria + nullable: true + description: "IE do Substituto Tributário da UF de destino da mercadoria, quando houver a retenção do ICMS ST para a UF de destino. (IEST)" + additionalProperties: false + IssuerResource: + type: "object" + properties: + accountId: + type: "string" + nullable: true # Identificador da Conta + description: "Identificador da Conta" + id: + type: "string" + nullable: true + description: "Identificação" + name: + type: "string" + nullable: true + description: "Nome ou Razão Social (xNome)" + federalTaxNumber: + type: "integer" + nullable: true # O valor padrão de consumerType é determinado com base neste campo. Se for um CNPJ, o padrão será "Normal"; se for um CPF ou NIF, será "FinalConsumer". + description: "CNPJ ou CPF (CNPJ/CPF)" + format: "int64" + email: + type: "string" + nullable: true + description: "Email (email)" + address: + description: "Dados do Endereço (enderEmit)" + $ref: "#/components/schemas/AddressResource" + type: + description: "Tipo da pessoa (indIEDest)" + $ref: "#/components/schemas/PersonType" + tradeName: + type: "string" + nullable: true + description: "Nome Fantasia (xFant)" + openningDate: + type: "string" + nullable: true + description: "Data abertura da empresa (dIniAtiv)" + format: "date-time" + taxRegime: + description: "Regime de tributação (CRT)" + $ref: "#/components/schemas/TaxRegime" + specialTaxRegime: + description: "Regime especial de tributação (indRegTrib)" + $ref: "#/components/schemas/SpecialTaxRegime" + legalNature: + description: "Natureza jurídica (natJuridica)" + $ref: "#/components/schemas/LegalNature" + economicActivities: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/EconomicActivityResource" + description: "Atividades da Empresa (CNAE)" + companyRegistryNumber: + type: "integer" + nullable: true + description: "Número de Inscrição na Junta Comercial (nIRE)" + format: "int64" + regionalTaxNumber: + type: "integer" + nullable: true + description: "Número de Inscrição na SEFAZ (IE)" + format: "int64" + regionalSTTaxNumber: + type: "integer" + nullable: true + description: "Inscrição Estadual do Substituto Tributário (IEST)" + format: "int64" + municipalTaxNumber: + type: "string" + nullable: true + description: "Número de Inscrição na Prefeitura (IM/CCM)" + stStateTaxNumber: + type: "string" + nullable: true + description: "IE do Substituto Tributário (IEST)" + additionalProperties: false + description: "Grupo de identificação do emitente da NF-e" + LegalNature: + type: "string" + enum: + - "EmpresaPublica" + - "SociedadeEconomiaMista" + - "SociedadeAnonimaAberta" + - "SociedadeAnonimaFechada" + - "SociedadeEmpresariaLimitada" + - "SociedadeEmpresariaEmNomeColetivo" + - "SociedadeEmpresariaEmComanditaSimples" + - "SociedadeEmpresariaEmComanditaporAcoes" + - "SociedadeemContaParticipacao" + - "Empresario" + - "Cooperativa" + - "ConsorcioSociedades" + - "GrupoSociedades" + - "EmpresaDomiciliadaExterior" + - "ClubeFundoInvestimento" + - "SociedadeSimplesPura" + - "SociedadeSimplesLimitada" + - "SociedadeSimplesEmNomeColetivo" + - "SociedadeSimplesEmComanditaSimples" + - "EmpresaBinacional" + - "ConsorcioEmpregadores" + - "ConsorcioSimples" + - "EireliNaturezaEmpresaria" + - "EireliNaturezaSimples" + - "ServicoNotarial" + - "FundacaoPrivada" + - "ServicoSocialAutonomo" + - "CondominioEdilicio" + - "ComissaoConciliacaoPrevia" + - "EntidadeMediacaoArbitragem" + - "PartidoPolitico" + - "EntidadeSindical" + - "EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras" + - "FundacaoAssociacaoDomiciliadaExterior" + - "OrganizacaoReligiosa" + - "ComunidadeIndigena" + - "FundoPrivado" + - "AssociacaoPrivada" + description: | + Código da Natureza Jurídica da empresa (natJuridica), conforme tabela do IBGE. + Valores possíveis: + - `EmpresaPublica`: Empresa Pública + - `SociedadeEconomiaMista`: Sociedade de Economia Mista + - `SociedadeAnonimaAberta`: Sociedade Anônima Aberta + - `SociedadeAnonimaFechada`: Sociedade Anônima Fechada + - `SociedadeEmpresariaLimitada`: Sociedade Empresária Limitada (LTDA) + - `SociedadeEmpresariaEmNomeColetivo`: Sociedade Empresária em Nome Coletivo + - `SociedadeEmpresariaEmComanditaSimples`: Sociedade Empresária em Comandita Simples + - `SociedadeEmpresariaEmComanditaporAcoes`: Sociedade Empresária em Comandita por Ações + - `SociedadeemContaParticipacao`: Sociedade em Conta de Participação + - `Empresario`: Empresário Individual + - `Cooperativa`: Cooperativa + - `ConsorcioSociedades`: Consórcio de Sociedades + - `GrupoSociedades`: Grupo de Sociedades + - `EmpresaDomiciliadaExterior`: Empresa Domiciliada no Exterior + - `ClubeFundoInvestimento`: Clube/Fundo de Investimento + - `SociedadeSimplesPura`: Sociedade Simples Pura + - `SociedadeSimplesLimitada`: Sociedade Simples Limitada + - `SociedadeSimplesEmNomeColetivo`: Sociedade Simples em Nome Coletivo + - `SociedadeSimplesEmComanditaSimples`: Sociedade Simples em Comandita Simples + - `EmpresaBinacional`: Empresa Binacional + - `ConsorcioEmpregadores`: Consórcio de Empregadores + - `ConsorcioSimples`: Consórcio Simples + - `EireliNaturezaEmpresaria`: EIRELI de Natureza Empresária + - `EireliNaturezaSimples`: EIRELI de Natureza Simples + - `ServicoNotarial`: Serviço Notarial e Registral (Cartórios) + - `FundacaoPrivada`: Fundação Privada + - `ServicoSocialAutonomo`: Serviço Social Autônomo + - `CondominioEdilicio`: Condomínio Edilício + - `ComissaoConciliacaoPrevia`: Comissão de Conciliação Prévia + - `EntidadeMediacaoArbitragem`: Entidade de Mediação e Arbitragem + - `PartidoPolitico`: Partido Político + - `EntidadeSindical`: Entidade Sindical + - `EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras`: Estabelecimento no Brasil de Fundação ou Associação Estrangeiras + - `FundacaoAssociacaoDomiciliadaExterior`: Fundação ou Associação Domiciliada no Exterior + - `OrganizacaoReligiosa`: Organização Religiosa + - `ComunidadeIndigena`: Comunidade Indígena + - `FundoPrivado`: Fundo Privado + - `AssociacaoPrivada`: Associação Privada + MonophaseDefermentTaxResource: + type: "object" + description: "Deferimento na tributação monofásica (para biocombustíveis)." + properties: + ibsRate: + type: "number" + nullable: true + description: "Percentual de diferimento do IBS monofásico (pDifIBS)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor do diferimento IBS monofásico (vIBSMonoDif)." + format: "double" + cbsRate: + type: "number" + nullable: true + description: "Percentual de diferimento do CBS monofásico (pDifCBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor do diferimento CBS monofásico (vCBSMonoDif)." + format: "double" + additionalProperties: false + MonophaseIBSCBSTaxResource: + type: "object" + description: "Grupo de Informações do IBS e CBS sobre transações monofásicas" + properties: + standart: + description: "Informações de tributação monofásica padrão para IBS/CBS (gMonofasicoPadrao)." + $ref: "#/components/schemas/MonophaseStandardTaxResource" + withholding: + description: "Tributação monofásica sujeita à retenção (gMonofasicoRetido)." + $ref: "#/components/schemas/MonophaseWithholdingTaxResource" + previouslyWithheld: + description: "Tributação monofásica previamente retida (gMonofasicoRetidoAnt)." + $ref: "#/components/schemas/MonophasePreviouslyWithheldTaxResource" + deferment: + description: "Deferimento na tributação monofásica (para biocombustíveis) (gMonofasicoDif)." + $ref: "#/components/schemas/MonophaseDefermentTaxResource" + ibsAmount: + type: "number" + nullable: true + description: "Total de IBS monofásico do item (vTotIBSMonoItem)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Total de CBS monofásico do item (vTotCBSMonoItem)." + format: "double" + additionalProperties: false + MonophasePreviouslyWithheldTaxResource: + type: "object" + description: "Tributação monofásica previamente retida." + properties: + quantityBasis: + type: "number" + nullable: true + description: "Quantidade base previamente retida (qBCMonoRet)." + format: "double" + ibsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem IBS previamente retida (adRemIBSRet)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor IBS previamente retido (vIBSMonoRet)." + format: "double" + cbsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem CBS previamente retida (adRemCBSRet)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS previamente retido (vCBSMonoRet)." + format: "double" + additionalProperties: false + MonophaseStandardTaxResource: + type: "object" + description: "Informações de tributação monofásica padrão para IBS/CBS." + properties: + quantityBasis: + type: "number" + nullable: true + description: "Quantidade base tributada na monofásica (qBCMono)." + format: "double" + ibsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem IBS (adRemIBS)." + format: "double" + cbsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem CBS (adRemCBS)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor IBS monofásico (vIBSMono)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS monofásico (vCBSMono)." + format: "double" + additionalProperties: false + MonophaseWithholdingTaxResource: + type: "object" + description: "Tributação monofásica sujeita à retenção." + properties: + quantityBasis: + type: "number" + nullable: true + description: "Quantidade base tributada na retenção monofásica (qBCMonoReten)." + format: "double" + ibsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem IBS retida (adRemIBSReten)." + format: "double" + ibsAmount: + type: "number" + nullable: true + description: "Valor IBS monofásico retido (vIBSMonoReten)." + format: "double" + cbsAdRemRate: + type: "number" + nullable: true + description: "Alíquota ad rem CBS retida (adRemCBSReten)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "Valor CBS monofásico retido (vCBSMonoReten)." + format: "double" + additionalProperties: false + OperationalPresumedCreditResource: + type: "object" + description: "Informações sobre o crédito presumido de IBS para fornecimentos (gCredPresOper)." + properties: + basis: + type: "number" + nullable: true + description: "Valor da Base de Cálculo do Crédito Presumido da Operação (vBC)" + format: "double" + classificationCode: + description: "Código de Classificação do Crédito Presumido (cCredPres)." + $ref: "#/components/schemas/PresumedCreditClassificationCode" + ibs: + description: "Grupo de Informações do Crédito Presumido referente ao IBS (gIBSCredPres)" + $ref: "#/components/schemas/PresumedCreditDetailsResource" + cbs: + description: "Grupo de Informações do Crédito Presumido referente a CBS (gCBSCredPres)" + $ref: "#/components/schemas/PresumedCreditDetailsResource" + additionalProperties: false + OperationType: + type: "string" + enum: + - "Outgoing" + - "Incoming" # Entrada + description: | + Tipo de Operação (tpNF). + Valores possíveis: + - `Outgoing`: Saída + - `Incoming`: Entrada + default: "Outgoing" + PISTaxResource: + type: "object" + properties: + cst: + type: "string" + nullable: true # Código de Situação Tributária do PIS + description: "Código de Situação Tributária do PIS (CST)" + baseTax: + type: "number" + nullable: true + description: "Valor da Base de Cálculo do PIS (vBC)" + format: "double" + rate: + type: "number" + nullable: true # Alíquota do PIS (em percentual) + description: "Alíquota do PIS (em percentual) (pPIS)" + format: "double" + amount: + type: "number" + nullable: true + description: "Valor do PIS (vPIS)" + format: "double" + baseTaxProductQuantity: + type: "number" + nullable: true # Quantidade Vendida + description: "Quantidade Vendida (qBCProd)" + format: "double" + productRate: + type: "number" + nullable: true + description: "Alíquota do PIS (em reais) (vAliqProd)" + format: "double" + additionalProperties: false + description: "Grupo do PIS" + PaymentDetailResource: + type: "object" + required: + - method + - amount + properties: + method: + description: "Forma de pagamento (tPag)" + $ref: "#/components/schemas/PaymentMethod" # Forma de pagamento + methodDescription: + type: "string" + nullable: true + description: "Descrição do meio de pagamento (xPag)" + paymentType: + description: "Indicador da forma de pagamento (indPag)" + $ref: "#/components/schemas/PaymentType" + amount: + type: "number" + description: "Valor do Pagamento (vPag)" + format: "double" + card: + description: "Grupo de Cartões (card)" + $ref: "#/components/schemas/CardResource" + paymentDate: + type: "string" + nullable: true + description: "Data do pagamento (dPag) - Data e hora no formato UTC (Universal Coordinated Time): AAAA-MM-DDThh:mm:ssTZD" + format: "date-time" + federalTaxNumberPag: + type: "string" # CNPJ transacional do pagamento + nullable: true + description: "CNPJ transacional do pagamento (CNPJPag)" + statePag: + type: "string" + nullable: true + description: "UF do CNPJ do estabelecimento onde o pagamento foi processado/transacionado/recebido (UFPag)" + additionalProperties: false + PaymentMethod: + type: "string" + enum: + - "Cash" + - "Cheque" + - "CreditCard" + - "DebitCard" + - "StoreCredict" + - "FoodVouchers" + - "MealVouchers" + - "GiftVouchers" + - "FuelVouchers" + - "MercantileDuplicate" + - "BankBill" + - "BankDeposit" + - "InstantPayment" + - "WireTransfer" + - "Cashback" + - "StaticInstantPayment" + - "StoreCredit" + - "ElectronicPaymentNotInformed" + - "WithoutPayment" + - "Others" + description: | + Forma de pagamento (tPag). + Valores possíveis: + - `Cash`: 01 - Dinheiro + - `Cheque`: 02 - Cheque + - `CreditCard`: 03 - Cartão de Crédito + - `DebitCard`: 04 - Cartão de Débito + - `StoreCredict`: 05 - Crédito Loja + - `FoodVouchers`: 10 - Vale Alimentação + - `MealVouchers`: 11 - Vale Refeição + - `GiftVouchers`: 12 - Vale Presente + - `FuelVouchers`: 13 - Vale Combustível + - `MercantileDuplicate`: 14 - Duplicata Mercantil + - `BankBill`: 15 - Boleto Bancário + - `BankDeposit`: 16 - Depósito Bancário + - `InstantPayment`: 17 - Pagamento Instantâneo (PIX) + - `WireTransfer`: 18 - Transferência bancária, Carteira Digital + - `Cashback`: 19 - Programa de fidelidade, Cashback, Crédito Virtual + - `StaticInstantPayment`: 20 - Pagamento Instantâneo (PIX) Estático + - `StoreCredit`: 21 - Crédito em Loja + - `ElectronicPaymentNotInformed`: 22 - Pagamento Eletrônico Não Informado + - `WithoutPayment`: 90 - Sem Pagamento + - `Others`: 99 - Outros + PaymentResource: + type: "object" + required: + - paymentDetail + properties: + paymentDetail: + type: "array" + items: + $ref: "#/components/schemas/PaymentDetailResource" + description: "YA01a - Grupo Detalhamento da Forma de Pagamento (detPag) VERSÃO 4.00" + payBack: + type: "number" + nullable: true + description: "Valor do troco (vTroco) VERSÃO 4.00" + format: "double" + additionalProperties: false + PaymentType: + type: "string" + enum: + - "InCash" + - "Term" + description: | + Indicador da forma de pagamento (indPag). + Valores possíveis: + - `InCash`: Pagamento à vista + - `Term`: Pagamento a prazo + PersonType: + type: "string" + enum: + - "Undefined" + - "NaturalPerson" + - "LegalEntity" + - "Company" + - "Customer" + description: | + Tipo de Pessoa. + Valores possíveis: + - `Undefined`: Não definido + - `NaturalPerson`: Pessoa Física + - `LegalEntity`: Pessoa Jurídica + - `Company`: Empresa + - `Customer`: Cliente + PresumedCreditClassificationCode: + type: "string" + nullable: true + enum: + - "RuralProducerNonTaxpayer" + - "TacPfTransportServiceNonTaxpayer" + - "RecyclingFromIndividual" + - "UsedMovableGoodsFromIndividualForResale" + - "OptionalRegimeForCooperative" + description: | + Código de Classificação do Crédito Presumido (cCredPres). + Valores possíveis: + - `RuralProducerNonTaxpayer`: Produtor rural não contribuinte + - `TacPfTransportServiceNonTaxpayer`: TAC Pessoa Física não contribuinte do serviço de transporte + - `RecyclingFromIndividual`: Reciclagem de pessoa física + - `UsedMovableGoodsFromIndividualForResale`: Bens móveis usados de pessoa física para revenda + - `OptionalRegimeForCooperative`: Regime opcional para cooperativa + PresumedCreditDetailsResource: + type: "object" + description: "Grupo de Informações do Crédito Presumido" + properties: + rate: + type: "number" + nullable: true + description: "Percentual do Crédito Presumido (pCredPres)" + format: "double" + amount: + type: "number" # Valor do Crédito Presumido + nullable: true + description: "Valor do Crédito Presumido (vCredPres)" + format: "double" + suspensiveConditionAmount: + type: "number" + nullable: true + description: "Valor do Crédito Presumido em condição suspensiva. (vCredPresCondSus)" + format: "double" + additionalProperties: false + PresumedCreditResource: + type: "object" + description: "Informações de Crédito Presumido por item (gCred). Preenchimento conforme exigência da UF (NT 2019.001)." + properties: + code: + type: "string" + nullable: true # Código do Benefício de Crédito Presumido na UF + description: "Código do Benefício de Crédito Presumido na UF (cCredPresumido). Use o mesmo código utilizado na EFD/declarações da UF. Tamanho 8 ou 10." + rate: + type: "number" + nullable: true + description: "Percentual do Crédito Presumido (pCredPresumido). Use fração: 0.04 = 4%. Até 4 casas decimais." + format: "double" + amount: + type: "number" + nullable: true # Valor do Crédito Presumido + description: "Valor do Crédito Presumido (vCredPresumido)." + format: "double" + additionalProperties: false + PrintType: + type: "string" + enum: + - "None" + - "NFeNormalPortrait" + - "NFeNormalLandscape" + - "NFeSimplified" + - "DANFE_NFC_E" + - "DANFE_NFC_E_MSG_ELETRONICA" + description: | + Formato de impressão do DANFE (tpImp). + Valores possíveis: + - `None`: Não definido + - `NFeNormalPortrait`: DANFE normal, Retrato + - `NFeNormalLandscape`: DANFE normal, Paisagem + - `NFeSimplified`: DANFE Simplificado + - `DANFE_NFC_E`: DANFE NFC-e + - `DANFE_NFC_E_MSG_ELETRONICA`: DANFE NFC-e em mensagem eletrônica + ProductInvoicesResource: + type: "object" + properties: + productInvoices: + type: "array" + nullable: true + items: + $ref: "#/components/schemas/InvoiceWithoutEventsResource" + description: "Lista de Notas Fiscais Eletrônicas (NF-e)" + hasMore: # Identificador de possibilidade de mais itens + type: "boolean" + description: "Identificador de possibilidade de mais itens." + additionalProperties: false + description: "Notas Fiscais Eletrônicas (NF-e)" + PumpResource: + type: "object" + properties: + spoutNumber: + type: "integer" + nullable: true # Número de identificação do bico utilizado no abastecimento + description: "Número de identificação do bico utilizado no abastecimento (nBico)" + format: "int32" + number: + type: "integer" + nullable: true + description: "Número de identificação da bomba ao qual o bico está interligado (nBomba)" + format: "int32" + tankNumber: + type: "integer" + nullable: true # Número de identificação do tanque + description: "Número de identificação do tanque ao qual o bico está interligado (nTanque)" + format: "int32" + beginningAmount: + type: "number" + nullable: true + description: "Valor do Encerrante no início do abastecimento (vEncIni)" + format: "double" + endAmount: + type: "number" + nullable: true # Valor do Encerrante no final do abastecimento + description: "Valor do Encerrante no final do abastecimento (vEncFin)" + format: "double" + percentageBio: + type: "number" + nullable: true + description: "Percentual do índice de mistura do Biodiesel (B100) no Óleo Diesel B instituído pelo órgão regulamentador" + format: "double" + additionalProperties: false + PurchaseInformationResource: + type: "object" + description: "Grupo Compra. Additional purchase information (compra)" + properties: + commitmentNote: + type: "string" + nullable: true # Nota de Empenho + description: "Nota de Empenho. Identification of the Note of Commitment, when dealing with public purchases (xNEmp)" + minLength: 1 + maxLength: 22 + purchaseOrder: + type: "string" + nullable: true + description: "Pedido. (xPed)" + minLength: 1 + maxLength: 60 + contractNumber: # Contrato + type: "string" + nullable: true + description: "Contrato. (xcont)" + minLength: 1 + maxLength: 60 + additionalProperties: false + PurposeType: + type: "string" + enum: + - "None" + - "Normal" + - "Complement" + - "Adjustment" + - "Devolution" # Devolução + default: "Normal" + description: | + Finalidade da emissão da NF-e (finNFe). + Valores possíveis: + - `None`: Não definido + - `Normal`: NF-e normal + - `Complement`: NF-e complementar + - `Adjustment`: NF-e de ajuste + - `Devolution`: Devolução de mercadoria + QueueEventResource: + type: "object" + properties: + reason: + type: "string" + nullable: true # Justificativa da carta de correção + description: "Justificativa da carta de correção\r\nO Texto deve \r\nconter no mínimo 15 e no máximo 1.000 caracteres\r\n(os quais não poderão conter acentos e/ou caracteres especiais)" + additionalProperties: false + ReboqueResource: + type: "object" + properties: + plate: + type: "string" + nullable: true + description: "Placa do Veiculo (placa)" + uf: + type: "string" + nullable: true # UF Veiculo Reboque + description: "UF Veiculo Reboque (UF)" + rntc: + type: "string" + nullable: true + description: "Registro Nacional de Transportador de Carga (ANTT) (RNTC)" + wagon: + type: "string" + nullable: true + description: "Identificação do Vagão (vagao)" + ferry: + type: "string" + nullable: true # Identificação da Balsa + description: "Identificação da Balsa (balsa)" + additionalProperties: false + description: "Grupo Reboque" + ReceiverStateTaxIndicator: + type: "string" + enum: + - "None" + - "TaxPayer" + - "Exempt" + - "NonTaxPayer" + description: | + Indicador da IE do Destinatário (indIEDest). + Valores possíveis: + - `None`: Não definido + - `TaxPayer`: Contribuinte ICMS (informar a IE do destinatário) + - `Exempt`: Contribuinte isento de Inscrição no cadastro de Contribuintes do ICMS + - `NonTaxPayer`: Não Contribuinte, que pode ou não possuir Inscrição Estadual no Cadastro de Contribuintes do ICMS + ReductionTaxResource: + type: "object" + description: "Grupo de informações da redução da alíquota" + properties: + rateReduction: + type: "number" + nullable: true + description: "Percentual da redução de alíquota" + format: "double" + effectiveRate: + type: "number" # Alíquota Efetiva que será aplicada a Base de Cálculo + nullable: true + description: "Alíquota Efetiva que será aplicada a Base de Cálculo (em percentual)" + format: "double" + additionalProperties: false + ReferencedProcessResource: + type: "object" + properties: + identifierConcessory: + type: "string" # Identificador do ato concessório + nullable: true + description: "Identificador do ato concessório (identificadorAtoConcessorio)." + identifierOrigin: + type: "integer" + nullable: true + format: "int32" + description: "Identificador de origem do processo (identificadorOrigemProcesso)." + concessionActType: + type: "integer" + nullable: true # Tipo do ato concessório + format: "int32" + description: "Tipo do ato concessório (tipoAtoConcessorio)." + additionalProperties: false + ReferencedDFeResource: + type: "object" + nullable: true + description: "Documento Fiscal Eletrônico Referenciado (DFeReferenciado). Grupo para referenciamento de itens de outro DF-e." + properties: + accessKey: + type: "string" + description: "Chave de acesso do DF-e referenciado (chaveAcesso)." + maxLength: 44 + minLength: 44 + pattern: "^[0-9]{44}$" + itemNumber: # Número do item do documento referenciado + type: "integer" + nullable: true + description: "Número do item do documento referenciado (nItem). Corresponde ao atributo “nItem” do elemento “det” do documentooriginal." + maximum: 999 + minimum: 1 + format: "int32" + required: + - "accessKey" + additionalProperties: false + ISTotalsResource: + type: "object" + nullable: true + description: "Grupo de totais do Imposto Seletivo. (ISTot)" + properties: + amount: + type: "number" # Total do imposto seletivo + nullable: true + description: "Total do imposto seletivo. (vIS)" + format: "double" + additionalProperties: false + IBSCBSTotalsResource: + type: "object" + nullable: true + description: "Totais da NF-e com IBS e CBS. (IBSCBSTot)" + properties: + basis: + type: "number" + nullable: true # Valor total da Base de Cálculo do IBS e da CBS + description: "Valor total da Base de Cálculo do IBS e da CBS. (vBCIBSCBS)" + format: "double" + ibs: + description: "Grupo total do IBS (gIBS)" + $ref: "#/components/schemas/IBSTotalsResource" + cbs: + description: "Grupo total da CBS (gCBS)" + $ref: "#/components/schemas/CBSTotalsResource" + monophase: + description: "Grupo de totais da tributação monofásica." # Grupo de totais da tributação monofásica + $ref: "#/components/schemas/MonophaseTotalsResource" + creditReversal: + description: "Grupo total do Estorno de Crédito (gEstornoCred)" + $ref: "#/components/schemas/CreditReversalTotalsResource" + additionalProperties: false + IBSTotalsResource: + type: "object" + nullable: true + description: "Grupo total do IBS (gIBS)" + properties: + state: + description: "Informações do IBS da UF." + $ref: "#/components/schemas/IBSStateTotalsResource" + municipal: + description: "Informações do IBS do Município." # Informações do IBS do Município + $ref: "#/components/schemas/IBSMunicipalTotalsResource" + totalAmount: + type: "number" + nullable: true + description: "Valor total do IBS (vIBS)" + format: "double" + presumedCreditAmount: + type: "number" + nullable: true + description: "Valor total do crédito presumido (vCredPres)" + format: "double" + presumedCreditConditionalAmount: + type: "number" + nullable: true + description: "Valor total do crédito presumido em condição suspensiva. (vCredPresCondSus)" + format: "double" + additionalProperties: false + IBSStateTotalsResource: + type: "object" + nullable: true + description: "Informações do IBS da UF (gIBSUF)" + properties: + defermentAmount: + type: "number" + nullable: true # Valor total do diferimento + description: "Valor total do diferimento (vDif)" + format: "double" + returnedAmount: + type: "number" + nullable: true + description: "Valor total de devolução de tributos (vDevTrib)" + format: "double" + amount: + type: "number" + nullable: true # Valor total do IBS da UF + description: "Valor total do IBS da UF. (vIBSUF)" + format: "double" + additionalProperties: false + IBSMunicipalTotalsResource: + type: "object" + nullable: true + description: "Informações do IBS do Município (gIBSMun)" + properties: + defermentAmount: + type: "number" + nullable: true # Valor total do diferimento + description: "Valor total do diferimento (vDif)" + format: "double" + returnedAmount: + type: "number" + nullable: true + description: "Valor total de devolução de tributos (vDevTrib)" + format: "double" + amount: + type: "number" + nullable: true # Valor total do IBS do Município + description: "Valor total do IBS do Município. (vIBSMun)" + format: "double" + additionalProperties: false + CBSTotalsResource: + type: "object" + nullable: true + description: "Grupo total da CBS (gCBS)" + properties: + defermentAmount: + type: "number" + nullable: true # Valor total do diferimento + description: "Valor total do diferimento (vDif)" + format: "double" + returnedAmount: + type: "number" + nullable: true + description: "Valor total de devolução de tributos (vDevTrib)" + format: "double" + amount: + type: "number" + nullable: true # Valor total da CBS + description: "Valor total da CBS (vCBS)" + format: "double" + presumedCreditAmount: + type: "number" + nullable: true # Valor total do crédito presumido + description: "Valor total do crédito presumido (vCredPres)" + format: "double" + presumedCreditConditionalAmount: + type: "number" + nullable: true + description: "Valor total do crédito presumido em condição suspensiva. (vCredPresCondSus)" + format: "double" + additionalProperties: false + MonophaseTotalsResource: + type: "object" + nullable: true + description: "Grupo de totais da tributação monofásica." + properties: + ibs: + description: "Totais do IBS monofásico" + $ref: "#/components/schemas/MonophaseIBSTotalsResource" # Totais do IBS monofásico + cbs: + description: "Totais da CBS monofásica" + $ref: "#/components/schemas/MonophaseCBSTotalsResource" + additionalProperties: false + RegularTaxationResource: + type: "object" + description: "Tributação regular hipotética caso condição resolutória/suspensiva não se aplique. Informar como a tributação seria aplicada se a condição resolutória/suspensiva não for atendida." + properties: + situationCode: + type: "string" + nullable: true # CST regular + description: "CST regular (CSTReg), 3 dígitos. Use tabela CST do IBS/CBS" + classCode: + type: "string" + nullable: true + description: "Classificação tributária regular (cClassTribReg), 6 dígitos. Use tabela cClassTrib" + stateEffectiveRate: + type: "number" + nullable: true # Alíquota efetiva IBS UF + description: "Alíquota efetiva IBS UF (pAliqEfetRegIBSUF)." + format: "double" + amount: + type: "number" + nullable: true + description: "IBS UF regular (vTribRegIBSUF)." + format: "double" + municipalEffectiveRate: + type: "number" + nullable: true # Alíquota efetiva IBS Município + description: "Alíquota efetiva IBS Município (pAliqEfetRegIBSMun)." + format: "double" + municipalAmount: + type: "number" + nullable: true + description: "IBS Município regular (vTribRegIBSMun)." + format: "double" + cbsEffectiveRate: + type: "number" + nullable: true # Alíquota efetiva CBS + description: "Alíquota efetiva CBS (pAliqEfetRegCBS)." + format: "double" + cbsAmount: + type: "number" + nullable: true + description: "CBS regular (vTribRegCBS)." + format: "double" + additionalProperties: false + MonophaseIBSTotalsResource: + type: "object" + nullable: true + description: "Totais do IBS monofásico" + properties: + amount: + type: "number" + nullable: true # Total do IBS monofásico + description: "Total do IBS monofásico. (vIBSMono)" + format: "double" + withheldAmount: + type: "number" + nullable: true + description: "Total do IBS monofásico sujeito a retenção. (vIBSMonoReten)" + format: "double" + previouslyWithheldAmount: + type: "number" + nullable: true # Total do IBS monofásico retido anteriormente + description: "Total do IBS monofásico retido anteriormente. (vIBSMonoRet)" + format: "double" + additionalProperties: false + MonophaseCBSTotalsResource: + type: "object" + nullable: true + description: "Totais da CBS monofásica" + properties: + amount: + type: "number" + nullable: true # Total da CBS monofásica + description: "Total da CBS monofásica. (vCBSMono)" + format: "double" + withheldAmount: + type: "number" + nullable: true + description: "Total da CBS monofásica sujeita a retenção. (vCBSMonoReten)" + format: "double" + previouslyWithheldAmount: + type: "number" + nullable: true # Total da CBS monofásica retida anteriormente + description: "Total da CBS monofásica retida anteriormente. (vCBSMonoRet)" + format: "double" + additionalProperties: false + RequestCancellationResource: + type: "object" + properties: + accountId: + type: "string" + nullable: true # Identificador da Conta + companyId: + type: "string" + nullable: true + productInvoiceId: + type: "string" + nullable: true + reason: + type: "string" + nullable: true # Motivo do cancelamento + additionalProperties: false + ReturnedTaxResource: + type: "object" + description: "Grupo de Informações da Devolução de Tributos" + properties: + amount: + type: "number" + nullable: true # Valor do tributo devolvido + description: "Valor do tributo devolvido (vDevTrib)" + format: "double" + additionalProperties: false + ShippingModality: + type: "string" + enum: + - "ByIssuer" + - "ByReceiver" + - "ByThirdParties" + - "OwnBySender" + - "OwnByBuyer" + - "Free" # Transporte grátis + default: "Free" + description: | + Modalidade do frete (modFrete). + Valores possíveis: + - `ByIssuer`: Contratação do Frete por conta do Remetente (CIF) + - `ByReceiver`: Contratação do Frete por conta do Destinatário (FOB) + - `ByThirdParties`: Contratação do Frete por conta de Terceiros + - `OwnBySender`: Transporte Próprio por conta do Remetente + - `OwnByBuyer`: Transporte Próprio por conta do Destinatário + - `Free`: Sem Ocorrência de Transporte + SpecialTaxRegime: + type: "string" + enum: + - "Nenhum" + - "MicroempresaMunicipal" + - "Estimativa" + - "SociedadeDeProfissionais" + - "MicroempreendedorIndividual" + - "MicroempresarioEmpresaPequenoPorte" + - "Automatico" + description: | + Regime especial de tributação. + Valores possíveis: + - `Nenhum`: Nenhum + - `MicroempresaMunicipal`: Microempresa Municipal + - `Estimativa`: Estimativa + - `SociedadeDeProfissionais`: Sociedade de Profissionais + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `MicroempresarioEmpresaPequenoPorte`: Microempresário e Empresa de Pequeno Porte (ME/EPP) + - `Automatico`: Automático + StateCode: + type: "string" + enum: + - "NA" + - "RO" + - "AC" + - "AM" + - "RR" + - "PA" + - "AP" + - "TO" + - "MA" + - "PI" + - "CE" + - "RN" + - "PB" + - "PE" + - "AL" + - "SE" + - "BA" + - "MG" + - "ES" + - "RJ" + - "SP" + - "PR" + - "SC" + - "RS" + - "MS" + - "MT" + - "GO" + - "DF" + - "EX" # Exterior + StateTaxProcessingAuthorizer: + type: "string" + enum: + - "Normal" + - "EPEC" + description: | + Autorizador de Processamento de Imposto Estadual. + Valores possíveis: + - `Normal`: Autorizador Normal + - `EPEC`: Autorizador de Evento Prévio de Emissão em Contingência + TaxCouponInformationResource: + type: "object" + properties: + modelDocumentFiscal: + type: "string" + nullable: true + description: "Modelo de Documento Fiscal (mod)" + orderECF: + type: "string" + nullable: true # Número de Ordem Sequencial do ECF + description: "Número de Ordem Sequencial do ECF (nECF)" + orderCountOperation: + type: "integer" + nullable: true + description: "Número do Contador de Ordem de Operação (nCOO)" + format: "int32" + additionalProperties: false + TaxDeterminationResource: + type: "object" + description: "Grupo de informações fiscais para o cálculo automático de impostos. Se este grupo for preenchido, o grupo `tax.IBSCBS` será calculado automaticamente. Se não for preenchido, o cálculo automático do grupo `tax.IBSCBS` torna-se opcional." + properties: + operationCode: + type: "integer" + nullable: true # Código interno para determinação de natureza de operação + description: "Código interno para determinação de natureza de operação" + format: "int32" + issuerTaxProfile: + type: "string" + nullable: true + description: "Perfil fiscal do vendedor (origem) - usado para o cálculo automático de impostos" + buyerTaxProfile: + type: "string" + nullable: true + description: "Perfil fiscal do comprador (destino) - usado para o cálculo automático de impostos" + origin: + type: "string" + nullable: true # Origem da mercadoria + description: "Origem da mercadoria" + acquisitionPurpose: + type: "string" + nullable: true + description: "Finalidade de aquisição - usado para o \r\ncálculo automático de impostos" + additionalProperties: false + TaxDocumentsReferenceResource: + type: "object" + properties: + taxCouponInformation: + $ref: "#/components/schemas/TaxCouponInformationResource" + documentInvoiceReference: + $ref: "#/components/schemas/DocumentInvoiceReferenceResource" + documentElectronicInvoice: + $ref: "#/components/schemas/DocumentElectronicInvoiceResource" + additionalProperties: false + TaxRegime: + type: "string" + enum: + - "None" + - "LucroReal" + - "LucroPresumido" + - "SimplesNacional" + - "SimplesNacionalExcessoSublimite" + - "MicroempreendedorIndividual" + - "Isento" + description: | + Código de Regime Tributário (CRT). + Valores possíveis: + - `None`: Não definido + - `LucroReal`: Lucro Real + - `LucroPresumido`: Lucro Presumido + - `SimplesNacional`: Simples Nacional + - `SimplesNacionalExcessoSublimite`: Simples Nacional – excesso de sublimite de receita bruta + - `MicroempreendedorIndividual`: Microempreendedor Individual - MEI + - `Isento`: Isento + TaxpayerCommentsResource: + type: "object" + properties: + field: + type: "string" + nullable: true + description: "Campo (xCampo)" + text: + type: "string" + nullable: true + description: "Texto (xTexto)" + additionalProperties: false + Total: + type: "object" + properties: + icms: + $ref: "#/components/schemas/ICMSTotal" + issqn: # Grupo de Valores Totais referentes ao ISSQN + $ref: "#/components/schemas/ISSQNTotal" + withheldTaxes: + description: "Grupo Retenções de Tributos (retTrib)" + $ref: "#/components/schemas/TotalsWithholdings" + isTotals: + description: "Grupo de totais do Imposto Seletivo. (ISTot)" + $ref: "#/components/schemas/ISTotalsResource" + ibsCbsTotals: + description: "Totais da NF-e com IBS e CBS. (IBSCBSTot)" + $ref: "#/components/schemas/IBSCBSTotalsResource" # Totais da NF-e com IBS e CBS + totalInvoiceAmount: + type: "number" + nullable: true + description: "Valor total da NF-e com IBS / CBS / IS (vNFTot)" + format: "double" + additionalProperties: false + TotalResource: + type: "object" + properties: + icms: + $ref: "#/components/schemas/ICMSTotalResource" + issqn: + $ref: "#/components/schemas/ISSQNTotalResource" + additionalProperties: false + TransportGroupResource: + type: "object" + properties: + accountId: + type: "string" + nullable: true # Identificador da Conta + description: "Identificador da Conta" + id: + type: "string" + nullable: true + description: "Identificação" + name: + type: "string" + nullable: true + description: "Nome ou Razão Social (xNome)" + federalTaxNumber: + type: "integer" + nullable: true # CNPJ ou CPF + description: "CNPJ ou CPF" + format: "int64" + email: + type: "string" + nullable: true + description: "Email" + address: + $ref: "#/components/schemas/AddressResource" + type: + $ref: "#/components/schemas/PersonType" + stateTaxNumber: + type: "string" # Inscrição Estadual do Transportador + nullable: true + description: "Inscrição Estadual do Transportador (IE)" + transportRetention: + type: "string" + nullable: true + description: "Grupo de Retenção do ICMS do transporte" + additionalProperties: false + description: "Grupo Transportador" + TransportInformationResource: + type: "object" + properties: + freightModality: + $ref: "#/components/schemas/ShippingModality" + transportGroup: + $ref: "#/components/schemas/TransportGroupResource" + reboque: + $ref: "#/components/schemas/ReboqueResource" + volume: + $ref: "#/components/schemas/VolumeResource" # Volumes + transportVehicle: + $ref: "#/components/schemas/TransportVehicleResource" + sealNumber: + type: "string" + nullable: true + description: "Número dos Lacres" + transpRate: + $ref: "#/components/schemas/TransportRateResource" + additionalProperties: false + description: "Grupo de Informações do Transporte da NF-e\r\nId: X01 Pai: A1" + TransportRateResource: + type: "object" + properties: + serviceAmount: + type: "number" + nullable: true # Valor do Serviço + description: "Valor do Serviço (vServ)" + format: "double" + bcRetentionAmount: + type: "number" + nullable: true + description: "BC da Retenção do ICMS (vBCRet)" + format: "double" + icmsRetentionRate: + type: "number" + nullable: true # Alíquota da Retenção + description: "Alíquota da Retenção (pICMSRet) //Change to Rate" + format: "double" + icmsRetentionAmount: + type: "number" + nullable: true + description: "Valor do ICMS Retido (vICMSRet)" + format: "double" + cfop: + type: "integer" + nullable: true # CFOP de Serviço de Transporte + description: "CFOP de Serviço de Transporte (CFOP)" + format: "int64" + cityGeneratorFactCode: + type: "integer" + nullable: true + description: "Código do Municipio de ocorrencia do fato gerador do ICMS do Transporte (cMunFG)" + format: "int64" + additionalProperties: false + TransportVehicleResource: + type: "object" + properties: + plate: + type: "string" + nullable: true # Placa do Veiculo + description: "Placa do Veiculo (placa)" + state: + type: "string" + nullable: true + description: "Sigla da UF (UF)" + rntc: + type: "string" + nullable: true + description: "Registro Nacional de Transportador de Carga (ANTT) (RNTC)" + additionalProperties: false + description: "Grupo Veiculo" + UsedMovableAssetIndicator: # Indica fornecimento de bem móvel usado + type: "boolean" + nullable: false + description: "Indica fornecimento de bem móvel usado (indBemMovelUsado). true = bem usado; false = bem novo." + VolumeResource: + type: "object" + properties: + volumeQuantity: + type: "integer" + nullable: true # Quantidade de volumes transportados + description: "Quantidade de volumes transportados (qVol)" + format: "int32" + species: + type: "string" + nullable: true + description: "Espécie dos volumes transportados (esp)" + brand: + type: "string" + nullable: true + description: "Marca dos Volumes Transportados (marca)" + volumeNumeration: + type: "string" + nullable: true # Numeração dos Volumes Transportados + description: "Numeração dos Volumes Transportados (nVol)" + netWeight: + type: "number" + nullable: true + description: "Peso Liquido(em Kg) (pesoL)" + format: "double" + grossWeight: + type: "number" + nullable: true + description: "Peso Bruto(em Kg) (pesoB)" + format: "double" + additionalProperties: false + description: "Volumes\r\nId:X26" + WithdrawalInformationResource: + type: "object" + properties: + accountId: + type: "string" + nullable: true # Identificador da Conta + description: "Identificador da Conta" + id: + type: "string" + nullable: true + description: "Identificação" + name: + type: "string" + nullable: true # Nome ou Razão Social + description: "Nome ou Razão Social (xNome)" + federalTaxNumber: + type: "integer" + nullable: true # CNPJ ou CPF + description: "CNPJ ou CPF" + format: "int64" + email: + type: "string" + nullable: true + description: "Email" + address: + $ref: "#/components/schemas/AddressResource" + type: + $ref: "#/components/schemas/PersonType" + stateTaxNumber: + type: "string" # Inscrição Estadual + nullable: true + description: "Inscrição Estadual (IE)" + additionalProperties: false + description: "Identificação do Local de retirada (retirada)" + TotalsWithholdings: + type: "object" + nullable: true + description: "Grupo Retenções de Tributos (retTrib)" + properties: + pisAmount: + type: "number" + nullable: true # Valor Retido de PIS + description: "Valor Retido de PIS (vRetPIS)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + cofinsAmount: + type: "number" + nullable: true + description: "Valor Retido de COFINS (vRetCOFINS)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + csllAmount: # Valor Retido de CSLL + type: "number" + nullable: true + description: "Valor Retido de CSLL (vRetCSLL)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + irrfBasis: + type: "number" + nullable: true + description: "Base de Cálculo do IRRF (vBCIRRF)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + irrfAmount: # Valor Retido do IRRF + type: "number" + nullable: true + description: "Valor Retido do IRRF (vIRRF)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + socialSecutiryBasis: + type: "number" + nullable: true + description: "Base de Cálculo da Retenção da Previdência Social (vBCRetPrev)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + socialSecutiryAmount: # Valor da Retenção da Previdência Social + type: "number" + nullable: true + description: "Valor da Retenção da Previdência Social (vRetPrev)" + format: "double" + maximum: 9999999999999.99 + minimum: 0 + additionalProperties: false + ZfmPresumedCreditResource: + type: "object" + description: "Informações sobre o crédito presumido de IBS para fornecimentos da ZFM (gCredPresIBSZFM)." + properties: + classificationCode: + description: "Tipo de crédito presumido (tpCredPresIBSZFM)." + $ref: "#/components/schemas/IbsZfmPresumedCreditClassification" # Tipo de crédito presumido + amount: + type: "number" + nullable: true + description: "Valor do crédito presumido ZFM (vCredPresIBSZFM). Obrigatório para notas de crédito com tpNFCredito = 02." + format: "double" + additionalProperties: false diff --git a/openapi/product-register-pt-br-v1.yaml b/openapi/product-register-pt-br-v1.yaml new file mode 100644 index 0000000..b955fe5 --- /dev/null +++ b/openapi/product-register-pt-br-v1.yaml @@ -0,0 +1,751 @@ +openapi: 3.0.1 +info: + title: API de Cadastro de Produtos + description: | + ### Introdução + API para gerenciar o cadastro de produtos e suas classificações tributárias. Nossa API é projetada para simplificar a complexidade do sistema tributário brasileiro e tem como objetivo principal possibilitar a customização avançada de regras tributárias. + + ### Customização e Conformidade + Esta API permite que empresas de todos os tamanhos realizem cadastros precisos de produtos configurando cenários tributários customizados, garantindo conformidade fiscal e otimizando processos administrativos. + + > **Atenção** + > _Sujeito a alterações mediante notas técnicas e processos de homologação._ + version: 1.0.0 + +servers: + - url: https://api.nfse.io + description: Servidor de Produção + +security: + - Authorization_Header: [] + Authorization_QueryParam: [] + - Authorization_JwtBearer: [] + +paths: + /{tenantId}/products: + post: + operationId: Products_Post + summary: Criar um novo produto + description: Adiciona um novo produto com suas informações tributárias no sistema. O ID do produto é gerado automaticamente pelo servidor. + tags: + - Produtos + parameters: + - name: tenantId + in: path + description: Identificador único do cliente (Tenant). + required: true + schema: + type: string + requestBody: + description: Objeto do produto a ser cadastrado. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInput' + examples: + basic_example: + summary: Exemplo Básico + value: + tenantId: "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d" + collectionId: "seller-company-id-001" + sku: "SKU-PROD-00123" + origin: "national" + description: "Produto de Exemplo para Integração" + gtin: "7891234567890" + taxGtin: "7891234567890" + tax: + ncm: "85171300" + cest: "2105301" + customTax: + - OperationCode: 120 + issuer: + - taxRegime: "RealProfit" + taxProfile: "industry" + recipient: + - taxProfile: "retail" + intraState: + cfop: 5102 + icms: + cst: "00" + pICMS: "18.00" + modBC: "3" + pis: + cst: "01" + pPIS: "1.65" + cofins: + cst: "01" + pCOFINS: "7.60" + interState: + cfop: 6102 + icms: + cst: "00" + pICMS: "12.00" + modBC: "3" + pis: + cst: "01" + pPIS: "1.65" + cofins: + cst: "01" + pCOFINS: "7.60" + exhaustive_example: + summary: Exemplo Completo (Exaustivo) + value: + tenantId: "a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6" + collectionId: "seller-company-id-999" + sku: "SKU-EXHAUSTIVE-999" + origin: "foreignDirectImport" + description: "Produto exaustivo com todos os campos preenchidos para teste" + gtin: "9876543210987" + taxGtin: "9876543210988" + tax: + ncm: "33049990" + cest: "2002400" + customTax: + - OperationCode: 121 + issuer: + - taxRegime: "RealProfit" + taxProfile: "importer" + recipient: + - taxProfile: "final_consumer_non_icms_contributor" + intraState: + cfop: 5405 + icms: + cst: "60" + modBC: "3" + modBCST: "4" + motDesICMS: "9" + motDesICMSST: "7" + pICMS: "18.00" + pRedBC: "10.00" + pMVAST: "40.00" + pRedBCST: "15.00" + pICMSST: "18.00" + pFCP: "2.00" + pFCPST: "2.00" + pFCPSTRet: "2.00" + pRedBCEfet: "5.00" + pICMSEfet: "17.50" + pDif: "6.00" + pFCPDif: "1.00" + pCredSN: "1.25" + pis: + cst: "01" + pPIS: "1.65" + cofins: + cst: "01" + pCOFINS: "7.60" + interState: + cfop: 6404 + icms: + cst: "10" + modBC: "0" + modBCST: "5" + pICMS: "12.00" + pMVAST: "45.00" + pICMSST: "12.00" + pFCP: "1.00" + pFCPST: "1.00" + pis: + cst: "02" + pPIS: "0.00" + cofins: + cst: "02" + pCOFINS: "0.00" + multiple_scenarios_example: + summary: Exemplo com Múltiplos Cenários Tributários + value: + tenantId: "f0e1d2c3-b4a5-f6e7-d8c9-b0a1f2e3d4c5" + collectionId: "seller-multi-scenario-007" + sku: "SKU-MULTI-SCENARIO-007" + origin: "national" + description: "Produto com Múltiplas Regras Fiscais" + gtin: "1122334455667" + tax: + ncm: "64029990" + cest: "2803200" + customTax: + - OperationCode: 120 # Cenário 1: Venda para Consumidor Final (Dentro do Estado) + issuer: + - taxRegime: "RealProfit" + taxProfile: "retail" + recipient: + - taxProfile: "final_consumer_non_icms_contributor" + intraState: + cfop: 5102 + icms: + cst: "00" + pICMS: "18.00" + pis: + cst: "01" + pPIS: "1.65" + cofins: + cst: "01" + pCOFINS: "7.60" + - OperationCode: 125 # Cenário 2: Venda para Revenda (Entre Estados) + issuer: + - taxRegime: "RealProfit" + taxProfile: "wholesale" + recipient: + - taxProfile: "retail" + interState: + cfop: 6108 + icms: + cst: "00" + pICMS: "12.00" + pis: + cst: "01" + pPIS: "1.65" + cofins: + cst: "01" + pCOFINS: "7.60" + responses: + '201': + description: Produto criado com sucesso. + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + '400': + description: Dados fornecidos são inválidos. + + /{tenantId}/products/{productId}: + get: + summary: Consultar produto por ID + description: Retorna um único produto a partir do seu identificador único. + tags: + - Produtos + parameters: + - name: tenantId + in: path + description: Identificador único do cliente (Tenant). + required: true + schema: + type: string + - name: productId + in: path + description: Identificador único do produto que será retornado. + required: true + schema: + type: string + responses: + '200': + description: Operação realizada com sucesso. + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + '404': + description: Produto não encontrado. + + put: + summary: Atualizar um produto existente + description: Atualiza todas as informações de um produto específico. + tags: + - Produtos + parameters: + - name: tenantId + in: path + description: Identificador único do cliente (Tenant). + required: true + schema: + type: string + - name: productId + in: path + description: Identificador único do produto que será atualizado. + required: true + schema: + type: string + requestBody: + description: Objeto do produto com as informações atualizadas. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProductInput' + responses: + '200': + description: Produto atualizado com sucesso. + content: + application/json: + schema: + $ref: '#/components/schemas/Product' + '400': + description: Dados fornecidos são inválidos. + '404': + description: Produto não encontrado. + + delete: + summary: Excluir um produto + description: Exclui um produto a partir do seu identificador único. + tags: + - Produtos + parameters: + - name: tenantId + in: path + description: Identificador único do cliente (Tenant). + required: true + schema: + type: string + - name: productId + in: path + description: Identificador único do produto que será excluído. + required: true + schema: + type: string + responses: + '204': + description: Produto excluído com sucesso. + '404': + description: Produto não encontrado. + +tags: + - name: Produtos + description: Operações referentes aos produtos + +components: + securitySchemes: + Authorization_Header: + type: apiKey + name: Authorization + in: header + description: "Autenticar usando o Cabeçalho HTTP Authorization com sua API Key" + Authorization_QueryParam: + type: apiKey + name: apikey + in: query + description: 'Autenticar usando o Parametro na URL, exemplo: "/?apikey={APIKEY_TOKEN}"' + Authorization_JwtBearer: + type: http + scheme: bearer + bearerFormat: Json Web Token + description: "Autenticar usando o cabeçalho HTTP" + schemas: + Product: + type: object + description: Representa um produto e suas informações tributárias completas. + required: + - id + - tenantId + - collectionId + - sku + - origin + - description + - customTax + properties: + id: + type: string + description: Identificador único do produto (gerado pelo servidor). + tenantId: + type: string + description: Identificador do Tenant (Por exemplo, o AccountId do Marketplace). + collectionId: + type: string + maxLength: 60 + description: Identificador da coleção. Utilize o companyId do seller para isolar o produto por vendedor. + sku: + type: string + maxLength: 60 + description: Código único de identificação do produto (SKU do Marketplace). + x-sefaz-tag: cProd + origin: + type: string + enum: + - national + - foreignDirectImport + - foreignInternalMarket + - nationalWith40To70Import + - nationalPpb + - nationalWithLess40Import + - foreignDirectImportWithoutNationalSimilar + - foreignInternalMarketWithoutNationalSimilar + - nationalWithGreater70Import + description: Origem da mercadoria (NT 2013.006). + x-sefaz-tag: orig + description: + type: string + maxLength: 120 + description: Descrição detalhada do produto. + x-sefaz-tag: xProd + gtin: + type: string + maxLength: 14 + description: GTIN (Global Trade Item Number) do produto (Antigo código EAN ou código de barras). + x-sefaz-tag: cEAN + taxGtin: + type: string + maxLength: 14 + description: GTIN da unidade tributável. + x-sefaz-tag: cEANTrib + tax: + type: object + description: Grupo de classificação tributária básica. + required: + - ncm + properties: + ncm: + type: string + maxLength: 8 + description: Código NCM com 8 dígitos ou 2 dígitos (gênero). + x-sefaz-tag: NCM + cest: + type: string + maxLength: 7 + description: Código CEST (Código Especificador da Substituição Tributária). + x-sefaz-tag: CEST + customTax: + type: array + description: Cenários Tributários Customizados. + items: + $ref: '#/components/schemas/CustomTaxScenario' + + ProductInput: + type: object + description: Schema para criação ou atualização de um produto. O 'id' é omitido, pois é controlado pelo servidor. + required: + - tenantId + - collectionId + - sku + - origin + - description + - customTax + properties: + tenantId: + type: string + description: Identificador do Tenant (Por exemplo, o AccountId do Marketplace). + collectionId: + type: string + maxLength: 60 + description: Identificador da coleção. Utilize o companyId do seller para isolar o produto por vendedor. + sku: + type: string + maxLength: 60 + description: Código único de identificação do produto (SKU). + x-sefaz-tag: cProd + origin: + type: string + enum: + - national + - foreignDirectImport + - foreignInternalMarket + - nationalWith40To70Import + - nationalPpb + - nationalWithLess40Import + - foreignDirectImportWithoutNationalSimilar + - foreignInternalMarketWithoutNationalSimilar + - nationalWithGreater70Import + description: | + Origem da Mercadoria (conforme NT 2013.006). + - `national`: 0 - Nacional, exceto as indicadas nos códigos 3, 4, 5 e 8. + - `foreignDirectImport`: 1 - Estrangeira Importação direta, exceto a indicada no código 6. + - `foreignInternalMarket`: 2 - Estrangeira Adquirida no mercado interno, exceto a indicada no código 7. + - `nationalWith40To70Import`: 3 - Nacional, mercadoria ou bem com Conteúdo de Importação superior a 40% e inferior ou igual a 70%. + - `nationalPpb`: 4 - Nacional, cuja produção tenha sido feita em conformidade com os processos produtivos básicos de que tratam as legislações citadas nos Ajustes. + - `nationalWithLess40Import`: 5 - Nacional, mercadoria ou bem com Conteúdo de Importação inferior ou igual a 40%. + - `foreignDirectImportWithoutNationalSimilar`: 6 - Estrangeira Importação direta, sem similar nacional, constante em lista da CAMEX e gás natural. + - `foreignInternalMarketWithoutNationalSimilar`: 7 - Estrangeira Adquirida no mercado interno, sem similar nacional, constante lista CAMEX e gás natural. + - `nationalWithGreater70Import`: 8 - Nacional, mercadoria ou bem com Conteúdo de Importação superior a 70%. + x-sefaz-tag: orig + description: + type: string + maxLength: 120 + description: Descrição detalhada do produto. + x-sefaz-tag: xProd + gtin: + type: string + maxLength: 14 + description: GTIN (Global Trade Item Number) do produto (Antigo código EAN ou código de barras). + x-sefaz-tag: cEAN + taxGtin: + type: string + maxLength: 14 + description: GTIN da unidade tributável. + x-sefaz-tag: cEANTrib + tax: + type: object + description: Grupo de classificação tributária básica. + required: + - ncm + properties: + ncm: + type: string + maxLength: 8 + description: Código NCM com 8 dígitos ou 2 dígitos (gênero). + x-sefaz-tag: NCM + cest: + type: string + maxLength: 7 + description: Código CEST (Código Especificador da Substituição Tributária). + x-sefaz-tag: CEST + customTax: + type: array + description: Cenários Tributários Customizados. + items: + $ref: '#/components/schemas/CustomTaxScenario' + + CustomTaxScenario: + type: object + required: + - OperationCode + properties: + issuer: + type: array + description: Configuração tributária validada para o emitente. + items: + type: object + required: + - taxRegime + - taxProfile + properties: + taxRegime: + $ref: '#/components/schemas/TaxRegimeEnum' + taxProfile: + $ref: '#/components/schemas/IssuerTaxProfileEnum' + recipient: + type: array + description: Configuração tributária validada para o destinatário. + items: + type: object + required: + - taxProfile + properties: + taxProfile: + $ref: '#/components/schemas/RecipientTaxProfileEnum' + OperationCode: + type: integer + format: int32 + description: Código da Operação. Define a natureza comercial a ser configurada (ex. Venda, Remessa). Utilizado em conjunto para buscar o cenário tributário específico correspondente. + minimum: 0 + maximum: 999 + intraState: + $ref: '#/components/schemas/IntraStateTaxGroup' + interState: + $ref: '#/components/schemas/InterStateTaxGroup' + + TaxRegimeEnum: + type: string + description: | + Regime Tributário do Emitente. + - `NationalSimple`: Simples Nacional. + - `NationalSimpleSublimitExceeded`: Simples Nacional, excesso de sublimite da receita bruta. + - `RealProfit`: Regime Normal - Lucro Real. + - `PresumidProfile`: Regime Normal - Lucro Presumido. + enum: + - NationalSimple + - NationalSimpleSublimitExceeded + - RealProfit + - PresumidProfile + x-sefaz-tag: CRT + + IssuerTaxProfileEnum: + type: string + description: | + Perfil tributário do emitente. + - `none`: Nenhum / Não especificado. + - `retail`: Varejista. + - `wholesale`: Atacadista. + - `wholesale_industry`: Atacado e Indústria. + - `importer`: Importador. + - `industry`: Indústria. + - `cooperative`: Cooperativa. + enum: + - none + - retail + - wholesale + - wholesale_industry + - importer + - industry + - cooperative + + RecipientTaxProfileEnum: + type: string + description: | + Perfil tributário do destinatário. + - `none`: Nenhum / Não especificado. + - `industry`: Indústria. + - `final_consumer_icms_contributor`: Consumidor final, contribuinte do ICMS. + - `final_consumer_non_icms_contributor`: Consumidor final, Não contribuinte do ICMS. + - `general_warehouse`: Armazém geral. + - `closed_deposit`: Depósito fechado. + - `natural_person`: Pessoa física. + - `commercial_exporter`: Empresa comercial exportadora. + - `importer`: Importador. + - `coop`: Cooperativa. + - `wholesale`: Atacadista. + - `retail`: Varejista. + - `interdependent_company`: Empresa interdependente. + - `retail_branch`: Filial varejista. + - `non_retail_branch`: Filial não varejista. + - `wholesale_branch`: Filial atacadista. + - `closed_warehouse`: Armazém fechado. + enum: + - none + - industry + - final_consumer_icms_contributor + - final_consumer_non_icms_contributor + - general_warehouse + - closed_deposit + - natural_person + - commercial_exporter + - importer + - coop + - wholesale + - retail + - interdependent_company + - retail_branch + - non_retail_branch + - wholesale_branch + - closed_warehouse + + IcmsTaxGroup: + type: object + description: Detalhes do Imposto sobre Circulação de Mercadorias e Serviços (ICMS). + properties: + cst: + type: string + maxLength: 3 + description: Código de Situação Tributária (CST) do ICMS. + x-sefaz-tag: CST + modBC: + type: string + maxLength: 1 + description: Modalidade de determinação da Base de Cálculo do ICMS. + x-sefaz-tag: modBC + modBCST: + type: string + maxLength: 1 + description: Modalidade de determinação da Base de Cálculo do ICMS ST (Substituição Tributária). + x-sefaz-tag: modBCST + motDesICMS: + type: string + maxLength: 1 + description: Motivo da desoneração do ICMS. + x-sefaz-tag: motDesICMS + motDesICMSST: + type: string + maxLength: 1 + description: Motivo da desoneração do ICMS ST. + x-sefaz-tag: motDesICMSST + pICMS: + type: string + maxLength: 8 + description: Alíquota do ICMS (percentual). + x-sefaz-tag: pICMS + pRedBC: + type: string + maxLength: 8 + description: Percentual de redução da Base de Cálculo do ICMS. + x-sefaz-tag: pRedBC + pMVAST: + type: string + maxLength: 8 + description: Percentual da Margem de Valor Adicionado para ICMS ST. + x-sefaz-tag: pMVAST + pRedBCST: + type: string + maxLength: 8 + description: Percentual de redução da Base de Cálculo do ICMS ST. + x-sefaz-tag: pRedBCST + pICMSST: + type: string + maxLength: 8 + description: Alíquota do ICMS ST (percentual). + x-sefaz-tag: pICMSST + pFCP: + type: string + maxLength: 8 + description: Percentual do Fundo de Combate à Pobreza (FCP). + x-sefaz-tag: pFCP + pFCPST: + type: string + maxLength: 8 + description: Percentual do Fundo de Combate à Pobreza (FCP) retido por Substituição Tributária. + x-sefaz-tag: pFCPST + pFCPSTRet: + type: string + maxLength: 8 + description: Percentual do FCP retido anteriormente por Substituição Tributária. + x-sefaz-tag: pFCPSTRet + pRedBCEfet: + type: string + maxLength: 8 + description: Percentual de redução da Base de Cálculo Efetiva. + x-sefaz-tag: pRedBCEfet + pICMSEfet: + type: string + maxLength: 8 + description: Alíquota Efetiva do ICMS (percentual). + x-sefaz-tag: pICMSEfet + pDif: + type: string + maxLength: 8 + description: Percentual do diferimento. + x-sefaz-tag: pDif + pFCPDif: + type: string + maxLength: 8 + description: Percentual do FCP diferido. + x-sefaz-tag: pFCPDif + pCredSN: + type: string + maxLength: 8 + description: Alíquota aplicável de cálculo do crédito (Simples Nacional). + x-sefaz-tag: pCredSN + + PisTaxGroup: + type: object + description: Detalhes da tributação do PIS. + properties: + cst: + type: string + maxLength: 3 + description: Código de Situação Tributária (CST) do PIS. + x-sefaz-tag: CST + pPIS: + type: string + maxLength: 8 + description: Alíquota do PIS (percentual). + x-sefaz-tag: pPIS + + CofinsTaxGroup: + type: object + description: Detalhes da tributação da COFINS. + properties: + cst: + type: string + maxLength: 3 + description: Código de Situação Tributária (CST) da COFINS. + x-sefaz-tag: CST + pCOFINS: + type: string + maxLength: 8 + description: Alíquota da COFINS (percentual). + x-sefaz-tag: pCOFINS + + IntraStateTaxGroup: + type: object + description: Detalhes da tributação para operações internas (dentro do mesmo Cidadão/Estado). + required: + - cfop + properties: + cfop: + type: number + maxLength: 4 + description: Código Fiscal de Operações e Prestações (CFOP) para operações estaduais. + x-sefaz-tag: CFOP + icms: { $ref: '#/components/schemas/IcmsTaxGroup' } + pis: { $ref: '#/components/schemas/PisTaxGroup' } + cofins: { $ref: '#/components/schemas/CofinsTaxGroup' } + + InterStateTaxGroup: + type: object + description: Detalhes da tributação para operações interestaduais (entre Estados distintos). + properties: + cfop: + type: number + maxLength: 4 + description: Código Fiscal de Operações e Prestações (CFOP) para operações interestaduais. + x-sefaz-tag: CFOP + icms: { $ref: '#/components/schemas/IcmsTaxGroup' } + pis: { $ref: '#/components/schemas/PisTaxGroup' } + cofins: { $ref: '#/components/schemas/CofinsTaxGroup' } \ No newline at end of file diff --git a/openapi/service-invoice-rtc-v1.yaml b/openapi/service-invoice-rtc-v1.yaml new file mode 100644 index 0000000..0c25fd5 --- /dev/null +++ b/openapi/service-invoice-rtc-v1.yaml @@ -0,0 +1,1727 @@ +openapi: 3.0.1 +info: + title: API de Emissão de Nota Fiscal de Serviços Eletrônica (NFS-e) - RTC + version: v3 + description: | + ### Introdução + API para envio de dados de RPS/DPS para emissão de NFS-e, alinhada com o padrão nacional e complementada com campos específicos do Web Service da Prefeitura de São Paulo (NF-e/NFS-e). + + ### Adequação de Leiaute + + Nesta adequação de leiaute, foram considerados os leiautes do **Ambiente Nacional**, **São Paulo e ABRASF**. + + > **Atenção** + > _Sujeito a alterações mediante notas técnicas e processos de homologação._ +servers: + - url: https://api.nfe.io + description: Para realizar testes no ambiente de homologação da prefeitura, é necessário entrar em contato com o suporte para que a empresa seja parametrizada com os dados necessários. +tags: + - name: Nota Fiscal de Serviço (RTC) + description: Operações relacionadas à Nota Fiscal Eletrônica de Serviço + +paths: + /v1/companies/:company_id/serviceinvoices: + post: + tags: + - Nota Fiscal de Serviço (RTC) + summary: Envio de dados para emissão de NFS-e (RPS/DPS) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NFSeRequest' + examples: + MinimumExample: + summary: Exemplo Mínimo (Apenas campos obrigatórios + IBSCBS obrigatórios) + value: + borrower: + name: CONSUMIDOR MINIMO LTDA + federalTaxNumber: 191 + cityServiceCode: '4444' + federalServiceCode: '01.01' + description: "Serviço de Consultoria e Assessoria (Exemplo Mínimo V4)." + servicesAmount: 1000.00 + nbsCode: '101010100' + ibsCbs: + operationIndicator: '1005011' + classCode: '000001' + IntermediateExample: + summary: Exemplo Intermediário (Raiz do IBSCBS + subgrupos ibs e cbs) + value: + borrower: + name: CONSUMIDOR INTERMEDIARIO S.A. + federalTaxNumber: 201 + address: + country: BRA + postalCode: "01001-001" + street: AVENIDA PRINCIPAL + number: '500' + district: BROOKLIN + city: + code: '3550308' + state: SP + externalId: NFSE-INT-V4-0002 + cityServiceCode: '4444' + federalServiceCode: '01.02' + description: "Assessoria tributária para reforma de 2026 (Exemplo Intermediário V4)." + servicesAmount: 5000.00 + issuedOn: '2026-01-20T11:30:00-03:00' + taxationType: OutsideCity + location: + country: BRA + postalCode: "13000-000" + street: RUA FORA DA CIDADE + number: '120' + district: INTERIOR + city: + code: '3509502' + state: SP + nbsCode: '102020200' + recipient: + name: RECIPIENTE INTERMEDIARIO LTDA. + federalTaxNumber: 301 + address: + country: BRA + postalCode: "01000-000" + city: + code: '3550308' + state: SP + ibsCbs: + purpose: regular # Este campo tem um default 'regular', então não é estritamente necessário no envio. + isDonation: false + personalUse: false + destinationIndicator: SameAsBuyer + operationIndicator: '1005011' + situationCode: '000' # Este campo é opcional e pode ser derivado do classCode. + classCode: '000001' + basis: 5000.00 + reimbursedResuppliedAmount: 0.00 + ibs: + totalAmount: 100.00 + state: + rate: 0.04 + effectiveRate: 0.03 + amount: 50.00 + municipal: + rate: 0.04 + effectiveRate: 0.03 + amount: 50.00 + cbs: + rate: 0.08 + effectiveRate: 0.07 + amount: 350.00 + CompleteExample: + summary: Exemplo Completo e Exaustivo (100% dos campos) + value: + borrower: + type: LegalEntity # O valor já estava correto. + name: TOMADOR COMPLETO GLOBAL LTDA (EXAUSTIVO) + federalTaxNumber: 12345678000199 + municipalTaxNumber: '999999999999' + stateTaxNumber: '111222333444' + caepf: '12345678901234' + taxRegime: LucroReal + phoneNumber: '5511988887777' + email: tomador.exausto@exemplo.com + noTaxIdReason: NotRequired + address: + country: USA + postalCode: "10001-000" + street: 1st AVENUE + number: '10' + additionalInformation: SUITE 50 FLOOR 10 + district: MANHATTAN + city: + name: NEW YORK + code: '9999999' + state: NY + externalId: NFSE-EXAUSTIVO-V4-0004 + cityServiceCode: '4444' + federalServiceCode: '17.01' + cnaeCode: '6201501' + nbsCode: '117010000' + ncmCode: '85044021' + description: 'Desenvolvimento e licenciamento de software customizado, conforme contrato. Inclui valores de multa, juros, deduções, benefícios, suspensão, etc. (Exemplo Exaustivo V4)' + servicesAmount: 25000.00 + paidAmount: 26000.00 + rpsSerialNumber: A0002 + issuedOn: '2026-01-25T09:15:30-03:00' + accrualOn: '2026-01-01' + rpsNumber: 87654321 + taxationType: Immune + issRate: 0.00 + issTaxAmount: 0.00 + deductionsAmount: 1500.00 + discountUnconditionedAmount: 200.00 + discountConditionedAmount: 100.00 + irAmountWithheld: 250.00 + pisRate: 0.0065 + pisCofinsBaseTax: 25000.00 + pisAmountWithheld: 162.50 + cofinsRate: 0.04 + cofinsAmountWithheld: 1000.00 + csllAmountWithheld: 250.00 + inssAmountWithheld: 2750.00 + issAmountWithheld: 0.00 + ipiRate: 0.05 + ipiAmount: 1250.00 + othersAmountWithheld: 50.00 + additionalInformation: 'Informações adicionais exaustivas para o fisco, incluindo detalhes do contrato XYZ.' + isEarlyInstallmentPayment: true + location: + country: BRA + postalCode: "90000-000" + street: RUA DA PRESTACAO EXAUSTIVA + number: '999' + additionalInformation: 'Bloco Z, Apto 101' + district: FLORESTA NOVA + city: + code: '4314902' + name: PORTO ALEGRE + state: RS + activityEvent: + name: EVENTO CULTURAL COMPLETO + beginOn: '2026-02-10T08:00:00-03:00' + endOn: '2026-02-12T22:00:00-03:00' + Code: EVT-COMPLEX + address: + country: BRA + postalCode: "90000-010" + street: ARENA DO EVENTO + number: SN + district: ARENA DISTRICT + city: + code: '4314902' + state: RS + approximateTax: + source: IBPT + version: '24.1.A' + totalRate: 0.15 + totalAmount: 3750.00 + referenceSubstitution: + id: '99998888777766665555444433332222111100009999' + reason: RejectionBuyerOrIntermediary + lease: + category: RightOfWay + objectType: cables + totalLength: 2500.75 + construction: + propertyFiscalRegistration: '9876543210-FISCAL-OBRA' + workId: + scheme: bra.cei + value: CEI-OBRA-EXAUSTIVA + cibCode: 'CIB-9876543210' + siteAddress: + country: BRA + postalCode: "01000-001" + street: RUA DA OBRA COMPLETA + number: '1000' + district: CENTRO NOVO + city: + code: '3550308' + state: SP + realEstate: + propertyFiscalRegistration: 'SQL-IMOVEL-98765' + cibCode: 'CIB-IMOVEL-54321' + siteAddress: + country: BRA + postalCode: "04571-010" + street: RUA DO IMOVEL EXEMPLO + number: '200' + district: BROOKLIN + city: + code: '3550308' + state: SP + foreignTrade: + serviceMode: ConsumptionAbroad + relationShip: affiliate + currency: 220 + serviceAmountInCurrency: 20000.00 + supportMechanismProvider: ProexFinancing + supportMechanismReceiver: Zpe + temporaryGoods: no + importDeclaration: DI-123456-2026 + exportRegistration: 'RE-EXP-COMPLETO-123' + mdicDelivery: true + additionalInformationGroup: + responsibilityDocumentIdentifier: DOC-RESP-001 + referencedDocument: REF-DOC-002 + order: 'PEDIDO-COMPRA-456' + items: + - item: 'Item A - Detalhe 1' + - item: 'Item B - Detalhe 2' + otherInformation: Outras informações complementares. + intermediary: + type: LegalEntity + name: INTERMEDIARIO COMPLETO S/A + federalTaxNumber: 87654321000100 + municipalTaxNumber: '111111111111' + stateTaxNumber: '999888777666' + taxRegime: SimplesNacional + phoneNumber: '5521977776666' + email: interm.completo@teste.com + address: + country: BRA + postalCode: "20000-000" + street: AV INTERMEDIACAO COMPLETA + number: '123' + district: CENTRO RIO + city: + code: '3304557' + state: RJ + recipient: + name: DESTINATARIO DETALHADO COMPLETO LTDA + federalTaxNumber: 100100100100 + email: dest@detalhe.completo.com + address: + country: BRA + postalCode: "01000-000" + street: RUA DESTINO FINAL + number: '10' + district: CENTRO + city: + code: '3550308' + state: SP + deduction: + documents: + - nfseKey: '11111222223333344444555556666677777888889999900000' + deductionType: Subcontracting + issueDate: '2026-01-10' + deductibleTotal: 1000.00 + usedAmount: 1000.00 + supplier: + type: LegalEntity + name: SUBEMPREITEIRO EXEMPLO LTDA + federalTaxNumber: 10101010000110 + address: + country: BRA + postalCode: "01234-000" + street: RUA DO SUBEMPREITEIRO + number: '10' + district: VILA INDUSTRIAL + city: + code: '3550308' + state: SP + benefit: + id: '35503080100002' + amount: 300.00 + suspension: + reason: Administrative + processNumber: ADM-SUSP-2026-XYZ + immunityType: BooksPressPaper + retentionType: WithheldByIntermediary + approximateTotals: + federal: + rate: 0.12 + amount: 3000.00 + state: + rate: 0.03 + amount: 750.00 + municipal: + rate: 0.00 + amount: 0.00 + rate: 0.15 + amount: 3750.00 + ibsCbs: + purpose: regular + isDonation: false + personalUse: true + leasedMovableAssets: + - ncmCode: '84713012' + description: 'Notebook para locação' + quantity: 5 + - ncmCode: '84716052' + description: 'Monitor para locação' + quantity: 10 + destinationIndicator: DifferentFromBuyer + relatedDocs: + items: + - 'NFSE11112222333344445555666677778888999900001111' + - 'NFSE11112222333344445555666677778888999900002222' + operationIndicator: '4' + operationType: SupplyForPastPay + situationCode: '200' # Este campo é opcional e pode ser derivado do classCode. + classCode: '200045' + basis: 25000.00 + reimbursedResuppliedAmount: 150.00 + ibscbsDeductionReductionAmount: 250.00 + realEstate: + propertyFiscalRegistration: 'SQL-IMOVEL-98765' + cibCode: 'CIB-IMOVEL-54321' + siteAddress: + country: BRA + postalCode: "04571-010" + street: RUA DO IMOVEL EXEMPLO + number: '200' + district: BROOKLIN + city: + code: '3550308' + state: SP + ibs: + totalAmount: 500.00 + state: + rate: 0.05 + rateReduction: 0.1 + effectiveRate: 0.045 + deferment: + rate: 0.5 + amount: 125.00 + returnedAmount: 25.00 + amount: 250.00 + municipal: + rate: 0.05 + rateReduction: 0 + effectiveRate: 0.05 + deferment: + rate: 0 + amount: 0 + returnedAmount: 0 + amount: 250.00 + cbs: + rate: 0.08 + rateReduction: 0.05 + effectiveRate: 0.076 + deferment: + rate: 0.2 + amount: 400.00 + returnedAmount: 50.00 + amount: 2000.00 + regularTaxation: + situationCode: '550' + classCode: '550016' + ibs: + totalAmount: 550.00 + state: + effectiveRate: 0.05 + amount: 275.00 + municipal: + effectiveRate: 0.05 + amount: 275.00 + cbs: + effectiveRate: 0.085 + amount: 2125.00 + presumedCredits: + ibs: + code: '01' + rate: 0.01 + amount: 250.00 + conditionalAmount: 50.00 + cbs: + code: '02' + rate: 0.005 + amount: 125.00 + conditionalAmount: 25.00 + governmentPurchase: + entityType: state + ibs: + totalAmount: 450.00 + state: + rate: 0.04 + amount: 225.00 + municipal: + rate: 0.04 + amount: 225.00 + cbs: + rate: 0.07 + amount: 1750.00 + creditTransfer: + ibsAmount: 100.00 + cbsAmount: 50.00 + thirdPartyReimbursements: + documents: + - otherNationalDfe: + dfeKey: DFE-NACIONAL-CHAVE-EXEMPLO-12345678901234567890 + dfeTypeText: Outro Documento Fiscal Eletronico Nacional + dfeType: '9' + supplier: + name: FORNECEDOR DFE NACIONAL LTDA + federalTaxNumber: 30303030000130 + issueDate: '2026-01-05' + accrualOn: '2026-01-05' + reimbursementType: RealEstateBrokerPassThrough + amount: 150.00 + serviceAmountDetails: + initialChargedAmount: 25000.00 + finalChargedAmount: 26000.00 + fineAmount: 250.00 + interestAmount: 750.00 + responses: + '200': + description: Processamento do RPS/DPS iniciado com sucesso + '400': + description: Dados inválidos na requisição + /v1/companies/:company_id/serviceinvoices/:id/cancellation-xml: + get: + tags: + - Nota Fiscal de Serviço (RTC) + summary: Download do XML do evento de cancelamento da NFS-e (Ambiente Nacional) + description: | + Retorna o XML do **evento de cancelamento** (`e110001`) de uma NFS-e emitida no **Ambiente Nacional (ADN)**. + + > **Atenção** + > Disponível **apenas** para notas do Ambiente Nacional. Provedores de layout municipal/ABRASF não possuem evento de cancelamento próprio e retornam `404`. + + Quando existem o XML enviado (request do `e110001`) e o XML do evento autorizado (retorno do ADN — `procEventoNFSe`), o **retorno autorizado é priorizado**. O XML só está disponível para notas com status `Cancelled`. + parameters: + - name: company_id + in: path + description: ID da empresa + required: true + schema: + type: string + - name: id + in: path + description: ID da Nota Fiscal de Serviço (NFS-e) + required: true + schema: + type: string + responses: + '200': + description: XML do evento de cancelamento retornado com sucesso + content: + application/xml: + schema: + type: string + '404': + description: Não há XML de evento de cancelamento para esta nota (provedor legado, ambiente não Nacional ou nota ainda não cancelada) + +components: + schemas: + NFSeRequest: + type: object + title: Nota Fiscal de Serviço (NFSe) Schema + required: + - cityServiceCode + - description + - servicesAmount + - nbsCode + properties: + externalId: + type: string + description: Identificação única do cliente + cityServiceCode: + type: string + description: Código do serviço no municipio + federalServiceCode: + type: string + description: Código federal do servico (Item da lista de serviço LC 116) (CodigoServico, tpCodigoServico) + maxLength: 5 + description: + type: string + description: Descrição dos serviços (Discriminacao, tpDiscriminacao) + maxLength: 2000 + servicesAmount: + type: number + description: Valor do serviços (ValorServicos - V1.0 SP) - Valor total dos serviços (tpValor) + nbsCode: + type: string + description: Código do NBS no municipio (somente quando necessario na cidade) (NBS, tpCodigoNBS) + maxLength: 9 + cnaeCode: + type: string + description: Código CNAE (somente quando necessario na cidade) + ncmCode: + type: string + description: Código NCM (Nomenclatura Comum do Mercosul) (NCM, tpCodigoNCM) + maxLength: 8 + paidAmount: + type: number + description: Valor dos Serviços pago (Valor Total Recebido, tpValor) + issuedOn: + type: string + format: date-time + description: | + Data da emissão no formato YYYY-MM-DDTHH:MM:SS.SSSSSS-03:00 (dhEmi, DataEmissaoNFe). + **Automático**: Se não for informado, o sistema utilizará a data e hora atuais no momento do processamento. + accrualOn: + type: string + format: date + description: | + Data da competência da prestação do serviço no formato AAAA-MM-DD (Competencia). + **Automático**: Se não for informado, o sistema utilizará a data do campo `issuedOn`. + rpsSerialNumber: + type: string + description: | + Número de Série da RPS (SerieRPS, serie, tpSerieRPS). + **Prioridade**: Se informado, o valor enviado será utilizado. + **Automático**: Se não for informado, o sistema utilizará o valor definido no cadastro da empresa. + maxLength: 5 + rpsNumber: + type: number + description: | + Número da RPS (NumeroRPS, nDPS, tpNumero). + **Prioridade**: Se informado, o valor enviado será utilizado. + **Automático**: Se não for informado, o sistema utilizará o próximo número da sequência automática. + taxationType: + type: string + description: | + **Tipo de Tributação (taxationType)** + + O campo `taxationType` define o regime de tributação do **ISSQN (Imposto Sobre Serviços de Qualquer Natureza)**. Ele é um campo legado, mantido para compatibilidade com os layouts municipais existentes, como o da Prefeitura de São Paulo, e continua sendo fundamental para o cálculo do ISS durante o período de transição da Reforma Tributária. + + **Finalidade Principal (Contexto do ISSQN):** + + Este campo indica ao sistema como o ISSQN deve ser tratado na operação. Com base no valor selecionado (ex: `WithinCity`, `OutsideCity`, `Immune`), o sistema determina se o ISSQN é devido, se a tributação ocorrerá dentro ou fora do município, ou se a operação é isenta ou imune a este imposto específico. + + **Relação com a Reforma Tributária (IBS/CBS):** + + É crucial entender que o `taxationType` **não se aplica aos novos tributos (IBS e CBS)**. Para a apuração do IBS e da CBS, as regras de tributação e o local de incidência são definidos exclusivamente pelos campos dentro do grupo `IbsCbs`, como o `operationIndicator` e o `classCode`. + + **Em resumo:** + * **`taxationType`**: Governa o comportamento do **ISSQN**. + * **`ibsCbs`**: Governa o comportamento do **IBS e da CBS**. + + Durante o período de transição, ambos os sistemas de tributação coexistirão, tornando o preenchimento correto de todos esses campos essencial para a conformidade fiscal da nota. + + --- + + Tipo da tributação (TributacaoRPS, tpTributacaoNFe). + Valores possíveis: + - `None`: Nenhuma + - `WithinCity`: Tributação no município + - `OutsideCity`: Tributação fora do município + - `Export`: Exportação + - `Free`: Isenta + - `Immune`: Imune + - `SuspendedCourtDecision`: Exigibilidade suspensa por decisão judicial + - `SuspendedAdministrativeProcedure`: Exigibilidade suspensa por procedimento administrativo + - `OutsideCityFree`: Isenta e fora do município + - `OutsideCityImmune`: Imune e fora do município + - `OutsideCitySuspended`: Suspensa e fora do município + - `OutsideCitySuspendedAdministrativeProcedure`: Suspensa por processo administrativo e fora do município + - `ObjectiveImune`: Imunidade Objetiva + enum: [None, WithinCity, OutsideCity, Export, Free, Immune, SuspendedCourtDecision, SuspendedAdministrativeProcedure, OutsideCityFree, OutsideCityImmune, OutsideCitySuspended, OutsideCitySuspendedAdministrativeProcedure, ObjectiveImune] + default: WithinCity + issRate: + type: number + description: | + Alíquota do ISS (pAliq, tpAliquota). + **Automático**: Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + issTaxAmount: + type: number + description: | + Valor do ISS (ValorISS, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + deductionsAmount: + type: number + description: | + **Deduções: Simples vs. Estruturado (`deductionsAmount` vs. `deduction`)** + + O layout oferece duas formas de registrar deduções da base de cálculo do ISSQN, visando flexibilidade e conformidade com os diferentes padrões (municipal legado vs. nacional). + + * **`deductionsAmount` (Valor Simples):** + Um campo numérico para informar o **valor total consolidado** das deduções. É uma abordagem direta, compatível com layouts mais antigos que não exigem o detalhamento dos documentos que comprovam a dedução. + + * **`deduction` (Grupo Estruturado):** + Um objeto complexo que permite justificar cada dedução com base em documentos fiscais, alinhando-se ao **padrão da NFS-e Nacional**. Ele detalha a origem de cada valor (chave do documento, tipo, valor, fornecedor). + + **Relação e Recomendação:** + A coexistência dos campos oferece compatibilidade. `deductionsAmount` é uma opção simplificada, enquanto o grupo `deduction` é a forma mais completa e recomendada para garantir rastreabilidade e conformidade fiscal com o padrão nacional. O sistema de emissão priorizará os dados detalhados do grupo `deduction`, se fornecidos. + + **Recomendação de Uso:** + * Use `deductionsAmount` para integrações simples ou quando não há detalhamento dos documentos. + * Use o grupo `deduction` sempre que a informação detalhada dos documentos estiver disponível para garantir a máxima conformidade. + + --- + + Valor de deduções (vDR, tpValor). + discountUnconditionedAmount: + type: number + description: Valor do desconto incondicionado (vDescIncond, tpValor). + discountConditionedAmount: + type: number + description: Valor do desconto condicionado (vDescCond, tpValor). + irAmountWithheld: + type: number + description: | + Valor retido do Imposto de Renda (IR) (vRetIRRF, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + cstPisCofins: + type: string + description: | + Código de Situação Tributária do PIS/COFINS (CST). + Valores: + - `00`: Nenhum + - `01`: Operação Tributável com Alíquota Básica + - `02`: Operação Tributável com Alíquota Diferenciada + - `03`: Operação Tributável com Alíquota por Unidade de Medida de Produto + - `04`: Operação Tributável monofásica - Revenda a Alíquota Zero + - `05`: Operação Tributável por Substituição Tributária + - `06`: Operação Tributável a Alíquota Zero + - `07`: Operação Tributável da Contribuição + - `08`: Operação sem Incidência da Contribuição + - `09`: Operação com Suspensão da Contribuição + enum: ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09"] + pisCofinsBaseTax: + type: number + description: Base de cálculo para o Pis e Cofins (vBCPisCofins, tpValor). + pisRate: + type: number + description: | + Alíquota do PIS (pAliqPis). + **Automático**: Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + pisAmount: + type: number + description: Valor do PIS (vPis, tpValor). Campo utilizado para informar o valor do PIS, porém sem retenção. + pisAmountWithheld: + type: number + description: | + Valor retido do PIS (vPis, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + cofinsRate: + type: number + description: | + Alíquota do COFINS (pAliqCofins). + **Automático**: Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + cofinsAmount: + type: number + description: Valor do COFINS (vCofins, tpValor). Campo utilizado para informar o valor do COFINS, porém sem retenção. + cofinsAmountWithheld: + type: number + description: | + Valor retido do COFINS (vCofins, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + csllAmount: + type: number + description: Valor do CSLL (vCSLL, tpValor). Campo utilizado para informar o valor do CSLL, porém sem retenção. + csllRate: + type: number + description: Alíquota do CSLL (pAliqCSLL). + csllAmountWithheld: + type: number + description: | + Valor retido do CSLL (vRetCSLL, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + inssAmountWithheld: + type: number + description: | + Valor retido do INSS (vRetCP, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + issAmountWithheld: + type: number + description: | + Valor retido do ISS (vISSQN). + **Automático**: Se não for informado, o sistema realizará o cálculo automático quando houver retenção de ISS. + ipiRate: + type: number + description: | + SP - Alíquota IPI (pAliqIPI, tpAliquota). + **Automático**: Se não for informado, o sistema utilizará o valor definido no cadastro do código de serviço. + ipiAmount: + type: number + description: | + SP - Valor IPI (vIPI, tpValor). + **Automático**: Se não for informado, o sistema realizará o cálculo automático. + othersAmountWithheld: + type: number + description: Valor de outras retenções (vOutrasRet, tpValor). + additionalInformation: + type: string + description: | + **Informações Adicionais: Simples vs. Estruturado (`additionalInformation` vs. `additionalInformationGroup`)** + + O layout oferece duas formas de enviar informações complementares, visando flexibilidade e completude. + + * **`additionalInformation` (Texto Simples):** + Um campo de `string` para adicionar qualquer observação em formato de texto livre. É ideal para anotações rápidas e genéricas. + + * **`additionalInformationGroup` (Objeto Estruturado):** + Um objeto que organiza dados complementares em campos específicos, como `responsibilityDocumentIdentifier` (ART/RRT), `registrationWork` (Matrícula de Obra), `order` (Pedido), etc. É a forma mais completa e padronizada de enviar esses dados. + + **Comportamento e Relação:** + Para facilitar a integração, o campo `additionalInformation` funciona como um atalho. Se você preencher apenas este campo, seu conteúdo será automaticamente copiado para `additionalInformationGroup.otherInformation`. Isso garante que todas as informações adicionais fiquem consolidadas na estrutura mais completa, mantendo a consistência interna dos dados. + + **Recomendação:** + * Para observações simples, use `additionalInformation`. + * Para dados específicos como ART, Matrícula de Obra, etc., use os campos dedicados dentro de `additionalInformationGroup`. + additionalInformationGroup: + type: object + description: | + **Informações Adicionais: Simples vs. Estruturado (`additionalInformation` vs. `additionalInformationGroup`)** + + O layout oferece duas formas de enviar informações complementares, visando flexibilidade e completude. + + * **`additionalInformation` (Texto Simples):** + Um campo de `string` para adicionar qualquer observação em formato de texto livre. É ideal para anotações rápidas e genéricas. + + * **`additionalInformationGroup` (Objeto Estruturado):** + Um objeto que organiza dados complementares em campos específicos, como `responsibilityDocumentIdentifier` (ART/RRT), `registrationWork` (Matrícula de Obra), `order` (Pedido), etc. É a forma mais completa e padronizada de enviar esses dados. + + **Comportamento e Relação:** + Para facilitar a integração, o campo `additionalInformation` funciona como um atalho. Se você preencher apenas este campo, seu conteúdo será automaticamente copiado para `additionalInformationGroup.otherInformation`. Isso garante que todas as informações adicionais fiquem consolidadas na estrutura mais completa, mantendo a consistência interna dos dados. + + **Recomendação:** + * Para observações simples, use `additionalInformation`. + * Para dados específicos como ART, Matrícula de Obra, etc., use os campos dedicados dentro de `additionalInformationGroup`. + properties: + responsibilityDocumentIdentifier: + type: string + description: "Identificador do documento de responsabilidade técnica (ART, RRT, etc.) (idDocTec)." + referencedDocument: + type: string + description: "Documento de referência relacionado ao serviço prestado (docRef)." + order: + type: string + description: "Número do pedido/ordem de compra/ordem de serviço (xPed)." + items: + type: array + description: "Grupo de itens do pedido/ordem de compra/ordem de serviço (gItemPed)." + items: + type: object + properties: + item: {type: string, description: "Item do pedido/ordem de compra/ordem de serviço (xItemPed)."} + otherInformation: + type: string + description: "Outras informações complementares (xInfComp)." + isEarlyInstallmentPayment: + type: boolean + description: "Indica se é uma nota fiscal de pagamento parcelado antecipado, realizado antes do fornecimento do serviço. (PagamentoParceladoAntecipado, tpNaoSim)" + immunityType: + type: string + description: | + **Tipo de Imunidade (immunityType)** + + O campo `immunityType` é condicional e deve ser utilizado **exclusivamente quando o campo `taxationType` for definido como `Immune`**. + + Sua finalidade é especificar a base legal que fundamenta a imunidade tributária do **ISSQN (Imposto Sobre Serviços de Qualquer Natureza)** para a operação. Cada valor disponível no campo corresponde a uma alínea específica do Artigo 150, Inciso VI, da Constituição Federal, que trata das limitações ao poder de tributar. + + **Relação com a Reforma Tributária (IBS/CBS):** + + É fundamental destacar que este campo se refere **apenas à imunidade do ISSQN**. As regras de imunidade para os novos tributos (IBS e CBS) são tratadas de forma separada, dentro do grupo `ibsCbs`, através de códigos específicos no campo `classCode` (ex: códigos iniciados com `41xxxx`). + + **Em resumo:** + A correta especificação do `immunityType` é essencial para validar a justificativa legal da não incidência do ISSQN na nota fiscal, garantindo a conformidade perante as autoridades fiscais municipais durante o período de transição. + + --- + + Tipo de imunidade (tpImunidade) — usar apenas quando taxationMode = 'immunity'. + Valores possíveis: + - `unspecified`: Imunidade (tipo não informado na nota de origem) + - `PublicEntitiesMutual`: Patrimônio, renda ou serviços, uns dos outros (CF88, Art 150, VI, a) + - `Temples`: Templos de qualquer culto (CF88, Art 150, VI, b) + - `PartiesUnionsEducationSocialNonprofit`: Patrimônio, renda ou serviços dos partidos políticos, inclusive suas fundações, das entidades sindicais dos trabalhadores, das instituições de educação e de assistência social, sem fins lucrativos (CF88, Art 150, VI, c) + - `BooksPressPaper`: Livros, jornais, periódicos e o papel destinado a sua impressão (CF88, Art 150, VI, d) + - `BrazilianMusicPhonograms`: Fonogramas e videofonogramas musicais produzidos no Brasil (CF88, Art 150, VI, e) + enum: [Unspecified, PublicEntitiesMutual, Temples, PartiesUnionsEducationSocialNonprofit, BooksPressPaper, BrazilianMusicPhonograms] + retentionType: + type: string + description: | + **Tipo de Retenção do ISSQN (retentionType)** + + O campo `retentionType` determina quem é o responsável pelo recolhimento do **ISSQN (Imposto Sobre Serviços de Qualquer Natureza)**. Ele é um dos campos mais importantes para a correta apuração do ISSQN, pois define a transferência da responsabilidade de pagamento do imposto do prestador para outra parte na operação. + + **Finalidade e Opções:** + + * **`notWithheld` (Não Retido):** Esta é a situação padrão. O **prestador** do serviço é o responsável por calcular e recolher o ISSQN devido. + * **`withheldByBuyer` (Retido pelo Tomador):** A responsabilidade pelo recolhimento do ISSQN é transferida para o **tomador** (cliente/comprador) do serviço. O valor do ISSQN é descontado do total a ser pago ao prestador, e o tomador fica encarregado de repassá-lo ao município. + * **`withheldByIntermediary` (Retido pelo Intermediário):** Em operações que contam com um intermediário (como marketplaces ou agências), a responsabilidade pelo recolhimento do ISSQN é transferida para este **intermediário**. + + **Comportamento Automático vs. Manual:** + + Conforme a descrição do campo, ele possui uma lógica de prioridade: + 1. **Manual:** Se um valor for explicitamente enviado na requisição, ele será utilizado. + 2. **Automático:** Se o campo não for enviado (nulo), o sistema aplicará as regras de cálculo automáticas (baseadas na legislação, local da prestação e cadastro dos envolvidos) para definir se a retenção é aplicável e quem é o responsável. + + **Relação com a Reforma Tributária (IBS/CBS):** + + Assim como outros campos legados, o `retentionType` aplica-se **exclusivamente ao ISSQN**. As regras de retenção e recolhimento para os novos tributos (IBS e CBS) serão definidas por legislação complementar específica e tratadas em outros campos do layout. + + --- + + Tipo de retenção do ISSQN (tpRetISSQN). + Valores possíveis: + - `NotWithheld`: Não Retido + - `WithheldByBuyer`: Retido pelo Tomador + - `WithheldByIntermediary`: Retido pelo Intermediário + + Define o tipo de retenção. Prioridade: Se um valor for enviado na integração, ele será utilizado. Automático: Se o campo não for enviado (nulo), o sistema aplicará a regra de cálculo automática para definir a retenção. + enum: [NotWithheld, WithheldByBuyer, WithheldByIntermediary] + default: NotWithheld + borrower: + $ref: '#/components/schemas/partyDefinition' + description: | + Tomador dos serviços. + + **Opcional**: o grupo `borrower` pode ser omitido. Quando informado, aplicam-se validações condicionais aos seus campos: + - `name`: se informado, no máximo 115 caracteres; + - `federalTaxNumber`: se informado (diferente de zero), deve ser um CNPJ/CPF válido e coerente com o `type` (`NaturalPerson` → CPF; `LegalEntity` → CNPJ). Para tomador no exterior (`address.country` ≠ `BRA`), não é validado; + - `phoneNumber`: se informado, entre 7 e 20 dígitos; + - `address`: opcional, mas se um endereço **brasileiro** for parcialmente preenchido, passam a ser obrigatórios `postalCode`, `street`, `city.code` (código IBGE de 7 dígitos), `city.name` e `state` (UF de 2 letras), que devem ser consistentes entre si. + intermediary: + $ref: '#/components/schemas/partyDefinition' + description: | + Grupo de informações relativas ao intermediário do serviço (interm). + + **Opcional**: pode ser omitido; envie apenas quando houver intermediário na operação (por exemplo, quando a retenção dos tributos é feita pelo intermediário, `issWithheldIndicator = WithheldByIntermediary`). Quando informado, segue a mesma estrutura do `borrower` (ex.: `type`, `federalTaxNumber`, `name`). + recipient: + $ref: '#/components/schemas/partyDefinition' + description: | + Representa o **Destinatário Final do Serviço**, quando ele é diferente do tomador. Utiliza a estrutura `partyDefinition`. + + **IMPORTANTE**: Quando este objeto for preenchido, é obrigatório informar o valor `DifferentFromBuyer` na propriedade `destinationIndicator` dentro do grupo `ibsCbs`. + location: + $ref: '#/components/schemas/addressDefinition' + description: Local da Prestação do Serviço (cLocPrestacao, cPaisPrestacao) + activityEvent: + $ref: '#/components/schemas/activityEvent' + ReferenceSubstitution: + $ref: '#/components/schemas/ReferenceSubstitution' + lease: + $ref: '#/components/schemas/lease' + construction: + $ref: '#/components/schemas/construction' + realEstate: + $ref: '#/components/schemas/realEstate' + description: "Grupo de informações de operações relacionadas a bens imóveis, exceto obras. (imovel)" + foreignTrade: + $ref: '#/components/schemas/foreignTrade' + deduction: + $ref: '#/components/schemas/deduction' + benefit: + $ref: '#/components/schemas/benefit' + suspension: + $ref: '#/components/schemas/suspension' + serviceAmountDetails: + $ref: '#/components/schemas/serviceAmountDefinitions' + description: "Detalhes dos valores do serviço, incluindo encargos. (RetornoComplementarIBSCBS)" + ibsCbs: + $ref: '#/components/schemas/ibsCbs' + approximateTax: # A descrição foi movida para dentro do schema referenciado para melhor organização. + $ref: '#/components/schemas/approximateTax' + approximateTotals: + $ref: '#/components/schemas/approximateTotals' + + # ========================================================================= + # Definições de Sub-Esquemas + # ========================================================================= + + addressDefinition: + type: object + description: Definição de endereço reutilizável, alinhada com as estruturas nacionais e complementada para endereços no exterior (tpEnderecoExterior, tpEstadoProvinciaRegiao). + properties: + country: {type: string, default: BRA, description: "Sigla do País (padrão ISO 3166-1). Exemplo: BRA, USD, ARG (country do partyDefinition, cPais da NFS-e NAC).", minLength: 3, maxLength: 3} + postalCode: {type: string, description: "CEP (Exemplo: 99999-999) ou Código de Endereçamento Postal no exterior (cEndPost).", minLength: 9, maxLength: 9} + street: {type: string, description: "Logradouro (xLgr, tpLogradouro)"} + number: {type: string, description: "Número (Exemplo: 185 ou S/N) (nro, tpNumeroEndereco)"} + additionalInformation: {type: string, description: "Complemento (Exemplo: BLC A; APT 10) (xCpl, tpComplementoEndereco)"} + district: {type: string, description: "Bairro (xBairro, tpBairro)"} + city: + type: object + description: Cidade + properties: + code: {type: string, description: "Código do IBGE (cMun, tpCidade)", minLength: 7, maxLength: 7} + name: {type: string, description: "Nome da Cidade (tpNomeCidade) - Usado para endereços no exterior."} + state: {type: string, description: "Estado/UF (tpUF) ou Estado, Província, Região no exterior (xEstProvReg, tpEstadoProvinciaRegiao)", minLength: 2, maxLength: 60} + + partyDefinition: + type: object + description: Definição reutilizável para um participante (Tomador, Intermediário, Fornecedor). Baseado em partyDefinition da NFSe Nacional, com campos alinhados aos tipos de São Paulo (tpInformacoesPessoa, gpCPFCNPJNIF). + properties: + type: + type: string + description: | + Tipo do participante. + Valores possíveis: + - `Undefined`: Não definido + - `NaturalPerson`: Pessoa Física + - `LegalEntity`: Pessoa Jurídica + enum: [Undefined, NaturalPerson, LegalEntity] + name: {type: string, description: "Nome / Razão Social (xNome, tpRazaoSocial), obrigatório quando aplicável (tpRazaoSocialObrigatorio)", maxLength: 115} + federalTaxNumber: {type: number, description: "CNPJ, CPF ou NIF (Número de Identificação Fiscal) (tpCNPJ, tpCPF, tpNIF)"} + municipalTaxNumber: {type: string, description: "Inscrição Municipal (tpInscricaoMunicipal, tamanho 8 ou 12 na v2.0 SP)", maxLength: 12} + stateTaxNumber: {type: string, description: "Inscrição Estadual (Opcional, não se aplica a todos) (tpInscricaoEstadual)", maxLength: 19} + taxRegime: + type: string + description: | + Tipo do Regime Tributário. + Valores possíveis: + - `Isento`: Isento + - `MicroempreendedorIndividual`: Microempreendedor Individual (MEI) + - `SimplesNacional`: Simples Nacional + - `LucroPresumido`: Lucro Presumido + - `LucroReal`: Lucro Real + enum: [Isento, MicroempreendedorIndividual, SimplesNacional, LucroPresumido, LucroReal] + caepf: + type: string + description: "Número do Cadastro de Atividade Econômica da Pessoa Física (CAEPF)." + maxLength: 14 + phoneNumber: {type: string, description: "Telefone", minLength: 7, maxLength: 20} + email: {type: string, description: "Endereço eletrônico (email, tpEmail)"} + noTaxIdReason: + type: string + description: | + Justificativa para ausência de NIF (tpNaoNIF, 0 - Não informado na nota de origem, 1 - Dispensado do NIF, 2 - Não exigência do NIF, além dos padrões nacionais). + Valores possíveis: + - `NotInformedOriginal`: Não informado na nota de origem + - `Exempted`: Dispensado do NIF + - `NotRequired`: Não exigência do NIF + enum: [NotInformedOriginal, Exempted, NotRequired] + maxLength: 500 + address: {$ref: '#/components/schemas/addressDefinition'} + + serviceAmountDefinitions: + type: object + description: "Detalhes dos valores do serviço, incluindo encargos. (tpRetornoComplementarIBSCBS)" + properties: + initialChargedAmount: {type: number, description: "Valor Inicial Cobrado (ValorInicialCobrado) - Valor dos serviços antes de tributos, multa e juros. (Versão 2.0 SP)"} + finalChargedAmount: {type: number, description: "Valor Final Cobrado (ValorFinalCobrado) - Valor total cobrado pela prestação do serviço, incluindo todos os tributos. (Versão 2.0 SP)"} + fineAmount: {type: number, description: "Valor da Multa (ValorMulta) (Versão 2.0 SP)"} + interestAmount: {type: number, description: "Valor dos Juros (ValorJuros) (Versão 2.0 SP)"} + + activityEvent: + type: object + description: Detalhes da atividade do evento (atvEvento, tpAtividadeEvento) + properties: + name: {type: string, description: "Nome do evento (xNomeEvt, tpXNomeEvt)"} + beginOn: {type: string, format: date-time, description: "Data de início do evento no formato YYYY-MM-DDTHH:MM:SS.SSSSSS-03:00 (dtiniEvt)"} + endOn: {type: string, format: date-time, description: "Data do fim do evento no formato YYYY-MM-DDTHH:MM:SS.SSSSSS-03:00 (dtFimEvt)"} + Code: {type: string, description: "Código da atividade do evento"} + address: {$ref: '#/components/schemas/addressDefinition', description: "Endereço do evento (end, tpEnderecoSimplesIBSCBS)"} + + approximateTax: + type: object + description: | + Totais aproximados dos tributos (Lei 12.741/2012). (totTrib) - Define os totais aproximados de tributos. **Prioridade**: Se informado, o valor enviado será utilizado, ignorando o cálculo automático. **Automático**: Caso o campo não seja enviado (nulo), os valores serão calculados automaticamente pelo sistema. + + **Estrutura Simplificada vs. Detalhada (`approximateTax` vs. `approximateTotals`)** + + Ambos os campos, `approximateTax` e `approximateTotals`, servem para atender à Lei 12.741/2012 ("Lei De Olho no Imposto"), que exige a informação da carga tributária aproximada na nota fiscal. A principal diferença entre eles está na **granularidade** da informação. + + * **`approximateTax` (Estrutura Simplificada):** + Permite informar a carga tributária de forma consolidada, através de um percentual (`totalRate`) ou valor monetário (`totalAmount`) totais. É ideal para sistemas que não possuem a decomposição dos tributos por esfera governamental. + + * **`approximateTotals` (Estrutura Detalhada):** + Permite um detalhamento completo, separando os valores por esfera: `federal`, `state` e `municipal`. É a escolha ideal quando o sistema possui essa informação decomposta, oferecendo maior transparência. + + **Flexibilidade e Comportamento Automático:** + A coexistência dos dois campos oferece **flexibilidade**. O `approximateTax` simplifica a integração para sistemas com dados consolidados, enquanto o `approximateTotals` atende a sistemas que desejam fornecer o detalhamento completo. O sistema de emissão priorizará a informação mais detalhada, se disponível. + + **Importante:** Se nenhum dos grupos (`approximateTax` ou `approximateTotals`) for preenchido, o sistema realizará o cálculo automático e preencherá o grupo `approximateTax`. + properties: + source: {type: string, description: "Fonte de informação da carga tributária (tpFonteCargaTributaria)"} + version: {type: string} + totalRate: {type: number, description: "Valor percentual da carga tributária (tpPercentualCargaTributaria)"} + totalAmount: {type: number, description: "Valor da carga tributária total em R$ (ValorCargaTributaria, tpValor)"} + + ReferenceSubstitution: + type: object + description: Grupo de informações relativas à NFS-e a ser substituída + additionalProperties: false + properties: + id: {type: string, pattern: '^[0-9]{44}$', description: "Identificador da NFS-e a ser substituída (chSubstda)."} + reason: + type: string + description: | + Motivo da substituição (equivale ao cMotivo). + Valores possíveis: + - `SnOut`: Desenquadramento de NFS-e do Simples Nacional + - `SnIn`: Enquadramento de NFS-e no Simples Nacional + - `ImmunityAddRetro`: Inclusão Retroativa de Imunidade/Isenção para NFS-e + - `ImmunityRemoveRetro`: Exclusão Retroativa de Imunidade/Isenção para NFS-e + - `RejectionBuyerOrIntermediary`: Rejeição de NFS-e pelo tomador ou pelo intermediário se responsável pelo recolhimento do tributo + - `Other`: Outros + enum: [SnOut, SnIn, ImmunityAddRetro, ImmunityRemoveRetro, RejectionBuyerOrIntermediary, Other] + reasonText: {type: string, maxLength: 500, description: "Descrição quando reason = 'other' (equivale ao xMotivo)."} + + lease: + type: object + description: Grupo de informações relativas a atividades de Locação, sublocação, arrendamento, direito de passagem ou permissão de uso, compartilhado ou não, de ferrovia, rodovia, postes, cabos, dutos e condutos de qualquer natureza. + additionalProperties: false + properties: + category: + type: string + description: | + Categoria do serviço (categ). + Valores possíveis: + - `Lease`: Locação + - `Sublease`: Sublocação + - `Leasehold`: Arrendamento + - `RightOfWay`: Direito de passagem + - `UsePermission`: Permissão de uso + enum: [Lease, Sublease, Leasehold, RightOfWay, UsePermission] + objectType: + type: string + description: | + Objeto da locação/sublocação/arrendamento/etc. (objeto). + Valores possíveis: + - `Railway`: Ferrovia + - `Road`: Rodovia + - `Poles`: Postes + - `Cables`: Cabos + - `Pipelines`: Dutos + - `Conduits`: Condutos + enum: [Railway, Road, Poles, Cables, Pipelines, Conduits] + totalLength: {type: number, description: "Comprimento total de ferrovia/rodovia/cabos/dutos/condutos (extensao)."} + polesCount: {type: integer, minimum: 0, description: "Número total de postes (nPostes)."} + + construction: + type: object + description: Grupo de informações relativas à obras de construção civil e congêneres. Apenas uma das opções (workId, cibCode ou siteAddress) deve ser preenchida. (obra) + additionalProperties: false + properties: + propertyFiscalRegistration: {type: string, maxLength: 60, description: "Inscrição imobiliária fiscal (inscImobFisc), exemplos: SQL ou INCRA. (tpinsclmobFisc)"} + workId: + type: object + additionalProperties: false + description: Identificação da obra (CNO/CEI) — cObra. + properties: + scheme: + type: string + description: | + Tipo de cadastro da obra (CNO/CEI). (tpCObra) - Cadastro Nacional de Obras, ou do Cadastro Específico do INSS. + Valores possíveis: + - `bra.cno`: Cadastro Nacional de Obras + - `bra.cei`: Cadastro Específico do INSS + enum: ["bra.cno", "bra.cei"] + value: {type: string, maxLength: 30, description: "Número da obra no cadastro selecionado. (tpCObra, tpNumero)"} + cibCode: {type: string, maxLength: 30, description: "Código do Cadastro Imobiliário Brasileiro (cCIB). (tpCCIB)"} + siteAddress: {$ref: '#/components/schemas/addressDefinition', description: "Endereço da obra (nacional ou exterior). (siteAddress)"} + encapsulationNumber: + type: string + minLength: 1 + maxLength: 12 + pattern: '^[0-9]{1,12}$' + description: | + Número do encapsulamento da obra (NumeroEncapsulamento). String numérica com 1 a 12 dígitos. + Atualmente utilizado apenas pelo serializador do município de São Paulo (Paulistana): quando informado, é emitido como o elemento XML `` nos blocos `` e ``, imediatamente antes de ``. Zeros à esquerda são preservados. (tpNumero: 1-12 dígitos) + example: "123456" + oneOf: + - required: [workId] + - required: [cibCode] + - required: [siteAddress] + + realEstate: + type: object + description: Grupo de informações de operações relacionadas a bens imóveis, exceto obras. Apenas uma das opções (cibCode ou siteAddress) deve ser preenchida. (imovel) + additionalProperties: false + properties: + propertyFiscalRegistration: {type: string, maxLength: 60, description: "Inscrição imobiliária fiscal (inscImobFisc), exemplos: SQL ou INCRA. (tpinsclmobFisc)"} + cibCode: {type: string, maxLength: 30, description: "Código do Cadastro Imobiliário Brasileiro (cCIB). (tpCCIB)"} + siteAddress: {$ref: '#/components/schemas/addressDefinition', description: "Endereço do imóvel (nacional ou exterior). (siteAddress)"} + oneOf: + - required: [cibCode] + - required: [siteAddress] + + foreignTrade: + type: object + description: Grupo de informações sobre transações entre residentes ou domiciliados no Brasil com residentes ou domiciliados no exterior + additionalProperties: false + properties: + serviceMode: + type: string + description: | + Modo de prestação (mdPrestacao). + Valores possíveis: + - `Unknown`: Desconhecido (tipo não informado na nota de origem) + - `CrossBorder`: Transfronteiriço + - `ConsumptionInBrazil`: Consumo no Brasil + - `TemporaryPersonnel`: Movimento Temporário de Pessoas Físicas + - `ConsumptionAbroad`: Consumo no Exterior + enum: [Unknown, CrossBorder, ConsumptionInBrazil, TemporaryPersonnel, ConsumptionAbroad] + default: unknown + relationShip: + type: string + description: | + Vínculo entre as partes (vincPrest). + Valores possíveis: + - `NoLink`: Sem vínculo com o Tomador/Prestador + - `Controlled`: Controlada + - `Controller`: Controladora + - `Affiliate`: Coligada + - `HeadOffice`: Matriz + - `Branch`: Filial ou sucursal + - `OtherLink`: Outro vínculo + enum: [NoLink, Controlled, Controller, Affiliate, HeadOffice, Branch, OtherLink] + default: NoLink + currency: {type: string, pattern: '^[0-9]+$', description: "Moeda da transação (tabela de moedas do Banco Central do Brasil) — tpMoeda."} + serviceAmountInCurrency: {type: number, description: "Valor do serviço na moeda informada em currency — vServMoeda."} + supportMechanismProvider: + type: string + description: | + Mecanismo de apoio/fomento utilizado pelo prestador (mecAFComexP). + Valores possíveis: + - `Unknown`: Desconhecido + - `None`: Nenhum + - `Acc`: ACC - Adiantamento sobre Contrato de Câmbio + - `Ace`: ACE – Adiantamento sobre Cambiais Entregues + - `BndesEximPostShipServices`: BNDES-Exim Pós-Embarque – Serviços + - `BndesEximPreShipServices`: BNDES-Exim Pré-Embarque - Serviços + - `Fge`: FGE - Fundo de Garantia à Exportação + - `ProexEqualization`: PROEX - EQUALIZAÇÃO + - `ProexFinancing`: PROEX - Financiamento + enum: [Unknown, None, Acc, Ace, BndesEximPostShipServices, BndesEximPreShipServices, Fge, ProexEqualization, ProexFinancing] + default: unknown + supportMechanismReceiver: + type: string + description: | + Mecanismo de apoio/fomento utilizado pelo tomador (mecAFComexT). + Valores possíveis: + - `Unknown`: Desconhecido + - `None`: Nenhum + - `PublicAdminAndInternationalRep`: Adm. Pública e Repr. Internacional + - `LeasesMachineryShipsAircraft`: Alugueis e Arrend. Mercantil de maquinas, equip., embarc. e aeronaves + - `AircraftLeaseAirTransportPublic`: Arrendamento Mercantil de aeronave para empresa de transporte aéreo público + - `ExportAgentsCommission`: Comissão a agentes externos na exportação + - `StorageHandlingTransportAbroad`: Despesas de armazenagem, mov. e transporte de carga no exterior + - `FifaEventsSubsidiary`: Eventos FIFA (subsidiária) + - `FifaEvents`: Eventos FIFA + - `FreightsVesselAircraftRentalsOthers`: Fretes, arrendamentos de embarcações ou aeronaves e outros + - `AeronauticalMaterial`: Material Aeronáutico + - `PromotionGoodsAbroad`: Promoção de Bens no Exterior + - `PromotionBrazilianTourism`: Promoção de Dest. Turísticos Brasileiros + - `PromotionBrazilAbroad`: Promoção do Brasil no Exterior + - `PromotionServicesAbroad`: Promoção Serviços no Exterior + - `Recine`: RECINE + - `Recopa`: RECOPA + - `TrademarksPatentsCultivars`: Registro e Manutenção de marcas, patentes e cultivares + - `Reicomp`: REICOMP + - `Reidi`: REIDI + - `Repenec`: REPENEC + - `Repes`: REPES + - `Retaero`: RETAERO + - `Retid`: RETID + - `RoyaltiesTechnicalAssistance`: Royalties, Assistência Técnica, Científica e Assemelhados + - `ConformityAssessmentWto`: Serviços de avaliação da conformidade vinculados aos Acordos da OMC + - `Zpe`: ZPE + enum: [Unknown, None, PublicAdminAndInternationalRep, LeasesMachineryShipsAircraft, AircraftLeaseAirTransportPublic, ExportAgentsCommission, StorageHandlingTransportAbroad, FifaEventsSubsidiary, FifaEvents, FreightsVesselAircraftRentalsOthers, AeronauticalMaterial, PromotionGoodsAbroad, PromotionBrazilianTourism, PromotionBrazilAbroad, PromotionServicesAbroad, Recine, Recopa, TrademarksPatentsCultivars, Reicomp, Reidi, Repenec, Repes, Retaero, Retid, RoyaltiesTechnicalAssistance, ConformityAssessmentWto, Zpe] + default: unknown + temporaryGoods: + type: string + description: | + Vínculo à movimentação temporária de bens (movTempBens). + Valores possíveis: + - `Unknown`: Desconhecido + - `No`: Não + - `LinkedImportDeclaration`: Vinculada - Declaração de Importação + - `LinkedExportDeclaration`: Vinculada - Declaração de Exportação + enum: [Unknown, No, LinkedImportDeclaration, LinkedExportDeclaration] + importDeclaration: {type: string, maxLength: 60, description: "Número da Declaração de Importação (DI/DSI/DA/DRI-E) averbado — nDI."} + exportRegistration: {type: string, maxLength: 60, description: "Número do Registro de Exportação (RE) averbado — nRE."} + mdicDelivery: {type: boolean, description: "Indicador de envio da NFS-e ao MDIC (mdic)."} + + deduction: + type: object + description: | + Grupo de informações relativas ao valores para dedução/redução do valor da base de cálculo (vDedRed). Dedução/Redução aplicada SOMENTE à base de cálculo do ISSQN. + + **Deduções: Simples vs. Estruturado (`deductionsAmount` vs. `deduction`)** + + O layout oferece duas formas de registrar deduções da base de cálculo do ISSQN, visando flexibilidade e conformidade com os diferentes padrões (municipal legado vs. nacional). + + * **`deductionsAmount` (Valor Simples):** + Um campo numérico para informar o **valor total consolidado** das deduções. É uma abordagem direta, compatível com layouts mais antigos que não exigem o detalhamento dos documentos que comprovam a dedução. + + * **`deduction` (Grupo Estruturado):** + Um objeto complexo que permite justificar cada dedução com base em documentos fiscais, alinhando-se ao **padrão da NFS-e Nacional**. Ele detalha a origem de cada valor (chave do documento, tipo, valor, fornecedor). + + **Relação e Recomendação:** + A coexistência dos campos oferece compatibilidade. `deductionsAmount` é uma opção simplificada, enquanto o grupo `deduction` é a forma mais completa e recomendada para garantir rastreabilidade e conformidade fiscal com o padrão nacional. O sistema de emissão priorizará os dados detalhados do grupo `deduction`, se fornecidos. + + **Recomendação de Uso:** + * Use `deductionsAmount` para integrações simples ou quando não há detalhamento dos documentos. + * Use o grupo `deduction` sempre que a informação detalhada dos documentos estiver disponível para garantir a máxima conformidade. + oneOf: + - required: [rate] + - required: [amount] + - required: [documents] + properties: + rate: {type: number, description: "Percentual padrão de dedução/redução (pDR, %)."} + amount: {type: number, description: "Valor monetário padrão de dedução/redução (vDR, R$)."} + documents: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/deductionDocument' + + deductionDocument: + type: object + additionalProperties: false + description: | + Documento base que justifica um item de dedução/redução (docDedRed, TCDocDedRed). + Pelo menos **um** identificador deve ser preenchido — `nfseKey`, `nfeKey`, + `municipalNfse`, `fiscalDocumentNumber` ou `nonFiscalDocumentNumber`. Se mais + de um for enviado, o backend aplica a precedência nessa ordem. Quando + `deductionType = Other`, o campo `otherDeductionDescription` passa a ser obrigatório. + required: [deductionType, issueDate, deductibleTotal, usedAmount] + oneOf: + - properties: + deductionType: + type: string + enum: [Other] + required: [otherDeductionDescription] + - properties: + deductionType: + not: + enum: [Other] + anyOf: + - required: [nfseKey] + - required: [nfeKey] + - required: [municipalNfse] + - required: [fiscalDocumentNumber] + - required: [nonFiscalDocumentNumber] + properties: + nfseKey: {type: string, pattern: '^[0-9]{50}$', description: "Chave de acesso da NFS-e nacional, exatamente 50 dígitos (chNFSe, TSChaveNFSe)."} + nfeKey: {type: string, pattern: '^[0-9]{44}$', description: "Chave de acesso da NF-e (produto), exatamente 44 dígitos (chNFe)."} + municipalNfse: + type: object + additionalProperties: false + description: Referência a uma NFS-e municipal no padrão legado (NFSeMun). + required: [cityCode, number, verificationCode] + properties: + cityCode: {type: string, description: "Código IBGE do município emissor (cMunNFSeMun)."} + number: {type: string, maxLength: 15, description: "Número da NFS-e municipal (nNFSeMun)."} + verificationCode: {type: string, maxLength: 9, description: "Código de verificação (cVerifNFSeMun)."} + fiscalDocumentNumber: {type: string, maxLength: 255, description: "Identificador de outro documento fiscal não eletrônico (nDocFisc)."} + nonFiscalDocumentNumber: {type: string, maxLength: 255, description: "Identificador de documento não fiscal, ex: nota de débito interna (nDoc)."} + deductionType: + type: string + description: | + Tipo da dedução/redução (tpDedRed). + Valores aceitos (nome do enum — código numérico — descrição): + - `FoodAndBeverages` (1): Alimentação e bebidas/frigobar + - `Materials` (2): Materiais + - `ConsortiumPassThrough` (5): Repasse consorciado + - `HealthPlanPassThrough` (6): Repasse plano de saúde + - `Services` (7): Serviços + - `Subcontracting` (8): Subempreitada de mão de obra + - `Other` (99): Outras deduções — exige `otherDeductionDescription` + enum: [FoodAndBeverages, Materials, ConsortiumPassThrough, HealthPlanPassThrough, Services, Subcontracting, Other] + otherDeductionDescription: {type: string, maxLength: 150, description: "Obrigatório quando deductionType = 'Other' (xDescOutDed)."} + issueDate: {type: string, format: date, description: "Data de emissão do documento de origem (dtEmiDoc, AAAA-MM-DD)."} + deductibleTotal: {type: number, description: "Valor total dedutível/redutível no documento de origem (vDedutivelRedutivel)."} + usedAmount: {type: number, description: "Valor efetivamente utilizado como dedução nesta NFS-e (vDeducaoReducao). Deve ser ≤ deductibleTotal."} + supplier: {$ref: '#/components/schemas/partyDefinition', description: "Fornecedor do documento (fornec)."} + + benefit: + type: object + description: Benefício Municipal aplicado à base de cálculo do ISSQN (BM). + additionalProperties: false + required: [id] + oneOf: + - required: [amount] + - required: [rate] + properties: + id: {type: string, pattern: '^\d{14}$', description: "Identificador do benefício (nBM: IBGE[7] + tipo[2] + seq[5])."} + amount: {type: number, description: "Redução da BC por valor (vRedBCBM, R$)."} + rate: {type: number, description: "Redução da BC por percentual (pRedBCBM, %)."} + + suspension: + type: object + description: Suspensão da exigibilidade do ISSQN (exigSusp). + additionalProperties: false + required: [reason, processNumber] + properties: + reason: + type: string + description: | + Motivo da suspensão (tpSusp). + Valores possíveis: + - `Judicial`: Exigibilidade Suspensa por Decisão Judicial + - `Administrative`: Exigibilidade Suspensa por Processo Administrativo + enum: [Judicial, Administrative] + processNumber: {type: string, maxLength: 30, description: "Número do processo (nProcesso)."} + + approximateTotals: + type: object + additionalProperties: false + description: | + Totais aproximados dos tributos (Lei 12.741/2012). (totTrib) - Define os totais aproximados de tributos. **Prioridade**: Se informado, o valor enviado será utilizado, ignorando o cálculo automático. **Automático**: Caso o campo não seja enviado (nulo), os valores serão calculados automaticamente pelo sistema. + + **Estrutura Simplificada vs. Detalhada (`approximateTax` vs. `approximateTotals`)** + + Ambos os campos, `approximateTax` e `approximateTotals`, servem para atender à Lei 12.741/2012 ("Lei De Olho no Imposto"), que exige a informação da carga tributária aproximada na nota fiscal. A principal diferença entre eles está na **granularidade** da informação. + + * **`approximateTax` (Estrutura Simplificada):** + Permite informar a carga tributária de forma consolidada, através de um percentual (`totalRate`) ou valor monetário (`totalAmount`) totais. É ideal para sistemas que não possuem a decomposição dos tributos por esfera governamental. + + * **`approximateTotals` (Estrutura Detalhada):** + Permite um detalhamento completo, separando os valores por esfera: `federal`, `state` e `municipal`. É a escolha ideal quando o sistema possui essa informação decomposta, oferecendo maior transparência. + + **Flexibilidade e Comportamento Automático:** + A coexistência dos dois campos oferece **flexibilidade**. O `approximateTax` simplifica a integração para sistemas com dados consolidados, enquanto o `approximateTotals` atende a sistemas mais robustos que desejam fornecer o detalhamento completo. O sistema de emissão priorizará a informação mais detalhada, se disponível. + + **Importante:** Se nenhum dos grupos (`approximateTax` ou `approximateTotals`) for preenchido, o sistema realizará o cálculo automático e preencherá o grupo `approximateTax`. + properties: + federal: + type: object + additionalProperties: false + description: Tributos federais. + properties: + rate: {type: number, minimum: 0, description: "Valor percentual total aproximado dos tributos federais (%). (pTotTribFed)"} + amount: {type: number, minimum: 0, description: "Valor monetário total aproximado dos tributos federais (R$). (vTotTribFed)"} + state: + type: object + additionalProperties: false + description: Tributos estaduais. + properties: + rate: {type: number, minimum: 0, description: "Valor percentual total aproximado dos tributos estaduais (%). (vTotTribEst)"} + amount: {type: number, minimum: 0, description: "Valor monetário total aproximado dos tributos estaduais (R$). (vTotTribEst)"} + municipal: + type: object + additionalProperties: false + description: Tributos municipais. + properties: + rate: {type: number, minimum: 0, description: "Valor percentual total aproximado dos tributos municipais (%). (pTotTribMun)"} + amount: {type: number, minimum: 0, description: "Valor monetário total aproximado dos tributos municipais (R$). (vTotTribMun)"} + rate: {type: number, minimum: 0, description: "Valor percentual total aproximado dos tributos (%)."} + amount: {type: number, minimum: 0, description: "Valor monetário total aproximado dos tributos (R$)."} + + ibsCbs: + type: object + additionalProperties: false + description: Informações referentes ao IBS e à CBS por item (NFSe/infNFSe/DPS/infDPS/IBSCBS). (tpIBSCBS) + required: [classCode, operationIndicator] + properties: + purpose: + type: string + description: | + Finalidade da emissão da NFS-e (finNFe). (tpfinNFSe) - default: 'regular'. + Valores possíveis: + - `regular`: Regular + enum: [regular] + default: "regular" + destinationIndicator: + type: string + description: | + Relação entre destinatário e comprador/tomador indicado na NFS-e (indDest). (tpindDest) - default: 'sameAsBuyer'. Quando o valor for 'differentFromBuyer', o preenchimento do objeto 'recipient' se torna obrigatório. + Valores possíveis: + - `SameAsBuyer`: O destinatário é o mesmo que o comprador/tomador + - `DifferentFromBuyer`: O destinatário é diferente do comprador/tomador + enum: [SameAsBuyer, DifferentFromBuyer] + default: "SameAsBuyer" + basis: {type: number, description: "Base de cálculo antes de reduções para cálculo do tributo bruto (vBC)."} + reimbursedResuppliedAmount: {type: number, description: "Montante relativo a reembolso/repasse/ressarcimento não integrante da BC (vReembRepasse)."} + ibscbsDeductionReductionAmount: + type: number + description: "Valor monetário (R$) total relativo aos valores de dedução e redução da Base de Cálculo do IBS e da CBS referentes às operações de locação, cessão onerosa ou arrendamento de bens imóveis, e serviços médicos (vCalcDedRedIBSCBS)." + isDonation: + type: boolean + nullable: true + description: "Indica se a operação é uma doação (indDoacao). (tpNaoSim)" + personalUse: + type: + - boolean + - 'null' + description: "**Indicador de Uso ou Consumo Pessoal**\n\nIndica se a operação é para uso ou consumo pessoal do adquirente. Este campo é crucial para a aplicação de regras tributárias específicas, como a não geração de crédito de IBS/CBS para o tomador. (indFinal)" + operationIndicator: + type: string + description: | + **Indicador da Operação (operationIndicator / cIndOp)** + + O campo `operationIndicator` (ou `cIndOp` nos schemas XSD) é um código obrigatório que define a natureza e a característica da operação de fornecimento do serviço ou bem, sendo um dos campos mais importantes introduzidos pela Reforma Tributária. + + Sua principal finalidade é determinar o **local de incidência** (onde o imposto é devido) para os novos tributos, o IBS (Imposto sobre Bens e Serviços) e a CBS (Contribuição sobre Bens e Serviços). Diferente do modelo anterior, onde o local da prestação era muitas vezes suficiente, este código traz uma regra específica para cada tipo de operação. + + **Como funciona?** + + Com base no código informado, o sistema tributário nacional identifica se o imposto deve ser recolhido: + * No município onde um imóvel está localizado (para serviços de construção ou sobre imóveis). + * No endereço do estabelecimento do fornecedor. + * No endereço do adquirente (comprador/tomador) do serviço. + * No local onde um evento ocorre. + * Entre outras regras específicas. + + A escolha do código correto é, portanto, fundamental para garantir a conformidade fiscal e o recolhimento do IBS para o estado e município corretos. A seleção de um código inadequado pode levar a apurações de impostos incorretas. + + **Exemplo prático:** + Para um serviço de reforma de um imóvel (`código 020201`), o imposto será devido no município onde o imóvel está localizado, independentemente de onde o prestador ou o tomador do serviço estejam estabelecidos. Já para um serviço de consultoria prestado à distância (`código 100301`), a regra geral aponta para o domicílio do adquirente. + + A lista completa de valores pode ser consultada na Tabela de [operationIndicator](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/documentacao-layout-nfse-rtc/#tabela-de-operationindicator) da documentação funcional. + minLength: 6 + maxLength: 6 + pattern: '^[0-9]{6}$' + operationType: + type: string + description: | + Tipo de Operação com Entes Governamentais ou outros serviços sobre bens imóveis (tpOper). + Valores possíveis: + - `SupplyFirstPayLater`: Fornecimento com pagamento posterior + - `PayForPastSupply`: Recebimento do pagamento com fornecimento já realizado + - `SupplyForPastPay`: Fornecimento com pagamento já realizado + - `PayFirstSupplyLater`: Recebimento do pagamento com fornecimento posterior + - `SupplyPayTogether`: Fornecimento e recebimento do pagamento concomitantes + enum: + - SupplyFirstPayLater + - PayForPastSupply + - SupplyForPastPay + - PayFirstSupplyLater + - SupplyPayTogether + situationCode: + type: string + description: | + Código de Situação Tributária do IBS/CBS. Opcional. + Quando não preenchido, o valor será obtido através dos 3 primeiros caracteres do valor informado no campo `classCode`. + A lista completa de valores pode ser consultada na Tabela de [situationCode](hhttps://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/documentacao-layout-nfse-rtc/#tabela-de-situationcode) da documentação funcional. + classCode: + type: string + maxLength: 6 + description: | + Código de Classificação Tributária do IBS/CBS. (cClassTrib, tpClassificacaoTributaria) + A lista completa de valores pode ser consultada na Tabela de [classCode](https://nfe.io/docs/documentacao/reforma-tributaria/conceitos-funcionais/documentacao-layout-nfse-rtc/#tabela-de-classcode) da documentação funcional. + relatedDocs: + type: object + description: "Grupo de NFS-e referenciadas (gRefNFSe)." + properties: + items: + type: array + description: "Chaves de NFS-e referenciadas (refNFSe)." + items: + type: string + maxLength: 50 + maxItems: 99 + leasedMovableAssets: + type: array + minItems: 0 + maxItems: 99 + description: "Grupo de informações relativas aos bens móveis objetos de locação (gLocBensMoveis). Grupo só é admitido quando se tratar de locação de bens móveis. cTribNac = 99.04.01." + items: + type: object + properties: + ncmCode: + type: string + maxLength: 8 + description: "Código da Nomenclatura Comum do Mercosul (NCM) do bem móvel objeto da locação (cNCMBemMovel)." + description: + type: string + maxLength: 150 + description: "Descrição do Bem Móvel objeto da locação (xNCMBemMovel)." + quantity: + type: integer + description: "Quantidade do Bem Móvel objeto da locação (qtdNCMBemMovel)." + ibs: + type: object + additionalProperties: false + description: Alíquotas e total do IBS por esfera subnacional. + required: [totalAmount, state, municipal] + properties: + totalAmount: {type: number, description: "Total do IBS (vIBSTot = vIBSUF + vIBSMun)."} + state: + type: object + additionalProperties: false + required: [rate, effectiveRate] + properties: + rate: {type: number, description: "Alíquota IBS (UF) (%) (pAliqIBSUF)."} + rateReduction: {type: number, description: "Redução de alíquota estadual (%).", default: 0} + effectiveRate: {type: number, description: "pAliqEfetUF = rate × (1 − rateReduction). Se rateReduction ausente, usar rate."} + deferment: + type: object + additionalProperties: false + description: Deferimento do IBS na esfera estadual. + properties: + rate: {type: number, description: "Percentual de diferimento (pDif, %)."} + amount: {type: number, multipleOf: 0.01, description: "Valor do diferimento (vDif)."} + returnedAmount: {type: number, multipleOf: 0.01, description: "Valor de imposto devolvido/devolução (vDevTrib) na esfera estadual."} + amount: {type: number, multipleOf: 0.01, description: "Valor do IBS da UF (vIBSUF)."} + municipal: + type: object + additionalProperties: false + required: [rate, effectiveRate] + properties: + rate: {type: number, description: "Alíquota IBS (Município) (%) (pAliqIBSMun)."} + rateReduction: {type: number, description: "Redução de alíquota municipal (%).", default: 0} + effectiveRate: {type: number, description: "pAliqEfetMun = rate × (1 − rateReduction). Se rateReduction ausente, usar rate."} + deferment: + type: object + additionalProperties: false + description: Deferimento do IBS na esfera municipal. + properties: + rate: {type: number, description: "Percentual de diferimento (pDif, %)."} + amount: {type: number, multipleOf: 0.01, description: "Valor do diferimento (vDif)."} + returnedAmount: {type: number, multipleOf: 0.01, description: "Valor de imposto devolvido/devolução (vDevTrib) na esfera municipal."} + amount: {type: number, multipleOf: 0.01, description: "Valor do IBS do Município (vIBSMun)."} + cbs: + type: object + additionalProperties: false + description: Alíquotas da CBS (esfera federal). + required: [rate, effectiveRate] + properties: + rate: {type: number, description: "Alíquota da CBS (%) (pAliqCBS)."} + rateReduction: {type: number, description: "Redução de alíquota da CBS (%).", default: 0} + effectiveRate: {type: number, description: "pAliqEfetCBS = rate × (1 − rateReduction). Se rateReduction ausente, usar rate."} + deferment: + type: object + additionalProperties: false + description: Deferimento da CBS. + properties: + rate: {type: number, description: "Percentual de diferimento (pDif, %)."} + amount: {type: number, multipleOf: 0.01, description: "Valor do diferimento (vDif)."} + returnedAmount: {type: number, multipleOf: 0.01, description: "Valor de imposto devolvido/devolução da CBS (vDevTrib)."} + amount: {type: number, multipleOf: 0.01, description: "Valor total da CBS (vCBS)."} + regularTaxation: + type: object + additionalProperties: false + description: Tributação regular hipotética caso condição resolutória/suspensiva não se aplique. (tpGTribRegular) + properties: + situationCode: {type: string, description: "CST regular (CSTReg), 3 dígitos."} + classCode: {type: string, description: "Classificação tributária regular (cClassTribReg), 6 dígitos."} + ibs: + type: object + additionalProperties: false + properties: + totalAmount: {type: number, description: "Total do IBS (vIBSTotReg)."} + state: + type: object + additionalProperties: false + properties: + effectiveRate: {type: number, description: "Alíquota efetiva IBS UF (pAliqEfetRegIBSUF)."} + amount: {type: number, multipleOf: 0.01, description: "IBS UF regular (vTribRegIBSUF)."} + municipal: + type: object + additionalProperties: false + properties: + effectiveRate: {type: number, description: "Alíquota efetiva IBS Município (pAliqEfetRegIBSMun)."} + amount: {type: number, multipleOf: 0.01, description: "IBS Município regular (vTribRegIBSMun)."} + cbs: + type: object + additionalProperties: false + properties: + effectiveRate: {type: number, description: "Alíquota efetiva CBS (pAliqEfetRegCBS)."} + amount: {type: number, multipleOf: 0.01, description: "CBS regular (vTribRegCBS)."} + presumedCredits: + type: object + additionalProperties: false + description: Créditos presumidos de IBS e CBS quando aplicáveis. + properties: + ibs: + type: object + additionalProperties: false + properties: + code: {type: string, pattern: '^\d{2}$', description: "Código do crédito presumido IBS (cCredPres)."} + rate: {type: number, description: "Percentual do crédito presumido IBS (pCredPres)."} + amount: {type: number, multipleOf: 0.01, description: "Valor do crédito presumido IBS (vCredPres)."} + conditionalAmount: {type: number, multipleOf: 0.01, description: "Valor do crédito presumido IBS sob condição suspensiva (vCredPresCondSus)."} + cbs: + type: object + additionalProperties: false + properties: + code: {type: string, pattern: '^\d{2}$', description: "Código do crédito presumido CBS (cCredPres)."} + rate: {type: number, description: "Percentual do crédito presumido CBS (pCredPres)."} + amount: {type: number, multipleOf: 0.01, description: "Valor do crédito presumido CBS (vCredPres)."} + conditionalAmount: {type: number, multipleOf: 0.01, description: "Valor do crédito presumido CBS sob condição suspensiva (vCredPresCondSus)."} + governmentPurchase: + type: object + additionalProperties: false + description: Composição do valor de IBS e CBS em compras governamentais. + properties: + entityType: + type: string + description: | + Tipo do ente da compra governamental (tpEnteGov). + Valores possíveis: + - `Union`: União + - `State`: Estado + - `FederalDistrict`: Distrito Federal + - `Municipality`: Município + enum: ["Union", "State", "FederalDistrict", "Municipality"] + operationType: + type: string + description: | + Tipo de Operação com Entes Governamentais (tpOperGov). + Valores possíveis: + - `SupplyFirstPayLater`: Fornecimento com pagamento posterior + - `PayForPastSupply`: Pagamento de fornecimento anterior + - `SupplyForPastPay`: Fornecimento com pagamento antecipado + - `SupplyPayTogether`: Fornecimento e pagamento concomitantes + enum: [SupplyFirstPayLater, PayForPastSupply, SupplyForPastPay, SupplyPayTogether] + ibs: + type: object + additionalProperties: false + properties: + totalAmount: {type: number, description: "Total do IBS em compras governamentais (vIBSTotGov)."} + state: + type: object + additionalProperties: false + properties: + rate: {type: number, description: "Alíquota IBS UF em compras governamentais (pAliqIBSUF)."} + amount: {type: number, multipleOf: 0.01, description: "Valor IBS UF em compras governamentais (vTribIBSUF)."} + municipal: + type: object + additionalProperties: false + properties: + rate: {type: number, description: "Alíquota IBS Município em compras governamentais (pAliqIBSMun)."} + amount: {type: number, multipleOf: 0.01, description: "Valor IBS Município em compras governamentais (vTribIBSMun)."} + cbs: + type: object + additionalProperties: false + properties: + rate: {type: number, description: "Alíquota CBS em compras governamentais (pAliqCBS)."} + amount: {type: number, multipleOf: 0.01, description: "Valor CBS em compras governamentais (vTribCBS)."} + creditTransfer: + type: object + additionalProperties: false + description: Transferência de créditos de IBS e CBS. + properties: + ibsAmount: {type: number, multipleOf: 0.01, description: "Valor de IBS a transferir (vIBS)."} + cbsAmount: {type: number, multipleOf: 0.01, description: "Valor de CBS a transferir (vCBS)."} + thirdPartyReimbursements: + type: object + additionalProperties: false + description: Valores de reembolso/repasse/ressarcimento já tributados e aqui referenciados. (tpGrupoReeRepRes) + properties: + documents: + type: array + minItems: 1 + maxItems: 1000 + items: + $ref: '#/components/schemas/thirdPartyReimbursementDocument' + + thirdPartyReimbursementDocument: + type: object + additionalProperties: false + description: Documento utilizado para justificar exclusão da BC de IBS/CBS/ISS. (tpDocumento) + required: [issueDate, accrualOn, reimbursementType, amount] + anyOf: + - required: [nfseKey] + - required: [nfeKey] + - required: [cteKey] + - required: [otherNationalDfe] + - required: [otherFiscalDoc] + - required: [otherDoc] + properties: + nfseKey: {type: string, maxLength: 50, description: "Chave NFS-e (padrão nacional)."} + nfeKey: {type: string, pattern: '^[0-9]{44}$', description: "Chave NF-e (44 dígitos)."} + cteKey: {type: string, pattern: '^[0-9]{44}$', description: "Chave CT-e (44 dígitos)."} + otherNationalDfe: + type: object + additionalProperties: false + description: Outro DF-e presente no repositório nacional. (tpDFeNacional) + required: [dfeKey, dfeTypeText] + properties: + dfeKey: {type: string, maxLength: 50, description: "Chave do DF-e (chDFE)."} + dfeTypeText: {type: string, maxLength: 255, description: "Tipo do DF-e (xTpDFE, xTipoChaveDFe)."} + dfeType: {type: string, maxLength: 1, description: "Documento fiscal a que se refere a chaveDfe (tipoChaveDFE, tpTipoChaveDFE)."} + otherFiscalDoc: + type: object + additionalProperties: false + description: Documento fiscal que não está no repositório nacional (eletrônico ou não). (tpDocFiscalOutro) + required: [issuerCityCode, fiscalDocNumber] + properties: + issuerCityCode: {type: string, description: "Código IBGE do município emissor do documento fiscal (cMunEmiDocFisc). (cMunDocFiscal)"} + fiscalDocNumber: {type: string, maxLength: 255, description: "Número do documento fiscal (nDocFisc). (nDocFiscal, tpNumeroDescricaoDocumento)"} + fiscalDocDescription: {type: string, maxLength: 255, description: "Descrição do documento fiscal (xDocFisc). (xDocFiscal, tpNumeroDescricaoDocumento)"} + otherDoc: + type: object + additionalProperties: false + description: Documento não fiscal. (tpDocOutro) + required: [docNumber, docDescription] + properties: + docNumber: {type: string, maxLength: 255, description: "Número do documento (nDoc). (nDoc, tpNumeroDescricaoDocumento)"} + docDescription: {type: string, maxLength: 255, description: "Descrição do documento (xDoc). (xDoc, tpNumeroDescricaoDocumento)"} + supplier: {$ref: '#/components/schemas/partyDefinition', description: "Fornecedor/emitente do documento referenciado (quando aplicável). (fornec, tpFornecedor)"} + issueDate: {type: string, format: date, description: "Data de emissão (AAAA-MM-DD) (dtEmiDoc)."} + accrualOn: {type: string, format: date, description: "Data de competência (AAAA-MM-DD) (dtCompDoc)."} + reimbursementType: + type: string + description: | + Motivo do reembolso/repasse/ressarcimento (tpReemb). (tpReeRepRes) + Valores possíveis: + - `RealEstateBrokerPassThrough`: Repasse de corretagem de imóveis + - `TravelAgencySupplierPassThrough`: Repasse de valores de fornecedores em agência de viagens + - `AdAgencyExternalProductionReimbursement`: Reembolso de produção externa em agência de publicidade + - `AdAgencyMediaReimbursement`: Reembolso de despesas com mídia em agência de publicidade + - `OtherReimbursement`: Outros reembolsos ou ressarcimentos + enum: [RealEstateBrokerPassThrough, TravelAgencySupplierPassThrough, AdAgencyExternalProductionReimbursement, AdAgencyMediaReimbursement, OtherReimbursement] + reimbursementTypeText: {type: string, maxLength: 150, description: "Obrigatório quando reimbursementType = 'otherReimbursement' (xReembOutros). (tpXTpReeRepRes)"} + amount: {type: number, description: "Valor considerado para exclusão da BC (total ou parcial, R$) (vReemb). (vlrReembRepasse)"} diff --git a/openspec/CHANGESET-OVERVIEW.md b/openspec/CHANGESET-OVERVIEW.md new file mode 100644 index 0000000..e41aee1 --- /dev/null +++ b/openspec/CHANGESET-OVERVIEW.md @@ -0,0 +1,94 @@ +# Visão geral do changeset — SDK Ruby NFE.io v1 + +## Introdução + +O SDK Ruby da NFE.io (gem `nfe-io`) está passando por uma **reescrita greenfield v1** (bump `0.3.2 → 1.0.0`). A v0.3.2 — baseada em `rest-client`, escrita para Ruby 2.4 e anos sem manutenção — é congelada num snapshot na branch `0.x-legacy` (quem precisar fixa `gem "nfe-io", "~> 0.3"`); a v1 nasce limpa em `master`, sem reaproveitar nada do código legado. + +Princípios da v1: + +- **Greenfield**: `lib/nfe/` nasce vazio; quebra total de compatibilidade documentada em `MIGRATION.md`. +- **Zero dependências de runtime**: apenas stdlib (`net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`). As deps de dev (RSpec, RuboCop, RBS, Steep, SimpleCov) e de codegen nunca entram no pacote publicado. +- **Paridade-plus com Node/PHP**: mesma superfície de 17 recursos dos SDKs de referência (`nfe-io` Node, `nfe/client-php`), com extensões (emissão de NFC-e, upload de certificado) e ergonomia estilo Stripe (`Nfe::Client.new(api_key:)` + acessores de recurso lazy `snake_case`), mas em Ruby idiomático (`Data.define`, keyword args, retorno síncrono, erros tipados via `raise`). +- **Rigor de tipos**: assinaturas RBS em `sig/`, type-check com Steep, lint com RuboCop, cobertura SimpleCov ≥ 80%, CI matrix Ruby 3.2/3.3/3.4. +- **Modelos gerados de OpenAPI**: DTOs `Data.define` imutáveis gerados a partir dos specs sincronizados do `nfeio-docs` (fonte da verdade), separados da camada de DX feita à mão. + +A v1 é entregue em **9 changes** que formam um grafo de dependências: uma fundação, três camadas de infraestrutura, um núcleo de DX, quatro famílias de recurso e um fechamento de release. + +## Tabela de changes + +| Change | Capabilities (novas) | Depende de | Escopo (uma linha) | +|---|---|---|---| +| `add-ruby-foundation` | `sdk-foundation` | — (foundational) | Gem `nfe-io` 1.0.0, namespace `Nfe`, piso Ruby 3.2, zero-dep de runtime, RBS/Steep/RuboCop/RSpec e CI matrix 3.2/3.3/3.4. | +| `add-http-transport` | `http-transport` | `add-ruby-foundation` | Camada HTTP zero-dep sobre `Net::HTTP`: request/response, retry com backoff+jitter, multi-base-URL, erros tipados + `ErrorFactory`, logger com redação. | +| `add-openapi-pipeline` | `openapi-pipeline` | `add-ruby-foundation` | Codegen Ruby (stdlib+dev-only) que lê specs OpenAPI sincronizados do `nfeio-docs` e emite `Data.define` + `.rbs`, com banner anti-edição e guarda de sincronia em CI. | +| `add-client-core` | `client-core` | `add-ruby-foundation`, `add-http-transport`, `add-openapi-pipeline` | Núcleo de DX: `Nfe::Client`, `Configuration` + host map fonte-única, `AbstractResource`, contrato 202 (`Pending`/`Issued`), `FlowStatus`, `IdValidator`, paginação e os 17 acessores lazy stub. | +| `add-entity-resources` | `entity-resources`, `webhook-signature-verification` | `add-client-core` | 4 recursos de entidade no host `api.nfe.io` — companies (+ upload de certificado PKCS#12), legal_people, natural_people, webhooks — mais verificação HMAC-SHA1 (`X-Hub-Signature`). | +| `add-invoice-resources` | `invoice-resources` | `add-client-core` | 5 recursos de invoice — service (NFS-e), product (NF-e), consumer (NFC-e, paridade-plus), transportation (CT-e inbound), inbound-product — exercitando o contrato 202 e o multi-host. | +| `add-lookup-resources` | `lookup-resources` | `add-client-core` | 8 recursos de lookup/consulta/dados auxiliares — addresses, legal_entity_lookup, natural_person_lookup, product/consumer_invoice_query, tax_calculation, tax_codes, state_taxes — principal exercitador do host map. | +| `add-rtc-invoice-emission` | `rtc-invoice-emission` | `add-client-core`, `add-invoice-resources`, `add-openapi-pipeline` | Recursos aditivos opt-in para emissão no layout RTC: `service_invoices_rtc` (NFS-e, grupo `ibsCbs` IBS/CBS, + XML do evento de cancelamento no Ambiente Nacional) e `product_invoices_rtc` (NF-e modelo 55 + NFC-e modelo 65, grupos item-level `IBSCBS` IBS estadual/municipal + CBS + `IS`/Imposto Seletivo). | +| `add-release-tooling` | `release-tooling` | todas as 8 anteriores | Fecha a v1.0.0: gemspec moderno, versão fonte-única, CHANGELOG/MIGRATION/README/CONTRIBUTING (pt-BR), samples, workflow de release (CI gate + RubyGems OIDC) e skill de IA `nfeio-ruby-sdk`. | + +Notas: + +- `add-entity-resources`, `add-invoice-resources` e `add-lookup-resources` dependem **só** de `add-client-core` e não compartilham arquivos entre si — podem ser implementadas em paralelo. +- `add-rtc-invoice-emission` é puramente aditiva: não modifica `invoice-resources`; os recursos clássicos `service_invoices` e `product_invoices` permanecem intactos (RTC entra como recursos novos `service_invoices_rtc` e `product_invoices_rtc`). +- Nenhuma change modifica a spec de outra (`Modified Capabilities` é sempre vazio) — o repositório ainda não tinha specs versionadas em `openspec/specs/`. Cada change apenas **adiciona** capability(ies) e **consome** as anteriores. + +## Ordem recomendada de implementação + +Respeitando o grafo de dependências (topological order): + +1. **`add-ruby-foundation`** — fundação obrigatória; nada de runtime sozinha, mas viabiliza tudo. +2. **`add-http-transport`** e **`add-openapi-pipeline`** — independentes entre si; ambas só dependem da fundação. Podem ser feitas em paralelo. +3. **`add-client-core`** — exige fundação + transport + pipeline. É o ponto de convergência; entrega os 17 acessores stub e os contratos compartilhados. +4. **`add-entity-resources`**, **`add-invoice-resources`** e **`add-lookup-resources`** — dependem só do core; sem sobreposição de arquivos; **paralelizáveis**. +5. **`add-rtc-invoice-emission`** — depois de `add-invoice-resources` (reusa as superfícies clássicas de service- e product-invoice como padrão) e do pipeline (gera os DTOs RTC de NFS-e e de NF-e/NFC-e). +6. **`add-release-tooling`** — por último; exige todas as changes irmãs aplicadas e estáveis. Política conservadora: ao menos um `v1.0.0-rc.1` + período de beta antes do GA (toca emissão fiscal). + +## Não-objetivos conscientes (v1) + +Lacunas de paridade deliberadamente adiadas, registradas como não-objetivos conhecidos da v1 (todas consistentes com os SDKs Node e PHP, que também não as cobrem): + +- **Inscrições municipais** — sem `municipal_taxes` (análogo a `state_taxes`); fora de escopo na v1. +- **Listagem inbound via OData** — sem query OData para os recursos inbound; apenas as operações já cobertas. +- **Variantes SERPRO** — sem os endpoints/fluxos específicos da SERPRO. +- **`switch-authorizer` e certs v2** — sem troca de autorizador nem a API v2 de certificados. +- **Autenticação JWT Bearer** — apenas API key (`Authorization`/header de chave); sem fluxo JWT Bearer. +- **`retrieve_by_external_id`** — sem busca por id externo; recuperação só pelo id NFE.io. + +Uma **revisão multi-perspectiva** do changeset foi executada; o relatório vive em `openspec/REVIEW-v1-changeset.md`. A partir dessa revisão, `idempotency_key`, thread-safety (mutex), `request_options` (por chamada) e configuração via variáveis de ambiente foram trazidos ao escopo do v1. + +## Grafo de dependências (Mermaid) + +```mermaid +graph TD + F[add-ruby-foundation
sdk-foundation] + H[add-http-transport
http-transport] + P[add-openapi-pipeline
openapi-pipeline] + C[add-client-core
client-core] + E[add-entity-resources
entity-resources + webhook-signature-verification] + I[add-invoice-resources
invoice-resources] + L[add-lookup-resources
lookup-resources] + R[add-rtc-invoice-emission
rtc-invoice-emission] + T[add-release-tooling
release-tooling] + + F --> H + F --> P + F --> C + H --> C + P --> C + C --> E + C --> I + C --> L + C --> R + I --> R + P --> R + F --> T + H --> T + P --> T + C --> T + E --> T + I --> T + L --> T + R --> T +``` diff --git a/openspec/REVIEW-v1-changeset.md b/openspec/REVIEW-v1-changeset.md new file mode 100644 index 0000000..099f30a --- /dev/null +++ b/openspec/REVIEW-v1-changeset.md @@ -0,0 +1,463 @@ +# Revisão multi-perspectiva — Changeset SDK Ruby NFE.io v1 + +## Introdução + +Este documento sintetiza uma revisão adversarial das **9 changes OpenSpec** que compõem a reescrita +greenfield do SDK Ruby (`gem nfe-io` 0.3.2 → 1.0.0): `add-ruby-foundation`, `add-http-transport`, +`add-openapi-pipeline`, `add-client-core`, `add-entity-resources`, `add-invoice-resources`, +`add-lookup-resources`, `add-rtc-invoice-emission`, `add-release-tooling`. É um artefato de +**planejamento** (nenhum código existe ainda). + +### As 6 lentes + +1. **API completeness vs nfeio-docs** — cobertura da superfície contra a fonte da verdade (specs OpenAPI + docs). +2. **SDK parity** — paridade com os SDKs Node v4 e PHP de referência. +3. **Ruby feasibility** — idiomas modernos de Ruby e viabilidade zero-dependência (stdlib). +4. **OpenSpec rigor** — consistência cruzada entre changes, nomes, namespaces e contratos. +5. **Security & compliance** — manejo de dados fiscais, segredos, TLS, logging, webhooks. +6. **Release & DX** — release, migração, documentação e experiência de desenvolvedor. + +### Método + +Cada lente produziu achados; cada achado passou por um veredito adversarial +(**confirmed / partial / refuted**) com verificação direta dos arquivos (specs, tasks, design, docs +fonte-da-verdade, e os SDKs Node/PHP). Esta síntese **deduplicou** achados que múltiplas lentes +levantaram, **descartou os refutados**, manteve os confirmados/parciais e **priorizou por severidade +ajustada** (a severidade pós-verificação, frequentemente menor que a original quando o "gap" era na +verdade paridade deliberada com Node/PHP). + +**Resultado:** 22 gaps confirmados (4 alta, 11 média, 7 baixa) e **5 achados refutados**. + +--- + +## Tabela de gaps confirmados + +| # | Área | Severidade | Achado | Ação | Change-alvo | +|---|---|---|---|---|---| +| 1 | DX / Erros | alta | MIGRATION/README/skill documentam classes de erro inexistentes (`ConnectionError`, `ValidationError`, `PollingTimeoutError`) | modify-change | add-release-tooling | +| 2 | Release | alta | Tag SemVer com hífen (`v1.0.0-rc.1`) não é prerelease RubyGems válido (precisa `1.0.0.rc.1`) | modify-change | add-release-tooling | +| 3 | Release | alta | Nome do gemspec divergente: foundation cria `nfe-io.gemspec`, release-tooling usa `nfe.gemspec` | modify-change | add-release-tooling | +| 4 | DX / Docs | alta | A página `ruby.md` do nfeio-docs já existe e ensina webhook/API errados — docs é UPDATE, não criação | modify-change | add-release-tooling | +| 5 | OpenSpec rigor | alta→média | Classes `Pending`/`Issued` em TRÊS namespaces contraditórios; RTC sem predicados `pending?`/`issued?` | modify-change | add-rtc-invoice-emission | +| 6 | OpenSpec rigor | alta→média | Downloads RTC de product contradizem o contrato clássico (`String` binária vs `NfeFileResource`/URI) | modify-change | add-rtc-invoice-emission | +| 7 | Ruby feasibility | alta | `from_api` exigido por client-core mas nenhuma change gera/implementa o factory + mapeamento camel→snake + hidratação aninhada | modify-change | add-openapi-pipeline | +| 8 | OpenSpec rigor | média | `AbstractResource` referenciado em dois nomes (`Nfe::AbstractResource` vs `Nfe::Resources::AbstractResource`) | modify-change | add-lookup-resources, add-entity-resources, add-rtc-invoice-emission | +| 9 | OpenSpec rigor | média | Stubs `*_resource.rb` de client-core não batem com `*.rb` das changes de recurso | modify-change | add-client-core | +| 10 | OpenSpec rigor / Erros | média | `PollingTimeoutError`/`ConnectionError`/`ValidationError` em project.md e release-tooling sem classe definida | modify-change | add-release-tooling | +| 11 | SDK parity | média | Retry de POST diverge de Node/PHP e `idempotency_key` não é exposto em nenhum método público | modify-change | add-http-transport, add-invoice-resources | +| 12 | Security | média | `idempotency_key` é slot dormente nunca conectado por recurso — emissão duplicada não é mitigada | modify-change | add-invoice-resources, add-rtc-invoice-emission | +| 13 | SDK parity | média | Sem override de request-options por chamada (PHP expõe `RequestOptions` em todo método) | clarify-with-maintainer | add-client-core | +| 14 | Ruby feasibility / Segurança | média | `Client` estilo Stripe sem requisito de thread-safety; pool de conexão é Hash mutável sem mutex | modify-change | add-http-transport, add-client-core | +| 15 | Security | média→ | Body de request/response logado no erro, mas redação só cobre HEADERS — CNPJ/CPF/senha vazam em log | modify-change | add-http-transport | +| 16 | Security | média | Senha de certificado sem requisito in-memory/never-logged/zeroize | modify-change | add-entity-resources | +| 17 | Security | média | Proteção de replay de webhook nem especificada nem reconhecida como inviável | modify-change | add-entity-resources, add-release-tooling | +| 18 | Security | média | `ca_file` (escape hatch TLS) só na prosa de design, ausente do spec de Configuration | modify-change | add-client-core | +| 19 | OpenSpec rigor | média→baixa | Precedência de config (env var vs args) não especificada; diverge do Node que lê `NFE_API_KEY` | clarify-with-maintainer | add-client-core | +| 20 | DX | média | Sem config de sandbox/teste de primeira classe; dual-axis `environment` (símbolo vs string) confunde | modify-change | add-release-tooling, add-client-core | +| 21 | Release | média→baixa | OIDC trusted publishing: dono admin RubyGems indefinido + fallback de API-key sub-especificado | clarify-with-maintainer | add-release-tooling | +| 22 | DX | média | MIGRATION descreve a API v0.3.x errada (`Nfe.api_key =` vs `Nfe.api_key(...)`); omite `Nfe.configure` e `company_id` por classe | modify-change | add-release-tooling | + +Gaps de severidade **baixa** (registro): inscrições municipais ausentes (paridade — aceitar/diferir), +listagem inbound OData (paridade — diferir), product-catalog DTO sem accessor (paridade — diferir), +SERPRO out-of-scope (documentar), switch-authorizer/certs v2 (documentar), CT-e inbound reprocess +(documentar), JWT Bearer auth (documentar como non-goal), proxy HTTP (hardening), `message` de erro +sem cap de tamanho (hardening), supply-chain dev/codegen sem Gemfile.lock pinning (hardening), +forward-compat dos helpers diferidos (consolidar), banner README pós-GA (fechar o loop), RBS template +de `Data` não fixado byte-a-byte (refinar), loader de arquivos gerados não decidido (decidir), +content-length obsoleto pós-gzip (limpeza). + +--- + +## Detalhe — gaps de severidade ALTA + +### 1. Erros documentados que não existem no SDK +**Área:** DX / Erros · **Ação:** modify-change → `add-release-tooling` + +MIGRATION/README/skill (proposal.md:41, tasks.md:3.8/3.9, spec.md:56) instruem documentar +`Nfe::ConnectionError`/`Nfe::ValidationError`/`Nfe::PollingTimeoutError`. A hierarquia autoritativa +(`add-http-transport/spec.md:114`) define `ApiConnectionError`, `TimeoutError < ApiConnectionError`, +`InvalidRequestError` — **nunca** `ConnectionError`/`ValidationError`. `PollingTimeoutError` não é +definido por change nenhuma (polling foi diferido). Integradores copiando `rescue Nfe::ConnectionError` +escreverão cláusulas que **nunca disparam** — buraco silencioso de correção em tratamento de erro fiscal. + +**Recomendação:** corrigir a tabela de erros do MIGRATION/README/skill para a hierarquia real +(`AuthenticationError`, `AuthorizationError`, `InvalidRequestError`, `NotFoundError`, `ConflictError`, +`RateLimitError`, `ServerError`, `ApiConnectionError`, `TimeoutError`, `SignatureVerificationError`, +`ConfigurationError`, `InvoiceProcessingError`). Remover `ConnectionError`/`ValidationError`/`PollingTimeoutError`. +Reconciliar project.md:40. (Ver também gap #10 — mesmo defeito sob a lente OpenSpec.) + +### 2. Tag SemVer não vira versão de gem prerelease válida +**Área:** Release · **Ação:** modify-change → `add-release-tooling` + +`release.sh` valida `^\d+\.\d+\.\d+(-(rc|beta)\.\d+)?$` (forma com hífen) e grava esse valor literal em +`Nfe::VERSION` (tasks 7.4/7.6). RubyGems exige a forma com **ponto** (`1.0.0.rc.1`) para reconhecer +prerelease — o próprio spec usa `1.0.0.rc.1` no cenário Bundler (spec.md:230). Um gem com +`VERSION = "1.0.0-rc.1"` não é tratado como prerelease, quebrando a garantia "Prerelease not +auto-installed" e a política RC-antes-de-GA; sob RubyGems moderno `gem build` falha. + +**Recomendação:** regra explícita — tags git usam `vX.Y.Z(-rc.N)`, mas `Nfe::VERSION` e o gem +publicado usam `X.Y.Z(.rc.N)` (ponto). Mapeamento determinístico (tira `v`; troca `-rc.`/`-beta.` por +`.rc.`/`.beta.`); `release.sh` grava a forma com ponto e taggeia a com hífen. Adicionar step na +release.yml que afirma que a versão do gem construído == versão derivada da tag. + +### 3. Nome do gemspec divergente entre changes +**Área:** Release · **Ação:** modify-change → `add-release-tooling` + +`add-ruby-foundation` renomeia explicitamente `nfe.gemspec` → `nfe-io.gemspec` (tasks.md:23) e valida +com `gem build nfe-io.gemspec`. `add-release-tooling` referencia exclusivamente `nfe.gemspec` +(tasks 1.1/8.4/11.5, spec.md:6/11, design.md:17). Como release-tooling roda por último, o +`gem build nfe.gemspec` da release.yml mira um arquivo que já não existe — e a falha ocorre **depois** +da tag já ter sido empurrada para origin. + +**Recomendação:** padronizar `nfe-io.gemspec` (convenção Bundler para o gem `nfe-io`) em ambas as +changes; atualizar todos os `gem build`/`gem spec` em release.yml e release.sh. (Nota: +`add-openapi-pipeline` também cita `nfe.gemspec` em prosa de `add_dependency` — corrigir junto, embora +não quebre build.) + +### 4. A página ruby.md do nfeio-docs já existe e ensina conteúdo errado +**Área:** DX / Docs · **Ação:** modify-change → `add-release-tooling` + +A página existe, está viva e git-tracked em `docs/desenvolvedores/bibliotecas/ruby.md`. Contém (1) um +handler de webhook usando `X-NFEIO-Signature` + `Base64.strict_encode64(OpenSSL::HMAC.digest('sha1'...))` +— esquema que o SDK declara errado (o canônico é `X-Hub-Signature` + HMAC-SHA1 hex); (2) a API global +v0.3 (`Nfe.api_key('...')`, `Nfe::ServiceInvoice.company_id(...)`, `.download(...).body`) que a v1 +remove. O changeset enquadra o trabalho de docs como **criação** (tasks §10, spec.md:237, design.md:30), +nunca reconhecendo que a página já existe e precisa de remoção de conteúdo errado. Deixar a página como +está é pior que não ter página: ensina um esquema de assinatura que o SDK diz estar quebrado. + +**Recomendação:** reescrever o task §10 como "reescrever a `ruby.md` existente". Subtasks explícitas para +remover o snippet `X-NFEIO-Signature`+Base64 e os exemplos `Nfe.api_key(...)` globais, e adicionar o +quickstart `Nfe::Client.new(api_key:)`. Considerar espelhar a estrutura Node +(`migracao-v2.md`/`changelog.md`/`exemplos.md`). + +--- + +## Detalhe — gaps de severidade MÉDIA + +### 5. `Pending`/`Issued` em três namespaces contraditórios +**Área:** OpenSpec rigor · **Ação:** modify-change → `add-rtc-invoice-emission` (+ varredura) + +Coexistem `Nfe::Pending`/`Nfe::Issued` (client-core spec.md:142), `Nfe::Resources::ServiceInvoicePending` +(invoice-resources spec.md:243-249) e `Nfe::ServiceInvoiceRtcPending` no top-level (RTC spec.md:107-114). +Pior: a cláusula RTC "distinct from the classic `Nfe::ServiceInvoicePending`" referencia um nome que +nenhuma change define (o clássico é `Nfe::Resources::ServiceInvoicePending`). E o RTC nunca declara os +predicados `pending?`/`issued?` que invoice-resources exige — então `result.pending?` do fluxo clássico +falha silenciosamente em resultados RTC. + +**Recomendação:** padronizar todos os value objects discriminados sob `Nfe::Resources::` (convenção da +change mais concreta). RTC vira `Nfe::Resources::ServiceInvoiceRtcPending`. Corrigir a cláusula +"distinct from" para o nome certo. Harmonizar os predicados `pending?`/`issued?` entre RTC e invoice. + +### 6. Downloads RTC de product contradizem o contrato clássico +**Área:** OpenSpec rigor · **Ação:** modify-change → `add-rtc-invoice-emission` + +Os mesmos endpoints de download de product-invoice têm tipos de retorno opostos: clássico exige +`Nfe::Models::NfeFileResource` (URI), "NOT raw bytes" (invoice-resources spec.md:120-122,302-305); RTC +exige `String` ASCII-8BIT (rtc spec.md:245-248, tasks 9.8/10.12). A fonte da verdade resolve o impasse: +`nf-produto-v2.yaml` mostra `/pdf`, `/xml`, `/xml/rejection`, `/xml-epec` etc. retornando `FileResource` +(`{uri}`) — uma URI, não bytes. O Node declara todos como `Promise`. **O clássico está +certo; o lado RTC é o errado.** O RTC é até auto-contraditório (proposal.md:51/design.md:168 dizem que +herda os "tipos de resposta" do clássico = URI). + +**Recomendação:** corrigir rtc spec.md:245-248 e tasks 9.8/9.9/10.12 para retornar +`Nfe::Models::NfeFileResource` (URI). Não tocar o clássico. + +### 7. Factory `from_api` órfão (hidratação camel→snake + aninhada sem dono) +**Área:** Ruby feasibility · **Ação:** modify-change → `add-openapi-pipeline` + +client-core exige `klass.from_api(payload)` (spec.md:128, design D7) em todo DTO. Mas +`add-openapi-pipeline` emite value objects **anêmicos** (`Const = Data.define(...)`, sem `from_api`, +Non-Goals design.md:33). A API devolve chaves camelCase (`federalTaxNumber`) e os atributos são +snake_case (`federal_tax_number`): um Hash JSON cru **não** pode ser splatado no construtor `Data` — +levanta `ArgumentError`. O nome original só vai num **comentário** (não machine-readable). Objetos/arrays +aninhados voltam como Hash/Array, não como os DTOs aninhados que o `.rbs` promete. Ninguém é dono de: +(a) o `from_api` por DTO, (b) o mapa camel→snake em runtime, (c) descarte de chaves desconhecidas, (d) +recursão em refs/arrays aninhados. + +**Recomendação:** decidir e atribuir dono: OU `add-openapi-pipeline` gera `from_api` por DTO (mapeia +chaves, ignora desconhecidas, recursa) + emite o `.rbs`; OU `add-client-core` define um `Nfe::Hydrator` +genérico usando os membros do `Data` + mapa camel→snake gerado + tabela de tipos aninhados gerada. +Adicionar cenários para tolerância a chaves desconhecidas e hidratação de arrays aninhados. + +### 8. `AbstractResource` em dois nomes +**Área:** OpenSpec rigor · **Ação:** modify-change → lookup/entity/rtc + +O dono define `Nfe::Resources::AbstractResource` (client-core spec.md:93,112; tasks 9.1). invoice-resources +usa a forma qualificada. Mas lookup-resources (spec.md:6,8 + tasks), entity-resources (tasks 35,58,81) e +RTC (proposal.md:16 + tasks) declaram `< Nfe::AbstractResource` (sem `Resources::`). São constantes +diferentes em Ruby — as superclasses não resolveriam. Não há alias em lugar nenhum. + +**Recomendação:** varrer lookup-resources (spec+tasks), entity-resources (tasks) e RTC (proposal/tasks) +para `Nfe::Resources::AbstractResource`. Opcionalmente apertar a prosa do próprio client-core, que usa a +forma curta informalmente. + +### 9. Nomes de arquivo dos stubs não batem com as changes de recurso +**Área:** OpenSpec rigor · **Ação:** modify-change → `add-client-core` + +client-core cria 17 stubs com sufixo `_resource` (`service_invoices_resource.rb` etc., tasks 10.1). Toda +change de recurso cria `service_invoices.rb` (sem sufixo). Como são "substituir o stub" greenfield, o +implementador acaba com um arquivo paralelo e um stub `*_resource.rb` órfão (a lista de requires de +client-core ainda exige os stubs sufixados). + +**Recomendação:** alinhar os stubs de client-core tasks 10.1 para a convenção sem sufixo +(`service_invoices.rb` / `Nfe::Resources::ServiceInvoices`), tornando a relação "substitui o stub" +exata em nome de arquivo. (Relaciona-se ao gap #8 — corrigir os dois juntos.) + +### 10. Nomes de classe de erro inexistentes em project.md/release-tooling +**Área:** OpenSpec rigor / Erros · **Ação:** modify-change → `add-release-tooling` + +(Mesmo defeito do gap #1, visto pela lente de consistência cruzada.) project.md:40 e release-tooling +listam `ValidationError`/`ConnectionError`/`PollingTimeoutError`; nenhuma é definida pelas changes. As +classes de erro reais SÃO especificadas (client-core tasks.md 2.1-2.3 define `ConfigurationError`, +`InvalidRequestError`, `InvoiceProcessingError` com pais), então o gap é a **varredura de nomes +canônicos**, não classes faltando. + +**Recomendação:** sweep de project.md:40 e release-tooling para os nomes canônicos +(`InvalidRequestError`, `ApiConnectionError`); remover `PollingTimeoutError` (polling diferido). + +### 11. Retry de POST diverge de Node/PHP e `idempotency_key` é inalcançável +**Área:** SDK parity · **Ação:** modify-change → `add-http-transport` + `add-invoice-resources` + +Node e PHP retentam qualquer 5xx/429 independente do método; Ruby (corretamente, por segurança) **não** +retenta POST não-idempotente. Mas nenhum método `create()` aceita `idempotency_key:`/`options:`, então o +caller não consegue reativar a elegibilidade de retry — o slot `idempotency_key` do `Request` é +inalcançável pela API pública. A decisão de segurança está bem justificada no design interno (D8/D9), mas +**não** está nos docs voltados ao integrador. + +**Recomendação:** (a) documentar a divergência no README (não no MIGRATION, que mira usuários v0.3.x); +(b) expor `idempotency_key:` nos métodos `create()`/`create_with_state_tax()` para tornar a emissão +retry-elegível. + +### 12. `idempotency_key` é slot dormente — emissão duplicada não mitigada +**Área:** Security · **Ação:** modify-change → `add-invoice-resources` + `add-rtc-invoice-emission` + +D9 delega geração (`SecureRandom.uuid`) e a decisão de "quando habilitar" à camada de recurso — que nunca +o faz. Nenhum `create` gera/envia uma key. Em timeout de rede após o servidor já ter criado a invoice, o +retry natural do caller pode emitir documento duplicado. (A proteção "não auto-retentar POST" É entregue; +o risco residual é o retry do **caller**, e depende de o API honrar o header.) + +**Recomendação:** OU conectar (kwarg `idempotency_key:` default `SecureRandom.uuid`, enviado como header, +com requisito + cenário) OU escopar explicitamente para fora com um requisito documentando que a v1 não +garante emissão at-most-once e instruindo o caller a fazer retrieve-by-business-key antes de retentar. + +### 13. Sem override de request-options por chamada +**Área:** SDK parity · **Ação:** clarify-with-maintainer → `add-client-core` + +PHP expõe `?RequestOptions $options = null` em todo método (apiKey/baseUrl/timeout por chamada). Ruby +configura só no nível do `Client`. Um migrante PHP perde a capacidade de sobrescrever timeout/baseUrl e, +sobretudo, **apiKey por chamada (multi-tenant)** sem reconstruir o Client. (Nota: PHP NÃO carrega +idempotencyKey no RequestOptions — o gap real é apiKey/baseUrl/timeout.) + +**Recomendação:** decisão de escopo do mantenedor — adicionar `request_options:` por chamada (ao menos +nos POST de emissão) OU documentar em design.md que overrides por chamada são deliberadamente diferidos +para um minor futuro e que o caller constrói um segundo Client. + +### 14. Sem requisito de thread-safety para Client estilo Stripe +**Área:** Ruby feasibility / Segurança · **Ação:** modify-change → `add-http-transport` + `add-client-core` + +O SDK promove explicitamente o padrão Stripe de Client compartilhado (acessores lazy memoizados via +`||=`, não-sincronizados), mas o pool de conexão por origem é um `Hash` mutável sem mutex e a thread-safety +aparece **só** numa "Open Question" do design (não como requisito). Rails/Sidekiq/Puma compartilharão um +Client entre threads, causando data races no pool e nos acessores. + +**Recomendação:** decisão v1 — (a) mutex no pool e nos acessores lazy (barato, torna o padrão seguro), OU +(b) `NetHttp` abre conexão por chamada (sem pool mutável). Adicionar requisito + cenário declarando a +garantia de thread-safety. Não deixar em "Open Questions" para um SDK de emissão fiscal. + +### 15. Body logado no erro, mas redação só cobre headers +**Área:** Security · **Ação:** modify-change → `add-http-transport` + +No erro, o logger loga "status + corpo truncado" (corpo = RESPONSE body) e o `Nfe::Error` retém +`response_body`. A redação só cobre valores de **headers** sensíveis — nada redige segredos/PII dentro do +body. Respostas 422/500 verbosas podem ecoar CNPJ/CPF e dados do tomador/comprador para o log. (Nuance: o +REQUEST body — incluindo o multipart com `password` do certificado — não é input do logger; e `Error#to_h` +já é escopado e não inclui o body. O vetor real é a linha de log do response-body truncado e o atributo +`Error#response_body`.) + +**Recomendação:** requisito explícito — não logar request/response body por default (logar só método, +URL, status, request_id); gatear qualquer log de body atrás de flag opt-in. Adicionar cenário afirmando +que segredos/PII não aparecem em nenhuma linha de log. + +### 16. Lifecycle da senha de certificado sem requisito de segurança +**Área:** Security · **Ação:** modify-change → `add-entity-resources` + +A senha PKCS#12 passa por `validate_certificate` e `upload_certificate` como String Ruby comum. Nada +declara que a senha (ou bytes do .pfx / chave privada) deve ficar só em memória, nunca em disco, nunca em +log/exceção, e idealmente ser zerada após uso — embora o changeset estabeleça exatamente essa postura de +compliance para headers. (Gap latente/de documentação: não há vazamento ativo hoje, pois o request body +não é logado e `to_h` é escopado; mas o requisito defensivo está ausente.) + +**Recomendação:** requisito em add-entity-resources: a senha e os bytes PKCS#12 SHALL ser manejados só em +memória, SHALL NOT ser persistidos em disco, SHALL NOT aparecer em log/exceção/Error, e (onde viável) a +String da senha SHALL NOT ser retida além da chamada de upload. Cenários: "senha ausente dos logs" e +"senha ausente de qualquer exceção / Error#to_h". + +### 17. Proteção de replay de webhook não especificada +**Área:** Security · **Ação:** modify-change → `add-entity-resources` + `add-release-tooling` + +O spec de webhook especifica HMAC-SHA1 sobre os bytes do body, mas nada sobre replay. A NFE.io envia só +`X-Hub-Signature` — sem timestamp/nonce/delivery-id. Uma assinatura válida capturada e reenviada passa em +`verify_signature` para sempre. + +**Recomendação:** (a) requisito documentando que a NFE.io não fornece primitiva anti-replay, instruindo o +consumidor a deduplicar pelo id do evento/invoice e tratar handlers como idempotentes (e `construct_event` +expor um id estável quando presente); no mínimo o README/skill deve avisar que validade de assinatura ≠ +frescor e que handlers devem ser idempotentes. + +### 18. `ca_file` (escape hatch TLS) só na prosa de design +**Área:** Security · **Ação:** modify-change → `add-client-core` + +O design promete `Configuration#ca_file` como escape hatch documentado, mas a lista de opções de +Configuration (client-core spec.md:20-21) não o inclui, e o requisito de TLS só manda `VERIFY_PEER`. +Deixa espaço para um implementador adicionar um toggle inseguro `verify_mode` em vez disso. (Mitigação +parcial: http-transport spec.md:25 já proíbe desabilitar verificação por default.) + +**Recomendação:** especificar `ca_file` (e opcionalmente `ca_path`) na lista de opções como o ÚNICO +override de confiança TLS, com requisito de que só pode ADICIONAR/substituir bundle de CA e SHALL NEVER +expor `VERIFY_NONE`/`insecure_ssl`. Cenário afirmando que não há API pública para desabilitar verificação. +Esclarecer que o `insecureSsl` do spec nf-consumidor-v2 é atributo server-side do alvo do webhook, NÃO o +TLS de saída do SDK. + +### 19. Precedência de config (env var vs args) não especificada +**Área:** OpenSpec rigor · **Ação:** clarify-with-maintainer → `add-client-core` + +A resolução de chaves é puramente sobre args do construtor; nada trata fallback de env var. O Node de +referência (paridade declarada) LÊ env internamente (`config.dataApiKey || config.apiKey || NFE_DATA_API_KEY +|| NFE_API_KEY`). O cenário Ruby "Missing all keys" levanta erro sem chave passada — divergindo do Node +quando env vars estão setadas. (A metade de thread-safety deste achado original já está coberta no design.) + +**Recomendação:** decisão do mantenedor — OU especificar fallback de env com ordem "arg explícito vence" +(igual ao Node) OU declarar explicitamente que a v1 NÃO lê env. + +### 20. Sem config de sandbox/teste de primeira classe +**Área:** DX · **Ação:** modify-change → `add-release-tooling` + `add-client-core` + +`:production`/`:development` resolvem para a MESMA URL, diferindo só pela chave — mas nada documenta como o +usuário obtém/aponta credenciais de sandbox, e não há sample de env de teste. Pior: product/consumer +invoice exigem `environment: "Production"/"Test"` como STRING por chamada — um eixo diferente do símbolo +`:development` do client (pitfall que o skill Node sinaliza). (Parcialmente coberto: o modelo "símbolo +seleciona chave, não URL" já está no spec/design.) + +**Recomendação:** seção README/skill "Sandbox vs Production": (a) o símbolo seleciona chave, não URL; +(b) como obter credenciais de teste; (c) que invoice de product/consumer usa um param string `environment` +SEPARADO. Um sample mostrando emissão em ambiente Test. + +### 21. OIDC trusted publishing: ownership e fallback abertos +**Área:** Release · **Ação:** clarify-with-maintainer → `add-release-tooling` + +Open Questions admite que "quem tem acesso admin da conta nfe-io no RubyGems" é desconhecido, e a duração +do beta é indecisa — ambos GA-blockers. O fallback `RUBYGEMS_API_KEY` não tem task de provisão/rotação, e +não há nota sobre a interação MFA-vs-push-CI (`rubygems_mfa_required => true`). + +**Recomendação:** antes de cortar rc.1: (1) confirmar admin RubyGems e fazer o binding de trusted +publisher, ou provisionar `RUBYGEMS_API_KEY` como chave push-only escopada (+ task para armazená-la); +(2) verificar que `rubygems_mfa_required` não bloqueia o push de CI no método escolhido; (3) fixar a +janela de beta (recomendado 14 dias para SDK fiscal) para tornar §12.3 testável. + +### 22. MIGRATION descreve a API v0.3.x errada +**Área:** DX · **Ação:** modify-change → `add-release-tooling` + +O lado "antes" usa `Nfe.api_key = "..."` (atribuição), mas o legado define `def self.api_key(api_key)` — +um setter de método chamado `Nfe.api_key('...')`. A sibling change `add-ruby-foundation` usa a forma certa, +então o changeset se **auto-contradiz**. Faltam também o bloco `Nfe.configure { |c| c.url= }` e o +state por classe `Nfe::ServiceInvoice.company_id("...")` — exatamente as linhas que os usuários copiaram do +README legado. + +**Recomendação:** corrigir o "antes" para `Nfe.api_key('...')` (forma de método) e adicionar a migração de +`Nfe.configure { |c| c.url = ... }` e do padrão `Nfe::ServiceInvoice.company_id(...)` → `client.service_invoices.create(company_id:, ...)`. + +--- + +## Gaps de severidade BAIXA (registro / hardening) + +Itens reais mas de baixo impacto, em sua maioria **paridade deliberada** com Node/PHP ou hardening +defensivo. Recomendação geral: registrar como non-goal consciente ou diferir. + +- **Inscrições municipais ausentes** (sem `municipal_taxes`): gap herdado de Node E PHP; a alegação "17 + recursos = PHP 1:1" está correta. **Ação: aceitar-as-is** e registrar como gap conhecido-mas-diferido em + CHANGESET-OVERVIEW.md (opcionalmente liderar os outros SDKs adicionando depois). +- **Listagem inbound OData ausente** (sem `list`/`list_events` em InboundProductInvoices/TransportationInvoices): + omissão intencional em toda a família (Node e PHP não têm). **Ação: aceitar-as-is**, registrar em "Fora de escopo". +- **Product-catalog DTO sem accessor**: padrão cross-SDK deliberado (PHP tem os DTOs gerados sem resource). + **Ação: aceitar-as-is** (já coberto pela decisão de superfície de 17 recursos). +- **CT-e inbound reprocess/batch/consolidation ausentes**: nenhum SDK de referência implementa. + **Ação: aceitar-as-is**, opcionalmente adicionar `reprocess_webhook` por simetria com NF-e. +- **NFS-e clássica `download_cancellation_xml`**: a capacidade existe via `service_invoices_rtc` (Ambiente + Nacional). **Ação: modify-change** (add-invoice-resources) — só adicionar um cross-reference doc. +- **`retrieve_by_external_id` ausente**: consistente com baseline Node. **Ação: aceitar-as-is** (idempotência + já coberta como conceito distinto). +- **Variantes SERPRO ausentes**, **switch-authorizer + certs v2**: ambos consistentes com Node 1:1. + **Ação: aceitar-as-is** — adicionar uma linha em "Não inclui (fora de escopo)". +- **JWT Bearer auth**: consistente com Node/PHP (só X-NFE-APIKEY). **Ação: aceitar-as-is** — registrar como + deferral consciente em project.md/design. +- **Proxy HTTP ausente**: não é regressão de paridade (Node/PHP também não expõem). **Ação: modify-change** + (add-client-core) — `Configuration#proxy` é um one-liner de stdlib; barato. +- **`message` de erro sem cap de tamanho/scrub**: pode ecoar input do servidor. **Ação: modify-change** + (add-http-transport) — capar tamanho e documentar que pode conter input ecoado. +- **Supply-chain dev/codegen sem Gemfile.lock pinning**: decisão deliberada (não commitar lock é convenção + para gem-lib). **Ação: clarify-with-maintainer** — preferir `bundler-audit`/dependabot em CI a commitar lock. +- **Forward-compat dos helpers diferidos**: promessas existem mas espalhadas. **Ação: modify-change** + (add-release-tooling) — consolidar uma linha declarando Pending/Issued + FlowStatus como API pública estável. +- **Banner README pós-GA**: existe task para adicionar, falta task para remover no GA. **Ação: modify-change** + (add-release-tooling) — amarrar o estado do banner ao fluxo prerelease-vs-final do release.sh. +- **content-length obsoleto pós-gzip**: cosmético (body é a fonte da verdade). **Ação: modify-change** + (add-http-transport) — remover/recomputar content-length após inflar. +- **RBS template de `Data` / loader de arquivos gerados**: decisões abertas registradas. **Ação: + clarify-with-maintainer / modify-change** (add-openapi-pipeline) — fixar template `< Data` e decidir + `require_relative` explícito. + +--- + +## Sugestões de novas changes + +Nenhuma área de capacidade inteira está faltando que justifique uma nova change OpenSpec autônoma. Todos +os gaps confirmados são corrigíveis dentro das 9 changes existentes (modify-change) ou são non-goals a +registrar. A maior parte das "ausências de cobertura" verificou-se como **paridade deliberada** com os SDKs +Node/PHP, não como lacunas reais. + +Único candidato fraco a futura change (pós-v1, opcional, não-bloqueante): + +- **`add-municipal-taxes`** — recurso `municipal_taxes` (CRUD + `series/{serie}` + `updateprefecture`) que + lideraria os SDKs Node/PHP. Só se inscrição municipal virar necessidade de negócio próxima; caso + contrário, registrar como gap conhecido e seguir. + +--- + +## Verificado e OK (áreas bem cobertas) + +A revisão confirmou que vastas porções do changeset estão sólidas. Registrado para mostrar amplitude: + +- **Multipart de upload de certificado é viável e tem dono** (refutado o "incompatível com o contrato"): + `AbstractResource#upload_multipart` usando `Net::HTTP::Post#set_form` está in-scope em add-entity-resources + (tasks 2.1, design D6). `Net::HTTP` tem multipart na stdlib (diferente do PHP/cURL que precisou diferir). +- **Gzip / Accept-Encoding manual**: o gotcha do Net::HTTP (desabilitar auto-decompress) está antecipado e + tratado via `Zlib::GzipReader` com fallback em `Zlib::Error` (D5, tasks 2.8); só content-length residual. +- **Encoding ASCII-8BIT / ownership de body**: D4 atribui ownership UMA vez (transport "burro" devolve bytes + crus; camada de recurso decide JSON vs download). O `force_encoding` no helper é re-asserção idempotente, + não ambiguidade; o `.dup` é prática defensiva correta (sem FrozenError real). +- **RBS de `Data.define`**: a estratégia (emitir `class ... end` com atributos tipados + assinatura + do construtor) já está especificada (pipeline tasks 4.8, spec.md:56) e validada em CI (3.2/3.3/3.4 via + `rbs validate` + `steep check`). +- **RTC adicionando acessores ao Client (17→19)**: NÃO é inconsistência (refutado). O spec de client-core é + um contrato aberto deliberado ("at least seventeen ... opt-in changes MAY register further"); a edição de + client.rb está totalmente disclosed (proposal.md:79, design D9). "Modified Capabilities vazio" é correto + porque não há spec arquivada para modificar. +- **Campo multipart `file` (não `certificate`)**: Ruby segue corretamente o spec OpenAPI e a divergência do + Node já está documentada (design D6, tasks 4.12) — refutada a alegação de que faltava documentar. +- **`environment` selects key, not URL**: o modelo está correto e end-to-end documentado (D3); confirmado + contra o PHP `Config.php` que NÃO ramifica por environment. Só wording "sandbox" a apertar. +- **`get_status` derivado de `retrieve`**: entregue, não diferido (refutada a alegação de que MIGRATION o + trata como ausente — o parêntese inline já esclarece "derivado no v1"). +- **Streaming de download + read_timeout per-call**: deferral de streaming está explicitamente listado em 3 + lugares e read_timeout JÁ é configurável por Request (refutadas as duas metades). +- **Gate de cobertura SimpleCov ≥80% e abstração de transport substituível**: ambos são requisitos de + capability de primeira classe (sdk-foundation spec.md:164; http-transport spec.md:6-10). +- **Hierarquia de erro core (`ConfigurationError`/`InvalidRequestError`/`InvoiceProcessingError`)**: SÃO + especificadas (em client-core tasks §2 com pais), e a escolha `InvalidRequestError` sobre `ValidationError` + é deliberada e justificada (design.md:145). O defeito real é só a varredura de nomes nos docs (gaps #1/#10). +- **Publicação endurecida**: OIDC trusted publishing, `rubygems_mfa_required`, `.gem` + `.sha256` checksum, + guarda de drift do spec via SHA-256 — tudo presente em add-release-tooling. + +--- + +*Relatório gerado a partir da síntese adversarial das 6 lentes. 22 gaps confirmados, 5 refutados.* diff --git a/openspec/changes/archive/2026-06-25-add-client-core/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-client-core/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-client-core/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-client-core/README.md b/openspec/changes/archive/2026-06-25-add-client-core/README.md new file mode 100644 index 0000000..175bb51 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-client-core/README.md @@ -0,0 +1,3 @@ +# add-client-core + +Núcleo de DX feito à mão do SDK Ruby v1: `Nfe::Client`, `Nfe::Configuration`, host map multi-base-URL, `AbstractResource`, contrato 202 discriminado (Pending/Issued), `Nfe::FlowStatus` e os 17 acessores lazy snake_case de recurso. diff --git a/openspec/changes/archive/2026-06-25-add-client-core/design.md b/openspec/changes/archive/2026-06-25-add-client-core/design.md new file mode 100644 index 0000000..7355179 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-client-core/design.md @@ -0,0 +1,255 @@ +# Design — add-client-core + +## Context + +A reescrita greenfield do SDK Ruby v1 monta o terreno (**add-ruby-foundation**), a camada HTTP (**add-http-transport**) e os DTOs gerados (**add-openapi-pipeline**) antes desta change. `add-client-core` é a **superfície pública** que amarra os três blocos, no modelo do SDK Node (`NfeClient`) e do SDK PHP (`Nfe\Client`), porém idiomático em Ruby moderno. + +Filosofia de referência (estilo Stripe, cliente único + acessores): + +```ruby +# Stripe-ruby +stripe = Stripe::StripeClient.new("sk_test_...") +customer = stripe.v1.customers.create(...) + +# Nfe v1 (alvo) +client = Nfe::Client.new(api_key: ENV.fetch("NFE_API_KEY")) +invoice = client.service_invoices.retrieve(company_id, invoice_id) +``` + +A NFE.io expõe **vários subdomínios** (api.nfe.io, api.nfse.io, address.api.nfe.io, etc.). O roteamento de host é uma decisão de primeira classe: vive **só** na `Configuration` (host map), e nenhum recurso hard-coda URL. O contrato de emissão assíncrona (HTTP 202 + `Location`) precisa de tipos de resultado discrimináveis (`Pending`/`Issued`) já na base, pois adicioná-los depois quebra assinaturas públicas. + +Esta change **possui o registro de recursos**: entrega 17 acessores stub que as changes de recurso preenchem depois. A decisão central é o conjunto de idiomas Ruby que diferem de PHP/Node: `Data.define` para objetos de valor imutáveis, keyword args, `snake_case`, `Net::HTTP`, módulos, `raise` de erros tipados, downloads como `String` binária, e retornos síncronos (sem Promises/Futures). + +## Goals / Non-Goals + +**Goals** + +- `Nfe::Client.new(api_key: "...")` funciona com defaults sensatos (produção, retries default, transporte `Net::HTTP` default). +- 17 acessores lazy snake_case memoizados na primeira leitura, paridade-plus com o SDK PHP. +- `Nfe::Configuration` tipada, validada no `initialize`. +- Host map multi-base-URL como **fonte única de verdade** com resolução por família e fallback `main`. +- `AbstractResource` cobre o CRUD plano via helpers (`get`/`post`/`put`/`delete`), `hydrate`, `download`, `hydrate_list`. +- `IdValidator` fail-fast em pt-BR antes de qualquer chamada HTTP. +- Contrato 202 discriminado (`Pending`/`Issued`) e `FlowStatus.terminal?` entregues agora. +- `ListResponse`/`ListPage` cobrindo paginação page-style e cursor-style. +- Tudo testável com transporte mock injetado via `Configuration`. + +**Non-Goals** + +- `create_and_wait` / `poll_until_complete` — diferido pós-1.0 (paridade com decisão de PHP/Node). `FlowStatus.terminal?` já habilita loop manual. +- `create_batch` — açúcar concorrente; sem ganho real no modelo síncrono v1. +- Implementação concreta de qualquer recurso (vem nas changes de recurso). +- Downloads em streaming — retornamos `String` completa (binary-safe). Arquivos muito grandes ficam para release futura. +- Validação de dígito verificador de CNPJ/CPF além de formato/normalização — a API valida no servidor; o validador local é fail-fast para typos, não substituto. +- Hot-swap de transporte em runtime — config é resolvida na construção. + +## Decisions + +### D1. Cliente único com acessores lazy memoizados (não eager) + +**Decisão**: `Nfe::Client` expõe 17 métodos acessores snake_case. Cada um memoiza a instância do recurso na primeira leitura (`@service_invoices ||= ServiceInvoicesResource.new(self)`). + +**Por quê**: +- Paridade com o lazy-init do SDK Node (`NfeClient` cria recursos e clientes HTTP sob demanda) — um cliente só com `data_api_key` funciona para recursos de dados sem nunca tocar (e validar) a chave principal. +- Em Ruby, expor método acessor (não atributo público gravável) é idiomático e mantém o objeto imutável por fora. +- A memoização evita realocar recursos a cada acesso sem o custo de construir 17 objetos no boot. + +**Alternativa rejeitada**: binding eager de todos os recursos no `initialize` (como o SDK PHP). Funciona, mas força resolução de chave/transporte de famílias nunca usadas e perde a propriedade "cliente com só data_api_key é válido". + +### D2. `Configuration` como objeto tipado, não Hash + +**Decisão**: `Nfe::Configuration` com atributos nomeados, validado no `initialize`. `Nfe::Client.new` aceita ou keyword args de conveniência (que montam a `Configuration`) ou uma `configuration:` explícita. + +```ruby +Nfe::Client.new(api_key: "k", timeout: 120) # atalho +Nfe::Client.new(configuration: Nfe::Configuration.new(...)) # controle total +``` + +**Por quê**: typos viram erro cedo; defaults explícitos na assinatura; validação centralizada. Hash de config é "Ruby-ish" mas perde checagem e autocomplete (Steep/RBS). + +### D3. `environment` como Symbol (`:production`/`:development`), não string + +**Decisão**: `environment:` aceita `:production` (default) ou `:development`. Valor inválido levanta `Nfe::ConfigurationError`. + +**Por quê**: paridade com o Node (`validateAndNormalizeConfig` aceita só `production`/`development`). Ambos os ambientes usam o mesmo endpoint — a diferenciação é por **chave de API**, não por URL. Documentar isso evita a expectativa errada de "sandbox URL". (O Node às vezes diz "sandbox" no README, mas só valida production/development — não replicar a confusão.) + +### D4. Host map é a fonte única de verdade na `Configuration` + +**Decisão**: `Configuration#base_url_for(family)` é o **único** lugar que conhece hosts. Mapa confirmado (CANONICAL FACTS): + +| Família | Host | +|---|---| +| `main` (companies, service invoices, legal/natural people, webhooks) | `https://api.nfe.io` | +| `addresses` | `https://address.api.nfe.io/v2` (o `/v2` é parte do host) | +| `nfe-query` (product/consumer invoice query) | `https://nfe.api.nfe.io` | +| `legal-entity` (lookup CNPJ) | `https://legalentity.api.nfe.io` | +| `natural-person` (lookup CPF) | `https://naturalperson.api.nfe.io` | +| `cte` (transportation, inbound product, tax calc/codes, product/consumer invoices, state taxes) | `https://api.nfse.io` | +| desconhecida | `https://api.nfe.io` (default seguro) | + +Cada recurso declara sua família via `api_family` (ex.: `:cte`), nunca uma URL literal. Overrides por família via `base_url_overrides` na `Configuration` (escape hatch). + +**Por quê**: centralizar elimina a classe de bug "recurso aponta para host errado → 404" (exatamente o bug que o SDK PHP teve de corrigir em c05, quando 6 famílias estavam mapeadas para hosts errados). Uma única tabela auditável, coberta por teste por família. + +**Por quê da divergência de docs**: as deltas do SDK PHP listavam `api-legalentity.nfe.io`/`api-naturalperson.nfe.io`; o host autoritativo (Node + client-core PHP) é `*.api.nfe.io`. Usamos `legalentity.api.nfe.io` / `naturalperson.api.nfe.io`. + +### D5. Resolução de chave por família (modelo de duas chaves) + +**Decisão**: `Configuration#api_key_for(family)`. Famílias de dados (`addresses`, `legal-entity`, `natural-person`, `nfe-query`) usam `data_api_key` quando presente; caso contrário caem para `api_key`. Demais famílias usam `api_key`. + +**Por quê**: a plataforma separa cobrança entre a API principal (emissão/companies/webhooks) e a API de dados (CEP/CNPJ/CPF/query). Espelha a cadeia `resolveDataApiKey` do Node (`dataApiKey ?? apiKey`). Um cliente só com chave principal continua funcionando para recursos de dados (fallback). As próprias chaves caem para `ENV` quando não passadas explicitamente (ver D17). + +### D6. `AbstractResource` provê CRUD genérico + helpers + +**Decisão**: base abstrata recebe o `Client` na construção e expõe (protected): `get`/`post`/`put`/`delete`, `full_path`, `hydrate`, `download`, `hydrate_list`, `handle_async_response`. Cada subclasse declara `api_family` e `api_version`. + +```ruby +class AbstractResource + def initialize(client) = @client = client + protected + def api_family = raise NotImplementedError + def api_version = "v1" # subclasses sobrescrevem; addresses retorna "" + def get(path, query: {}, **opts) = request(:get, path, query: query, **opts) + # post/put/delete análogos + def full_path(path) + # tolera api_version vazia (addresses) sem gerar "//addresses/x" + version = api_version.to_s + version.empty? ? path : "/#{version}#{path}" + end + def hydrate(klass, payload) = klass.from_api(payload) # Data.define value object + def download(path, **opts) + body = get(path, accept: "application/octet-stream", **opts).body + body.dup.force_encoding(Encoding::ASCII_8BIT) + end +end +``` + +**Por quê**: ~80% dos endpoints são CRUD plano; helpers eliminam boilerplate. `full_path` precisa tolerar `api_version` vazia porque o host de `addresses` já embute `/v2`. + +### D7. `hydrate` materializa DTOs `Data.define` imutáveis + +**Decisão**: `hydrate(klass, payload)` chama um construtor de fábrica do DTO gerado (ex.: `klass.from_api(hash)`), produzindo um objeto de valor `Data.define` imutável de **add-openapi-pipeline**. O desempacotamento de envelope (`{"serviceInvoice" => {...}}`) é feito **no recurso** (cada endpoint conhece seu wrapper), não na base. + +**Por quê**: `Data.define` é o idioma Ruby 3.2+ para objetos de valor imutáveis — equivalente aos `readonly`/`Data` do PHP e às interfaces TS. Wrappers variam por endpoint; centralizar viraria chuva de `if`. + +**Alternativa rejeitada**: `OpenStruct`/Hash cru — perde imutabilidade, tipo e autocomplete via RBS. + +### D8. Downloads retornam `String` binary-safe (ASCII-8BIT) + +**Decisão**: `download(path)` retorna `String` com bytes crus, com `force_encoding(Encoding::ASCII_8BIT)`. O chamador decide se persiste (`File.binwrite`) ou faz streaming. + +**Por quê**: Ruby não tem `Buffer` (Node) nem decisão de "string binary-safe" implícita (PHP). Forçar ASCII-8BIT garante que PDFs/XMLs/ZIPs não sejam corrompidos por transcodificação UTF-8. Mapeia `Buffer` (Node) e `string` (PHP) para o idioma Ruby correto. + +**Nota de divergência (foldada nas changes de recurso)**: downloads de `product_invoices` retornam um `NfeFileResource` (URI), **não** bytes — ao contrário de service/query/inbound. O helper `download` aqui serve aos que retornam bytes; recursos URI-resource usam `get` + `hydrate` normal. + +### D9. Contrato 202 discriminado: `Pending` / `Issued` + +**Decisão**: dois tipos base de resultado em `lib/nfe/results.rb`: + +```ruby +module Nfe + # 202 + Location: emissão assíncrona pendente + Pending = Data.define(:invoice_id, :location) + # 201 + body: emissão materializada + Issued = Data.define(:resource) +end +``` + +Recursos que podem retornar 202 retornam `Pending` ou `Issued`; o consumidor discrimina com `case result when Nfe::Pending` / `result.is_a?(Nfe::Pending)`. `handle_async_response` na base extrai o `invoice_id` do header `Location` (regex `%r{/([a-z0-9-]+)\z}i` sobre o último segmento), levantando `Nfe::InvoiceProcessingError` se 202 vier sem `Location`. + +**Por quê**: o consumidor escreve `if result.is_a?(Nfe::Pending)` em vez de inspecionar `status`. `Data.define` dá igualdade por valor, imutabilidade e `to_h` de graça. Refatorar isso depois seria breaking change — por isso entra agora, mesmo sem polling. + +**Por quê tipos base genéricos (não por família)**: o registro de recursos (esta change) só precisa do contrato base. As changes de recurso podem subclassificar (`ServiceInvoicePending < Nfe::Pending`?) se precisarem de `instanceof` mais fino, mas o piso é o par genérico `Pending`/`Issued`. + +### D10. `FlowStatus.terminal?` agora; polling diferido + +**Decisão**: `Nfe::FlowStatus.terminal?(status)` retorna `true` para exatamente `"Issued"`, `"IssueFailed"`, `"Cancelled"`, `"CancelFailed"` (cravado em `client-nodejs/src/core/types.ts`). NÃO entregar `create_and_wait`/`poll_until_complete` em 1.0. + +**Por quê**: paridade com a decisão de PHP/Node de diferir polling. O contrato discriminado + `terminal?` bastam para um loop de polling manual: + +```ruby +result = client.service_invoices.create(company_id, data) +if result.is_a?(Nfe::Pending) + loop do + sleep 2 + invoice = client.service_invoices.retrieve(company_id, result.invoice_id) + break invoice if Nfe::FlowStatus.terminal?(invoice.flow_status) + end +end +``` + +Quando o helper de polling chegar (release futura), `terminal?` já está pronto para ser consumido — sem breaking change. + +### D11. `ListResponse`/`ListPage` cobrem dois shapes de paginação + +**Decisão**: `Nfe::ListResponse` carrega `data` (lista de DTOs) + `page` (`Nfe::ListPage`). `ListPage` expõe `page_index`, `page_count`, `starting_after`, `ending_before`, `total` — todos opcionais. O recurso preenche a metade relevante ao seu endpoint. + +```ruby +ListResponse = Data.define(:data, :page) +ListPage = Data.define(:page_index, :page_count, :starting_after, :ending_before, :total) +``` + +`hydrate_list(klass, payload, wrapper_key:)` desempacota `{wrapper_key => [...]}`, hidrata cada item e detecta o shape de página. + +**Por quê**: a API usa page-style (`page_index`/`page_count` — service invoices, companies, tax codes) **e** cursor-style (`starting_after`/`ending_before` — product/consumer invoices, state taxes) no mesmo SDK. Um único tipo, com metades opcionais, mantém `result.data` idêntico nos dois casos. Dois tipos separados seriam "mais corretos" mas forçariam o chamador a discriminar. + +### D12. `IdValidator` fail-fast em pt-BR + +**Decisão**: módulo `Nfe::IdValidator` com métodos `company_id`, `invoice_id`, `access_key`, `state_tax_id`, `event_key`, `cnpj`, `cpf`, `cep`, `state`. Cada método valida (e quando aplicável normaliza) e levanta `Nfe::InvalidRequestError` com mensagem em português antes de qualquer HTTP. + +- `access_key`: aceita entrada formatada (espaços/pontos/hífens), remove não-dígitos, valida `/^\d{44}$/`, retorna a string normalizada. +- `cnpj`/`cpf`: normalizam para 14/11 dígitos (formato; sem dígito verificador). **Nota v3**: a partir de jul/2026 o CNPJ pode ser alfanumérico nos endpoints v3 — `cnpj` NÃO deve coagir para Integer (gap a evitar; o `validateCNPJ` do Node assume numérico). +- `cep`: normaliza removendo hífen, valida 8 dígitos. +- `state`: UF maiúscula (27 + `EX`/`NA`). + +**Por quê**: paridade com os validadores do Node (`validateCompanyId`, `validateAccessKey`, etc.). Fail-fast com mensagem clara em português alinha com a audiência (NFE.io é Brasil). + +### D13. `Nfe::Client` é a classe pública final; customização por composição + +**Decisão**: customização do comportamento é via transporte/`Configuration` injetáveis, não via subclasse do `Client`. + +**Por quê**: composição > herança. Testes usam transporte mock (de add-http-transport), não subclasse. Mantém a superfície pública estreita e estável. + +### D14. `Nfe::VERSION` em arquivo dedicado + +**Decisão**: `lib/nfe/version.rb` com `Nfe::VERSION = "1.0.0"`. O transporte lê esse valor ao montar `User-Agent` (com `user_agent_suffix` opcional anexado). + +**Por quê**: convenção de gem Ruby (`lib//version.rb`); sem IO no boot; o `*.gemspec` lê a constante. Bump 0.3.2 → 1.0.0 conforme decisão canônica. + +### D15. Acessores memoizados são thread-safe (Mutex) + +**Decisão**: a memoização lazy dos 17 acessores no `Client` é guardada por um `Mutex` (`@resource_mutex.synchronize { @x ||= ... }`), de modo que um único `Client` compartilhado entre threads é seguro (Rails/Sidekiq/Puma). O pool de conexões keep-alive por origem é guardado por seu próprio `Mutex` em **add-http-transport**. + +**Por quê**: o padrão de uso real é um `Client` global compartilhado por workers concorrentes. Sem o Mutex, duas threads na primeira leitura do mesmo acessor podem construir o recurso duas vezes (race benigna em estrutura, mas evitável e barata). Não é Open Question — é requisito. + +### D16. `RequestOptions` para opções por chamada (multi-tenant) + +**Decisão**: `Nfe::RequestOptions = Data.define(:api_key, :base_url, :timeout)` (campos opcionais). `Client#request` aceita `request_options:`; campos não-nil sobrepõem a resolução da família por chamada, nil cai para a resolução normal. `AbstractResource` repassa `request_options:` nos helpers; métodos de emissão o aceitam. + +**Por quê**: integradores multi-tenant precisam de uma `api_key` por chamada sem alocar um `Client` por tenant. `Data.define` mantém o objeto imutável e seguro para compartilhar. + +### D17. Chaves caem para variáveis de ambiente (fallback) + +**Decisão**: `api_key`/`data_api_key` caem para `ENV["NFE_API_KEY"]`/`ENV["NFE_DATA_API_KEY"]` quando o arg explícito for nil (ordem: arg explícito || env). A validação "ao menos uma chave" roda após o fallback. + +**Por quê**: convenção de 12-factor; `Nfe::Client.new` sem args funciona em ambientes com as env vars setadas, sem vazar a chave para o código. + +### D18. Confiança TLS só ADICIONA; nunca desliga verificação + +**Decisão**: `Configuration#ca_file` (e opcionalmente `#ca_path`) é o ÚNICO override de confiança TLS e só ADICIONA/substitui um CA bundle. NÃO há API pública para `VERIFY_NONE`/`insecure_ssl` — a verificação de peer nunca pode ser desligada. `#proxy` é repassado ao `Net::HTTP`. + +**Por quê**: ambientes corporativos exigem CA bundle próprio (proxy de inspeção), mas desligar verificação é um risco que o SDK não deve expor. O `insecureSsl` upstream é atributo server-side do alvo de webhook, não a TLS de saída do SDK — não confundir. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| Host map errado derruba múltiplos recursos com 404 (foi exatamente o bug de c05 no SDK PHP) | Tabela única auditável em `Configuration#base_url_for`; teste por família (6 hosts) obrigatório; nenhum recurso hard-coda URL | +| Refatorar o contrato 202 (`Pending`/`Issued`) depois é breaking change | Definir o par `Pending`/`Issued` + `handle_async_response` agora, na base, antes de qualquer recurso concreto | +| Shapes de paginação variam por endpoint (page vs cursor) | `ListPage` com metades opcionais acomoda ambos; cada `list()` documenta qual metade preenche | +| DTOs gerados podem não cobrir o shape real de algumas respostas (gen cobre `components.schemas`) | Changes de recurso criam DTOs hand-written fora de `lib/nfe/generated/` quando preciso; `hydrate` aceita qualquer `klass` com `.from_api` | +| Stubs vazios dos 17 recursos enganam o consumidor antes das changes de recurso | Cada stub levanta `NotImplementedError` com nome da change que o preenche | +| `regex` de `access_key` (44 dígitos) é frouxa e aceita sequências inválidas | Aceitar — validação local é fail-fast para typo, não substitui validação server-side | +| Cliente só com `data_api_key` não deve falhar na construção | Resolução de chave é lazy (no acesso ao recurso/transporte da família), não no `initialize` | +| Ausência de `create_and_wait` frustra quem espera polling automático | README documenta loop manual com `is_a?(Nfe::Pending)` + `FlowStatus.terminal?`; helper vem em release futura sem breaking change | +| CNPJ alfanumérico (v3, jul/2026) quebra coerção numérica | `IdValidator.cnpj` valida formato sem coagir para Integer; documentar que endpoints v3 aceitam alfanumérico | diff --git a/openspec/changes/archive/2026-06-25-add-client-core/proposal.md b/openspec/changes/archive/2026-06-25-add-client-core/proposal.md new file mode 100644 index 0000000..15f7ae7 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-client-core/proposal.md @@ -0,0 +1,79 @@ +# add-client-core + +## Why + +O SDK Ruby v1 (gem `nfe-io`, bump 0.3.2 → 1.0.0, reescrita greenfield) é montado em camadas: + +- **add-ruby-foundation** entrega o terreno: namespace `Nfe`, layout `lib/nfe/`, piso Ruby 3.2, `# frozen_string_literal: true` em todo `.rb`, RuboCop/Steep/RSpec/SimpleCov, zero dependências de runtime (só stdlib). +- **add-http-transport** entrega a camada HTTP testável sobre `Net::HTTP`: request/response, retries com backoff, timeouts, hierarquia de erros tipados (`Nfe::Error` e filhos) e injeção de transporte para teste. +- **add-openapi-pipeline** entrega o gerador: specs OpenAPI sincronizadas de `nfeio-docs` → objetos de valor imutáveis `Data.define` em `lib/nfe/generated/` + assinaturas `.rbs` em `sig/`. + +Falta a **superfície pública** que amarra tudo e que o consumidor de fato usa: o objeto `Nfe::Client` instanciável, no estilo Stripe (cliente único + acessores de recurso), a configuração tipada, o **host map multi-base-URL como fonte única de verdade**, a base `AbstractResource` que cobre ~80% dos endpoints CRUD com helpers, e o **contrato 202 discriminado** (Pending/Issued) que precisa existir na base antes de qualquer recurso concreto — adicioná-lo depois seria breaking change. + +Esta change é o núcleo de DX feito à mão. Ela **possui o registro de recursos**: entrega os **17 acessores stub lazy** que as changes de recurso (entity/invoice/lookup/rtc) depois preenchem. Sem ela, as três camadas anteriores são infraestrutura abstrata; com ela fechada, o SDK é exercitável internamente (dogfooding) mesmo antes de qualquer recurso concreto, porque a `AbstractResource` já contém o CRUD genérico. + +Depende de **add-ruby-foundation**, **add-http-transport** e **add-openapi-pipeline** (todas pré-requisitos). + +## What Changes + +### `Nfe::Client` — entrypoint único estilo Stripe + +- `Nfe::Client.new(api_key: "...", **config)` — cliente único com **17 acessores lazy snake_case** de recurso, memoizados na primeira leitura. +- Acessores são snake_case (`client.service_invoices`, `client.legal_entity_lookup`), paridade-plus com o SDK PHP (mesma superfície de 17 recursos). +- Cada acessor cria seu recurso preguiçosamente passando o transporte já resolvido para a família de host correta. +- `Nfe::Client` é a classe final pública; customização é por composição (transporte/config injetáveis), não herança. +- Os acessores memoizados são guardados por `Mutex` — um `Client` compartilhado é thread-safe (Rails/Sidekiq/Puma). +- `Nfe::RequestOptions` (`api_key`/`base_url`/`timeout`, opcionais) permite sobrepor a resolução por chamada — `api_key` por tenant sem um segundo `Client`. + +### `Nfe::Configuration` — config tipada + +- `api_key`, `data_api_key` (fallback para `api_key`), `environment` (`:production` | `:development`, default `:production`), `timeout`, `open_timeout`, `max_retries`, `logger`, `user_agent_suffix`, `ca_file`/`ca_path` (override de confiança TLS — só ADICIONA CA, nunca desliga verificação), `proxy`. +- `api_key`/`data_api_key` caem para `NFE_API_KEY`/`NFE_DATA_API_KEY` do ambiente como fallback; arg explícito vence. +- Overrides de base-URL por família (escape hatch para apontar para hosts customizados/sandbox). +- Validação no `initialize` (api_key não vazia, environment válido) levantando `Nfe::ConfigurationError`. + +### Host map multi-base-URL — fonte única de verdade + +- `Nfe::Configuration#base_url_for(family)` resolve o host correto por família de produto NFE.io. **Nenhum recurso hard-coda URL.** +- Mapa confirmado (CANONICAL FACTS): `main → https://api.nfe.io`; `addresses → https://address.api.nfe.io/v2`; `nfe-query → https://nfe.api.nfe.io`; `legal-entity → https://legalentity.api.nfe.io`; `natural-person → https://naturalperson.api.nfe.io`; `cte → https://api.nfse.io`. Família desconhecida → `main` como default seguro. +- Resolução da chave de API por família (chave de dados para `addresses`/`legal-entity`/`natural-person`/`nfe-query`, com fallback para a chave principal). + +### `Nfe::Resources::AbstractResource` — base de recurso + +- Helpers `get`/`post`/`put`/`delete` que delegam ao transporte com base-URL e versão da família. +- `full_path` tolerando versão de API vazia (caso `addresses`, cujo `/v2` está embutido no host). +- `hydrate(klass, payload)` para materializar DTOs `Data.define` gerados. +- `download(path)` retornando bytes crus como `String` binary-safe (`force_encoding("ASCII-8BIT")`). +- `hydrate_list` produzindo `Nfe::ListResponse` + `Nfe::ListPage` que cobre paginação **page-style** (`page_index`/`page_count`) **e** cursor-style (`starting_after`/`ending_before`). +- `Nfe::IdValidator` (`company_id`, `invoice_id`, `access_key` normalizando para `/^\d{44}$/`, `state_tax_id`, `event_key`, `cnpj`, `cpf`, `cep`, `state`) levantando `Nfe::InvalidRequestError` fail-fast com mensagens em pt-BR. + +### Contrato 202 discriminado + FlowStatus + +- Tipos base de resultado: `Nfe::Pending` (expõe `invoice_id`/`location`) e `Nfe::Issued` (expõe `resource`). Recursos que podem retornar 202 retornam um dos dois, discriminável por classe. +- `Nfe::FlowStatus.terminal?(status)` retornando `true` para `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`. + +### Diferido explicitamente (pós-1.0) + +- `create_and_wait` / helper de polling (`poll_until_complete`) — paridade com a decisão de PHP/Node de diferir. `Nfe::FlowStatus.terminal?` já é entregue agora para habilitar loops de polling manuais. +- `create_batch` — açúcar concorrente, sem ganho real no modelo síncrono v1. + +## Capabilities + +### New Capabilities + +- `client-core`: classe `Nfe::Client` com 17 acessores lazy snake_case; `Nfe::Configuration` tipada; host map multi-base-URL como fonte única de verdade; `Nfe::Resources::AbstractResource` com helpers (get/post/put/delete, full_path, hydrate, download, hydrate_list); `Nfe::IdValidator`; tipos base do contrato 202 (`Pending`/`Issued`); `Nfe::ListResponse`/`Nfe::ListPage`; `Nfe::FlowStatus.terminal?`. + +### Modified Capabilities + +- (nenhuma — greenfield) + +## Impact + +- **Código afetado**: `lib/nfe/client.rb`, `lib/nfe/configuration.rb`, `lib/nfe/request_options.rb` (`RequestOptions`), `lib/nfe/resources/abstract_resource.rb`, `lib/nfe/id_validator.rb`, `lib/nfe/pagination.rb` (`ListResponse`/`ListPage`), `lib/nfe/results.rb` (`Pending`/`Issued`), `lib/nfe/flow_status.rb`, `lib/nfe/version.rb`, e 17 stubs de recurso UNSUFFIXED em `lib/nfe/resources/.rb` (`Nfe::Resources::`). Assinaturas correspondentes em `sig/`. +- **Spec impact**: adiciona a capability `client-core`. +- **Dependências**: depende de **add-ruby-foundation** (namespace/tooling), **add-http-transport** (transporte + erros) e **add-openapi-pipeline** (DTOs `Data.define` para `hydrate`). +- **Downstream**: as changes de recurso (entity/invoice/lookup/rtc) substituem os 17 stubs por implementações reais reaproveitando `AbstractResource`, `IdValidator`, `ListResponse`, `Pending`/`Issued` e o host map daqui. +- **Riscos**: + - O contrato 202 (`Pending`/`Issued`) precisa estar correto agora — refatorá-lo depois é breaking change. + - Shapes de paginação variam por endpoint (page vs cursor); `ListPage` acomoda ambos. + - O host map é a única fonte de verdade — um erro aqui derruba múltiplos recursos com 404; cobertura de teste por família é obrigatória. diff --git a/openspec/changes/archive/2026-06-25-add-client-core/specs/client-core/spec.md b/openspec/changes/archive/2026-06-25-add-client-core/specs/client-core/spec.md new file mode 100644 index 0000000..58396af --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-client-core/specs/client-core/spec.md @@ -0,0 +1,299 @@ +# client-core — Delta + +## ADDED Requirements + +### Requirement: Public Client class as the single entry point +The SDK SHALL expose `Nfe::Client` as the single primary entry point. Consumers SHALL instantiate it with at minimum an API key and obtain access to all SDK functionality through this object. The class SHALL be the public surface and SHALL NOT be designed for subclassing; customization SHALL be achieved by composing `Nfe::Configuration` and an injected transport. + +#### Scenario: Minimal instantiation +- **WHEN** a consumer writes `Nfe::Client.new(api_key: "my-key")` +- **THEN** the object SHALL be ready to use with sensible defaults (production environment, default retry policy, default `Net::HTTP`-based transport) + +#### Scenario: Instantiation with explicit configuration +- **WHEN** a consumer writes `Nfe::Client.new(configuration: Nfe::Configuration.new(api_key: "k", timeout: 120))` +- **THEN** the supplied `Nfe::Configuration` SHALL govern all subsequent requests and the convenience keyword arguments SHALL be ignored + +#### Scenario: Missing all keys +- **WHEN** a consumer writes `Nfe::Client.new` with neither `api_key` nor `data_api_key` nor `configuration`, **and** neither `NFE_API_KEY` nor `NFE_DATA_API_KEY` is present in the environment +- **THEN** the SDK SHALL raise `Nfe::ConfigurationError` indicating that an API key is required + +### Requirement: Typed Configuration with constructor validation +The SDK SHALL provide `Nfe::Configuration` carrying all configuration options: `api_key`, `data_api_key`, `environment`, `timeout`, `open_timeout`, `max_retries`, `logger`, `user_agent_suffix`, `base_url_overrides`, `ca_file`, `ca_path`, and `proxy`. Construction SHALL validate the inputs and SHALL raise `Nfe::ConfigurationError` on invalid values. + +#### Scenario: Defaults applied +- **WHEN** a consumer writes `Nfe::Configuration.new(api_key: "k")` +- **THEN** `environment` SHALL default to `:production`, `max_retries` SHALL default to a non-negative integer, and `timeout`/`open_timeout` SHALL default to positive values + +#### Scenario: Empty API key rejected +- **WHEN** a consumer writes `Nfe::Configuration.new(api_key: "")` with no `data_api_key` and no `NFE_API_KEY`/`NFE_DATA_API_KEY` in the environment +- **THEN** the constructor SHALL raise `Nfe::ConfigurationError` + +#### Scenario: Data-only configuration is valid +- **WHEN** a consumer writes `Nfe::Configuration.new(data_api_key: "d")` with no `api_key` +- **THEN** the object SHALL construct successfully, deferring the main-key requirement until a main-family resource is accessed + +#### Scenario: Invalid environment rejected +- **WHEN** a consumer writes `Nfe::Configuration.new(api_key: "k", environment: :sandbox)` +- **THEN** the constructor SHALL raise `Nfe::ConfigurationError`, since only `:production` and `:development` are accepted + +### Requirement: Environment selects key, not URL +The SDK SHALL accept `environment` as one of `:production` (default) or `:development`. Both environments SHALL target the same API endpoints; the active environment SHALL be differentiated by the API key in use, not by a distinct base URL. + +#### Scenario: Production and development share endpoints +- **WHEN** a consumer constructs a client with `environment: :development` +- **THEN** the resolved base URLs SHALL be identical to those used under `:production`, and only the API key SHALL differ in effect + +### Requirement: Multi-base-URL host map is the single source of truth +`Nfe::Configuration` SHALL expose `base_url_for(family)` returning the correct host per NFE.io product family. This method SHALL be the only place that knows hosts; no resource SHALL hard-code a URL. The mapping SHALL be: `main` → `https://api.nfe.io`; `addresses` → `https://address.api.nfe.io/v2`; `nfe-query` → `https://nfe.api.nfe.io`; `legal-entity` → `https://legalentity.api.nfe.io`; `natural-person` → `https://naturalperson.api.nfe.io`; `cte` → `https://api.nfse.io`. An unknown family SHALL fall back to the `main` host. + +#### Scenario: Main family resolution +- **WHEN** `base_url_for(:main)` (or an alias such as `:companies`, `:service_invoices`, `:legal_people`, `:natural_people`, `:webhooks`) is called +- **THEN** it SHALL return `https://api.nfe.io` + +#### Scenario: Addresses host embeds the version +- **WHEN** `base_url_for(:addresses)` is called +- **THEN** it SHALL return `https://address.api.nfe.io/v2`, where the `/v2` is part of the base URL and not the resource path + +#### Scenario: CT-e family resolution +- **WHEN** `base_url_for(:cte)` (or an alias such as `:transportation`, `:inbound_product`, `:product_invoices`, `:consumer_invoices`, `:tax_calculation`, `:tax_codes`, `:state_taxes`) is called +- **THEN** it SHALL return `https://api.nfse.io` + +#### Scenario: Query and lookup hosts +- **WHEN** `base_url_for(:nfe_query)`, `base_url_for(:legal_entity)`, and `base_url_for(:natural_person)` are called +- **THEN** they SHALL return `https://nfe.api.nfe.io`, `https://legalentity.api.nfe.io`, and `https://naturalperson.api.nfe.io` respectively + +#### Scenario: Unknown family falls back to main +- **WHEN** `base_url_for(:something_unknown)` is called +- **THEN** it SHALL return `https://api.nfe.io` + +#### Scenario: Per-family override +- **WHEN** a `Configuration` is built with `base_url_overrides: { cte: "https://staging.example" }` and `base_url_for(:cte)` is called +- **THEN** it SHALL return `https://staging.example`, taking precedence over the default map + +### Requirement: API key resolution per family (two-key model) +`Nfe::Configuration` SHALL expose `api_key_for(family)`. Data-services families (`addresses`, `legal-entity`, `natural-person`, `nfe-query`) SHALL use `data_api_key` when present and SHALL fall back to `api_key` otherwise. All other families SHALL use `api_key`. When the resolved key is `nil` at the time a resource is accessed, the SDK SHALL raise `Nfe::ConfigurationError`. + +#### Scenario: Data family uses data key +- **WHEN** a configuration has both `api_key` and `data_api_key` set and `api_key_for(:addresses)` is called +- **THEN** it SHALL return the `data_api_key` + +#### Scenario: Data family falls back to main key +- **WHEN** a configuration has only `api_key` set and `api_key_for(:nfe_query)` is called +- **THEN** it SHALL return the `api_key` + +#### Scenario: Main family always uses main key +- **WHEN** `api_key_for(:main)` is called on a configuration that also has a `data_api_key` +- **THEN** it SHALL return the `api_key`, never the `data_api_key` + +### Requirement: Configuration keys fall back to environment variables +`Nfe::Configuration` SHALL resolve `api_key` from the `NFE_API_KEY` environment variable and `data_api_key` from the `NFE_DATA_API_KEY` environment variable as a FALLBACK. An explicit constructor argument SHALL always win over the environment value (resolution order: explicit argument, then environment). The "at least one key provided" validation SHALL run after this fallback is applied. + +#### Scenario: API key read from environment +- **WHEN** `NFE_API_KEY` is set in the environment and a consumer writes `Nfe::Configuration.new` with no explicit `api_key` +- **THEN** the configuration SHALL adopt the `NFE_API_KEY` value as its `api_key` + +#### Scenario: Data API key read from environment +- **WHEN** `NFE_DATA_API_KEY` is set in the environment and a consumer writes `Nfe::Configuration.new` with no explicit `data_api_key` +- **THEN** the configuration SHALL adopt the `NFE_DATA_API_KEY` value as its `data_api_key` + +#### Scenario: Explicit argument wins over environment +- **WHEN** `NFE_API_KEY` is set in the environment and a consumer writes `Nfe::Configuration.new(api_key: "explicit")` +- **THEN** the configuration SHALL use `"explicit"` and SHALL ignore the environment value + +### Requirement: TLS trust can only be added, never disabled +`Nfe::Configuration#ca_file` (and optionally `#ca_path`) SHALL be the ONLY override of the TLS trust store, and it SHALL only be able to ADD or replace a CA bundle used to verify the peer. The SDK SHALL NOT expose any public API to set `OpenSSL::SSL::VERIFY_NONE` or otherwise disable peer verification (no `insecure_ssl` flag). The upstream `insecureSsl` attribute is a server-side property of a webhook delivery target and SHALL NOT be confused with the SDK's outbound TLS configuration. `Nfe::Configuration#proxy`, when set, SHALL be passed through to the underlying `Net::HTTP` proxy configuration. + +#### Scenario: Custom CA bundle is honored +- **WHEN** a `Configuration` is built with `ca_file: "/path/to/corporate-ca.pem"` +- **THEN** the transport SHALL use that bundle to verify the server certificate while STILL performing full peer verification + +#### Scenario: Peer verification cannot be disabled +- **WHEN** a consumer searches the public `Nfe::Configuration` and `Nfe::Client` surface for a way to disable certificate verification +- **THEN** no public option SHALL set `VERIFY_NONE` or an `insecure_ssl` mode, and peer verification SHALL remain enabled on every request + +### Requirement: Seventeen lazy snake_case resource accessors +`Nfe::Client` SHALL expose at least the following seventeen core resource accessors, each a snake_case method that lazily constructs and memoizes its resource on first read. Opt-in additive changes (e.g. `add-rtc-invoice-emission`) MAY register further accessors on top of these seventeen. The accessors SHALL be: `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, and `state_taxes`. This surface matches the PHP SDK 1:1 — parity-plus over the 16-resource Node SDK: the Ruby/PHP surface adds the 17th resource, `consumer_invoices` (NFC-e emission), which the Node SDK does not expose. + +#### Scenario: Accessing a resource accessor +- **WHEN** consumer code reads `client.service_invoices` +- **THEN** it SHALL return an instance of the corresponding resource class (a subclass of `Nfe::Resources::AbstractResource`) + +#### Scenario: Memoization +- **WHEN** consumer code reads `client.companies` twice +- **THEN** both reads SHALL return the same object identity (the resource SHALL be constructed once and cached) + +#### Scenario: All seventeen core accessors present +- **WHEN** the seventeen accessor names are enumerated against `Nfe::Client` +- **THEN** each SHALL be a defined public method; these seventeen form the core resource surface, and no additional **core** accessor SHALL exist beyond them (opt-in extension changes MAY register further accessors, such as `service_invoices_rtc` and `product_invoices_rtc` from `add-rtc-invoice-emission`) + +#### Scenario: Data-only client serves data resources +- **WHEN** a client constructed with only `data_api_key` reads `client.addresses` +- **THEN** the resource SHALL be usable without raising, because the addresses family resolves the data key + +#### Scenario: Main resource without main key raises on access +- **WHEN** a client constructed with only `data_api_key` reads `client.companies` and issues a request +- **THEN** the SDK SHALL raise `Nfe::ConfigurationError`, because the main family has no resolvable key + +### Requirement: Lazy resource accessors are thread-safe +A single `Nfe::Client` instance SHALL be safe to share across threads. The lazy, memoized resource accessors SHALL guard their memoization with a `Mutex` so that concurrent first reads of the same accessor construct the resource exactly once and never race. This makes a shared `Client` safe under Rails, Sidekiq, and Puma. (The per-origin keep-alive connection pool is guarded by its own `Mutex` in `add-http-transport`.) + +#### Scenario: Concurrent first read returns one instance +- **WHEN** many threads read `client.companies` for the first time concurrently on a shared `Nfe::Client` +- **THEN** every thread SHALL observe the same single resource instance and no duplicate resource SHALL be constructed by a race + +### Requirement: AbstractResource provides HTTP and hydration helpers +The SDK SHALL define `Nfe::Resources::AbstractResource`, constructed with the owning `Nfe::Client`. It SHALL provide protected helpers `get`, `post`, `put`, and `delete` that build requests through the client's transport for the resource's declared family, plus `full_path`, `hydrate`, `download`, `hydrate_list`, and `handle_async_response`. Each subclass SHALL declare its `api_family` and (optionally) `api_version`. + +#### Scenario: Subclass issues a request +- **WHEN** a resource whose `api_family` is `:cte` calls `get("/v2/companies/x/productinvoices")` +- **THEN** the outgoing request SHALL target `https://api.nfse.io` (resolved via `base_url_for(:cte)`) with the family's resolved API key applied + +#### Scenario: full_path with a version +- **WHEN** a resource with `api_version` `"v1"` calls `full_path("/companies/x")` +- **THEN** the result SHALL be `/v1/companies/x` + +#### Scenario: full_path with an empty version +- **WHEN** a resource with an empty `api_version` (e.g., the addresses resource, whose host embeds `/v2`) calls `full_path("/addresses/01310100")` +- **THEN** the result SHALL be `/addresses/01310100` with no doubled leading slash + +#### Scenario: hydrate produces an immutable value object +- **WHEN** `hydrate(SomeDto, payload)` is called with a payload hash +- **THEN** it SHALL return an immutable `Data.define` value object produced by the generated DTO's factory (e.g., `SomeDto.from_api(payload)`) + +### Requirement: Downloads return raw bytes as a binary-safe String +`AbstractResource#download(path)` SHALL return the response body as a Ruby `String` whose encoding is `Encoding::ASCII_8BIT` (binary-safe), so binary documents (PDF/XML/ZIP) are not corrupted by transcoding. The caller decides whether to persist (e.g., `File.binwrite`) or stream the bytes. + +#### Scenario: PDF download is binary-safe +- **WHEN** `download("/.../pdf")` succeeds against the API +- **THEN** the return value SHALL be a `String` with encoding `ASCII-8BIT` whose first four bytes are `%PDF` + +#### Scenario: XML download is binary-safe +- **WHEN** `download("/.../xml")` succeeds +- **THEN** the return value SHALL be a `String` with encoding `ASCII-8BIT` containing the raw XML bytes + +### Requirement: Discriminated 202 contract with Pending and Issued results +The SDK SHALL define `Nfe::Pending` (a `Data.define` exposing `invoice_id` and `location`) and `Nfe::Issued` (a `Data.define` exposing `resource`). `AbstractResource#handle_async_response` SHALL return `Nfe::Pending` for an HTTP 202 response carrying a `Location` header, and `Nfe::Issued` (wrapping a hydrated DTO) for an HTTP 201/200 response with a body. Consumers SHALL discriminate the result with `is_a?`/`case`. + +#### Scenario: Async 202 yields Pending +- **WHEN** `handle_async_response` receives an HTTP 202 with `Location: /v1/companies/x/serviceinvoices/abc-123` +- **THEN** it SHALL return an `Nfe::Pending` whose `invoice_id` is `abc-123` (parsed from the final path segment) and whose `location` is the header value + +#### Scenario: Immediate 201 yields Issued +- **WHEN** `handle_async_response` receives an HTTP 201 with the materialized invoice body +- **THEN** it SHALL return an `Nfe::Issued` whose `resource` is the DTO hydrated from the response body + +#### Scenario: 202 without Location is a protocol violation +- **WHEN** `handle_async_response` receives an HTTP 202 with no `Location` header +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` describing the missing header + +#### Scenario: Discriminating the result +- **WHEN** consumer code branches on `result.is_a?(Nfe::Pending)` +- **THEN** the pending branch SHALL expose `invoice_id`/`location` and the other branch SHALL expose `resource` + +### Requirement: FlowStatus terminal-state helper +The SDK SHALL provide `Nfe::FlowStatus.terminal?(status)` returning `true` for `"Issued"`, `"IssueFailed"`, `"Cancelled"`, and `"CancelFailed"`, and `false` for all other values. The method SHALL accept either a `String` or a `Symbol`. This helper enables manual polling loops in the absence of an automatic polling helper. + +#### Scenario: Terminal status +- **WHEN** `Nfe::FlowStatus.terminal?("Issued")`, `"IssueFailed"`, `"Cancelled"`, or `"CancelFailed"` is called +- **THEN** the method SHALL return `true` + +#### Scenario: Non-terminal status +- **WHEN** `Nfe::FlowStatus.terminal?("WaitingDefineRpsNumber")` (or any of `PullFromCityHall`, `WaitingCalculateTaxes`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, `WaitingDownload`) is called +- **THEN** the method SHALL return `false` + +#### Scenario: Unknown status +- **WHEN** `Nfe::FlowStatus.terminal?("Whatever")` is called +- **THEN** the method SHALL return `false` + +### Requirement: ListResponse accommodates page-style and cursor-style pagination +The SDK SHALL provide `Nfe::ListResponse` carrying `data` (a list of hydrated DTOs) and `page` (`Nfe::ListPage`). `Nfe::ListPage` SHALL expose `page_index`, `page_count`, `starting_after`, `ending_before`, and `total`, all optional, so each resource populates the half relevant to its endpoint. `AbstractResource#hydrate_list(klass, payload, wrapper_key:)` SHALL unwrap `payload[wrapper_key]`, hydrate each item, and build the appropriate `ListPage`. + +#### Scenario: Page-style listing +- **WHEN** a resource paginates with `page_index`/`page_count` (e.g., service invoices, companies, tax codes) +- **THEN** the returned `ListResponse.page` SHALL have `page_index` and `page_count` set and the cursor fields `nil` + +#### Scenario: Cursor-style listing +- **WHEN** a resource paginates with `starting_after`/`ending_before` (e.g., product invoices, consumer invoices, state taxes) +- **THEN** the returned `ListResponse.page` SHALL have the cursor fields set and `page_index` `nil` + +#### Scenario: Data is uniform across shapes +- **WHEN** a consumer reads `result.data` regardless of pagination shape +- **THEN** it SHALL be a list of hydrated DTOs accessible identically in both cases + +### Requirement: ID and access-key validators run before HTTP +The SDK SHALL provide `Nfe::IdValidator` with methods `company_id`, `invoice_id`, `access_key`, `state_tax_id`, `event_key`, `cnpj`, `cpf`, `cep`, and `state`. Each validator SHALL run client-side and SHALL raise `Nfe::InvalidRequestError`, with a Portuguese-language message identifying the invalid argument, before any HTTP request is issued. `access_key` SHALL accept formatted input, strip non-digit characters, validate the result against `/\A\d{44}\z/`, and return the normalized string. `cnpj` SHALL normalize and validate format without coercing to Integer, so that future alphanumeric CNPJ (v3) input is not corrupted. + +#### Scenario: Empty company ID rejected synchronously +- **WHEN** `Nfe::IdValidator.company_id("")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously, without making an HTTP request, with a pt-BR message + +#### Scenario: Access key with formatting is normalized +- **WHEN** `Nfe::IdValidator.access_key("3526 1234 ... (44 digits with separators)")` is called +- **THEN** it SHALL return a 44-character digits-only string and SHALL NOT raise + +#### Scenario: Access key of wrong length rejected +- **WHEN** `Nfe::IdValidator.access_key("123")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` + +#### Scenario: CNPJ is not coerced to Integer +- **WHEN** `Nfe::IdValidator.cnpj("12.345.678/0001-90")` is called +- **THEN** it SHALL return a normalized `String` of digits and SHALL NOT return or rely on an Integer + +#### Scenario: Invalid state rejected +- **WHEN** `Nfe::IdValidator.state("ZZ")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` + +### Requirement: Resource registry maps each accessor to the correct host +Each of the seventeen resource stubs SHALL declare an `api_family` such that, through `Configuration#base_url_for`, it resolves to the canonical host for that product. The five families involved SHALL be: `main` (service_invoices, companies, legal_people, natural_people, webhooks), `cte` (product_invoices, consumer_invoices, transportation_invoices, inbound_product_invoices, tax_calculation, tax_codes, state_taxes), `nfe-query` (product_invoice_query, consumer_invoice_query), `addresses` (addresses), `legal-entity` (legal_entity_lookup), and `natural-person` (natural_person_lookup). + +#### Scenario: Each accessor resolves its expected host +- **WHEN** a resource's declared `api_family` is resolved via `base_url_for` +- **THEN** the host SHALL match the canonical map (e.g., `transportation_invoices` → `https://api.nfse.io`, `addresses` → `https://address.api.nfe.io/v2`, `legal_entity_lookup` → `https://legalentity.api.nfe.io`) + +#### Scenario: Stub method raises until filled by a resource change +- **WHEN** consumer code calls a business method on an unfilled resource stub +- **THEN** the SDK SHALL raise `NotImplementedError` naming the change that implements the resource (e.g., `add-invoice-resources`) + +### Requirement: Low-level request escape hatch +`Nfe::Client` SHALL expose an internal method to issue an arbitrary request against any family, allowing consumers and resources to call endpoints not yet wrapped by a resource. It SHALL resolve the family's host and key and apply the standard authorization and User-Agent headers. + +#### Scenario: Calling an unwrapped endpoint +- **WHEN** a consumer calls `client.request(:get, family: :main, path: "/v1/some/new/endpoint")` +- **THEN** the SDK SHALL issue the request to `https://api.nfe.io/v1/some/new/endpoint` with the main key and standard headers, returning the raw response + +### Requirement: Per-call request options for multi-tenant overrides +The SDK SHALL define `Nfe::RequestOptions` as an immutable `Data.define` carrying optional `api_key`, `base_url`, and `timeout`. `Nfe::Client#request` SHALL accept an optional `request_options:` keyword, and when present its non-nil fields SHALL override the family-resolved `api_key`, `base_url`, and `timeout` for that single call; nil fields SHALL fall back to the normal family resolution. `Nfe::Resources::AbstractResource` SHALL accept and thread an optional `request_options:` through its helpers to `Nfe::Client#request`, and resource methods (at least the emission methods) SHALL accept it. This enables a multi-tenant per-call `api_key` without constructing a second `Client`. + +#### Scenario: Per-call api_key overrides the family key +- **WHEN** a caller passes `request_options: Nfe::RequestOptions.new(api_key: "tenant-key")` to a request on a `Client` configured with a different `api_key` +- **THEN** that single request SHALL authenticate with `"tenant-key"` while other requests continue to use the client's configured key + +#### Scenario: Nil fields fall back to family resolution +- **WHEN** a caller passes `Nfe::RequestOptions.new(timeout: 90)` with `api_key` and `base_url` left nil +- **THEN** only the timeout SHALL be overridden for that call and the `api_key`/`base_url` SHALL resolve normally from the family + +#### Scenario: Two tenants share one client +- **WHEN** two requests on the same `Client` each pass a distinct `request_options.api_key` +- **THEN** each request SHALL use its own tenant key, with no second `Client` instance required + +### Requirement: User-Agent carries the SDK version +The transport SHALL build a `User-Agent` header from `Nfe::VERSION`, optionally appending `user_agent_suffix` when configured. + +#### Scenario: Version in User-Agent +- **WHEN** any request is issued +- **THEN** the `User-Agent` header SHALL include the `Nfe::VERSION` string + +#### Scenario: Integrator suffix appended +- **WHEN** the client is configured with `user_agent_suffix: "my-app/2.1"` +- **THEN** the `User-Agent` header SHALL include both the SDK version and `my-app/2.1` + +### Requirement: createAndWait and polling helper are deferred past 1.0 +The SDK v1.0 SHALL NOT implement `create_and_wait`, `create_batch`, or a `poll_until_complete` helper on the client or any resource. The discriminated `Nfe::Pending`/`Nfe::Issued` contract plus `Nfe::FlowStatus.terminal?` SHALL be sufficient for writing manual polling loops, and these helpers are explicitly deferred to a future release without breaking the public contract. + +#### Scenario: Looking for an automatic polling helper +- **WHEN** consumer code references `client.poll_until_complete(...)` or a resource's `create_and_wait(...)` against v1.0 +- **THEN** Ruby SHALL raise `NoMethodError`, since the method is not defined + +#### Scenario: Manual polling is documented +- **WHEN** v1.0 documentation describes polling +- **THEN** it SHALL show a manual loop using `result.is_a?(Nfe::Pending)`, `retrieve`, and `Nfe::FlowStatus.terminal?` until a terminal state is reached diff --git a/openspec/changes/archive/2026-06-25-add-client-core/tasks.md b/openspec/changes/archive/2026-06-25-add-client-core/tasks.md new file mode 100644 index 0000000..3e84417 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-client-core/tasks.md @@ -0,0 +1,136 @@ +# Tasks — add-client-core + +> Depende de **add-ruby-foundation**, **add-http-transport** e **add-openapi-pipeline** (todas arquivadas). Todo `.rb` começa com `# frozen_string_literal: true`. Ruby floor 3.2; CI 3.2/3.3/3.4. Zero dependências de runtime (só stdlib). Tipos via RBS em `sig/`, Steep no CI, RuboCop no lint, RSpec com SimpleCov >= 80%. +> +> **Status (2026-06-25): IMPLEMENTADO e verificado verde via Docker na matrix Ruby 3.2/3.3/3.4.** Entregue: `Nfe::Configuration` completa (host map + aliases, `api_key_for` dois-modos, fallback `NFE_API_KEY`/`NFE_DATA_API_KEY`, `ca_file`/`ca_path`/`proxy`), `Nfe::Client` (transporte `RetryingTransport(NetHttp)` por família com mutex, `#request` levantando `ErrorFactory` em não-2xx, 17 acessores lazy memoizados), `Nfe::RequestOptions` (override por chamada/multi-tenant), `Nfe::Pending`/`Issued`, `Nfe::ListResponse`/`ListPage`, `Nfe::IdValidator`, `Nfe::Resources::AbstractResource` (get/post/put/delete, `full_path`, `hydrate`→`from_api`, `download` ASCII-8BIT, `hydrate_list` page/cursor, `handle_async_response` 202→Pending), os **17 stubs** de recurso, e `ConfigurationError`/`InvoiceProcessingError`. `FlowStatus`/`VERSION` reaproveitados da fundação. Gate: rspec 298/0 (cobertura ~95.6%), rubocop 0, steep 0, rbs ok, generate:check in-sync — nos três Rubies. Decisões na verificação: acessores explícitos (não `define_method`, p/ Steep ver o método privado); ENV fallback via `ENV.fetch`; `proxy` armazenado mas wiring no `NetHttp` reservado. + +## 1. Versão e constantes + +- [ ] 1.1 Criar `lib/nfe/version.rb` com `module Nfe; VERSION = "1.0.0"; end` (bump 0.3.2 → 1.0.0). +- [ ] 1.2 `*.gemspec` lê `Nfe::VERSION` (carregar o arquivo no gemspec; sem hardcode duplicado). +- [ ] 1.3 Assinatura `sig/nfe/version.rbs` (`Nfe::VERSION: String`). +- [ ] 1.4 Spec `spec/nfe/version_spec.rb` — `Nfe::VERSION` casa com `/\A\d+\.\d+\.\d+/`. + +## 2. Erros do core (estendendo a hierarquia de add-http-transport) + +- [ ] 2.1 Garantir `Nfe::ConfigurationError < Nfe::Error` (config inválida: api_key faltando para uma família, environment inválido). Se já existir em add-http-transport, apenas referenciar; senão definir em `lib/nfe/errors.rb`. +- [ ] 2.2 Garantir `Nfe::InvalidRequestError < Nfe::Error` (validação client-side: id vazio, access_key malformada, etc.) — mensagens em pt-BR. +- [ ] 2.3 Garantir `Nfe::InvoiceProcessingError < Nfe::Error` (202 sem `Location`, invoice_id não extraível). +- [ ] 2.4 Assinaturas `sig/` para quaisquer erros novos introduzidos aqui. +- [ ] 2.5 Spec `spec/nfe/errors_spec.rb` cobrindo herança e `message`/`code`/`status` dos erros novos. + +## 3. Configuration + host map (fonte única de verdade) + +- [ ] 3.1 Criar `lib/nfe/configuration.rb` — `Nfe::Configuration` com `api_key`, `data_api_key`, `environment` (default `:production`), `timeout` (default 30), `open_timeout`, `max_retries` (default 3), `logger`, `user_agent_suffix`, `base_url_overrides` (Hash família→URL), `ca_file` (default nil), `ca_path` (opcional, default nil) e `proxy` (default nil). +- [ ] 3.2 Validar no `initialize`: `api_key` não vazia (a menos que só `data_api_key` seja fornecida — ver 3.3); `environment` ∈ `{:production, :development}` senão `raise Nfe::ConfigurationError`; `timeout`/`open_timeout` positivos. +- [ ] 3.3 Permitir cliente só com `data_api_key` (resolução de chave principal é lazy, não no `initialize`). Validar que ao menos uma chave foi fornecida (após aplicar o fallback de ENV da 3.8). +- [ ] 3.4 Implementar `#base_url_for(family)` com o mapa confirmado: `main → https://api.nfe.io`; `addresses → https://address.api.nfe.io/v2`; `nfe-query → https://nfe.api.nfe.io`; `legal-entity → https://legalentity.api.nfe.io`; `natural-person → https://naturalperson.api.nfe.io`; `cte → https://api.nfse.io`; default (desconhecida) → `main`. Aceitar aliases de família (ex.: `:companies`, `:service_invoices` → `main`; `:transportation`, `:inbound_product`, `:tax_calculation`, `:tax_codes`, `:product_invoices`, `:consumer_invoices`, `:state_taxes` → `cte`). +- [ ] 3.5 `#base_url_for` consulta `base_url_overrides[family]` primeiro (escape hatch); só então aplica o mapa. +- [ ] 3.6 Implementar `#api_key_for(family)` — famílias de dados (`:addresses`, `:legal_entity`, `:natural_person`, `:nfe_query`) usam `data_api_key` quando presente, senão `api_key`; demais usam `api_key`. Levantar `Nfe::ConfigurationError` se a chave resolvida for nil quando o recurso é acessado. +- [ ] 3.7 Documentar (comentário): produção e desenvolvimento usam o MESMO endpoint, diferenciados por chave (não por URL). Não expor "sandbox URL". +- [ ] 3.8 Resolução de chaves a partir do ambiente como FALLBACK: `api_key` cai para `ENV["NFE_API_KEY"]` e `data_api_key` cai para `ENV["NFE_DATA_API_KEY"]` quando o arg explícito for nil/ausente (ordem: arg explícito || env). Args explícitos sempre vencem. Aplicar antes da validação de "ao menos uma chave fornecida". +- [ ] 3.9 TLS-trust: `ca_file` (e opcionalmente `ca_path`) é o ÚNICO override de confiança TLS e só pode ADICIONAR/substituir um CA bundle. NÃO expor API pública para `VERIFY_NONE`/`insecure_ssl` (a verificação de peer NUNCA pode ser desligada). Comentar que o `insecureSsl` upstream é atributo server-side do alvo de webhook, não a TLS de saída do SDK. `proxy` é repassado ao `Net::HTTP` (stdlib). +- [ ] 3.10 Assinatura `sig/nfe/configuration.rbs` (incluir `ca_file`, `ca_path`, `proxy`). +- [ ] 3.11 Spec `spec/nfe/configuration_spec.rb`: defaults; api_key vazia → erro; environment inválido → erro; só `data_api_key` constrói; `base_url_for` para as 6 famílias + default + override; `api_key_for` fallback data→main; env fallback `NFE_API_KEY`/`NFE_DATA_API_KEY` com arg explícito vencendo; nenhuma API pública desliga a verificação de peer. + +## 4. Client (entrypoint + 17 acessores lazy) + +- [ ] 4.1 Criar `lib/nfe/client.rb` — `Nfe::Client.new(api_key: nil, data_api_key: nil, configuration: nil, environment: :production, timeout: 30, max_retries: 3, logger: nil, user_agent_suffix: nil)`. Se `configuration:` vier, ignora os outros; senão monta `Configuration` a partir deles. +- [ ] 4.2 Expor `attr_reader :configuration` (e o transporte resolvido). Cliente é a classe pública final; sem subclasse suportada. +- [ ] 4.3 Implementar resolução/memoização de transporte por família (chama add-http-transport com `base_url_for(family)`, `api_key_for(family)`, timeout, retries, user-agent). Memoizar por família. +- [ ] 4.4 Implementar os **17 acessores lazy snake_case**, cada um memoizado sob Mutex (ex.: `@mutex.synchronize { @service_invoices ||= Nfe::Resources::ServiceInvoices.new(self) }`) e referenciando as classes UNSUFFIXED `Nfe::Resources::`: `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, `state_taxes`. +- [ ] 4.5 Método interno `#request(method, family:, path:, query: {}, body: nil, headers: {}, request_options: nil)` (escape hatch low-level) que resolve transporte da família e injeta auth/user-agent; quando `request_options` vier, sobrepõe api_key/base_url/timeout por chamada (ver 4b). Marcar como `@api private` no comentário. +- [ ] 4.6 Acessar um recurso de família de dados com só `data_api_key` funciona; acessar um recurso `main` sem `api_key` levanta `Nfe::ConfigurationError` no momento do acesso. +- [ ] 4.7 Assinatura `sig/nfe/client.rbs` (17 acessores tipados aos seus `*Resource`). +- [ ] 4.8 Spec `spec/nfe/client_spec.rb`: construção via api_key e via configuration; 17 acessores retornam a classe certa; memoização (mesma instância em 2 leituras); só data_api_key funciona para data, falha para main; user-agent inclui versão + suffix. +- [ ] 4.9 Thread-safety: o `Client` guarda os acessores memoizados com um `Mutex` (`@resource_mutex.synchronize { ... }`), de modo que um `Client` compartilhado entre threads (Rails/Sidekiq/Puma) construa cada recurso uma única vez sem race. (O pool de conexões keep-alive é guardado em add-http-transport.) +- [ ] 4.10 Spec: leitura concorrente de um acessor por N threads retorna sempre a MESMA instância (sem duplicação por race). + +## 4b. RequestOptions (opções por chamada / multi-tenant) + +- [ ] 4b.1 Criar `lib/nfe/request_options.rb` — `Nfe::RequestOptions = Data.define(:api_key, :base_url, :timeout)` (todos opcionais, default nil), objeto de valor imutável para sobrepor configuração por chamada. +- [ ] 4b.2 `Nfe::Client#request` aceita `request_options:` (opcional) e, quando presente, sobrepõe `api_key`/`base_url`/`timeout` resolvidos da família por chamada — habilita `api_key` por tenant SEM um segundo `Client`. Args não preenchidos no `RequestOptions` caem para a resolução normal da família. +- [ ] 4b.3 `Nfe::Resources::AbstractResource` aceita e repassa um `request_options:` opcional nos helpers (`get`/`post`/`put`/`delete`) até `client.request`; métodos de recurso (ao menos os de emissão) aceitam `request_options:`. +- [ ] 4b.4 Assinatura `sig/nfe/request_options.rbs`. +- [ ] 4b.5 Spec `spec/nfe/request_options_spec.rb`: `RequestOptions` por chamada sobrepõe a `api_key` da família; campos nil caem para a resolução normal; dois tenants no mesmo `Client` usam chaves distintas por chamada. + +## 5. Tipos base do contrato 202 (Pending / Issued) + +- [ ] 5.1 Criar `lib/nfe/results.rb` — `Nfe::Pending = Data.define(:invoice_id, :location)` e `Nfe::Issued = Data.define(:resource)`. +- [ ] 5.2 (Opcional, doc) Marcar `Pending`/`Issued` como o piso discriminável; changes de recurso podem subclassificar se precisarem de discriminação mais fina. +- [ ] 5.3 Assinatura `sig/nfe/results.rbs`. +- [ ] 5.4 Spec `spec/nfe/results_spec.rb`: `Pending` expõe `invoice_id`/`location`; `Issued` expõe `resource`; igualdade por valor; `is_a?` discrimina. + +## 6. FlowStatus + +- [ ] 6.1 Criar `lib/nfe/flow_status.rb` — `Nfe::FlowStatus.terminal?(status)` retorna `true` para `"Issued"`, `"IssueFailed"`, `"Cancelled"`, `"CancelFailed"`; `false` para os demais (`PullFromCityHall`, `WaitingCalculateTaxes`, `WaitingDefineRpsNumber`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, `WaitingDownload`). +- [ ] 6.2 Aceitar `String` e Symbol (normalizar para comparação). Definir constantes `TERMINAL` e `NON_TERMINAL` (arrays congelados). +- [ ] 6.3 Assinatura `sig/nfe/flow_status.rbs`. +- [ ] 6.4 Spec `spec/nfe/flow_status_spec.rb`: os 4 terminais → true; os 7 não-terminais → false; valor desconhecido → false. + +## 7. Paginação (ListResponse + ListPage) + +- [ ] 7.1 Criar `lib/nfe/pagination.rb` — `Nfe::ListResponse = Data.define(:data, :page)` e `Nfe::ListPage = Data.define(:page_index, :page_count, :starting_after, :ending_before, :total)` (todos opcionais, default nil). +- [ ] 7.2 `ListResponse` permite iterar `result.data` igual nos dois shapes; `ListPage` carrega só a metade relevante. +- [ ] 7.3 (Opcional) helper `ListPage.from_page(index:, count:, total: nil)` e `ListPage.from_cursor(starting_after:, ending_before:, total: nil)` para conveniência dos recursos. +- [ ] 7.4 Assinatura `sig/nfe/pagination.rbs`. +- [ ] 7.5 Spec `spec/nfe/pagination_spec.rb`: page-style preenche page_index/page_count e cursores nil; cursor-style preenche cursores e page_index nil; `data` íntegro nos dois. + +## 8. IdValidator (fail-fast em pt-BR) + +- [ ] 8.1 Criar `lib/nfe/id_validator.rb` — módulo `Nfe::IdValidator` com métodos: `company_id(v)`, `invoice_id(v)`, `state_tax_id(v)`, `event_key(v)` (não vazios; retornam o valor). +- [ ] 8.2 `access_key(v)` — remove não-dígitos, valida `/\A\d{44}\z/`, retorna string normalizada; senão `Nfe::InvalidRequestError` ("chave de acesso deve conter 44 dígitos"). +- [ ] 8.3 `cnpj(v)` — normaliza removendo separadores, valida formato (14 posições). NÃO coagir para Integer (suporte futuro a CNPJ alfanumérico v3). Retorna string normalizada. +- [ ] 8.4 `cpf(v)` — normaliza para 11 dígitos, valida formato. Retorna string normalizada. +- [ ] 8.5 `cep(v)` — remove hífen, valida 8 dígitos. Retorna string normalizada. +- [ ] 8.6 `state(v)` — UF maiúscula; valida contra lista (27 UFs + `EX`, `NA`). Retorna normalizada. +- [ ] 8.7 Todas as mensagens de erro em pt-BR, identificando qual argumento é inválido. +- [ ] 8.8 Assinatura `sig/nfe/id_validator.rbs`. +- [ ] 8.9 Spec `spec/nfe/id_validator_spec.rb`: company_id vazio → erro; access_key com separadores → 44 dígitos; access_key "123" → erro; cnpj/cpf/cep normalizam; state inválida → erro; cnpj alfanumérico não vira Integer. + +## 9. AbstractResource (base + helpers) + +- [ ] 9.1 Criar `lib/nfe/resources/abstract_resource.rb` — `Nfe::Resources::AbstractResource` recebe `client` no `initialize`; guarda referência. +- [ ] 9.2 `api_family` e `api_version` como métodos protected (subclasse sobrescreve; `api_version` default `"v1"`; `addresses` retorna `""`). +- [ ] 9.3 Helpers protected `get(path, query: {}, request_options: nil, **opts)`, `post(path, body: nil, request_options: nil, **opts)`, `put(path, body: nil, request_options: nil, **opts)`, `delete(path, query: {}, request_options: nil, **opts)` — delegam a `client.request(family:, path: full_path(path), request_options:, ...)`, repassando o `request_options` por chamada. +- [ ] 9.4 `full_path(path)` — prefixa `/#{api_version}` quando `api_version` não vazio; quando vazio (addresses) retorna `path` sem `//` duplicado. +- [ ] 9.5 `hydrate(klass, payload)` — materializa DTO `Data.define` chamando a fábrica `klass.from_api(payload)` do DTO gerado. O call site `from_api` fica aqui (client-core), mas o PRODUTOR de `from_api` (mapeamento camelCase→snake_case, drop de chaves desconhecidas, recursão em DTOs aninhados, `.rbs`) é **add-openapi-pipeline** — não redefinir `from_api` aqui. Desempacotamento de envelope fica no recurso, não na base. +- [ ] 9.6 `download(path, **opts)` — faz `get`, valida sucesso, retorna `response.body.dup.force_encoding(Encoding::ASCII_8BIT)` (bytes crus binary-safe). Define `Accept` apropriado quando o chamador passar (ex.: `application/pdf`). +- [ ] 9.7 `hydrate_list(klass, payload, wrapper_key:)` — desempacota `payload[wrapper_key]`, hidrata cada item em `klass`, monta `ListPage` detectando shape (page-style vs cursor-style) e retorna `Nfe::ListResponse`. +- [ ] 9.8 `handle_async_response(response, issued_klass:)` — se status 202: extrai `Location` (header, case-insensitive), parseia `invoice_id` do último segmento via `%r{/([a-z0-9-]+)\z}i`, retorna `Nfe::Pending`; sem `Location` → `Nfe::InvoiceProcessingError`. Se 201/200: hidrata `issued_klass` do body e retorna `Nfe::Issued`. +- [ ] 9.9 Assinatura `sig/nfe/resources/abstract_resource.rbs`. +- [ ] 9.10 Spec `spec/nfe/resources/abstract_resource_spec.rb` (via subclasse de teste + transporte mock): `full_path` com versão vazia e não-vazia; `get/post/put/delete` montam a request certa para a família; `download` retorna ASCII-8BIT; `hydrate_list` page e cursor; `handle_async_response` 202→Pending, 201→Issued, 202-sem-Location→InvoiceProcessingError. + +## 10. Os 17 stubs de recurso (registro de recursos) + +- [ ] 10.1 Criar 17 arquivos stub em `lib/nfe/resources/` na convenção UNSUFFIXED (`lib/nfe/resources/.rb` definindo `Nfe::Resources::`), um por recurso, cada classe `< Nfe::Resources::AbstractResource` declarando seu `api_family` correto. Os nomes SÃO os UNSUFFIXED exatos para que as changes de recurso substituam os stubs arquivo-a-arquivo: + - `service_invoices.rb` → `Nfe::Resources::ServiceInvoices` (`:main`), `product_invoices.rb` → `Nfe::Resources::ProductInvoices` (`:cte`), `consumer_invoices.rb` → `Nfe::Resources::ConsumerInvoices` (`:cte`), `transportation_invoices.rb` → `Nfe::Resources::TransportationInvoices` (`:cte`), `inbound_product_invoices.rb` → `Nfe::Resources::InboundProductInvoices` (`:cte`) + - `product_invoice_query.rb` → `Nfe::Resources::ProductInvoiceQuery` (`:nfe_query`), `consumer_invoice_query.rb` → `Nfe::Resources::ConsumerInvoiceQuery` (`:nfe_query`) + - `companies.rb` → `Nfe::Resources::Companies` (`:main`), `legal_people.rb` → `Nfe::Resources::LegalPeople` (`:main`), `natural_people.rb` → `Nfe::Resources::NaturalPeople` (`:main`), `webhooks.rb` → `Nfe::Resources::Webhooks` (`:main`) + - `addresses.rb` → `Nfe::Resources::Addresses` (`:addresses`, `api_version` `""`), `legal_entity_lookup.rb` → `Nfe::Resources::LegalEntityLookup` (`:legal_entity`), `natural_person_lookup.rb` → `Nfe::Resources::NaturalPersonLookup` (`:natural_person`) + - `tax_calculation.rb` → `Nfe::Resources::TaxCalculation` (`:cte`), `tax_codes.rb` → `Nfe::Resources::TaxCodes` (`:cte`), `state_taxes.rb` → `Nfe::Resources::StateTaxes` (`:cte`) +- [ ] 10.2 Cada stub declara `api_family`/`api_version` corretos mas NÃO implementa métodos de negócio — chamadas a métodos de negócio levantam `NotImplementedError` com a mensagem da change que o preenche (ex.: "implementado em add-invoice-resources"). +- [ ] 10.3 Garantir que `client.` retorna a instância stub correta e que sua família resolve o host esperado (sem 404 por host errado). +- [ ] 10.4 Assinaturas `sig/` para cada stub (classe + `api_family`). +- [ ] 10.5 Spec `spec/nfe/resources/registry_spec.rb`: para os 17 acessores, a família declarada mapeia para o host correto via `base_url_for`; cobre os 6 hosts distintos. + +## 11. Require/boot + +- [ ] 11.1 Garantir que `lib/nfe.rb` faz `require` de version, errors, configuration, request_options, results, flow_status, pagination, id_validator, abstract_resource, os 17 stubs UNSUFFIXED (`lib/nfe/resources/.rb`) e client (na ordem de dependência). +- [ ] 11.2 Confirmar que `require "nfe"` carrega tudo sem erro e que `Nfe::Client.new(api_key: "k")` instancia. + +## 12. Documentação e exemplos + +- [ ] 12.1 README: Quickstart com `Nfe::Client.new(api_key:)`, exemplo de acesso lazy a recurso, e tabela dos 17 acessores → família/host. +- [ ] 12.2 README: documentar o loop de polling MANUAL com `result.is_a?(Nfe::Pending)` + `Nfe::FlowStatus.terminal?`, com nota explícita de que `create_and_wait`/`poll_until_complete` são DIFERIDOS para release pós-1.0. +- [ ] 12.3 README: documentar modelo de duas chaves (`api_key` vs `data_api_key`) e quando cada família usa qual. +- [ ] 12.4 README: nota de que downloads retornam `String` binária (ASCII-8BIT) — usar `File.binwrite`. + +## 13. Validação end-to-end + +- [x] 13.1 `bundle exec rspec` — 298 exemplos / 0 falhas, cobertura ~95.6% (docker 3.2/3.3/3.4). +- [x] 13.2 `bundle exec rubocop` — 0 offenses; `# frozen_string_literal: true` em todo `.rb` (docker 3.2/3.3/3.4). +- [x] 13.3 `bundle exec steep check` — 0 erros (docker 3.2/3.3/3.4). +- [x] 13.4 Gate verde nas 3 versões da matriz (Ruby 3.2 / 3.3 / 3.4) via Docker. +- [x] 13.5 `openspec validate add-client-core --strict` — passa. +- [x] 13.6 Zero dependências de runtime no gemspec (confirmado em add-ruby-foundation; só stdlib). diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-entity-resources/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/README.md b/openspec/changes/archive/2026-06-25-add-entity-resources/README.md new file mode 100644 index 0000000..dfab725 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/README.md @@ -0,0 +1,3 @@ +# add-entity-resources + +Os quatro recursos de entidade do SDK Ruby v1 no host principal (`api.nfe.io`) — companies (CRUD + upload de certificado .pfx/.p12), legal_people, natural_people e webhooks — mais o helper de verificação de assinatura HMAC-SHA1 (`Nfe::Webhook.verify_signature`). diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/design.md b/openspec/changes/archive/2026-06-25-add-entity-resources/design.md new file mode 100644 index 0000000..5f3503e --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/design.md @@ -0,0 +1,161 @@ +# Design — add-entity-resources + +## Context + +**add-client-core** entregou o terreno: `Nfe::Client` com 17 acessores lazy snake_case, `Nfe::Configuration` com o host map multi-base-URL, `Nfe::Resources::AbstractResource`, o contrato 202 discriminado (`Pending`/`Issued`), `Nfe::FlowStatus`, `Nfe::ListResponse` e as exceções tipadas. Esta change é o **primeiro consumidor real** desses blocos no grupo de entidades. + +Os 4 recursos desta change rodam todos no host **principal** (`main` → `base_url_for(:main)` retorna `https://api.nfe.io`; o `/v1` vem do `api_version` do recurso, URL efetiva `https://api.nfe.io/v1/...`). Diferente dos invoice resources (que se espalham por `api.nfse.io`, `nfe.api.nfe.io` etc.), aqui não há roteamento exótico: todos resolvem via `Configuration#base_url_for(:main)`. + +Dois perfis distintos: + +- **CRUD de entidade** (companies, legal_people, natural_people): create/list/retrieve/update/delete com envelopes `{"" => ...}`, mais helpers de conveniência (`find_by_*`). +- **Segurança + gestão de notificação** (webhooks): CRUD de subscrição + `test` + lista estática de eventos, e — separado do recurso, como capability própria — o módulo `Nfe::Webhook` para verificar a assinatura HMAC de entregas recebidas. + +A canonicidade do esquema de assinatura (HMAC-SHA1 + `X-Hub-Signature`, bytes crus, hex maiúsculo, prefixo `sha1=`) está fundamentada em três fontes independentes: + +1. `docs/documentacao/webhooks/duvidas-frequentes.md:33` — "Segredo... gerar o valor do HMAC em hexadecimal... no cabeçalho HTTP X-Hub-Signature. O HMAC será gerado baseado no(s) bytes do evento de notificação." +2. `docs/documentacao/webhooks/ips-de-origem.md:44-45` — "Cabeçalho X-Hub-Signature, no formato sha1=. Algoritmo HMAC-SHA1." +3. Probe ao vivo (registrado em `client-nodejs/openspec/changes/fix-webhook-signature-verification`): `sha1=BCD17C02B9E3B40A18E745E7E04247E4AD2DD935`, confirmado em registros product/service/mixed, registro global único em `api.nfse.io`. + +## Goals / Non-Goals + +**Goals** +- 4 recursos com paridade método-por-método com o SDK Node, adaptados a idiomas Ruby (snake_case, keyword args, `Data.define`, retornos síncronos, `String` binária para downloads — embora estes recursos quase não tenham downloads). +- Gestão de certificado **completa** (upload + replace + validate local), indo **além** do PHP v3.0 que diferiu isso, aproveitando `Net::HTTP#set_form` (multipart) e `OpenSSL::PKCS12` (parse real) da stdlib — sem nenhuma dependência de runtime nova. +- Módulo `Nfe::Webhook` que torne a verificação de assinatura uma linha de código no caller, sem precisar instanciar `Client`, com `OpenSSL.secure_compare` (constante). +- `verify_signature` **nunca levanta exceção**; `construct_event` levanta `Nfe::SignatureVerificationError` apenas em assinatura inválida. +- 100% dos métodos com validação fail-fast de ID via os helpers de **add-client-core** antes de qualquer HTTP. + +**Non-Goals** +- `create_and_wait` / `create_batch` concorrente — pertencem aos invoice resources / release futura. `create_batch` aqui é loop sequencial. +- Iterador `Enumerator::Lazy` sofisticado de paginação — `list_each` (Enumerator simples) é suficiente para v1. +- Validação de check-digit de CNPJ/CPF no cliente — colide com CNPJ alfanumérico (jul/2026); deixamos para o servidor. +- Otimização de `find_by_*` e `get_companies_with_*` — replicamos o Node (N+1) como conveniência, sem rate-limit smartness. +- Suporte ao esquema antigo `X-NFe-Signature`/SHA-256 — explicitamente não-suportado (é um bug da documentação de distribuição). + +## Decisions + +### D1. `Nfe::Webhook` é um módulo de funções, sem dependência do `Client` +**Decisão**: `module Nfe::Webhook` com `module_function`. Não recebe `Client`, não lê `Configuration`. O caller passa `secret` direto. + +```ruby +event = Nfe::Webhook.construct_event( + payload: request.body.read, # bytes crus, ANTES do JSON.parse + signature: request.get_header("HTTP_X_HUB_SIGNATURE"), + secret: ENV.fetch("NFE_WEBHOOK_SECRET"), +) +``` + +**Por quê**: verificação de webhook é 100% offline — não precisa de credencial de API. O caller típico é um endpoint Rack/Rails/Sinatra onde nenhum `Nfe::Client` está no escopo. `Stripe::Webhook.construct_event` faz exatamente isso. Como a capability é independente do `Client`, ela ganha um `spec.md` separado (`webhook-signature-verification`). + +**Alternativa rejeitada**: método de instância `client.webhooks.verify_signature(...)` (o que o Node faz). Funciona, mas obriga a ter um `Client` configurado num lugar onde só se quer validar bytes. Manteremos um **alias** de instância `Nfe::Client#webhooks.verify_signature` delegando ao módulo, para paridade Node, mas a API canônica é o módulo estático. + +### D2. Dois níveis de API: `verify_signature` (Boolean) e `construct_event` (DTO) +**Decisão**: +- **Low-level** (paridade com `validateSignature` do Node): `verify_signature(payload:, signature:, secret:) -> Boolean`. Nunca levanta. +- **High-level** (preferido, ergonômico): `construct_event(payload:, signature:, secret:) -> Nfe::WebhookEvent`. Verifica, parseia o JSON e desembrulha o envelope; levanta `Nfe::SignatureVerificationError` em mismatch e `Nfe::SignatureVerificationError` (subclasse ou variante) em JSON malformado. + +**Por quê**: caller que quer logar assinaturas inválidas sem virar 500 usa o Boolean; caller comum usa `construct_event` e segue com `event.type`/`event.data`. + +### D3. Verificação de assinatura: bytes crus, prefixo `sha1=`, hex case-insensitive, `OpenSSL.secure_compare` +**Decisão**: o algoritmo de `verify_signature`, passo a passo (espelhando o `validateSignature` corrigido do Node, em Ruby): + +1. Retorna `false` se `secret` for `nil`/vazio ou `signature` for `nil`. +2. Normaliza o header: se vier `Array` (cabeçalho repetido), pega `[0]`. Se não for `String` não-vazia, `false`. +3. Exige e remove o prefixo `sha1=` (comparação do prefixo case-insensitive). Sem prefixo correto → `false`. **Recusa downgrade**: `sha256=...` → `false`. +4. Faz `downcase` no hex restante e valida a forma com `/\A[a-f0-9]{40}\z/` (HMAC-SHA1 é sempre 40 hex / 20 bytes). Forma errada → `false`. +5. Calcula `expected = OpenSSL::HMAC.hexdigest("SHA1", secret, body)` sobre os **bytes crus** do payload (sem reserializar JSON). Se o caller passar `String`, usa como está (já são os bytes recebidos); o caller é instruído a ler `request.body.read` antes do parse. +6. Compara com `OpenSSL.secure_compare(received_hex, expected_hex)` (tempo constante). Como ambos têm 40 chars garantidos, `secure_compare` é seguro. + +**Por quê**: `OpenSSL.secure_compare` é a primitiva de comparação constante da stdlib Ruby (existe desde Ruby 2.x via `openssl`), análoga ao `crypto.timingSafeEqual` do Node e ao `hash_equals` do PHP. Comparar a forma hex (case-normalizada) evita o problema de `Buffer.from(hex)` que o Node teve. Validar a forma antes evita alimentar lixo no compare. + +**Por quê não decodificar para bytes antes de comparar**: `OpenSSL.secure_compare` opera sobre strings de mesmo comprimento; 40 chars hex normalizados são suficientes e mais simples que decodificar para 20 bytes. A normalização de case (`downcase` nos dois lados) cobre a maiúscula-na-rede da NFE.io. + +### D4. Header tolerante: aceita com e sem prefixo? — **exige prefixo `sha1=`** +**Decisão**: `verify_signature` **exige** o prefixo `sha1=` (o formato canônico que a NFE.io envia em `X-Hub-Signature`). Hex puro sem prefixo → `false`. + +**Por quê**: a produção sempre envia `sha1=`. Exigir o prefixo (e recusar `sha256=`) é defesa contra confusão de algoritmo (vetor de CVE histórico em libs de webhook). Isso difere da decisão "aceita com ou sem prefixo" do PHP, mas alinha-se ao comportamento real e mais seguro confirmado no probe do Node. Documentamos: passe o valor bruto do header. + +### D5. `OpenSSL::PKCS12` faz validação **real** do certificado (vs magic-byte do Node) +**Decisão**: `companies.validate_certificate(file:, password:)`: +- Lê os bytes do .pfx/.p12 (aceita caminho de arquivo `String`/`Pathname` que é lido, ou os bytes já carregados como `String`). +- `pkcs12 = OpenSSL::PKCS12.new(der_bytes, password)` — isto **levanta `OpenSSL::PKCS12::PKCS12Error` em senha errada ou DER inválido**. Capturamos e levantamos `Nfe::InvalidRequestError` com mensagem clara em pt-BR. +- Extrai do `pkcs12.certificate`: `subject.to_s`, `issuer.to_s`, `not_before`, `not_after`, `serial.to_s`. +- Retorna `Nfe::CertificateInfo` (Data.define) com esses campos. `days_until_expiration` derivado de `not_after`. + +**Por quê**: o validador do Node é raso — só checa magic-byte `0x3082` e **fabrica** metadata (`subject: "Certificate Subject"`, `valid_to: now+365d`). O Ruby tem `OpenSSL::PKCS12` na stdlib, então fazemos o parse de verdade: validamos a senha de fato e extraímos a data de expiração real. É o "fix" #2 anotado no recon (o Node faz a checagem rasa; o Ruby deve usar `OpenSSL::PKCS12`). + +**Alternativa rejeitada**: replicar a checagem de magic-byte. Rejeitada — é fraca e nasceria com a mesma dívida do Node. + +### D6. `upload_certificate` usa multipart nativo do `Net::HTTP` +**Decisão**: incluir `upload_certificate(company_id, file:, password:, filename: nil)` e `replace_certificate(...)` (alias) no v1. +- Pré-valida formato (extensão `.pfx`/`.p12`) e roda `validate_certificate` (parse local) antes do upload — fail-fast. +- Monta `multipart/form-data` com os campos `file` (binário) e `password`, seguindo o spec OpenAPI: NFS-e v1 declara `POST /v1/companies/{company_id}/certificate` com partes `file` + `password`; v2 usa `/certificates` plural com `file` + `password`. O v1 Ruby segue o **nome de campo do spec** (`file`), não o `certificate` que o código Node usa por divergência. +- Delega a montagem multipart ao transport de **add-http-transport** (`Net::HTTP::Post#set_form([[...]], "multipart/form-data")`). + +**Por quê**: o PHP diferiu por não ter multipart no `CurlTransport`. O Ruby não tem essa limitação — `Net::HTTP` faz multipart nativamente. Entregar upload no v1 fecha o ciclo de cadastro de company (sem certificado, a company não emite nada), e a stdlib resolve sem gem nova, mantendo a regra de zero dependências de runtime. + +**Coordenação**: depende de o transport de add-http-transport expor um caminho que aceite corpo multipart (não só `String`). Registrado como dependência de implementação em tasks §2. + +### D7. Envelopes desembrulhados por recurso, não na base +**Decisão**: cada recurso conhece e desembrulha sua própria chave de envelope antes de hidratar o `Data.define`. A `AbstractResource` não sabe de envelopes. + +```ruby +# companies: payload["companies"] +# legal_people: payload["legalPeople"] +# natural_people: payload["naturalPeople"] +# webhooks: sem envelope (resposta plana) — list usa o ListResponse padrão +``` + +**Por quê**: cada endpoint conhece seu próprio envelope; centralizar na base vira uma chuva de `if`s. Espelha a decisão D3/D6 dos changes PHP e do Node (`response.data.companies`, `response.data.legalPeople`). + +### D8. Companies usa paginação page-style; converte 1-based → 0-based +**Decisão**: `companies.list(page_index:, page_count:)` usa paginação page-style. A API retorna `{"companies" => [...], "page" => N}` com `page` 1-based; o recurso converte para `page_index` 0-based no `Nfe::ListResponse` retornado (paridade exata com o Node `response.data.page - 1`). `list_all` itera com `page_count: 100` até a página vir com menos de 100 itens. `list_each` retorna um `Enumerator` que faz o mesmo loop sob demanda. + +**Por quê**: paridade com o Node. `legal_people`/`natural_people` **não** têm parâmetros de paginação na assinatura Node (`list(company_id)` retorna a lista inteira em `{"" => [...]}`), então seu `list` não converte página — só desembrulha. + +### D9. `find_by_*` e `get_companies_with_*` são conveniências client-side +**Decisão**: implementação trivial — `list_all` + filtro em Ruby. RDoc/YARD marca como "para contas pequenas; contas grandes devem filtrar no servidor". `get_companies_with_certificates` / `get_companies_with_expiring_certificates` fazem `list_all` + N chamadas a `get_certificate_status` (N+1), capturando erros por company (pula a que falhar), igual ao Node. + +**Por quê**: paridade + ergonomia para o caso comum. Quem tem 10.000 entidades não usa isso. + +### D10. `webhooks.test` chama `POST /test`; `get_available_events` é lista estática +**Decisão**: `test(company_id, webhook_id)` faz `POST /companies/{id}/webhooks/{webhook_id}/test` e retorna `{ success:, message: }` (Hash simples ou `Data.define`). `get_available_events` retorna a lista estática hard-coded (paridade Node): + +```ruby +%w[ + invoice.issued invoice.cancelled invoice.failed invoice.processing + company.created company.updated company.deleted +] +``` + +**Por quê**: o Node faz exatamente isto (constante hard-coded). A API tem `/webhooks/eventtypes`, mas o Node não chama; mantemos paridade. Os 7 eventos são superset do union de tipos do Node (que lista só 4) — replicamos os 7 que o `getAvailableEvents` retorna. + +### D11. `Nfe::WebhookEvent` é `Data.define` mínimo e desembrulha o envelope de entrega +**Decisão**: + +```ruby +Nfe::WebhookEvent = Data.define(:type, :data, :id, :created_at) +``` + +`construct_event` aceita o envelope de entrega da NFE.io e normaliza: `{"action" => t, "payload" => d}` ou `{"event" => t, "data" => d}` → `WebhookEvent.new(type: t, data: d, id: ..., created_at: ...)`. `data` é um `Hash` opaco; o caller refina conforme o `type`. + +**Por quê**: payloads de webhook variam; um DTO mínimo evita falsas garantias. Imutável (`Data.define`) por consistência com o resto do SDK. + +### D12. CNPJ/CPF: validar formato/comprimento, NÃO check-digit, NÃO coagir para Integer +**Decisão**: no `companies.create`/`update` e nos `find_by_tax_number`, normalizamos o tax number para dígitos (string) e validamos só formato/comprimento via os helpers de **add-client-core**. **Não** rodamos algoritmo de dígito verificador e **não** convertemos para `Integer`. + +**Por quê**: o `validateCNPJ` do Node assume CNPJ puramente numérico — incompatível com o **CNPJ alfanumérico** (IN RFB 2.229/2024, vigente jul/2026, letras nas 12 primeiras posições, dígitos verificadores ainda numéricos). Coagir para `Integer` quebraria o formato novo. O check-digit é validado no servidor; replicá-lo no cliente seria uma armadilha de v1. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| API muda o esquema de assinatura (ex.: para SHA-256) sem aviso | Esquema confirmado por 3 fontes + probe ao vivo; um parâmetro de algoritmo interno permite estender sem breaking change; fixtures de teste quebram cedo se a produção mudar | +| Caller computa HMAC sobre JSON reserializado (`payload.to_json`) em vez dos bytes crus → sempre `false` | RDoc + README mostram `request.body.read` ANTES do parse; bloco de aviso explícito; é a falha #1 mais comum de integradores | +| Envelopes (`{"companies" => {...}}`) inconsistentes entre endpoints | Cada método tem fixture de teste; mismatch falha no spec | +| `upload_certificate` depende de o transport (add-http-transport) aceitar corpo multipart | Coordenado em design D6 + tasks §2; se o transport só aceitar `String`, esta change inclui a extensão multipart mínima | +| `OpenSSL::PKCS12.new` pode levantar em certificados de cadeia incomum (não só senha errada) | Capturamos `OpenSSL::PKCS12::PKCS12Error` genericamente e levantamos `Nfe::InvalidRequestError` com a mensagem original anexada em `details` | +| `find_by_tax_number` lento em contas grandes | Documentado como conveniência; alternativa é filtro server-side (não exposto ainda) | +| Endpoint de `webhooks.test` diverge entre specs (`/test` vs `/pings/test`) | Smoke test em sandbox antes do GA; ajustar path se necessário | +| `OpenSSL.secure_compare` indisponível em build de Ruby sem openssl | openssl é stdlib padrão e está na lista de libs permitidas das decisões canônicas; CI roda em 3.2/3.3/3.4 com openssl presente | diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/proposal.md b/openspec/changes/archive/2026-06-25-add-entity-resources/proposal.md new file mode 100644 index 0000000..7cad5fd --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/proposal.md @@ -0,0 +1,66 @@ +# add-entity-resources + +## Why + +Os recursos de **entidade** são pré-requisito para qualquer integração funcional com a NFE.io: sem `company` cadastrada não se emite invoice; sem certificado digital A1 (.pfx/.p12) carregado a company não emite NF-e/NFS-e/NFC-e; sem `legal_person`/`natural_person` cadastrados o relacionamento tomador/destinatário fica manual; sem `webhook` registrado o integrador não recebe notificação de mudança de `FlowStatus`. Esta change implementa os 4 recursos de entidade que rodam no host principal (`api.nfe.io`) sobre o `Nfe::Client` e o `AbstractResource` entregues em **add-client-core**. + +Inclui também a **primeira camada de segurança servidor→cliente do SDK**: a verificação de assinatura HMAC dos webhooks. A NFE.io assina cada entrega com `HMAC-SHA1(secret, bytes_crus_do_corpo)`, hex em maiúsculas, prefixado com `sha1=`, no cabeçalho `X-Hub-Signature`. Isso é o **único** mecanismo que impede entregas forjadas no endpoint do consumidor (o allowlist de IP é só checagem secundária). O esquema foi confirmado por probe ao vivo contra `https://api.nfse.io/v2/webhooks` (registro `fix-webhook-signature-verification` do `client-nodejs`) e pela documentação fonte-de-verdade (`docs/documentacao/webhooks/duvidas-frequentes.md`, `ips-de-origem.md`). Por ser uma capability crítica e independente do `Client`, ela é especificada **em um spec.md separado** (`webhook-signature-verification`). + +Esta change depende de **add-client-core** (consome `Nfe::Client`, `Nfe::Configuration` com o host map, `Nfe::Resources::AbstractResource`, `Nfe::ListResponse`, helpers de validação de ID e as exceções tipadas). + +> ⚠️ **Atenção a defeitos conhecidos na documentação fonte** (NÃO replicar): os docs de distribuição (`distribuicao/02-doc-tecnica-clientes-dev.md` e `04-...-inbound-webhook.md`) descrevem o esquema ANTIGO e INCORRETO `X-NFe-Signature` + HMAC-SHA256. A produção usa `X-Hub-Signature` + HMAC-SHA1. O SDK Node atual também tem esse bug (corrigido na change `fix-webhook-signature-verification`). O Ruby **nasce certo**. + +## What Changes (high-level) + +### Recursos implementados (4) + +| Recurso (acessor snake_case) | Host base | Operações principais | +|---|---|---| +| `companies` | `api.nfe.io` | create, list, list_all, list_each, retrieve, update, remove, find_by_tax_number, find_by_name, get_companies_with_certificates, get_companies_with_expiring_certificates, **upload_certificate, replace_certificate, validate_certificate (local OpenSSL::PKCS12)**, get_certificate_status, check_certificate_expiration | +| `legal_people` | `api.nfe.io` | list, create, retrieve, update, delete, create_batch, find_by_tax_number | +| `natural_people` | `api.nfe.io` | list, create, retrieve, update, delete, create_batch, find_by_tax_number | +| `webhooks` | `api.nfe.io` | list, create, retrieve, update, delete, test, get_available_events | + +> Host base = `base_url_for(:main)` → `https://api.nfe.io`; o segmento `/v1` é fornecido pelo `api_version` do recurso (URL efetiva `https://api.nfe.io/v1/...`). + +### Diferença de escopo vs SDK PHP: upload de certificado **INCLUÍDO** no v1 Ruby + +O SDK PHP v3.0 **diferiu** upload/replace/validate de certificado por não ter multipart no `CurlTransport`. O Ruby v1 **inclui** essas operações desde a primeira release porque: +- `Net::HTTP` (stdlib, já é nossa dependência única de runtime) suporta multipart/form-data nativamente via `set_form` / `Net::HTTP::Post#set_form`, sem nenhuma gem extra. +- `OpenSSL::PKCS12` (stdlib) faz parse **real** do .pfx/.p12 e valida a senha (levanta `OpenSSL::PKCS12::PKCS12Error` em senha errada) — muito mais forte que a checagem de magic-byte `0x3082` do validador do Node, que é raso e fabrica metadata. Extraímos `subject`, `issuer`, `not_before`, `not_after` e calculamos `days_until_expiration` de verdade. + +### Adicionado (suporte) + +- **`Nfe::Webhook`** (módulo de funções, sem dependência de `Client`): + - `Nfe::Webhook.verify_signature(payload:, signature:, secret:)` — verificação low-level; retorna `Boolean`; nunca levanta exceção. HMAC-SHA1 sobre bytes crus, prefixo `sha1=`, hex case-insensitive, comparação constante via `OpenSSL.secure_compare`. + - `Nfe::Webhook.construct_event(payload:, signature:, secret:)` — high-level: verifica + parseia JSON + retorna `Nfe::WebhookEvent`; levanta `Nfe::SignatureVerificationError` em assinatura inválida (estilo `Stripe::Webhook.construct_event`). +- **`Nfe::WebhookEvent`** — `Data.define(:type, :data, :id, :created_at)` imutável; desempacota o envelope de entrega (`{"action" => ..., "payload" => ...}` ou `{"event" => ..., "data" => ...}`) para a forma canônica. +- **`Nfe::CertificateInfo`** — `Data.define(:subject, :issuer, :not_before, :not_after, :serial_number)` retornado por `validate_certificate`. +- **`Nfe::CertificateStatus`** — `Data.define(:has_certificate, :expires_on, :valid, :days_until_expiration, :expiring_soon, :details)` retornado por `get_certificate_status` (campos `days_until_expiration`/`expiring_soon` computados client-side a partir de `expires_on`). +- Desempacotamento de envelopes descobertos: `companies`/`legal_people`/`natural_people` retornam `{"" => ...}` na maioria dos endpoints; cada recurso desembrulha a chave correta antes de hidratar o `Data.define`. + +### Não inclui (deferido para fora deste change) + +- **Iterador auto-paginador "streaming"** equivalente ao `listIterator` (async generator) do Node — o Ruby idiomático oferece `list_each` (um `Enumerator` que pagina sob demanda via `Enumerator.new`/`yield`); um `Enumerator::Lazy` mais sofisticado fica para release futura. +- **`create_and_wait` / `create_batch` concorrente nos invoice resources** — fora do escopo desta change (pertence a add-invoice-resources). `create_batch` em `legal_people`/`natural_people` aqui é um loop **sequencial** (sem concorrência). +- **Validação de dígito verificador de CNPJ/CPF no `companies.create`** — o Node valida check-digit client-side, mas isso colide com o **CNPJ alfanumérico** (IN RFB 2.229/2024, vigente a partir de julho/2026) que admite letras nas 12 primeiras posições. O Ruby v1 valida apenas formato/comprimento e **não coage para Integer**, deixando o check-digit para o servidor — evitando a armadilha do `validateCNPJ` numérico-only do Node. + +## Capabilities + +### New Capabilities +- `entity-resources`: os 4 recursos de entidade (companies + certificado, legal_people, natural_people, webhooks) + DTOs `Data.define` de suporte (`CertificateInfo`, `CertificateStatus`, `WebhookEvent`). +- `webhook-signature-verification`: o módulo `Nfe::Webhook` (`verify_signature` + `construct_event`) com o esquema HMAC-SHA1/`X-Hub-Signature` validado em produção. + +### Modified Capabilities +- nenhuma — esta change apenas **consome** `add-client-core` (host map, `AbstractResource`, contrato 202, exceções) sem modificar a sua spec. + +## Impact + +- **Affected code**: `lib/nfe/resources/companies.rb`, `legal_people.rb`, `natural_people.rb`, `webhooks.rb`; `lib/nfe/webhook.rb`; `lib/nfe/webhook_event.rb`; `lib/nfe/certificate.rb` (validador OpenSSL + `CertificateInfo`/`CertificateStatus`). Assinaturas em `sig/nfe/resources/*.rbs`, `sig/nfe/webhook.rbs`, `sig/nfe/certificate.rbs`. Testes em `spec/nfe/resources/*_spec.rb`, `spec/nfe/webhook_spec.rb`, `spec/nfe/certificate_spec.rb`. +- **Spec impact**: adiciona as capabilities `entity-resources` e `webhook-signature-verification`. Consome `client-core` (host map family `main`, `AbstractResource`, exceções) sem modificá-la. +- **Dependencies**: depende de **add-client-core** (que por sua vez depende de add-http-transport e add-ruby-foundation). Compartilha os helpers de validação de ID/CNPJ/CPF e o `Nfe::ListResponse` definidos lá. +- **Riscos**: + - Envelopes de resposta (`{"companies" => {...}}`, `{"legalPeople" => [...]}`) precisam ser desembrulhados corretamente por método; um envelope inconsistente entre endpoints quebra a hidratação — coberto por fixtures de teste. + - `find_by_tax_number`/`find_by_name` fazem `list_all` + filtro client-side; em contas grandes (>50 entidades) é ineficiente — documentado como conveniência, não otimizado. + - `upload_certificate` depende de o `Net::HTTP` transport (de add-http-transport) expor um caminho multipart; se o transport só aceitar `String` body, esta change precisa coordenar com add-http-transport — registrado em design.md (D3) e tasks. + - O endpoint exato de `webhooks.test` (`/test` vs `/pings/test`) diverge entre specs OpenAPI — smoke test em sandbox antes do GA. diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/specs/entity-resources/spec.md b/openspec/changes/archive/2026-06-25-add-entity-resources/specs/entity-resources/spec.md new file mode 100644 index 0000000..1453ba5 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/specs/entity-resources/spec.md @@ -0,0 +1,186 @@ +# entity-resources — Delta + +## ADDED Requirements + +### Requirement: Four entity resources are fully implemented +The SDK SHALL implement four entity resource classes under `Nfe::Resources` — `Companies`, `LegalPeople`, `NaturalPeople`, and `Webhooks` — reachable through the lazy snake_case accessors `client.companies`, `client.legal_people`, `client.natural_people`, and `client.webhooks` on the `Nfe::Client` defined in `add-client-core`. All four resolve to the `main` host family (`base_url_for(:main)` → `https://api.nfe.io`, with the `/v1` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfe.io/v1/...`) via `Nfe::Configuration#base_url_for(:main)`. Method names and behaviour SHALL match the NFE.io Node.js SDK 1:1, adapted to Ruby idioms (snake_case methods, keyword arguments, `Data.define` value objects, synchronous returns, raised typed errors). + +#### Scenario: Resource availability on Client +- **WHEN** consumer code reads any of `client.companies`, `client.legal_people`, `client.natural_people`, `client.webhooks` +- **THEN** the accessor SHALL return a fully functional resource instance (not a stub raising `NoMethodError`) + +#### Scenario: Entity resources route to the main host +- **WHEN** any method of any of the four entity resources issues an HTTP request +- **THEN** the request SHALL target the host `https://api.nfe.io` resolved through `Configuration#base_url_for(:main)`, with the `/v1` segment supplied by the resource `api_version` (effective URL `https://api.nfe.io/v1/...`) and no hard-coded host in the resource + +#### Scenario: Parity with the Node SDK +- **WHEN** comparing method names, parameter order, and return-shape categories between this Ruby SDK and the Node SDK for any of the four entity resources +- **THEN** they SHALL be 1:1 equivalent modulo language idioms (snake_case, keyword args, `Data.define`, synchronous returns) and the additions and deferrals documented in this change's design.md + +### Requirement: Companies CRUD with response unwrapping +`Nfe::Resources::Companies` SHALL expose `create`, `list`, `list_all`, `list_each`, `retrieve`, `update`, and `remove` against `/companies`. The NFE.io API wraps responses in `{"companies" => }`; the resource SHALL transparently unwrap that envelope before hydrating a `Nfe::Company` value object. + +#### Scenario: Create returns hydrated value object +- **WHEN** `create(data)` succeeds with the API responding `{"companies" => {"id" => "abc", "name" => "Acme"}}` +- **THEN** the method SHALL return a `Nfe::Company` whose `id` and other fields are populated + +#### Scenario: List pagination converts 1-based to 0-based +- **WHEN** `list(page_count: 20, page_index: 0)` is called and the API responds `{"companies" => [...], "page" => 1}` +- **THEN** the method SHALL return a `Nfe::ListResponse` whose `page.page_index` is `0` (the API uses 1-based indexing and the resource converts to 0-based) + +#### Scenario: list_all auto-paginates +- **WHEN** `list_all` is called against an account with 250 companies +- **THEN** the method SHALL issue multiple GET requests with `page_count: 100` until a page returns fewer than 100 items and SHALL return a single `Array` aggregating all pages + +#### Scenario: list_each streams via an Enumerator +- **WHEN** `list_each` is called without a block +- **THEN** the method SHALL return an `Enumerator` that fetches pages on demand and yields one `Nfe::Company` at a time + +#### Scenario: Remove returns deletion confirmation +- **WHEN** `remove(company_id)` succeeds +- **THEN** the method SHALL return `{ deleted: true, id: company_id }` + +#### Scenario: Not found surfaces typed error +- **WHEN** `retrieve(company_id)` receives HTTP 404 from the API +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +### Requirement: Companies tax-number handling avoids numeric coercion +`Nfe::Resources::Companies#create` and `#update` SHALL validate the `federalTaxNumber` for format and length only (11 digits CPF or 14 digits CNPJ), normalised as a digit string. They SHALL NOT run check-digit validation client-side and SHALL NOT coerce the value to an `Integer`, so that alphanumeric CNPJ (IN RFB 2.229/2024, effective July 2026) is not corrupted. + +#### Scenario: Tax number kept as string +- **WHEN** `create` is called with a 14-character alphanumeric CNPJ +- **THEN** the SDK SHALL accept it without converting to `Integer` and without rejecting it on a numeric-only check-digit rule + +#### Scenario: Wrong-length tax number rejected +- **WHEN** `create` is called with a `federalTaxNumber` whose normalised digit length is neither 11 nor 14 +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` before issuing an HTTP request + +### Requirement: Companies search and finder helpers +`Nfe::Resources::Companies` SHALL expose `find_by_tax_number(tax_number)` returning a `Nfe::Company` or `nil`, and `find_by_name(name)` returning an `Array` of matching companies. Both are convenience helpers built on `list_all` plus client-side filtering and SHALL be documented as intended for small accounts. + +#### Scenario: Find by tax number +- **WHEN** `find_by_tax_number("12345678901234")` is called and a company with that `federalTaxNumber` exists +- **THEN** the method SHALL return that `Nfe::Company` + +#### Scenario: Find by name with no match +- **WHEN** `find_by_name("NonExistent Corp")` is called and no company matches +- **THEN** the method SHALL return an empty `Array` + +#### Scenario: Empty search name rejected +- **WHEN** `find_by_name("")` or a whitespace-only name is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` + +### Requirement: Company certificate upload with real PKCS#12 validation +`Nfe::Resources::Companies` SHALL expose `upload_certificate(company_id, file:, password:, filename: nil)` and `replace_certificate(...)` (an alias) that POST a `multipart/form-data` body to `/companies/{id}/certificate` with the fields `file` (the .pfx/.p12 binary) and `password`. Before uploading, the SDK SHALL pre-validate the certificate locally via `validate_certificate`. The multipart body SHALL be built using Ruby stdlib (`Net::HTTP` form posting), introducing no new runtime dependency. + +#### Scenario: Successful upload +- **WHEN** `upload_certificate(company_id, file: pfx_bytes, password: "secret", filename: "cert.pfx")` is called with a valid certificate and matching password +- **THEN** the SDK SHALL POST a multipart body carrying `file` and `password` to `/companies/{id}/certificate` and return `{ uploaded: true, message: }` + +#### Scenario: Unsupported file extension rejected before upload +- **WHEN** `upload_certificate` is called with `filename: "cert.pem"` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` without issuing an HTTP request + +#### Scenario: Replace is an alias of upload +- **WHEN** `replace_certificate(company_id, file:, password:)` is called +- **THEN** it SHALL behave identically to `upload_certificate` (the API handles replacement) + +### Requirement: Local certificate validation via OpenSSL::PKCS12 +`Nfe::Resources::Companies#validate_certificate(file:, password:)` SHALL perform a local-only validation (no HTTP) by parsing the PKCS#12 bytes with `OpenSSL::PKCS12.new(der_bytes, password)`. A wrong password or malformed DER SHALL raise `Nfe::InvalidRequestError`. On success it SHALL return a `Nfe::CertificateInfo` value object carrying `subject`, `issuer`, `not_before`, `not_after`, and `serial_number` extracted from the parsed certificate. + +#### Scenario: Valid certificate and password +- **WHEN** `validate_certificate(file: pfx_bytes, password: "correct")` is called with a real PKCS#12 and the correct password +- **THEN** the method SHALL return a `Nfe::CertificateInfo` whose `not_after` is the certificate's actual expiry date (not a fabricated placeholder) + +#### Scenario: Wrong password rejected +- **WHEN** `validate_certificate` is called with an incorrect password +- **THEN** `OpenSSL::PKCS12.new` SHALL raise, and the SDK SHALL surface a `Nfe::InvalidRequestError` + +#### Scenario: No HTTP request is made +- **WHEN** `validate_certificate` runs +- **THEN** the SDK SHALL NOT issue any HTTP request + +### Requirement: Certificate password and PKCS#12 bytes are handled in-memory only +The certificate password and PKCS#12 (.pfx/.p12) bytes SHALL be handled in-memory only. The SDK SHALL NOT persist either the password or the PKCS#12 bytes to disk (no temp files, no caches). Neither the password nor the PKCS#12 bytes SHALL appear in any log line, in any raised exception message, or in any `Nfe::Error` attribute (including `Error#to_h` / `Error#message`). The password `String` SHALL NOT be retained beyond the upload call where feasible (it SHALL NOT be stored on the resource instance or memoized). + +#### Scenario: Password absent from logs +- **WHEN** `upload_certificate` or `validate_certificate` runs with debug/body logging enabled +- **THEN** no log line SHALL contain the password value or the PKCS#12 bytes (the multipart body SHALL NOT be logged) + +#### Scenario: Password absent from any raised exception / Error#to_h +- **WHEN** `OpenSSL::PKCS12.new` raises (wrong password or malformed DER) and the SDK surfaces a `Nfe::InvalidRequestError` +- **THEN** the raised error's `message` and `to_h` SHALL NOT contain the password value or the raw PKCS#12 bytes + +### Requirement: Company certificate status and expiry helpers +`Nfe::Resources::Companies` SHALL expose `get_certificate_status(company_id)` returning a `Nfe::CertificateStatus`, `check_certificate_expiration(company_id, threshold_days: 30)`, `get_companies_with_certificates`, and `get_companies_with_expiring_certificates(threshold_days: 30)`. Each SHALL query `GET /companies/{id}/certificate`. The `days_until_expiration` and `expiring_soon` fields SHALL be computed client-side from `expires_on`. + +#### Scenario: Certificate status snapshot +- **WHEN** `get_certificate_status(company_id)` succeeds against `GET /companies/{id}/certificate` +- **THEN** the method SHALL return a `Nfe::CertificateStatus` carrying `has_certificate` (boolean), `expires_on` (string ISO date-time or nil), `valid` (boolean or nil), `days_until_expiration` (integer or nil, computed client-side from `expires_on`), `expiring_soon` (boolean or nil, computed client-side via threshold), and `details` (raw payload) + +#### Scenario: Expiration check within threshold +- **WHEN** `check_certificate_expiration(company_id, threshold_days: 30)` is called and the certificate expires in 10 days +- **THEN** the method SHALL return `{ expiring: true, days_remaining: 10, expires_on: }` + +#### Scenario: Expiration check outside threshold +- **WHEN** the certificate expires in 200 days with `threshold_days: 30` +- **THEN** the method SHALL return `nil` + +#### Scenario: Listing companies with expiring certificates +- **WHEN** `get_companies_with_expiring_certificates(30)` is called +- **THEN** the method SHALL list all companies, query certificate status for each (skipping companies whose status lookup fails), and return only those expiring within the threshold + +### Requirement: LegalPeople and NaturalPeople resources are parallel +`Nfe::Resources::LegalPeople` and `Nfe::Resources::NaturalPeople` SHALL expose the same operations — `list`, `create`, `retrieve`, `update`, `delete`, `create_batch`, and `find_by_tax_number` — differing only in endpoint base path (`/companies/{id}/legalpeople` vs `/companies/{id}/naturalpeople`), response envelope key (`legalPeople` vs `naturalPeople`), and tax-number semantics (CNPJ 14 digits vs CPF 11 digits). `list` takes only a `company_id` (no pagination parameters, matching the Node SDK) and unwraps `{"" => [...]}`. + +#### Scenario: Legal person create unwraps envelope +- **WHEN** `client.legal_people.create(company_id, data)` is called +- **THEN** the SDK SHALL POST `/companies/{company_id}/legalpeople`, unwrap the `legalPeople` envelope, and return a `Nfe::LegalPerson` + +#### Scenario: Natural person tax number normalised +- **WHEN** `find_by_tax_number(company_id, "123.456.789-01")` is called on `NaturalPeople` +- **THEN** the SDK SHALL normalise the input to 11 digits and search by `federalTaxNumber` + +#### Scenario: Batch creation is sequential +- **WHEN** `create_batch(company_id, [a, b, c])` is called +- **THEN** the SDK SHALL invoke `create` sequentially (no concurrency primitive) and return the three created entities in order + +#### Scenario: Delete returns nil +- **WHEN** `delete(company_id, legal_person_id)` succeeds +- **THEN** the method SHALL return `nil` + +### Requirement: Webhooks resource with CRUD, test, and available events +`Nfe::Resources::Webhooks` SHALL expose `list`, `create`, `retrieve`, `update`, `delete`, `test`, and `get_available_events`, all company-scoped under `/companies/{id}/webhooks`. The `test` method triggers a synthetic delivery. `get_available_events` returns a static list matching the Node SDK's hard-coded events. + +#### Scenario: Webhook subscription CRUD +- **WHEN** `client.webhooks.create(company_id, { url: "https://example.com/hook", events: ["invoice.issued"] })` is called +- **THEN** the API SHALL persist the subscription and the method SHALL return a `Nfe::Webhook` with `id`, `url`, `events`, and `secret` populated + +#### Scenario: Test webhook delivery +- **WHEN** `client.webhooks.test(company_id, webhook_id)` is called +- **THEN** the SDK SHALL POST `/companies/{id}/webhooks/{webhook_id}/test` and return `{ success: , message: }` + +#### Scenario: Available events list +- **WHEN** `client.webhooks.get_available_events` is called +- **THEN** the method SHALL return a static `Array` of exactly: `invoice.issued`, `invoice.cancelled`, `invoice.failed`, `invoice.processing`, `company.created`, `company.updated`, `company.deleted` + +### Requirement: ID validators run before HTTP +Every entity resource method that takes an identifier (`company_id`, `legal_person_id`, `natural_person_id`, `webhook_id`) SHALL validate it through the shared ID validators from `add-client-core` before issuing the HTTP request, failing fast with a Portuguese-language message. + +#### Scenario: Empty company ID rejected synchronously +- **WHEN** any entity resource method receives an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without making an HTTP request + +### Requirement: Certificate value objects are immutable +The SDK SHALL provide `Nfe::CertificateInfo = Data.define(:subject, :issuer, :not_before, :not_after, :serial_number)` and `Nfe::CertificateStatus = Data.define(:has_certificate, :expires_on, :valid, :days_until_expiration, :expiring_soon, :details)`. Both SHALL be immutable `Data` value objects. + +#### Scenario: CertificateInfo is frozen +- **WHEN** a `Nfe::CertificateInfo` instance is created +- **THEN** it SHALL be immutable (a `Data` instance), and attempting to mutate a field SHALL raise + +### Requirement: Frozen string literals on every source file +Every Ruby source file added by this change SHALL begin with the magic comment `# frozen_string_literal: true`. + +#### Scenario: Source file without the magic comment +- **WHEN** a contributor adds a file under `lib/nfe/resources/` without the `# frozen_string_literal: true` comment +- **THEN** RuboCop SHALL fail the build diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/specs/webhook-signature-verification/spec.md b/openspec/changes/archive/2026-06-25-add-entity-resources/specs/webhook-signature-verification/spec.md new file mode 100644 index 0000000..42189dd --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/specs/webhook-signature-verification/spec.md @@ -0,0 +1,127 @@ +# webhook-signature-verification — Delta + +## ADDED Requirements + +### Requirement: Webhook signature verification helper exists without a Client +The SDK SHALL provide `Nfe::Webhook` as a stateless module of functions (using `module_function`) that verifies NFE.io webhook signatures using only the caller-supplied payload, signature, and secret. It SHALL NOT require an instantiated `Nfe::Client`, SHALL NOT read `Nfe::Configuration`, and SHALL NOT perform any network access. This is the canonical API for signature verification; `Nfe::Resources::Webhooks#verify_signature` MAY delegate to it for Node parity. + +#### Scenario: Verifying without a configured Client +- **WHEN** a webhook endpoint runs in a process that has not instantiated `Nfe::Client` +- **THEN** `Nfe::Webhook.verify_signature(payload:, signature:, secret:)` SHALL function correctly using only the provided arguments + +#### Scenario: No network access +- **WHEN** any `Nfe::Webhook` method runs +- **THEN** it SHALL NOT issue any HTTP request + +### Requirement: verify_signature matches the production HMAC-SHA1 scheme +`Nfe::Webhook.verify_signature(payload:, signature:, secret:) -> Boolean` SHALL return `true` only when the provided signature matches `OpenSSL::HMAC.hexdigest("SHA1", secret, payload)` computed over the raw payload bytes, after requiring and stripping the `sha1=` prefix (compared case-insensitively) and normalising the remaining hex to lower case. The comparison SHALL use `OpenSSL.secure_compare` (constant-time). The method SHALL NOT re-serialize the payload; it SHALL operate on the bytes as given. + +#### Scenario: Validate a real signature from NFE.io (live fixture) +- **WHEN** the caller invokes `verify_signature` with a captured webhook body, the configured secret, and the header value `sha1=BCD17C02B9E3B40A18E745E7E04247E4AD2DD935` whose HMAC-SHA1 over the body bytes with that secret produces that digest +- **THEN** the method SHALL return `true` + +#### Scenario: Uppercase hex on the wire is accepted +- **WHEN** the header value carries the digest in uppercase hex (as NFE.io sends it) +- **THEN** the method SHALL return `true` (comparison is case-insensitive) + +#### Scenario: Lowercase hex is accepted +- **WHEN** the same digest is provided in lowercase hex +- **THEN** the method SHALL return `true` + +#### Scenario: Round-trip of a self-computed signature +- **WHEN** the caller computes `sha1=` + `OpenSSL::HMAC.hexdigest("SHA1", secret, body)` for a random body and secret and passes it back +- **THEN** the method SHALL return `true` + +#### Scenario: Constant-time comparison +- **WHEN** the method compares the received and expected digests +- **THEN** it SHALL use `OpenSSL.secure_compare` and SHALL NOT use `==`, `eql?`, or `String#==` on the hex strings + +### Requirement: verify_signature rejects malformed, missing, and forged input without raising +`Nfe::Webhook.verify_signature` SHALL return `false` — and SHALL NEVER raise an exception — for any tampered body, missing input, malformed signature, wrong algorithm prefix, missing prefix, wrong length, or non-hex content. + +#### Scenario: Tampered body +- **WHEN** a valid signature for body A is checked against body A mutated by one byte +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Wrong secret +- **WHEN** the body and signature are valid for one secret but verified with a different secret +- **THEN** the method SHALL return `false` + +#### Scenario: Wrong algorithm prefix (downgrade attempt) +- **WHEN** the header value is `sha256=<64 hex chars>` +- **THEN** the method SHALL return `false` and SHALL NOT raise (no implicit algorithm upgrade or downgrade) + +#### Scenario: Missing prefix +- **WHEN** the header value is a bare 40-character hex string with no `sha1=` prefix +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Wrong length +- **WHEN** the header value is `sha1=abc` +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Non-hex content +- **WHEN** the header value is `sha1=` followed by 40 non-hex characters +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Missing or empty secret +- **WHEN** `secret` is `nil` or an empty string +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Missing or empty signature +- **WHEN** `signature` is `nil`, an empty string, or an empty array +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Header delivered as an array +- **WHEN** the signature argument is a single-element array (the shape some Rack/HTTP stacks expose for repeated headers) +- **THEN** the method SHALL use the first element and verify normally + +### Requirement: construct_event verifies, parses, and returns a typed event +`Nfe::Webhook.construct_event(payload:, signature:, secret:) -> Nfe::WebhookEvent` SHALL first call `verify_signature`. If verification fails it SHALL raise `Nfe::SignatureVerificationError`. Otherwise it SHALL parse the payload as JSON, unwrap the NFE.io delivery envelope, and return a `Nfe::WebhookEvent`. A payload that is not valid JSON SHALL raise `Nfe::SignatureVerificationError`. + +#### Scenario: Valid signature yields a WebhookEvent +- **WHEN** `construct_event` is called with a valid signature over the body `{"action":"invoice.issued","payload":{"id":"abc","status":"Issued"}}` +- **THEN** it SHALL return a `Nfe::WebhookEvent` with `type == "invoice.issued"` and `data == {"id" => "abc", "status" => "Issued"}` + +#### Scenario: Invalid signature raises +- **WHEN** `construct_event` is called with a signature that does not match the body and secret +- **THEN** it SHALL raise `Nfe::SignatureVerificationError` and SHALL NOT return an event + +#### Scenario: Malformed JSON raises +- **WHEN** `construct_event` is called with a valid signature but a body that is not valid JSON +- **THEN** it SHALL raise `Nfe::SignatureVerificationError` + +### Requirement: WebhookEvent is an immutable value object +The SDK SHALL provide `Nfe::WebhookEvent = Data.define(:type, :data, :id, :created_at)`. `type` is a required string; `data` is a `Hash` of payload data; `id` and `created_at` are optional (default `nil`). `construct_event` SHALL unwrap both the `{"action" => type, "payload" => data}` and `{"event" => type, "data" => data}` envelope shapes into this form. + +#### Scenario: Envelope unwrapping (action/payload) +- **WHEN** the delivered body is `{"action":"invoice.issued","payload":{"id":"abc"}}` +- **THEN** `construct_event` SHALL produce a `WebhookEvent` with `type == "invoice.issued"` and `data == {"id" => "abc"}` + +#### Scenario: Event is immutable +- **WHEN** a `Nfe::WebhookEvent` is created +- **THEN** it SHALL be a frozen `Data` instance whose fields cannot be mutated + +### Requirement: Documentation steers callers to raw body bytes +The SDK documentation (README and RDoc/YARD on `Nfe::Webhook`) SHALL instruct callers to read the raw request body (e.g. `request.body.read` in Rack/Rails) BEFORE parsing JSON and pass those exact bytes to `verify_signature`/`construct_event`. It SHALL warn explicitly that re-serializing a parsed object (e.g. `payload.to_json`) will not match the signed bytes and will fail unpredictably. + +#### Scenario: Documented example uses raw bytes +- **WHEN** a reader copies the documented webhook-verification example +- **THEN** the snippet SHALL pass the raw request body to the verifier and SHALL parse JSON only after verification succeeds, and SHALL NOT pass a re-serialized object + +### Requirement: No anti-replay primitive — handlers must be idempotent and dedupe on event/invoice id +NFE.io provides no webhook anti-replay primitive: deliveries carry only the `X-Hub-Signature` HMAC-SHA1 over the body, with no timestamp and no nonce. A valid signature therefore proves authenticity but NOT freshness — a replayed delivery carries a perfectly valid signature. The SDK documentation (README and RDoc/YARD on `Nfe::Webhook`) SHALL state this explicitly and instruct consumers that webhook handlers MUST be idempotent and MUST dedupe on the event/invoice id. To support deduplication, `construct_event` SHALL surface a stable event id on `Nfe::WebhookEvent#id` when the delivery envelope carries one (e.g. the event id or the invoice id), and `nil` when absent. + +#### Scenario: Documentation warns that a valid signature is not freshness +- **WHEN** a reader consults the webhook-verification documentation +- **THEN** it SHALL state that NFE.io sends no timestamp/nonce, that signature validity does not imply freshness, and that handlers MUST be idempotent and dedupe on the event/invoice id + +#### Scenario: Stable event id surfaced for deduplication +- **WHEN** `construct_event` parses a delivery whose envelope carries an event id (or invoice id) +- **THEN** the returned `Nfe::WebhookEvent#id` SHALL expose that id so the consumer can dedupe replays, and SHALL be `nil` when no such id is present + +### Requirement: The legacy X-NFe-Signature / SHA-256 scheme is not implemented +The SDK SHALL implement only the `X-Hub-Signature` + HMAC-SHA1 scheme. It SHALL NOT implement the legacy `X-NFe-Signature` header or HMAC-SHA256 algorithm described in the (incorrect) distribuição documentation. + +#### Scenario: SHA-256 header is rejected +- **WHEN** a caller passes a signature header using the legacy `sha256=` form +- **THEN** `verify_signature` SHALL return `false` (the SHA-1 scheme is the only supported scheme) diff --git a/openspec/changes/archive/2026-06-25-add-entity-resources/tasks.md b/openspec/changes/archive/2026-06-25-add-entity-resources/tasks.md new file mode 100644 index 0000000..faa4e40 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-entity-resources/tasks.md @@ -0,0 +1,127 @@ +# Tasks — add-entity-resources + +> Depende de **add-client-core** (consome `Nfe::Client`, `Nfe::Configuration` com host map, `Nfe::Resources::AbstractResource`, `Nfe::ListResponse`, helpers de validação de ID/CNPJ/CPF e as exceções tipadas). Todo arquivo `.rb` começa com `# frozen_string_literal: true`. +> +> **Status (2026-06-25): IMPLEMENTADO e verificado verde via Docker na matrix Ruby 3.2/3.3/3.4.** Entregue: `Nfe::Webhook` (verify_signature HMAC-SHA1 nunca-levanta + construct_event) + `Nfe::WebhookEvent`; `Nfe::CertificateValidator`/`CertificateInfo`/`CertificateStatus` (OpenSSL::PKCS12); DTOs hand-written `Nfe::Company`/`LegalPerson`/`NaturalPerson`/`WebhookSubscription` (com `from_api`); `AbstractResource#upload_multipart`/`unwrap`; e os 4 recursos `Companies` (CRUD + certificado + multipart + finders), `LegalPeople`, `NaturalPeople`, `Webhooks` (CRUD + test + get_available_events + verify_signature). Gate: rspec 404/0 (cobertura ~95.9%), rubocop 0, steep 0, rbs ok, generate:check in-sync. Nota: o DTO de webhook é `Nfe::WebhookSubscription` (o constante `Nfe::Webhook` é o módulo de verificação). `get_*` mantêm o nome (paridade Node; `Naming/AccessorMethodName` desabilitado). + +## 1. Verificação de assinatura: `Nfe::Webhook` + `Nfe::WebhookEvent` + +- [ ] 1.1 Criar `lib/nfe/webhook_event.rb` — `Nfe::WebhookEvent = Data.define(:type, :data, :id, :created_at)`. Construtor por keyword (Data.define já é keyword/positional). `data` é `Hash`; `id`/`created_at` opcionais (default `nil`). +- [ ] 1.2 Criar `lib/nfe/webhook.rb` — `module Nfe::Webhook` com `module_function`: + - `verify_signature(payload:, signature:, secret:) -> bool` — implementa os 6 passos de design D3 (guarda de nil/vazio → normaliza header Array→[0] → exige/strip prefixo `sha1=` case-insensitive, recusa `sha256=` → `downcase` + valida `/\A[a-f0-9]{40}\z/` → `OpenSSL::HMAC.hexdigest("SHA1", secret, payload)` sobre bytes crus → `OpenSSL.secure_compare`). **Nunca levanta.** + - `construct_event(payload:, signature:, secret:) -> Nfe::WebhookEvent` — chama `verify_signature`; se `false`, levanta `Nfe::SignatureVerificationError`; senão `JSON.parse(payload)` (em `JSON::ParserError`, levanta `Nfe::SignatureVerificationError` com mensagem de payload malformado) e desembrulha o envelope (`action`/`payload` ou `event`/`data`) em `WebhookEvent`. + - Constante privada `SIGNATURE_PREFIX = "sha1="` e `HEX_RE = /\A[a-f0-9]{40}\z/`. +- [ ] 1.3 Garantir `require "openssl"`, `require "json"` no topo (stdlib; sem gem). +- [ ] 1.4 Expor delegação de instância para paridade Node: em `lib/nfe/resources/webhooks.rb`, método `verify_signature(payload:, signature:, secret:)` que delega a `Nfe::Webhook.verify_signature` (a API canônica é o módulo estático). +- [ ] 1.5 `sig/nfe/webhook.rbs` e `sig/nfe/webhook_event.rbs` — assinaturas RBS (`def self.verify_signature: (payload: String, signature: String?, secret: String?) -> bool`, etc.). +- [ ] 1.6 Tests `spec/nfe/webhook_spec.rb` — matriz completa (vide spec `webhook-signature-verification`): fixture real do probe (`sha1=BCD17C02B9E3B40A18E745E7E04247E4AD2DD935`-style), hex maiúsculo e minúsculo, round-trip aleatório, corpo adulterado, prefixo errado `sha256=`, sem prefixo, comprimento errado `sha1=abc`, não-hex, secret vazio/nil, signature nil/vazia/array, envelope `action`/`payload`, JSON malformado, "nunca levanta" em cada caso negativo (`expect { ... }.not_to raise_error`). + +## 2. Suporte de transporte: multipart para upload de certificado (coordenação com add-http-transport) + +- [ ] 2.1 Confirmar/garantir que o transport `Net::HTTP` de add-http-transport aceita corpo multipart. Se aceitar só `String`, adicionar caminho mínimo: `AbstractResource#upload_multipart(path, parts)` que monta `Net::HTTP::Post#set_form(parts, "multipart/form-data")` e usa o mesmo pipeline de auth/erro/host do GET/POST normais. +- [ ] 2.2 `AbstractResource#download(path, accept:) -> String` — GET com `Accept` específico retornando `response.body` cru com `force_encoding(Encoding::ASCII_8BIT)` (mesmo que estes recursos quase não baixem binário, mantém a interface consistente; reusa o helper de add-client-core se já existir). +- [ ] 2.3 Helper de desembrulho: `AbstractResource#unwrap(payload, key) -> Hash/Array` — retorna `payload[key]` se presente, senão `payload` (tolerante a envelope ausente). Reusa de add-client-core se já existir. + +## 3. Validador de certificado: `OpenSSL::PKCS12` + DTOs + +- [ ] 3.1 Criar `lib/nfe/certificate.rb` com: + - `Nfe::CertificateInfo = Data.define(:subject, :issuer, :not_before, :not_after, :serial_number)`. + - `Nfe::CertificateStatus = Data.define(:has_certificate, :expires_on, :valid, :days_until_expiration, :expiring_soon, :details)`. + - `module Nfe::CertificateValidator` (`module_function`): `supported_format?(filename) -> bool` (extensão `.pfx`/`.p12`, case-insensitive); `validate(der_bytes, password) -> Nfe::CertificateInfo` (faz `OpenSSL::PKCS12.new(der_bytes, password)`, captura `OpenSSL::PKCS12::PKCS12Error` → levanta `Nfe::InvalidRequestError` "Certificado ou senha inválidos"; extrai subject/issuer/not_before/not_after/serial); `days_until_expiration(not_after) -> Integer`; `expiring_soon?(not_after, threshold_days = 30) -> bool`. +- [ ] 3.2 `require "openssl"` no topo. +- [ ] 3.3 `sig/nfe/certificate.rbs` — assinaturas RBS dos `Data.define` e do `CertificateValidator`. +- [ ] 3.4 Tests `spec/nfe/certificate_spec.rb` — fixture .pfx de teste (gerado no setup via `OpenSSL::PKCS12.create`): senha correta extrai metadata real; senha errada levanta `Nfe::InvalidRequestError`; bytes inválidos (não-DER) levanta `Nfe::InvalidRequestError`; `supported_format?` para `.pfx`/`.p12`/`.PFX` true e `.pem`/`.txt` false; `days_until_expiration`/`expiring_soon?` com datas conhecidas. + +## 4. `CompaniesResource` + +- [ ] 4.1 Criar `lib/nfe/resources/companies.rb` — `Nfe::Resources::Companies < Nfe::Resources::AbstractResource`; `api_family` → `:main`; `api_version` → `"v1"`. +- [ ] 4.2 `create(data) -> Company` — POST `/companies`; valida formato de `federalTaxNumber` (11/14 dígitos, sem coagir para Integer, sem check-digit — design D12) e formato de e-mail se presente; desembrulha envelope `companies`; hidrata `Nfe::Company`. +- [ ] 4.3 `list(page_index: 0, page_count: 100) -> Nfe::ListResponse` — GET `/companies`; converte `page` 1-based da API para `page_index` 0-based. +- [ ] 4.4 `list_all -> Array[Company]` — pagina com `page_count: 100` até a página vir com < 100 itens. +- [ ] 4.5 `list_each -> Enumerator` (ou bloco) — `Enumerator.new` que pagina sob demanda e `yield`-a cada company (substituto idiomático do `listIterator` async do Node). +- [ ] 4.6 `retrieve(company_id) -> Company` — GET `/companies/{id}`; desembrulha `companies`; valida `company_id` antes; 404 → `Nfe::NotFoundError`. +- [ ] 4.7 `update(company_id, data) -> Company` — PUT `/companies/{id}`; valida dados; desembrulha. +- [ ] 4.8 `remove(company_id) -> Hash` — DELETE; retorna `{ deleted: bool, id: String }` (nome `remove` para evitar conflito com semântica de `delete`; paridade Node/PHP). +- [ ] 4.9 `find_by_tax_number(tax_number) -> Company?` — normaliza para dígitos, valida 11/14, `list_all` + filtro client-side; `nil` se não achar. +- [ ] 4.10 `find_by_name(name) -> Array[Company]` — `list_all` + `String#downcase.include?` case-insensitive; levanta `Nfe::InvalidRequestError` se nome vazio. +- [ ] 4.11 `validate_certificate(file:, password:) -> Nfe::CertificateInfo` — local-only; lê bytes (caminho de arquivo ou String binária) e delega a `Nfe::CertificateValidator.validate`. **Sem HTTP.** +- [ ] 4.12 `upload_certificate(company_id, file:, password:, filename: nil) -> Hash` — pré-valida `supported_format?` (se filename dado) + roda `validate_certificate` (fail-fast); monta multipart (`file` + `password`, nome de campo `file` conforme spec OpenAPI v1/v2) via `upload_multipart`; POST `/companies/{id}/certificate`; retorna `{ uploaded: bool, message: String? }`. +- [ ] 4.13 `replace_certificate(company_id, file:, password:, filename: nil) -> Hash` — alias de `upload_certificate` (a API trata a substituição). +- [ ] 4.14 `get_certificate_status(company_id) -> Nfe::CertificateStatus` — GET `/companies/{id}/certificate`; computa `days_until_expiration` e `expiring_soon` client-side a partir de `expires_on` (quando `has_certificate && expires_on`). +- [ ] 4.15 `check_certificate_expiration(company_id, threshold_days: 30) -> Hash?` — reusa `get_certificate_status`; retorna `{ expiring: true, days_remaining:, expires_on: }` se `0 <= days_remaining < threshold_days`, senão `nil`. +- [ ] 4.16 `get_companies_with_certificates -> Array[Company]` — `list_all` + N `get_certificate_status` (pula company que falhar); inclui as com `has_certificate && valid`. +- [ ] 4.17 `get_companies_with_expiring_certificates(threshold_days: 30) -> Array[Company]` — `list_all` + N `check_certificate_expiration`. +- [ ] 4.18 Validação de `company_id` via helper de add-client-core no início de cada método com ID. +- [ ] 4.19 `sig/nfe/resources/companies.rbs` — assinaturas RBS de todos os métodos públicos. +- [ ] 4.20 Tests `spec/nfe/resources/companies_spec.rb` (transport mockado): CRUD + envelope unwrap + `list` 1-based→0-based + `list_all` multi-página + `find_by_*` + cert status com threshold + `upload_certificate` multipart (assert campos `file`/`password` e path) + `validate_certificate` com .pfx fixture + `remove` retorna `{ deleted:, id: }` + 404 → `Nfe::NotFoundError` + `company_id` vazio → `Nfe::InvalidRequestError` sem HTTP. + +## 5. `LegalPeopleResource` + +- [ ] 5.1 Criar `lib/nfe/resources/legal_people.rb` — `< Nfe::Resources::AbstractResource`; `api_family :main`; `api_version "v1"`. +- [ ] 5.2 `list(company_id) -> Nfe::ListResponse` — GET `/companies/{id}/legalpeople`; desembrulha `{"legalPeople" => [...]}` (sem parâmetros de paginação, paridade Node). +- [ ] 5.3 `create(company_id, data) -> LegalPerson` — POST; desembrulha `{"legalPeople" => {...}}`. +- [ ] 5.4 `retrieve(company_id, legal_person_id) -> LegalPerson` — GET por ID; desembrulha. +- [ ] 5.5 `update(company_id, legal_person_id, data) -> LegalPerson` — PUT; desembrulha. +- [ ] 5.6 `delete(company_id, legal_person_id) -> nil` — DELETE. +- [ ] 5.7 `create_batch(company_id, list) -> Array[LegalPerson]` — loop **sequencial** sobre `create`; RDoc avisa "diferente do Node (Promise.all), é sequencial". +- [ ] 5.8 `find_by_tax_number(company_id, federal_tax_number) -> LegalPerson?` — `list` + filtro por `federal_tax_number` (CNPJ, normaliza para dígitos). +- [ ] 5.9 Validação de IDs antes de cada chamada. +- [ ] 5.10 `sig/nfe/resources/legal_people.rbs`. +- [ ] 5.11 Tests `spec/nfe/resources/legal_people_spec.rb` — CRUD + envelope `legalPeople` + create_batch sequencial + find_by_tax_number + ID inválido sem HTTP. + +## 6. `NaturalPeopleResource` + +- [ ] 6.1 Criar `lib/nfe/resources/natural_people.rb` — paralela a legal_people; `api_family :main`; `api_version "v1"`. +- [ ] 6.2 `list / create / retrieve / update / delete / create_batch / find_by_tax_number` com endpoint `/companies/{id}/naturalpeople` e envelope `{"naturalPeople" => ...}`. +- [ ] 6.3 `find_by_tax_number` normaliza CPF para 11 dígitos antes de filtrar. +- [ ] 6.4 Validação de IDs antes de cada chamada. +- [ ] 6.5 `sig/nfe/resources/natural_people.rbs`. +- [ ] 6.6 Tests `spec/nfe/resources/natural_people_spec.rb` — paralela a legal_people, com envelope `naturalPeople` e normalização CPF. + +## 7. `WebhooksResource` + +- [ ] 7.1 Criar `lib/nfe/resources/webhooks.rb` — `< Nfe::Resources::AbstractResource`; `api_family :main`; `api_version "v1"`. +- [ ] 7.2 `list(company_id) -> Nfe::ListResponse` — GET `/companies/{id}/webhooks` (company-scoped). +- [ ] 7.3 `create(company_id, data) -> Webhook` — POST; aceita `url`, `events`, `secret`, `active`. +- [ ] 7.4 `retrieve(company_id, webhook_id) -> Webhook` — GET por ID. +- [ ] 7.5 `update(company_id, webhook_id, data) -> Webhook` — PUT. +- [ ] 7.6 `delete(company_id, webhook_id) -> nil` — DELETE. +- [ ] 7.7 `test(company_id, webhook_id) -> Hash` — POST `/test`; retorna `{ success:, message: }`. (Confirmar path `/test` vs `/pings/test` em smoke.) +- [ ] 7.8 `get_available_events -> Array[String]` — lista estática hard-coded dos 7 eventos (design D10). +- [ ] 7.9 `verify_signature(payload:, signature:, secret:) -> bool` — delega a `Nfe::Webhook.verify_signature` (paridade Node; a API canônica é o módulo). +- [ ] 7.10 Validação de IDs antes de cada chamada. +- [ ] 7.11 `sig/nfe/resources/webhooks.rbs`. +- [ ] 7.12 Tests `spec/nfe/resources/webhooks_spec.rb` — CRUD + `test` + `get_available_events` (7 eventos exatos) + `verify_signature` delegando ao módulo. + +## 8. Hidratação de DTOs (Data.define) + +- [ ] 8.1 Confirmar que `Nfe::Company`, `Nfe::LegalPerson`, `Nfe::NaturalPerson`, `Nfe::Webhook` existem como `Data.define` gerados (de OpenAPI) sob `lib/nfe/generated/` OU criar DTOs hand-written sob `lib/nfe/resources/dto/` se o gerador não cobrir o shape de resposta (não editar arquivos gerados). +- [ ] 8.2 Cada recurso hidrata o `Data.define` correto a partir do payload desembrulhado, tolerando chaves ausentes (campos opcionais → `nil`). +- [ ] 8.3 `sig/` para quaisquer DTOs hand-written criados. + +## 9. Integração com `Nfe::Client` + +- [ ] 9.1 Confirmar que os acessores lazy snake_case `client.companies`, `client.legal_people`, `client.natural_people`, `client.webhooks` (de add-client-core) instanciam os recursos desta change com o HTTP client do host `main`. +- [ ] 9.2 Tests de integração leve em `spec/nfe/client_spec.rb` (ou no spec de cada recurso) confirmando que cada acessor devolve uma instância funcional (não stub) e roteia para a URL efetiva `https://api.nfe.io/v1/...` (host `https://api.nfe.io` de `base_url_for(:main)` + `/v1` do `api_version`). + +## 10. Documentação + +- [ ] 10.1 README — tabela de recursos com os 4 acessores de entidade e um exemplo 1-linha de cada. +- [ ] 10.2 README — seção "Verificação de assinatura de webhook" com exemplo Rack/Rails que lê `request.body.read` (bytes crus) ANTES do parse e bloco de aviso "não use `payload.to_json`". +- [ ] 10.3 README — seção "Certificado digital" com exemplo de `upload_certificate` e `validate_certificate` (OpenSSL::PKCS12 real). +- [ ] 10.4 RDoc/YARD em cada método público (paridade com o JSDoc do Node; pt-BR onde fizer sentido), marcando `find_by_*`/`get_companies_with_*` como "conveniência, não otimizado". + +## 11. Validação end-to-end + +- [x] 11.1 `bundle exec rspec` verde — 404 exemplos / 0 falhas, cobertura ~95.9% (docker 3.2/3.3/3.4); matriz completa de `Nfe::Webhook.verify_signature`. +- [x] 11.2 `bundle exec steep check` — 0 erros (docker 3.2/3.3/3.4). +- [x] 11.3 `bundle exec rubocop` — 0 offenses; `# frozen_string_literal: true` em todo `.rb`. +- [x] 11.4 `openspec validate add-entity-resources --strict` passa (ambas as capabilities). + +## 12. Smoke test manual (opt-in, fora do CI) + +- [ ] 12.1 Sandbox: create/list/retrieve/update/remove de company. +- [ ] 12.2 `upload_certificate` com um .pfx real → `get_certificate_status` retorna `expires_on` e `days_until_expiration` corretos. +- [ ] 12.3 Criar webhook → `test()` → confirmar entrega em webhook.site (confirmar path `/test`). +- [ ] 12.4 Receber payload real → `Nfe::Webhook.construct_event` → conferir `WebhookEvent` (assinatura válida) e `Nfe::SignatureVerificationError` (assinatura forjada). +- [ ] 12.5 Registrar resultados em `.notes/entity-resources-smoke.md`. diff --git a/openspec/changes/archive/2026-06-25-add-http-transport/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-http-transport/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-http-transport/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-http-transport/README.md b/openspec/changes/archive/2026-06-25-add-http-transport/README.md new file mode 100644 index 0000000..fa6219d --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-http-transport/README.md @@ -0,0 +1,3 @@ +# add-http-transport + +Camada HTTP zero-dependência sobre `Net::HTTP` (stdlib): transport `Nfe::Http`, value objects `Request`/`Response`, retry com backoff + jitter, hierarquia de erros tipados e `ErrorFactory`, roteamento multi-base-URL, logger duck-typed com redação de chaves. diff --git a/openspec/changes/archive/2026-06-25-add-http-transport/design.md b/openspec/changes/archive/2026-06-25-add-http-transport/design.md new file mode 100644 index 0000000..2fb10e6 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-http-transport/design.md @@ -0,0 +1,220 @@ +# Design — add-http-transport + +## Context + +A camada HTTP é o alicerce de todo o SDK v1. O rewrite é greenfield: nada do v0.3.2 (rest-client, congelado em `0.x-legacy`) é reaproveitado. As restrições canônicas que moldam cada decisão aqui: + +1. **Zero dependências de runtime** — apenas stdlib. O transport default é `Net::HTTP`; nada de Faraday/HTTParty/rest-client. +2. **Múltiplas base URLs** — a NFE.io distribui a API por ~6 hosts. Hardcodar host é insustentável. Cada `Request` carrega seu `base_url`; o transport não conhece host nenhum. O **mapa de hosts** em si mora em `Nfe::Configuration` (na change `add-client-core`), não aqui — esta change só garante que o transport respeita o `base_url` que recebe. +3. **202 + `Location`** — emissões assíncronas respondem 202 com `Location` apontando para o recurso final. O transport NÃO segue; expõe `status` e `Location` crus. O contrato discriminado `Pending`/`Issued` mora em `add-client-core`. +4. **Downloads binários** — PDF/XML/ZIP voltam como bytes. O `Response#body` é uma String binary-safe (`ASCII-8BIT`); a camada de recurso faz `force_encoding(Encoding::ASCII_8BIT)` quando o método é um download. +5. **Falhas transientes** — 429 com `Retry-After`, 5xx, timeouts e quedas de DNS/TLS são realidade. Sem retry policy, integrações falham em produção sem motivo legítimo. +6. **Testabilidade** — para testar recurso sem rede, o `Transport` é uma interface duck-typed substituível por um fake com fila de respostas. + +Referências de paridade: `client-nodejs/src/core/http/client.ts` (auth header `X-NFE-APIKEY`, processamento de 202, retry com backoff + jitter 10%, `parseResponseData` por content-type) e `client-php` `src/Http/*` + `src/Exception/*` (transport interface, `RetryingTransport` decorator, `RetryPolicy` com jitter ±30%, `ErrorFactory`, hierarquia plana de exceptions). Adaptamos ambos para Ruby idiomático. + +## Goals / Non-Goals + +**Goals** +- Contrato `Transport` duck-typed substituível por fake/mock em testes. +- Default `Net::HTTP` zero-dep funcionando out-of-the-box com TLS verificado. +- Value objects imutáveis (`Data.define`) para `Request`/`Response`/`RetryPolicy`. +- Reuso de conexão persistente por origem (keep-alive) e timeouts open/read separados. +- gzip transparente (request `Accept-Encoding: gzip`, response descomprimida). +- Retry com backoff exponencial + jitter para 429/5xx/rede, **só em métodos idempotentes**, honrando `Retry-After`. +- Hierarquia de erros tipados consumível com `rescue Nfe::NotFoundError` e `ErrorFactory` que mapeia status + corpo. +- User-Agent honesto; auth via `X-NFE-APIKEY`. +- Logger duck-typed (PSR-3-equivalente) com redação de segredos. +- Slot de `Idempotency-Key` (campo no `Request`, envio condicional). +- 202 expõe `Location` cru para a camada de cima. + +**Non-Goals** +- Polling (`pollUntilComplete`/`create_and_wait`) — diferido; contrato 202 nasce correto, helper vem depois. +- Concorrência/`createBatch` — Ruby síncrono não ganha nada aqui. +- Async/fibers, HTTP/2 server push, streaming download para disco, websockets. +- Cache de respostas, métricas automáticas. +- OAuth2 — a NFE.io usa chave de API (`X-NFE-APIKEY`); suficiente. +- O **host map** multi-base-URL em si — vive em `Nfe::Configuration` (`add-client-core`). Aqui só respeitamos `Request#base_url`. + +## Decisions + +### D1. Transport como interface duck-typed, não classe abstrata +**Decisão**: `Nfe::Http::Transport` é um módulo documental com `def call(request); raise NotImplementedError; end`. Qualquer objeto que responda a `call(Request) -> Response` é um transport válido. O default é `Nfe::Http::NetHttp`; o decorator é `Nfe::Http::RetryingTransport`; testes usam um fake com fila. + +**Por quê**: Ruby é duck-typed; forçar herança seria não-idiomático. Espelha o `Transport` do PHP (interface de método único `send`) mas sem o peso de `interface`. O nome do método é `call` (idioma Ruby para objetos invocáveis), em vez de `send` (que colide com `Object#send`). + +**Alternativa rejeitada**: classe abstrata com `raise NotImplementedError` em métodos — mais verboso, sem ganho. + +### D2. `Net::HTTP` como transport default, conexão persistente por origem +**Decisão**: `Nfe::Http::NetHttp` mantém um cache de instâncias `Net::HTTP` por `"#{host}:#{port}"`, com `start` mantido aberto (`keep_alive_timeout`) para reusar conexão TCP/TLS entre chamadas ao mesmo host. TLS sempre com `use_ssl = true` (para `https`), `verify_mode = OpenSSL::SSL::VERIFY_PEER`, usando o CA store do sistema (sem versionar bundle CA). + +**Por quê**: A NFE.io tem ~6 hosts; cada recurso bate sempre no mesmo. Reaproveitar a conexão TLS por host elimina o custo de handshake repetido. Um `Net::HTTP` por origem é o pool natural do `Net::HTTP` (que não é multi-host). + +**Por quê não versionar CA bundle**: Ruby 3.2+ usa o CA store do sistema; versionar bundle adiciona peso e dívida de manutenção. Documentar `Configuration#ca_file` como escape hatch para ambientes legados. + +### D3. `Request`/`Response`/`RetryPolicy` como `Data.define` imutáveis +**Decisão**: usar `Data.define` (Ruby 3.2+) em vez de `Struct` ou classe manual. + +```ruby +Request = Data.define(:method, :base_url, :path, :headers, :query, :body, + :open_timeout, :read_timeout, :idempotency_key) do + def url = ... # base_url + path + URI.encode_www_form(query) +end + +Response = Data.define(:status, :headers, :body) do + def header(name) = headers[name.downcase] + def success? = (200..299).cover?(status) + def location = header("location") +end +``` + +**Por quê**: `Data.define` dá imutabilidade real, `==` por valor, `with` para cópias, e keyword args — exatamente o que os value objects `readonly` do PHP entregam, mas idiomático em Ruby. Headers de `Response` são normalizados para **chaves lowercase** (HTTP headers são case-insensitive; espelha `Response#header` do PHP e `response.headers['location']` do Node). + +### D4. `Response#body` é String binary-safe (`ASCII-8BIT`) +**Decisão**: o transport não tenta decodificar/parsear o body. Devolve a String crua de bytes, com `force_encoding(Encoding::ASCII_8BIT)`. JSON parsing e `force_encoding` final ficam na camada de recurso (que sabe se é download binário ou JSON). + +**Por quê**: paridade com a regra canônica "downloads return raw bytes as a binary-safe String". Em Ruby uma String com encoding `ASCII-8BIT` é binary-safe; o caller faz `File.binwrite` ou `JSON.parse(body)` conforme o método. Centralizar parsing no transport (como o `parseResponseData` por content-type do Node) acoplaria o transport ao conhecimento de cada endpoint — preferimos manter o transport burro. + +**Trade-off**: gzip É descomprimido no transport (porque é uma camada de transporte, não de aplicação) — ver D5. + +### D5. gzip transparente no transport +**Decisão**: o transport injeta `Accept-Encoding: gzip` (a menos que o caller já tenha setado um `Accept-Encoding`), e descomprime a resposta quando `Content-Encoding: gzip`, removendo o header `content-encoding` do `Response` resultante (já que o body devolvido está descomprimido). `Net::HTTP` faz isso automaticamente se não setarmos `Accept-Encoding` manualmente; setamos explicitamente e tratamos via `Zlib::GzipReader` para controle determinístico e para que downloads também se beneficiem. + +**Por quê**: gzip é transporte, não semântica. O recurso não deve ver bytes comprimidos. `zlib` é stdlib (permitido implicitamente por `net/http`). + +### D6. Auth via `X-NFE-APIKEY`, injetado pela camada +**Decisão**: o header de autenticação é `X-NFE-APIKEY: ` (paridade exata com Node `buildHeaders`). A injeção do header acontece quando o `Client`/`AbstractResource` (em `add-client-core`) constrói o `Request`, não dentro do `NetHttp` — assim `NetHttp` e qualquer transport custom se beneficiam e o transport fica auth-agnostic. + +**Por quê**: espelha o refinamento do PHP (UA/auth injetados na camada `Client`, não no `CurlTransport`). Mantém o transport como pura mecânica de rede. + +**Nota**: a resolução `api_key` vs `data_api_key` por família de host é responsabilidade de `add-client-core`; aqui só documentamos que o header carrega a chave que o `Request` trouxer. + +### D7. User-Agent honesto +**Decisão**: `NFE.io Ruby Client v ruby/ ()`, ex.: `NFE.io Ruby Client v1.0.0 ruby/3.3.0 (x86_64-linux)`. Versão lida de `Nfe::VERSION`. Helper em `Nfe::Http::UserAgent.build(suffix = nil)`. + +**Por quê**: Stripe, Node e PHP fazem telemetria honesta de UA. Ajuda o time NFE.io a saber de qual SDK/versão vem cada chamada. + +### D8. Retry: 3 tentativas, base 1s, max 30s, jitter ±30%, só idempotente +**Decisão**: `RetryPolicy` default = `max_retries: 3, base_delay: 1.0, max_delay: 30.0, jitter: 0.3`. `RetryingTransport` decora qualquer transport e faz retry em: +- HTTP **429** (sempre, com backoff) +- HTTP **5xx** (500–599) +- **Erros de rede** (`Nfe::ApiConnectionError`/`Nfe::TimeoutError` levantados pelo transport interno) + +NÃO faz retry em 4xx exceto 429. Faz retry **apenas para métodos idempotentes** (`GET`, `HEAD`, `PUT`, `DELETE`) — ou para qualquer método que carregue um `Idempotency-Key`. POST sem idempotency-key NÃO é repetido (evita emitir invoice duplicada). + +`delay(n) = min(max_delay, base_delay * 2^(n-1)) * (1 - jitter + 2*jitter*rand())`. Honra `Retry-After` (segundos inteiros) com precedência sobre o backoff calculado, limitado a `max_delay`. `sleep` é injetável (`Closure`/lambda) para testes determinísticos. + +**Por quê**: defaults alinhados a Stripe/Node/PHP. A regra "só idempotente" é mais segura que o Node (que repete qualquer não-4xx-não-429): emitir NFS-e/NF-e é POST não idempotente; repetir cegamente poderia gerar nota duplicada. O slot de `Idempotency-Key` (D9) destrava retry seguro de POST quando a API suportar. + +**Alternativa rejeitada**: replicar o Node 1:1 (retry de qualquer não-4xx). Rejeitada por risco de emissão duplicada. + +### D9. Idempotency-Key como slot, envio condicional +**Decisão**: `Request` tem o campo `idempotency_key`. Quando presente, o transport envia `Idempotency-Key: `. A geração (`SecureRandom.uuid`) e a decisão de *quando* habilitar ficam na camada de recurso (`add-client-core`+); por padrão é `nil` (não enviado). + +**Por quê**: o task de escopo pede "idempotency-key support where the API allows it". Diferente do PHP (que removeu o slot por completo), aqui mantemos o **campo** porque (a) `securerandom` está na allowlist de stdlib e (b) destrava retry seguro de POST. Se a API NFE.io ainda não honra o header, o custo é zero (campo `nil`); quando honrar, é só a camada de recurso passar a chave — mudança aditiva não-breaking. + +### D10. Hierarquia de erros plana sob `Nfe::Error` +**Decisão**: 1 nível de herança. `Nfe::Error < StandardError` é a base; as subclasses concretas herdam direto dela. A informação detalhada mora em **attrs**, não em subclasses. + +```ruby +module Nfe + class Error < StandardError + attr_reader :status_code, :request_id, :error_code, :response_body, :response_headers + def initialize(message = nil, status_code: nil, request_id: nil, + error_code: nil, response_body: nil, response_headers: {}) + ... + end + def to_h = { ... } # logging + end + + class AuthenticationError < Error; end # 401 + class AuthorizationError < Error; end # 403 + class InvalidRequestError < Error; end # 400 / 422 + class NotFoundError < Error; end # 404 + class ConflictError < Error; end # 409 + class RateLimitError < Error; end # 429 (carrega retry_after) + class ServerError < Error; end # 5xx + class ApiConnectionError < Error; end # rede (DNS/TLS/socket) + class TimeoutError < ApiConnectionError; end # open/read timeout + class SignatureVerificationError < Error; end # webhooks (consumido depois) +end +``` + +**Por quê**: `rescue Nfe::Error` pega tudo; `rescue Nfe::NotFoundError` pega o específico. Plano e fácil de consumir — espelha a decisão D6 do PHP. `TimeoutError < ApiConnectionError` permite `rescue Nfe::ApiConnectionError` cobrir timeouts (semântica de rede), mas ainda discriminar timeout. Cobre a união Node (`ValidationError`/`AuthenticationError`/`NotFoundError`/`ConflictError`/`RateLimitError`/`ServerError`/`ConnectionError`/`TimeoutError`) + PHP (`AuthorizationException` 403, `SignatureVerificationException`). + +**Nomenclatura**: usamos `InvalidRequestError` (estilo PHP/Stripe) em vez de `ValidationError` (Node), porque o escopo da change pede `InvalidRequestError(400/422)`. O 422 (Unprocessable Entity) também mapeia para `InvalidRequestError`. + +### D11. `ErrorFactory` mapeia status + corpo → erro tipado +**Decisão**: `Nfe::ErrorFactory.from_response(response)` e `Nfe::ErrorFactory.from_network_error(exception)`. O primeiro decide a classe por `status` (`case` em Ruby), extrai `message` do corpo JSON (chaves `message`/`error`/`detail`/`details`/`errors[0]`), `error_code` (chaves `code`/`errorCode`/`error_code`), e `request_id` do header `x-request-id` (fallback `x-correlation-id`). O segundo mapeia exceptions de `Net::HTTP`/socket para `ApiConnectionError`/`TimeoutError`. + +Mapa de status: + +| Status | Erro | +|---|---| +| 400, 422 | `InvalidRequestError` | +| 401 | `AuthenticationError` | +| 403 | `AuthorizationError` | +| 404 | `NotFoundError` | +| 409 | `ConflictError` | +| 429 | `RateLimitError` (+ `retry_after`) | +| 5xx | `ServerError` | +| outros 4xx | `InvalidRequestError` (fallback) | +| outros ≥500 | `ServerError` (fallback) | + +**Por quê**: espelha `ErrorFactory::fromResponse` (PHP) e `ErrorFactory.fromHttpResponse` (Node). O `request_id` é uma adição sobre o PHP/Node — facilita suporte/debug (o task pede `request_id` explicitamente). + +### D12. Onde os erros são levantados (factory na camada de recurso, não no transport) +**Decisão**: `NetHttp#call` **não** levanta para 4xx/5xx — devolve o `Response` com o status. Quem levanta é a camada de recurso/`AbstractResource` (em `add-client-core`), chamando `ErrorFactory.from_response`. O `NetHttp` só levanta `ApiConnectionError`/`TimeoutError` para falhas de **rede** (não há `Response`). + +**Por quê**: espelha o contrato do `Transport` do PHP ("HTTP-level errors são retornados como Response para a retry layer e a exception factory agirem"). Permite que o `RetryingTransport` veja o status 429/5xx e decida retry **antes** de virar exceção. Só vira exceção depois de esgotado o retry. + +### D13. Logger duck-typed com redação de segredos +**Decisão**: `Configuration#logger` (de `add-client-core`) é qualquer objeto que responda a `info`/`warn`/`error` — incluindo `::Logger` da stdlib. O transport/decorator, quando recebe um logger, loga: início do request (`info`: método + URL + headers redigidos), retry (`warn`: tentativa + delay + status/erro), e falha final (`error`: status + corpo truncado). **Redação obrigatória**: `X-NFE-APIKEY`, `Authorization`, `Idempotency-Key` e qualquer chave contendo `secret`/`apikey`/`token` (case-insensitive) viram `[REDACTED]` antes de qualquer log. + +**Por quê**: PSR-3 não existe em Ruby; o equivalente idiomático é duck-typing sobre a interface de `::Logger`. Zero dependência. A redação é requisito de compliance (tratar tudo como sensível, nunca expor chaves) — vale para a NFE.io. + +### D14. 202 e redirects não são seguidos +**Decisão**: `NetHttp` configura para NÃO seguir redirects e devolve 202 cru com `Location` no `Response`. `Net::HTTP` não segue redirect por padrão (diferente de cURL `FOLLOWLOCATION`), então só garantimos não tratar 3xx como erro nem seguir. + +**Por quê**: o recurso é quem sabe se 202 vira `Pending` (com `Location`) ou se um 201 vira `Issued`. Seguir no transport esconderia a semântica. Espelha D5 do PHP e o `processResponse` do Node (que extrai `location` mas não busca). + +### D15. Pool de conexão por origem é thread-safe (Mutex) — DECISÃO (antes era Open Question) +**Decisão**: o cache de instâncias `Net::HTTP` por `"#{host}:#{port}"` dentro de `NetHttp` é guardado por um `Mutex`. Um `Client` compartilhado (que injeta um único transport) é **thread-safe** sob execução concorrente: o acesso ao pool é serializado e dois threads nunca usam o mesmo socket simultaneamente. Isso torna o `Client` seguro em Rails/Sidekiq/Puma multi-thread. + +**Por quê**: a decisão de manutenção colocou thread-safety em escopo para v1 (não é mais "instancie um Client por thread"). `Mutex` é stdlib, custo desprezível, e remove uma pegadinha clássica de SDK. Complementa o guard de acessores memoizados no `Client` (em `add-client-core`). + +### D16. Overrides por chamada via `Nfe::RequestOptions` +**Decisão**: o transport honra overrides por chamada (`api_key`/`base_url`/`timeout`) carregados no `Request` a partir de `Nfe::RequestOptions` (`Data.define`, definido em `add-client-core`). Uma chamada com override roteia para o `base_url` alternativo, usa o timeout alternativo e envia a `api_key` alternativa em `X-NFE-APIKEY`, **sem** mutar a configuração global nem afetar outras chamadas concorrentes. + +**Por quê**: habilita multi-tenant (uma `api_key` por chamada) sem um segundo `Client`. Como `Request` já é imutável (`Data.define`), o override é só um `Request` diferente — o transport permanece burro e auth-agnostic (D6). + +### D17. Logger nunca emite BODIES por padrão +**Decisão**: além da redação de headers (D13), o transport por padrão **não loga corpos** de request/response. As entradas default contêm só método, URL, status e `request_id`. Log de corpo fica atrás de um opt-in explícito (`Configuration#log_request_body`, em `add-client-core`); quando ligado, o corpo é truncado e passa pela redação. `Nfe::Error#response_body` continua disponível para inspeção programática, mas **não** é auto-logado. + +**Por quê**: compliance — CNPJ/CPF e a senha do certificado nunca devem vazar em log. Tratar tudo como sensível; o opt-in é decisão consciente do integrador, com truncamento e redação mesmo assim. + +### D18. Hardening barato: cap/scrub de mensagem de erro + Content-Length pós-gzip +**Decisão**: (a) `ErrorFactory` limita a `message` extraída do corpo a um tamanho máximo e remove caracteres de controle (a `message` ecoa input do servidor; sem cap, um corpo malicioso poderia inundar logs ou injetar sequências de terminal). (b) Após inflar gzip (D5), o transport **descarta ou recalcula** o header `content-length`, que passaria a anunciar o tamanho comprimido obsoleto. + +**Por quê**: dois one-liners de robustez sem custo de dependência; alinhados ao princípio de tratar todo input externo como hostil. + +| Risco | Mitigação | +|---|---| +| `Net::HTTP` parseia status/headers de forma diferente de cURL/fetch | Normalizar headers para lowercase no `Response`; testes cobrem multi-value join e `Location` | +| Conexão persistente vaza socket entre hosts ou após erro | Pool por `host:port`; resetar/recriar a conexão em `ApiConnectionError`; `keep_alive_timeout` curto | +| Retry de POST poderia emitir invoice duplicada | Retry só em métodos idempotentes (GET/HEAD/PUT/DELETE) ou POST com `Idempotency-Key` (D8/D9) | +| gzip mal-formado quebra descompressão | Tratar `Zlib::Error` como corpo cru (fallback) e logar `warn` | +| User-Agent revela versão de Ruby/plataforma (info disclosure?) | Aceitável — Stripe/Node/PHP fazem o mesmo; é norma de telemetria honesta | +| Logger custom pode levantar dentro do log | Envolver chamadas de log em `rescue StandardError` para nunca derrubar a request por causa de logging | +| Verificação TLS falha em ambiente com CA store desatualizado | `Configuration#ca_file` como escape hatch documentado; nunca desabilitar `VERIFY_PEER` por default | +| `Retry-After` em formato HTTP-date (não segundos) | v1 suporta só segundos inteiros (paridade PHP); HTTP-date cai no backoff calculado | + +## Open Questions + +- (nenhuma) — a thread-safety do pool foi resolvida (ver D15). + +## Resolved (durante o recon — 2026-06-24) + +- **Header de auth confirmado**: `X-NFE-APIKEY` (não `Authorization: Basic`). Confirmado em `client-nodejs/src/core/http/client.ts:287`. +- **Estados terminais de FlowStatus** (relevantes para o consumidor do 202, mas implementados em `add-client-core`): `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`. Esta change só garante que 202 + `Location` chegam crus à camada de cima. +- **`Idempotency-Key`**: diferente do PHP (que removeu), mantemos o campo no `Request` por estar na allowlist (`securerandom`) e por destravar retry seguro de POST. Envio condicional — `nil` por padrão, custo zero se a API não honrar. diff --git a/openspec/changes/archive/2026-06-25-add-http-transport/proposal.md b/openspec/changes/archive/2026-06-25-add-http-transport/proposal.md new file mode 100644 index 0000000..ef2a4c4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-http-transport/proposal.md @@ -0,0 +1,60 @@ +# add-http-transport + +## Why + +A API da NFE.io vive em **múltiplos hosts** (`api.nfe.io`, `api.nfse.io`, `address.api.nfe.io/v2`, `nfe.api.nfe.io`, `legalentity.api.nfe.io`, `naturalperson.api.nfe.io`), responde **202 + `Location`** para emissões assíncronas, devolve **downloads binários** (PDF/XML/ZIP), e tem o comportamento de rede de qualquer SaaS sério: throttling (429 com `Retry-After`), 5xx transientes, e gzip. O SDK v0.3.2 (rest-client, congelado em `0.x-legacy`) embute tudo isso de forma frágil e acoplada. + +A decisão canônica do rewrite v1 é **zero dependências de runtime — só stdlib** (`net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`). Isolar o HTTP numa camada testável é pré-requisito para todo recurso: o `Nfe::Client` (em `add-client-core`) injeta o transport, e os 17 recursos (em `add-invoice-resources` e changes irmãs) só conversam com a API pública dessa camada. Esta change entrega esse alicerce, espelhando as taxonomias de erro e o contrato 202 do SDK Node.js e PHP, mas em Ruby idiomático (`Data.define`, keyword args, `raise` de erros tipados, retorno síncrono em vez de `Promise`). + +Depende de **add-ruby-foundation** (gem `nfe-io`, namespace `Nfe`, piso Ruby 3.2, `# frozen_string_literal: true` em todo `.rb`, RBS/Steep/RuboCop/RSpec, SimpleCov >= 80%). É consumida por **add-client-core** (que injeta o transport e resolve o host map) e por todas as changes de recurso. + +## What Changes + +### Transport e value objects + +- **`Nfe::Http::Transport`** — interface duck-typed (módulo + `raise NotImplementedError`) com um único método `call(request) -> response`. Permite substituir o transport em testes sem tocar em rede. +- **`Nfe::Http::NetHttp`** — implementação default, zero-dep, sobre `Net::HTTP`. TLS com verificação obrigatória (`OpenSSL::SSL::VERIFY_PEER`), reuso de conexão persistente por host (`keep-alive`) com **pool guardado por `Mutex` (thread-safe sob Rails/Sidekiq/Puma)**, timeouts separados de `open` e `read`, `Accept-Encoding: gzip` com descompressão automática (descartando/recalculando `content-length` após inflar), e honra de overrides por chamada (`Nfe::RequestOptions`: `api_key`/`base_url`/`timeout`) sem mutar config global. +- **`Nfe::Http::Request`** — value object imutável (`Data.define`) com `method`, `base_url`, `path`, `headers`, `query`, `body`, `open_timeout`, `read_timeout`, `idempotency_key`. Helper `#url` compõe `base_url + path + query`. +- **`Nfe::Http::Response`** — value object imutável (`Data.define`) com `status`, `headers` (chaves lowercase), `body` (String binária). Helpers `#header(name)`, `#success?`, `#location`. + +### Confiabilidade + +- **`Nfe::Http::RetryPolicy`** — `Data.define` com `max_retries` (default 3), `base_delay` (1.0s), `max_delay` (30.0s), `jitter` (0.3 = ±30%); fábricas `.default` e `.none`; `#delay_for(attempt)` calcula backoff exponencial com jitter limitado. +- **`Nfe::Http::RetryingTransport`** — decorator que envolve qualquer `Transport`. Faz retry em **429**, **5xx** e **erros de rede** somente para requisições idempotentes; honra `Retry-After` (segundos inteiros); aplica backoff + jitter; aceita um `sleep` injetável para testes determinísticos. + +### Autenticação, identidade e observabilidade + +- **Header de auth**: `X-NFE-APIKEY: ` injetado pela camada (paridade exata com Node `buildHeaders`). +- **User-Agent**: `NFE.io Ruby Client v ruby/ ()`, lido de `Nfe::VERSION` (de `add-ruby-foundation`). +- **Idempotency-Key**: suporte de **slot** — `Request` carrega o campo e o transport envia `Idempotency-Key` quando presente. A chave é **fornecida pelo chamador** via kwarg `idempotency_key:` nos métodos de emissão (`create`/`create_with_state_tax`), **nunca auto-gerada** pelo transport. POST **não** é auto-retried (default de segurança), divergindo deliberadamente de Node/PHP (que repetem POST) — divergência documentada para integradores no README (release-tooling); só vira retry-eligible quando o chamador passa a chave; não enviado por padrão. +- **Logger duck-typed (equivalente PSR-3)**: `Configuration#logger` aceita qualquer objeto que responda a `info`/`warn`/`error` (incluindo `::Logger` da stdlib). Quando presente, loga início de request (`info`), retry (`warn`) e falha (`error`), sempre com **redação** de `X-NFE-APIKEY`, `Authorization` e qualquer `secret` (substituídos por `[REDACTED]`). **Por padrão NÃO loga corpos** de request/response (só método, URL, status, `request_id`); log de corpo é opt-in explícito (`Configuration#log_request_body`), truncado e redigido — CNPJ/CPF e senha de certificado nunca vazam em log. + +### Hierarquia de erros (`Nfe::*`) + +- `Nfe::Error` (base) carregando `message`, `status_code`, `request_id`, `error_code`, `response_body`, `response_headers`; `#to_h` para logging. +- `Nfe::AuthenticationError` (401), `Nfe::AuthorizationError` (403), `Nfe::InvalidRequestError` (400/422), `Nfe::NotFoundError` (404), `Nfe::ConflictError` (409), `Nfe::RateLimitError` (429), `Nfe::ServerError` (5xx), `Nfe::ApiConnectionError` (rede), `Nfe::TimeoutError` (timeout), `Nfe::SignatureVerificationError` (definido aqui, consumido por webhooks). +- **`Nfe::ErrorFactory`** — mapeia `status` + corpo para o erro tipado, extraindo `message`/`error_code`/`request_id` do payload e dos headers (`x-request-id`). + +### Fora de escopo (decisões registradas) + +- **Não seguir 202/redirects automaticamente** — o transport devolve `Response` cru com `Location`; quem decide é o recurso (contrato Pending/Issued mora em `add-client-core`). +- **Polling (`pollUntilComplete`/`create_and_wait`)** — diferido; o contrato 202 nasce correto, mas o helper de polling é entregue depois. +- **`createBatch`/concorrência** — fora de escopo; Ruby síncrono não tem ganho real aqui. + +## Capabilities + +### New Capabilities +- `http-transport`: contrato de transport (`Net::HTTP`), value objects request/response, retry com backoff + jitter, multi-base-URL, hierarquia de erros tipados + `ErrorFactory`, User-Agent, auth header, idempotency-key slot, logger duck-typed com redação. + +### Modified Capabilities +- (nenhuma) — esta é a primeira change a introduzir a capability `http-transport`. + +## Impact + +- **Affected code**: `lib/nfe/http/*` (transport, request, response, retry_policy, retrying_transport, user_agent), `lib/nfe/errors.rb` (+ `lib/nfe/error_factory.rb`), assinaturas em `sig/nfe/http/*.rbs` e `sig/nfe/errors.rbs`, testes em `spec/nfe/http/*` e `spec/nfe/error_factory_spec.rb`. +- **Spec impact**: adiciona a capability `http-transport`. +- **Dependencies**: depende de `add-ruby-foundation` (gem, namespace, `Nfe::VERSION`, toolchain). Consumida por `add-client-core` (injeção do transport + host map) e pelas changes de recurso. +- **Riscos**: + - `Net::HTTP` separa parsing de header/body de forma diferente do cURL/fetch — testes cobrem normalização lowercase e gzip. + - Reuso de conexão persistente entre hosts diferentes exige pool por `host:port` — mitigado mantendo um `Net::HTTP` por origem. + - Retry só em métodos idempotentes evita reemissão indevida de invoice (POST não idempotente sem `Idempotency-Key`). diff --git a/openspec/changes/archive/2026-06-25-add-http-transport/specs/http-transport/spec.md b/openspec/changes/archive/2026-06-25-add-http-transport/specs/http-transport/spec.md new file mode 100644 index 0000000..f414948 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-http-transport/specs/http-transport/spec.md @@ -0,0 +1,259 @@ +# http-transport — Delta + +## ADDED Requirements + +### Requirement: Transport abstraction +The SDK SHALL define a transport contract `Nfe::Http::Transport` exposing a single method `call(request) -> response`, allowing the HTTP transport implementation to be substituted (default `Net::HTTP`, PSR-3-style logging decorator, or an in-memory fake) without touching resource code. Any object responding to `call(Nfe::Http::Request)` and returning an `Nfe::Http::Response` SHALL be a valid transport (duck typing). + +#### Scenario: Substituting the transport for tests +- **WHEN** a test constructs the SDK with a fake object whose `call` returns queued `Nfe::Http::Response` instances +- **THEN** all HTTP requests SHALL be routed through that fake without reaching the network + +#### Scenario: Transport returns HTTP errors as responses, not exceptions +- **WHEN** a transport receives an HTTP 404 or HTTP 500 from the wire +- **THEN** it SHALL return an `Nfe::Http::Response` carrying that status code, and SHALL NOT raise — so the retry decorator and `Nfe::ErrorFactory` can act on the status + +### Requirement: Default zero-dependency Net::HTTP transport +The SDK SHALL ship `Nfe::Http::NetHttp` as the default transport, implemented using only the Ruby standard library (`net/http`, `uri`, `openssl`, `zlib`, `stringio`). It SHALL NOT require any external gem. + +#### Scenario: Using the SDK without any HTTP gem installed +- **WHEN** a consumer installs `nfe-io` and uses the client without configuring a transport +- **THEN** the SDK SHALL use `Nfe::Http::NetHttp` and perform HTTP requests successfully against the network + +#### Scenario: TLS verification is enforced by default +- **WHEN** `Nfe::Http::NetHttp` sends a request to an `https` base URL +- **THEN** it SHALL enable TLS with `OpenSSL::SSL::VERIFY_PEER` and SHALL NOT disable certificate verification + +#### Scenario: Persistent connection reuse per origin +- **WHEN** two consecutive requests target the same `host:port` +- **THEN** the transport SHALL reuse a single persistent `Net::HTTP` connection (keep-alive) for that origin rather than opening a new TCP/TLS connection each time + +### Requirement: Request value object +The SDK SHALL define `Nfe::Http::Request` as an immutable value object (`Data.define`) carrying `method`, `base_url`, `path`, `headers`, `query`, `body`, `open_timeout`, `read_timeout`, and `idempotency_key`. It SHALL expose `#url` composing the final URL from `base_url`, `path`, and the URL-encoded `query`, and `#idempotent?` returning true for `GET`/`HEAD`/`PUT`/`DELETE` (case-insensitive) or any request carrying an `idempotency_key`. + +#### Scenario: URL composition with query +- **WHEN** a `Request` has `base_url: "https://api.nfse.io"`, `path: "/v2/companies/abc/productinvoices"`, and `query: { environment: "Production", limit: 50 }` +- **THEN** `#url` SHALL return `https://api.nfse.io/v2/companies/abc/productinvoices?environment=Production&limit=50` + +#### Scenario: Idempotency classification +- **WHEN** `#idempotent?` is called on a `GET`, `HEAD`, `PUT`, or `DELETE` request, or on a `POST` request carrying a non-nil `idempotency_key` +- **THEN** it SHALL return `true`; for a `POST` request with no `idempotency_key` it SHALL return `false` + +### Requirement: Response value object +The SDK SHALL define `Nfe::Http::Response` as an immutable value object (`Data.define`) carrying `status` (Integer), `headers` (Hash with lowercase string keys), and `body` (a binary-safe `ASCII-8BIT` String). It SHALL expose `#header(name)` (case-insensitive lookup), `#success?` (true for 2xx), and `#location` (the `Location` header or nil). + +#### Scenario: Case-insensitive header lookup +- **WHEN** a server returns a `Location:` header in any letter casing +- **THEN** `#header("Location")`, `#header("location")`, and `#location` SHALL all return the same value + +#### Scenario: Body is binary-safe +- **WHEN** the response body contains raw PDF or ZIP bytes +- **THEN** `body` SHALL be a String with `ASCII-8BIT` encoding, preserving every byte without transcoding + +### Requirement: Multi-base-URL routing +The SDK SHALL allow each `Nfe::Http::Request` to specify its `base_url` independently, so resources targeting different NFE.io hosts (`api.nfe.io`, `api.nfse.io`, `address.api.nfe.io/v2`, `nfe.api.nfe.io`, `legalentity.api.nfe.io`, `naturalperson.api.nfe.io`) work uniformly through the same transport. The transport SHALL NOT hard-code any host. The host map itself is owned by `Nfe::Configuration` (defined in change `add-client-core`); this capability only requires that the transport honors the `base_url` it receives. + +#### Scenario: A resource targets a non-default host +- **WHEN** a resource constructs `Nfe::Http::Request.new(method: "GET", base_url: "https://api.nfse.io", path: "/v2/...")` +- **THEN** the transport SHALL send the request to `api.nfse.io` regardless of any global default base URL + +### Requirement: gzip transport encoding +The transport SHALL request `Accept-Encoding: gzip` (unless the caller already set an `Accept-Encoding` header) and SHALL transparently decompress a `Content-Encoding: gzip` response body before returning it, removing the `content-encoding` header from the resulting `Response`. + +#### Scenario: Compressed JSON response +- **WHEN** the server returns a body with `Content-Encoding: gzip` +- **THEN** the `Response#body` SHALL contain the decompressed bytes and `Response#header("content-encoding")` SHALL be nil + +#### Scenario: Content-Length reflects the decompressed body +- **WHEN** a `Content-Encoding: gzip` body is inflated +- **THEN** the transport SHALL drop or recompute the `content-length` header so it does not advertise the now-stale compressed byte count + +#### Scenario: Malformed gzip falls back to raw bytes +- **WHEN** the server claims `Content-Encoding: gzip` but the body cannot be inflated +- **THEN** the transport SHALL return the raw body unchanged and SHALL log a warning if a logger is configured, without raising + +### Requirement: Retry policy with exponential backoff and jitter +The SDK SHALL provide `Nfe::Http::RetryPolicy` (`Data.define`) with configurable `max_retries` (default 3), `base_delay` (default 1.0s), `max_delay` (default 30.0s), and `jitter` (default 0.3 = ±30%), plus factories `.default` and `.none`. `#delay_for(attempt)` SHALL compute `min(max_delay, base_delay * 2^(attempt-1))` and apply symmetric jitter, capped at `max_delay`. + +#### Scenario: Backoff is capped +- **WHEN** `#delay_for` is called for an attempt large enough that the exponential term exceeds `max_delay` +- **THEN** the returned delay SHALL NOT exceed `max_delay` + +#### Scenario: Jitter bounds +- **WHEN** `#delay_for(attempt)` is called repeatedly with `jitter: 0.3` +- **THEN** every returned value SHALL fall within `[base * 0.7, base * 1.3]` (clamped to `max_delay`), where `base = min(max_delay, base_delay * 2^(attempt-1))` + +#### Scenario: No-retry policy +- **WHEN** the policy is `RetryPolicy.none` +- **THEN** `max_retries` SHALL be 0 and the retrying transport SHALL make exactly one HTTP attempt + +### Requirement: Retrying transport for transient failures on idempotent requests +The SDK SHALL provide `Nfe::Http::RetryingTransport`, a decorator wrapping any transport with a `RetryPolicy` and an injectable sleep function. It SHALL retry on HTTP 429, HTTP 500–599, and network errors (`Nfe::ApiConnectionError`, including `Nfe::TimeoutError`), but ONLY for idempotent requests (per `Request#idempotent?`). It SHALL NOT retry HTTP 4xx other than 429, and SHALL NOT retry a non-idempotent `POST`. + +#### Scenario: Server returns 503 then succeeds +- **WHEN** the inner transport returns HTTP 503 on a `GET` then HTTP 200 on retry +- **THEN** the retrying transport SHALL transparently return the successful 200 response to the caller + +#### Scenario: Client error other than 429 is not retried +- **WHEN** the inner transport returns HTTP 400 +- **THEN** the retrying transport SHALL return that 400 response immediately without retrying + +#### Scenario: Non-idempotent POST is not retried +- **WHEN** the inner transport returns HTTP 503 for a `POST` request that carries no `idempotency_key` +- **THEN** the retrying transport SHALL return the 503 response without retrying, so the SDK never re-issues an invoice + +#### Scenario: Retries exhausted +- **WHEN** the inner transport returns HTTP 503 on every attempt for an idempotent request up to the configured maximum +- **THEN** the retrying transport SHALL return the last 503 response (which the resource layer maps to `Nfe::ServerError`) + +#### Scenario: Retry-After honored +- **WHEN** the inner transport returns HTTP 429 with `Retry-After: 5` for an idempotent request +- **THEN** the retrying transport SHALL wait at least 5 seconds (clamped to `max_delay`) before the next attempt + +#### Scenario: Network error is retried then propagated +- **WHEN** the inner transport raises `Nfe::ApiConnectionError` on every attempt for an idempotent request +- **THEN** the retrying transport SHALL retry up to `max_retries` and then re-raise the last `Nfe::ApiConnectionError` + +### Requirement: Error hierarchy +The SDK SHALL define an error hierarchy rooted at `Nfe::Error` (subclass of `StandardError`), with concrete subclasses: `AuthenticationError` (401), `AuthorizationError` (403), `InvalidRequestError` (400/422), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `ServerError` (5xx), `ApiConnectionError` (network), `TimeoutError` (a subclass of `ApiConnectionError`), and `SignatureVerificationError` (webhook verification). `Nfe::Error` SHALL expose `status_code`, `request_id`, `error_code`, `response_body`, and `response_headers`, plus a `#to_h` for logging. + +#### Scenario: Catching a specific error +- **WHEN** consumer code wraps a call with `rescue Nfe::NotFoundError` +- **THEN** the SDK SHALL raise that error specifically on HTTP 404 responses, not the base class + +#### Scenario: Catching all SDK errors +- **WHEN** consumer code wraps a call with `rescue Nfe::Error` +- **THEN** every SDK-raised error SHALL be caught through this base class + +#### Scenario: Timeout is a connection error +- **WHEN** consumer code wraps a call with `rescue Nfe::ApiConnectionError` +- **THEN** it SHALL also catch `Nfe::TimeoutError`, since `TimeoutError` is a subclass of `ApiConnectionError` + +#### Scenario: Error carries response context +- **WHEN** any `Nfe::Error` derived from an HTTP response is raised +- **THEN** it SHALL expose `status_code`, `request_id`, `error_code`, `response_body`, and `response_headers` + +### Requirement: ErrorFactory maps status and body to typed errors +The SDK SHALL provide `Nfe::ErrorFactory` with `from_response(response)` and `from_network_error(exception)`. `from_response` SHALL select the error class by status code (400/422 → `InvalidRequestError`, 401 → `AuthenticationError`, 403 → `AuthorizationError`, 404 → `NotFoundError`, 409 → `ConflictError`, 429 → `RateLimitError`, 500–599 → `ServerError`, other 4xx → `InvalidRequestError`, other ≥500 → `ServerError`). It SHALL extract `message` (from body keys `message`/`error`/`detail`/`details`/`errors`), `error_code` (from `code`/`errorCode`/`error_code`), and `request_id` (from header `x-request-id`, falling back to `x-correlation-id`). Because the extracted `message` echoes server input, the factory SHALL cap the message at a bounded length and scrub control characters before placing it on the error. + +#### Scenario: Oversized server message is capped and scrubbed +- **WHEN** `from_response` receives a body whose `message` is very long or contains control characters +- **THEN** the resulting error message SHALL be truncated to a bounded length with control characters removed, so an attacker-controlled body cannot flood logs or inject terminal sequences + +#### Scenario: 404 maps to NotFoundError +- **WHEN** `from_response` receives a `Response` with status 404 +- **THEN** it SHALL return an `Nfe::NotFoundError` whose `status_code` is 404 + +#### Scenario: 422 maps to InvalidRequestError +- **WHEN** `from_response` receives a `Response` with status 422 +- **THEN** it SHALL return an `Nfe::InvalidRequestError` + +#### Scenario: Rate limit carries retry-after +- **WHEN** `from_response` receives status 429 with a `Retry-After: 30` header +- **THEN** it SHALL return an `Nfe::RateLimitError` whose `retry_after` is 30 + +#### Scenario: Message and request id extracted +- **WHEN** `from_response` receives a JSON body `{ "message": "CNPJ inválido", "code": "INVALID_CNPJ" }` with header `x-request-id: req_123` +- **THEN** the raised error SHALL have message `"CNPJ inválido"`, `error_code` `"INVALID_CNPJ"`, and `request_id` `"req_123"` + +#### Scenario: Non-JSON body does not break the factory +- **WHEN** `from_response` receives a non-JSON body (e.g. HTML or plain text) +- **THEN** it SHALL still return the correct error class with a default message and SHALL NOT raise a parse error + +#### Scenario: Network exception mapping +- **WHEN** `from_network_error` receives a `Net::ReadTimeout` or `Net::OpenTimeout` +- **THEN** it SHALL return an `Nfe::TimeoutError`; for `SocketError`, `Errno::ECONNREFUSED`, or `OpenSSL::SSL::SSLError` it SHALL return an `Nfe::ApiConnectionError`, preserving the original exception as cause + +### Requirement: 202 responses are not auto-followed +The transport SHALL NOT follow HTTP 202 responses or any redirect automatically. The `Response` object SHALL expose the raw status code and headers (including `Location`) so the calling resource can implement the discriminated Pending/Issued contract (defined in `add-client-core`). + +#### Scenario: API returns 202 with Location +- **WHEN** the transport receives HTTP 202 with `Location: /v1/companies/{id}/serviceinvoices/{invoiceId}` +- **THEN** it SHALL return a `Response` with `status == 202` and the `Location` header preserved, without fetching the resource at `Location` + +### Requirement: User-Agent identification +Every outgoing request SHALL carry a `User-Agent` header in the format `NFE.io Ruby Client v ruby/ ()`, built via `Nfe::Http::UserAgent.build`, unless the caller overrides it explicitly. The SDK version SHALL be read from `Nfe::VERSION`. + +#### Scenario: Default User-Agent format +- **WHEN** `Nfe::Http::UserAgent.build` is called with `Nfe::VERSION == "1.0.0"` on Ruby 3.3 +- **THEN** it SHALL return a string matching `NFE.io Ruby Client v1.0.0 ruby/3.3.0 ()` + +### Requirement: API key authentication header +The SDK SHALL authenticate requests using the `X-NFE-APIKEY` header carrying the API key. The header value SHALL be the API key provided on the `Request` (resolved per host family by `Nfe::Configuration` in `add-client-core`). The transport itself SHALL remain authentication-agnostic and send whatever auth header the `Request` carries. + +#### Scenario: API key header sent +- **WHEN** a `Request` is built with header `X-NFE-APIKEY` set to the configured key +- **THEN** the transport SHALL transmit that header verbatim to the wire + +### Requirement: Idempotency-Key slot +The `Nfe::Http::Request` SHALL carry an optional `idempotency_key`. When present, the transport SHALL send it as the `Idempotency-Key` request header. When nil, no `Idempotency-Key` header SHALL be sent. A present key SHALL also make the request eligible for retry per `Request#idempotent?`. + +#### Scenario: Idempotency key sent when present +- **WHEN** a `Request` carries `idempotency_key: "9f1c..."` +- **THEN** the transport SHALL send `Idempotency-Key: 9f1c...` and the request SHALL be retry-eligible even for `POST` + +#### Scenario: No idempotency key by default +- **WHEN** a `Request` has `idempotency_key: nil` +- **THEN** the transport SHALL NOT send any `Idempotency-Key` header + +### Requirement: Pluggable duck-typed logger with secret redaction +The SDK SHALL support an optional logger (a duck-typed object responding to `info`/`warn`/`error`, such as Ruby's stdlib `::Logger`), configured via `Nfe::Configuration` (in `add-client-core`). When provided, the transport layer SHALL log request start at `info`, retries at `warn`, and final failures at `error`. Before logging, it SHALL redact the values of sensitive headers — `X-NFE-APIKEY`, `Authorization`, `Idempotency-Key`, and any header whose name matches `/secret|apikey|token/i` — replacing them with `[REDACTED]`. The SDK SHALL NOT declare any logging gem as a runtime dependency. + +#### Scenario: Logger provided and request fails +- **WHEN** a logger is configured and a request finally fails with HTTP 500 +- **THEN** the logger SHALL receive at least one `error` entry including the method, URL, and status code, with the API key value redacted to `[REDACTED]` + +#### Scenario: No logger provided +- **WHEN** no logger is configured +- **THEN** no logging SHALL occur and no logging gem SHALL be required at runtime + +#### Scenario: Logging never breaks the request +- **WHEN** the configured logger itself raises while logging +- **THEN** the SDK SHALL rescue the logging error and complete the HTTP request normally + +### Requirement: Request and response bodies are never logged by default +The SDK SHALL NOT log request or response BODIES by default. Default log entries SHALL be limited to the HTTP method, URL, status code, and `request_id`. Body logging SHALL be available only behind an explicit opt-in flag (`Nfe::Configuration#log_request_body`, defined in `add-client-core`); when enabled, any logged body SHALL be truncated to a bounded length and SHALL pass through redaction so that secrets and PII never appear verbatim. `Nfe::Error#response_body` SHALL remain available on raised errors for programmatic inspection, but SHALL NOT be auto-logged by the transport's default log entries. + +#### Scenario: Bodies are omitted from default logs +- **WHEN** a logger is configured with no body-logging opt-in and a request carrying a CNPJ/CPF in its body fails with HTTP 422 whose response body echoes the CNPJ/CPF +- **THEN** no log line SHALL contain the request body, the response body, the CNPJ, the CPF, the API key, or the certificate password — only method, URL, status, and `request_id` + +#### Scenario: Opt-in body logging is truncated and redacted +- **WHEN** `log_request_body` is explicitly enabled and a body is logged +- **THEN** the logged body SHALL be truncated to a bounded length and SHALL have sensitive values (API key, `Idempotency-Key`, secrets/tokens) redacted to `[REDACTED]` + +### Requirement: Connection pool is thread-safe +The per-origin keep-alive connection pool inside `Nfe::Http::NetHttp` SHALL be guarded by a `Mutex`, so a single transport (and the `Client` that shares it) MAY be used concurrently from multiple threads without corrupting the pool or sharing a `Net::HTTP` socket across two in-flight requests. This makes a shared `Client` safe under Rails/Sidekiq/Puma multi-threaded execution. + +#### Scenario: Concurrent requests share the transport safely +- **WHEN** multiple threads issue requests through the same `Nfe::Http::NetHttp` instance at the same time +- **THEN** access to the per-origin connection cache SHALL be serialized by a `Mutex` and no two threads SHALL use the same underlying socket simultaneously + +### Requirement: Per-call request option overrides +The transport SHALL honor per-call overrides supplied by the resource layer via `Nfe::RequestOptions` (`Data.define` with `api_key`, `base_url`, `timeout`; defined in `add-client-core`). When a `Request` is built with such overrides, the transport SHALL use the overridden `base_url` and timeout for that single call and SHALL transmit the overridden API key in the `X-NFE-APIKEY` header, without mutating any global configuration or affecting other concurrent calls. This enables multi-tenant per-call API keys without constructing a second `Client`. + +#### Scenario: Per-call base URL and timeout override +- **WHEN** a single `Request` carries an overridden `base_url` and `read_timeout` derived from `Nfe::RequestOptions` +- **THEN** the transport SHALL route that one call to the overridden `base_url` with the overridden timeout, leaving the default configuration unchanged for subsequent calls + +#### Scenario: Per-call API key override +- **WHEN** a single `Request` carries an API key derived from a per-call `Nfe::RequestOptions` +- **THEN** the transport SHALL send that key in `X-NFE-APIKEY` for that call only, enabling multi-tenant usage from one shared `Client` + +### Requirement: POST is not auto-retried even with an idempotency key available +The transport SHALL NOT automatically retry a `POST` request as a safety default, diverging deliberately from the Node.js and PHP SDKs (which retry POST). A `POST` becomes retry-eligible ONLY when the caller supplies an `idempotency_key` (set by the resource `create`/`create_with_state_tax` kwarg, NEVER auto-generated by the transport). This divergence SHALL be documented for integrators in the README (owned by the release-tooling change). + +#### Scenario: POST without idempotency key is never auto-retried +- **WHEN** a `POST` request without an `idempotency_key` receives HTTP 503 +- **THEN** the transport SHALL return the 503 response immediately without retrying, so an invoice is never re-issued automatically + +#### Scenario: POST with caller-supplied idempotency key is retry-eligible +- **WHEN** a `POST` request carries a caller-supplied `idempotency_key` and receives HTTP 503 +- **THEN** the request SHALL be eligible for retry (per `Request#idempotent?`), the `Idempotency-Key` header SHALL be replayed on each attempt, and the key SHALL NOT be auto-generated by the transport + +### Requirement: Polling and batch helpers are not part of v1.0 +The HTTP transport SHALL deliver the raw 202 + `Location` contract but SHALL NOT implement polling (`pollUntilComplete` / `create_and_wait`) nor concurrent batch helpers (`create_batch`). These are explicitly deferred; the discriminated Pending/Issued contract (in `add-client-core`) plus `Nfe::FlowStatus` terminal-state checks are sufficient for manual polling loops. + +#### Scenario: No automatic polling at the transport layer +- **WHEN** the transport returns a 202 with `Location` +- **THEN** it SHALL NOT issue any follow-up GET to that `Location`; resolving the async result is the caller's responsibility diff --git a/openspec/changes/archive/2026-06-25-add-http-transport/tasks.md b/openspec/changes/archive/2026-06-25-add-http-transport/tasks.md new file mode 100644 index 0000000..998cdac --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-http-transport/tasks.md @@ -0,0 +1,128 @@ +# Tasks — add-http-transport + +> Esta change depende de `add-ruby-foundation` +> (gem `nfe-io`, namespace `Nfe`, `Nfe::VERSION`, piso Ruby 3.2, `# frozen_string_literal: true` +> em todo `.rb`, RBS/Steep/RuboCop/RSpec, SimpleCov >= 80%). Consumida por `add-client-core` +> (injeção do transport + host map) e pelas changes de recurso. +> +> **Status (2026-06-24): IMPLEMENTADO e verificado verde via Docker na matrix Ruby 3.2/3.3/3.4.** +> Entregues §1–§9 e §11: value objects (`Request`/`Response`), `Transport` + `NetHttp` (pool com mutex, TLS VERIFY_PEER, gzip, timeouts), `RetryPolicy` + `RetryingTransport` (backoff/jitter, Retry-After, sem retry de POST não-idempotente), `UserAgent`, `Redactor`, hierarquia de erros `Nfe::Error` + `ErrorFactory`, logger duck-typed sem corpos, e specs (128 exemplos, cobertura de linha ~97.5%). Gate: `rspec` 128/0, `rubocop` 0 offenses, `steep` 0 erros, `rbs validate` ok — nos três Rubies. §12 (smoke manual em sandbox) permanece DEFERRED (precisa chave). Decisões de design realizadas durante a verificação: value objects usam `class X < Data.define(...)` (forma que o Steep resolve); `Request#method` mantém o nome (expõe o verbo HTTP); cops `Style/DataInheritance`/`Lint/DataDefineOverride` desabilitados com justificativa; `Layout/LeadingCommentSpace` aceita anotações RBS inline `#:`. + +## 1. Value objects: Request e Response + +- [ ] 1.1 Criar `lib/nfe/http/request.rb` — `Nfe::Http::Request = Data.define(:method, :base_url, :path, :headers, :query, :body, :open_timeout, :read_timeout, :idempotency_key)`. Defaults: `headers: {}`, `query: {}`, `body: nil`, `open_timeout: nil`, `read_timeout: nil`, `idempotency_key: nil`. `# frozen_string_literal: true` no topo. +- [ ] 1.2 Adicionar método `#url` em `Request` — compõe `base_url.chomp("/") + path`, anexa `?` + `URI.encode_www_form(query)` quando `query` não vazio; usa `&` se `path` já tiver `?`. Arrays em query viram chaves repetidas. +- [ ] 1.3 Adicionar `#idempotent?` em `Request` — true para `GET`/`HEAD`/`PUT`/`DELETE` (case-insensitive) OU quando `idempotency_key` presente. +- [ ] 1.4 Criar `lib/nfe/http/response.rb` — `Nfe::Http::Response = Data.define(:status, :headers, :body)`. Headers com **chaves lowercase**. `body` é String `ASCII-8BIT`. +- [ ] 1.5 Adicionar helpers em `Response`: `#header(name)` (lookup case-insensitive via `headers[name.downcase]`), `#success?` (`(200..299).cover?(status)`), `#location` (`header("location")`). + +## 2. Transport: interface + default Net::HTTP + +- [ ] 2.1 Criar `lib/nfe/http/transport.rb` — `module Nfe::Http::Transport` documentando o contrato: `def call(request) = raise NotImplementedError`. Documentar regras (não seguir 202/redirect; headers lowercase no Response; levantar só `ApiConnectionError`/`TimeoutError` em falha de rede; devolver 4xx/5xx como Response). +- [ ] 2.2 Criar `lib/nfe/http/net_http.rb` — `Nfe::Http::NetHttp` implementa `call(request)`. Constructor aceita `default_open_timeout: 10`, `default_read_timeout: 60`, `ca_file: nil`. +- [ ] 2.3 `NetHttp`: pool de conexões por origem — cache `Hash` keyed por `"#{host}:#{port}"` de instâncias `Net::HTTP` iniciadas (`start`), com `keep_alive_timeout` para reuso TCP/TLS. +- [ ] 2.4 `NetHttp`: TLS — `use_ssl = (uri.scheme == "https")`, `verify_mode = OpenSSL::SSL::VERIFY_PEER`, aplicar `ca_file` quando setado. Nunca desabilitar verificação por default. +- [ ] 2.5 `NetHttp`: timeouts — aplicar `open_timeout`/`read_timeout` do `Request` quando presentes, senão os defaults do transport. +- [ ] 2.6 `NetHttp`: construir o objeto `Net::HTTP::Get/Post/Put/Delete/Head` a partir de `request.method`; setar headers do request; setar `body` quando presente; setar `Accept-Encoding: gzip` se o caller não tiver setado. +- [ ] 2.7 `NetHttp`: executar a request; capturar `Timeout::Error`/`Net::OpenTimeout`/`Net::ReadTimeout` → `raise Nfe::TimeoutError`; `SocketError`/`Errno::*`/`OpenSSL::SSL::SSLError`/`EOFError`/`Net::HTTPBadResponse` → `raise Nfe::ApiConnectionError`. +- [ ] 2.8 `NetHttp`: descompressão gzip — se `Content-Encoding: gzip`, descomprimir via `Zlib::GzipReader` e remover o header `content-encoding`; em `Zlib::Error`, manter body cru e logar `warn`. +- [ ] 2.9 `NetHttp`: montar `Response` — `status` (Integer), `headers` normalizados para lowercase (multi-value join com `", "`), `body.force_encoding(Encoding::ASCII_8BIT)`. NÃO seguir redirect/202. +- [ ] 2.10 `NetHttp`: resetar/recriar a conexão da origem ao capturar erro de rede, para não reutilizar socket quebrado. +- [ ] 2.11 `NetHttp`: guardar o pool por origem com um `Mutex` — acesso ao cache serializado; dois threads nunca usam o mesmo socket simultaneamente (thread-safe sob Rails/Sidekiq/Puma). +- [ ] 2.12 `NetHttp`: honrar overrides por chamada do `Request` derivados de `Nfe::RequestOptions` (`base_url`/timeout/`api_key` via `X-NFE-APIKEY`) sem mutar config global nem afetar chamadas concorrentes. +- [ ] 2.13 `NetHttp`: após inflar gzip (2.8), descartar/recalcular o header `content-length` para não anunciar o tamanho comprimido obsoleto. + +## 3. Retry: policy + decorator + +- [ ] 3.1 Criar `lib/nfe/http/retry_policy.rb` — `Nfe::Http::RetryPolicy = Data.define(:max_retries, :base_delay, :max_delay, :jitter)`. Defaults via fábrica `.default` = `(3, 1.0, 30.0, 0.3)`. Fábrica `.none` = `max_retries: 0`. +- [ ] 3.2 `RetryPolicy#delay_for(attempt)` — `base = [base_delay * (2 ** (attempt - 1)), max_delay].min`; aplicar jitter simétrico `base * (1 - jitter + 2*jitter*rand())`, limitado a `max_delay`. `attempt` 1-based (1 = primeiro retry). +- [ ] 3.3 Criar `lib/nfe/http/retrying_transport.rb` — `Nfe::Http::RetryingTransport` decora um `inner` transport + `policy` + `sleep_fn` injetável (lambda, default `Kernel#sleep`). Implementa `call(request)`. +- [ ] 3.4 `RetryingTransport`: loop de tentativas — `inner.call(request)`; se `retryable_status?(response.status)` E `attempt < max_retries` E `request.idempotent?` → calcular delay, dormir, repetir; senão devolver `response`. +- [ ] 3.5 `RetryingTransport`: `rescue Nfe::ApiConnectionError` (inclui `TimeoutError`) — se `attempt < max_retries` E `request.idempotent?` → backoff e repetir; senão `raise`. +- [ ] 3.6 `RetryingTransport#retryable_status?` — `status == 429 || (500..599).cover?(status)`. +- [ ] 3.7 `RetryingTransport`: honrar `Retry-After` — quando o `Response` traz `retry-after` em segundos inteiros, usar `[retry_after, max_delay].min` no lugar do backoff calculado. +- [ ] 3.8 `RetryingTransport`: nunca repetir POST sem `idempotency_key` (via `request.idempotent?`), para não reemitir invoice. A `idempotency_key` é **fornecida pelo chamador** (kwarg em `create`/`create_with_state_tax`), nunca auto-gerada pelo transport; divergência de Node/PHP (que repetem POST) documentada para integradores no README (release-tooling). + +## 4. User-Agent + auth header helpers + +- [ ] 4.1 Criar `lib/nfe/http/user_agent.rb` — `Nfe::Http::UserAgent.build(suffix = nil)` retornando `"NFE.io Ruby Client v#{Nfe::VERSION} ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM})"` + sufixo opcional. +- [ ] 4.2 Documentar (docstring) que a injeção de `User-Agent`, `X-NFE-APIKEY`, `Accept: application/json` e `Idempotency-Key` é feita pela camada `Client`/`AbstractResource` (em `add-client-core`), não pelo `NetHttp` — mantendo o transport auth-agnostic. Esta change só garante que o transport respeita os headers que o `Request` trouxer. + +## 5. Hierarquia de erros + +- [ ] 5.1 Criar `lib/nfe/errors.rb` — `Nfe::Error < StandardError` com `attr_reader :status_code, :request_id, :error_code, :response_body, :response_headers`. Constructor com keyword args (`status_code:`, `request_id:`, `error_code:`, `response_body:`, `response_headers: {}`). +- [ ] 5.2 `Nfe::Error#to_h` — Hash para logging (`type`, `message`, `status_code`, `request_id`, `error_code`); NÃO incluir headers que possam conter segredos sem redação. +- [ ] 5.3 Definir subclasses concretas em `lib/nfe/errors.rb`: `AuthenticationError` (401), `AuthorizationError` (403), `InvalidRequestError` (400/422), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `ServerError` (5xx), `ApiConnectionError` (rede). +- [ ] 5.4 `Nfe::TimeoutError < Nfe::ApiConnectionError` — para `rescue ApiConnectionError` cobrir timeout, mas ainda discriminar. +- [ ] 5.5 `Nfe::RateLimitError` — `attr_reader :retry_after` (segundos, opcional) além dos attrs da base. +- [ ] 5.6 `Nfe::SignatureVerificationError < Nfe::Error` — definido aqui, consumido pela change de webhooks. + +## 6. ErrorFactory + +- [ ] 6.1 Criar `lib/nfe/error_factory.rb` — `Nfe::ErrorFactory.from_response(response)` retornando a subclasse de `Nfe::Error` apropriada por status. +- [ ] 6.2 Mapa de status (via `case`): 400/422→`InvalidRequestError`; 401→`AuthenticationError`; 403→`AuthorizationError`; 404→`NotFoundError`; 409→`ConflictError`; 429→`RateLimitError`; 500..599→`ServerError`; outros 4xx→`InvalidRequestError`; outros ≥500→`ServerError`. +- [ ] 6.3 `from_response`: extrair `message` do corpo JSON — chaves `message`/`error`/`detail`/`details`; se `errors` for String, usar; se Array, usar `errors[0]` (ou `errors[0]["message"]`). Fallback: `"API request failed with HTTP "`. +- [ ] 6.4 `from_response`: extrair `error_code` — chaves `code`/`errorCode`/`error_code` (String ou Integer → String). +- [ ] 6.5 `from_response`: extrair `request_id` — header `x-request-id` (fallback `x-correlation-id`). +- [ ] 6.6 `from_response`: para 429, popular `retry_after` a partir do header `retry-after` (segundos inteiros). +- [ ] 6.7 `from_response`: `response_body` (truncado p/ log) e `response_headers` (com redação aplicada em `to_h`) preservados nos attrs. +- [ ] 6.8 `Nfe::ErrorFactory.from_network_error(exception)` — mapear `Net::OpenTimeout`/`Net::ReadTimeout`/`Timeout::Error` → `TimeoutError`; demais (`SocketError`, `Errno::*`, `OpenSSL::SSL::SSLError`) → `ApiConnectionError`, preservando `cause`. +- [ ] 6.9 Decodificação JSON resiliente — `JSON.parse` em `rescue JSON::ParserError` devolve `nil` (corpo não-JSON não derruba a factory). +- [ ] 6.10 Cap + scrub da `message` extraída do corpo — limitar a um tamanho máximo e remover caracteres de controle (a `message` ecoa input do servidor; sem cap, corpo malicioso poderia inundar log ou injetar sequências de terminal). + +## 7. Logger duck-typed + redação + +- [ ] 7.1 Criar `lib/nfe/http/redactor.rb` — `Nfe::Http::Redactor.headers(hash)` substitui valores de chaves sensíveis (`x-nfe-apikey`, `authorization`, `idempotency-key`, qualquer chave casando `/secret|apikey|token/i`) por `"[REDACTED]"`. +- [ ] 7.2 Integrar logging no `RetryingTransport` (e/ou em um `LoggingTransport` opcional): se `logger` presente, logar `info` no início (método + URL + headers redigidos), `warn` em retry (tentativa + delay + status/erro), `error` na falha final (status + corpo truncado). +- [ ] 7.3 Envolver toda chamada de log em `rescue StandardError` — logging nunca derruba a request. +- [ ] 7.4 Documentar que `Configuration#logger` (definido em `add-client-core`) aceita qualquer objeto que responda a `info`/`warn`/`error` (incl. `::Logger` stdlib); zero dependência. +- [ ] 7.5 **Nunca logar corpos por padrão** — entradas default só com método, URL, status e `request_id`. Log de corpo atrás de opt-in explícito (`Configuration#log_request_body`, em `add-client-core`); quando ligado, truncar e passar pela redação. Garantir que CNPJ/CPF, API key e senha de certificado nunca aparecem em nenhuma linha de log. `Nfe::Error#response_body` continua disponível, mas não é auto-logado. + +## 8. Assinaturas RBS (sig/) + +- [ ] 8.1 `sig/nfe/http/request.rbs` — assinatura de `Nfe::Http::Request` (`Data` com os 9 campos) + `#url`, `#idempotent?`. +- [ ] 8.2 `sig/nfe/http/response.rbs` — `Nfe::Http::Response` + `#header`, `#success?`, `#location`. +- [ ] 8.3 `sig/nfe/http/transport.rbs` — `interface _Transport { def call: (Request) -> Response }` + módulo. +- [ ] 8.4 `sig/nfe/http/net_http.rbs`, `sig/nfe/http/retrying_transport.rbs`, `sig/nfe/http/retry_policy.rbs`, `sig/nfe/http/user_agent.rbs`, `sig/nfe/http/redactor.rbs`. +- [ ] 8.5 `sig/nfe/errors.rbs` — `Nfe::Error` + todas as subclasses, com attrs tipados. +- [ ] 8.6 `sig/nfe/error_factory.rbs` — `from_response`/`from_network_error`. +- [ ] 8.7 Rodar `steep check` — 0 erros nas assinaturas novas. + +## 9. Testes (RSpec, SimpleCov >= 80%) + +- [ ] 9.1 `spec/support/fake_transport.rb` — transport fake que responde a `call(request)`, com fila de `Response`s/erros enfileirados e registro das `Request`s recebidas (para asserts). +- [ ] 9.2 `spec/nfe/http/request_spec.rb` — `#url` (com/sem query, query repetida, path já com `?`), `#idempotent?` (GET/PUT/DELETE true, POST false, POST+idempotency_key true). +- [ ] 9.3 `spec/nfe/http/response_spec.rb` — `#header` case-insensitive, `#success?` (2xx vs 3xx/4xx), `#location`, body binário preservado. +- [ ] 9.4 `spec/nfe/http/retry_policy_spec.rb` — `delay_for` respeita cap `max_delay`, jitter dentro de `[base*(1-j), base*(1+j)]`, `.none` não dá delay. +- [ ] 9.5 `spec/nfe/http/retrying_transport_spec.rb` — 503→503→200 (sucesso transparente, sleep injetado), 400 não repete, retries esgotados devolvem último 503 (vira `ServerError` na camada de recurso), 429 com `Retry-After: 5` aguarda >= 5s, POST sem idempotency_key não repete, GET repete, erro de rede repete e propaga após esgotar. +- [ ] 9.6 `spec/nfe/http/net_http_spec.rb` — usando WEBrick/`Net::HTTP` contra servidor local stub (stdlib, sem dep): GET/POST básico, header lowercase, gzip descomprimido, 202 + Location preservados, timeout → `TimeoutError`, conexão recusada → `ApiConnectionError`, TLS verify on por default. +- [ ] 9.7 `spec/nfe/http/user_agent_spec.rb` — formato `NFE.io Ruby Client v ruby/ ()` + sufixo. +- [ ] 9.8 `spec/nfe/http/redactor_spec.rb` — `X-NFE-APIKEY`/`Authorization`/`Idempotency-Key`/chaves `*secret*`/`*token*` viram `[REDACTED]`; chaves benignas intactas. +- [ ] 9.9 `spec/nfe/errors_spec.rb` — attrs da base, `to_h` sem segredos, `TimeoutError` é `ApiConnectionError`, `RateLimitError#retry_after`. +- [ ] 9.10 `spec/nfe/error_factory_spec.rb` — cada status → classe correta (400, 401, 403, 404, 409, 422, 429, 500, 502, 599, 418 fallback); extração de `message`/`error_code`/`request_id`; corpo não-JSON não quebra; `from_network_error` mapeia timeout vs conexão. +- [ ] 9.11 Logging — spec verifica que com logger duck-typed presente há `error` em falha e `warn` em retry, com headers redigidos; sem logger não há chamada nem dependência. +- [ ] 9.12 Logging sem corpos — spec verifica que por padrão nenhuma linha de log contém corpo de request/response, CNPJ/CPF, API key ou senha de certificado (só método/URL/status/`request_id`); com `log_request_body` ligado, corpo é truncado e redigido. +- [ ] 9.13 Thread-safety — spec exerce o `NetHttp` (ou fake) a partir de múltiplos threads concorrentes contra a mesma origem e verifica que o pool guardado por `Mutex` não corrompe nem compartilha socket. +- [ ] 9.14 Per-call options — spec verifica que um `Request` com override de `base_url`/timeout/`api_key` (via `Nfe::RequestOptions`) é roteado/autenticado por chamada sem afetar a config global nem outras chamadas. +- [ ] 9.15 Hardening — spec verifica cap+scrub da `message` (corpo longo/com controle) e que `content-length` é descartado/recalculado após inflar gzip. + +## 10. Validação end-to-end + +- [x] 10.1 `bundle exec rspec` — toda a suite verde (128 exemplos / 0 falhas), cobertura de linha ~97.5% (docker 3.2/3.3/3.4). +- [x] 10.2 `bundle exec steep check` — 0 erros (docker 3.2/3.3/3.4). +- [x] 10.3 `bundle exec rubocop` — 0 offenses; `# frozen_string_literal: true` em todo `.rb` novo (docker 3.2/3.3/3.4). +- [x] 10.4 `openspec validate add-http-transport` — passa. +- [x] 10.5 Zero require de gem externa nos arquivos novos — só stdlib (`net/http`, `json`, `openssl`, `uri`, `zlib`, `stringio`). + +## 11. Documentação + +- [ ] 11.1 Docstrings (YARD-style) em `Transport` (como implementar), `NetHttp`, `RetryingTransport`, `RetryPolicy`, `ErrorFactory` e em cada classe de erro. +- [ ] 11.2 Nota no README (seção HTTP) — caminho default (`NetHttp` zero-dep) e como plugar um transport custom (qualquer objeto com `#call`) — **pode ser consolidado na change de release-tooling**. +- [ ] 11.3 Documentar `Configuration#ca_file` como escape hatch para CA store legado (a config em si vive em `add-client-core`). + +## 12. Smoke test manual (opt-in, fora do CI) + +- [ ] 12.1 GET real contra um host NFE.io retornando 200 + JSON (com chave sandbox) — **DEFERRED** (precisa chave). +- [ ] 12.2 Download real (PDF) retornando bytes começando com `%PDF` via `Response#body` binário — **DEFERRED**. +- [ ] 12.3 Forçar 429 (ou simular) e verificar honra de `Retry-After` — **DEFERRED**. +- [ ] 12.4 Registrar resultados em `.notes/http-transport-smoke.md` — **DEFERRED**. diff --git a/openspec/changes/archive/2026-06-25-add-invoice-resources/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-invoice-resources/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-invoice-resources/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-invoice-resources/README.md b/openspec/changes/archive/2026-06-25-add-invoice-resources/README.md new file mode 100644 index 0000000..f5bdbe0 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-invoice-resources/README.md @@ -0,0 +1,3 @@ +# add-invoice-resources + +Os cinco recursos de invoice do SDK Ruby v1 — service (NFS-e), product (NF-e), consumer (NFC-e, paridade-plus), transportation (CT-e inbound) e inbound-product (NF-e recebida) — sobre `Nfe::Client`. diff --git a/openspec/changes/archive/2026-06-25-add-invoice-resources/design.md b/openspec/changes/archive/2026-06-25-add-invoice-resources/design.md new file mode 100644 index 0000000..c530124 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-invoice-resources/design.md @@ -0,0 +1,206 @@ +# Design — add-invoice-resources + +## Context + +`add-client-core` montou o terreno: `Nfe::Client` com acessores lazy snake_case, transporte `Net::HTTP` (stdlib, zero dependências de runtime), `Nfe::Configuration` com o host map por família, hierarquia de erros tipados, e o contrato de resposta discriminada 202 (`Pending`/`Issued`). Esta change é o **primeiro consumidor real** desses blocos — os cinco recursos de invoice, que têm três perfis distintos: + +- **Emissão (síncrona/assíncrona)** — `service_invoices`, `product_invoices`, `consumer_invoices`: consomem o contrato 202, têm downloads, cancelamento, eventos, cartas de correção e inutilização. +- **Inbound settings + consulta** — `transportation_invoices` (CT-e), `inbound_product_invoices` (NF-e de fornecedores): não emitem — gerenciam auto-fetch via Distribuição DFe e consultam por `access_key` de 44 dígitos. + +Recon (Node SDK + PHP SDK + nfeio-docs) revelou três fatos que moldam o design: + +- O SDK Node expõe **16 recursos**; o PHP adiciona um 17º, `consumer_invoices` (emissão NFC-e), porque a API NFE.io oferece esse lifecycle completo em `nf-consumidor-v2.yaml`. Replicamos a decisão PHP: `consumer_invoices` entra como **paridade-plus**. +- `product_invoices.download_*` retorna uma **URI** (`NfeFileResource`), não bytes — divergência de contrato vs os demais downloads (que retornam bytes). +- A emissão RTC (IBS/CBS/IS) é um modelo NOVO de payload e fica na change separada `add-rtc-invoice-emission`; aqui implementamos só a emissão clássica. + +## Goals / Non-Goals + +**Goals** +- 5 recursos: 4 com paridade 1:1 de método-por-método com o Node SDK + 1 paridade-plus (NFC-e). +- Retorno discriminado `Pending | Issued` concreto para `create()` quando há contrato 202 (service, product, consumer). +- Downloads de bytes retornam `String` em `ASCII-8BIT` (binary-safe); downloads de `product_invoices` retornam `NfeFileResource` (URI), conforme a API. +- Validação de IDs e `access_key` antes do HTTP (fail-fast, mensagem clara em pt-BR). +- `ListResponse`/`ListPage` genéricos que cobrem os dois shapes de paginação (page-style e cursor-style). +- `FlowStatus.terminal?` para habilitar polling manual. +- Cobertura RSpec com WebMock para happy path + 202 + 201 + 400/404 + cancel + paginação + routing por host. + +**Non-Goals** +- `create_and_wait` / helper de polling — confirmado fora de escopo em `add-client-core`; caller escreve loop manual com `FlowStatus.terminal?`. +- `create_batch` — açúcar concorrente sem ganho no modelo síncrono do SDK Ruby. +- Streaming de downloads — retornamos a `String` completa; arquivos muito grandes ficam para release futura. +- Validação de dígito verificador de CNPJ/CPF na emissão — a API valida no servidor; replicar local seria custoso e duplicado (fica para os recursos de entidade, fora desta change). +- Emissão RTC (IBS/CBS/IS) — coberta por `add-rtc-invoice-emission`. + +## Decisions + +### D1. Pares de value objects concretos por família de invoice +**Decisão**: criar pares `Data.define` em `Nfe::Resources::`: + +``` +ServiceInvoicePending(:invoice_id, :location) # pending? => true +ServiceInvoiceIssued(:resource) # issued? => true +ProductInvoicePending / ProductInvoiceIssued +ConsumerInvoicePending / ConsumerInvoiceIssued +``` + +**Por quê**: +- Mantém `result.is_a?(ServiceInvoicePending)` e `case result; in ServiceInvoicePending` (pattern matching de `Data`) semanticamente precisos por família. +- `Data.define` dá value objects imutáveis e comparáveis por valor de graça (alinhado com a decisão canônica de modelos imutáveis). +- Se a API um dia adicionar um terceiro estado, adiciona-se um novo `Data` sem mexer nos existentes. + +**Alternativa rejeitada**: um único par genérico `InvoicePending`/`InvoiceIssued`. Funciona, mas o pattern matching fica ambíguo entre tipos de invoice e a inferência RBS fica frouxa. + +### D2. Discriminação por status HTTP + header `Location` +**Decisão**: `create()` decide o tipo de retorno pelo status: 202 → `*Pending` (extrai `invoice_id` do header `Location` via regex), 201 → `*Issued` (hidrata o body). Se 202 vier sem `Location` ou o ID não for extraível, levantar `Nfe::InvoiceProcessingError`. + +Regex de extração (paridade Node): service usa `%r{serviceinvoices/([a-z0-9-]+)}i`; product/consumer usam o segmento correspondente. Se o `Location` for URL absoluta, extrair o `path` antes (via `URI`). + +**Por quê**: é o contrato cravado em `add-client-core` e no SDK Node. O header `Location` é a única fonte do `invoice_id` no caso async. + +### D3. Cada recurso desempacota seu próprio envelope +**Decisão**: o desempacotamento do envelope (`{ "serviceInvoice" => {...} }`, `{ "serviceInvoices" => [...] }`) acontece no recurso, via helper `Base#unwrap(payload, *keys)` que retorna a primeira chave presente ou o `payload` cru. A `Base` não conhece os wrappers específicos. + +**Por quê**: cada endpoint conhece seu envelope; centralizar na base viraria uma cascata de condicionais. O helper só fornece o mecanismo, não o conhecimento. + +### D4. Downloads de bytes retornam `String` em ASCII-8BIT +**Decisão**: `download_pdf`, `download_xml`, `download_rejection_xml`, `download_event_xml`, `get_xml`, `get_event_xml`, `get_pdf` (service/consumer/transportation/inbound) retornam `String` com `force_encoding(Encoding::ASCII_8BIT)`. Helper `Base#download(path, accept:)` faz GET, valida 200 e devolve `response.body` cru, sem tentar `JSON.parse`. + +**Por quê**: +- Ruby `String` é binary-safe; `ASCII-8BIT` evita corrupção de bytes de PDF/ZIP por re-encoding UTF-8. +- O caller decide se persiste (`File.binwrite("x.pdf", bytes)`) ou faz stream para uma resposta HTTP. +- Adapta o `Buffer` do Node (a decisão canônica manda `Buffer → String` binária). + +### D5. `product_invoices.download_*` retorna `NfeFileResource` (URI), não bytes +**Decisão**: ao contrário de D4, os downloads de `product_invoices` (pdf/xml/rejection/epec/correction-letter) retornam um `Nfe::NfeFileResource` que carrega a URI do arquivo. Isso é comportamento da API NF-e (a API devolve um recurso com link, não os bytes). + +**Por quê**: paridade com o Node (`NfeFileResource`) e com a API real. Documentar explicitamente para o caller não confundir com os downloads dos outros recursos. O caller faz o GET na URI por conta própria (ou via um helper futuro). + +**Alternativa rejeitada**: normalizar tudo para bytes baixando a URI internamente. Rejeitada — esconderia a semântica real da API e adicionaria um round-trip implícito não solicitado. + +### D6. Validators fail-fast consumindo `Nfe::IdValidator` (de add-client-core) +**Decisão**: consumir o módulo `Nfe::IdValidator` já definido em `add-client-core` (NÃO redefinir, NÃO criar `Nfe::Util::IdValidator`): + +```ruby +Nfe::IdValidator.company_id(value) # raise InvalidRequestError se vazio/branco +Nfe::IdValidator.invoice_id(value) +Nfe::IdValidator.state_tax_id(value) +Nfe::IdValidator.event_key(value) +Nfe::IdValidator.access_key(value) # normaliza p/ dígitos, valida /\A\d{44}\z/, retorna a String +``` + +`access_key` aceita formato com espaços/pontos/traços, remove não-dígitos e valida 44 dígitos (paridade com o `/^\d{44}$/` do Node). Cada método levanta `Nfe::InvalidRequestError` (de `add-client-core`) com mensagem em pt-BR identificando o argumento. + +**Por quê**: fail-fast antes do HTTP, paridade com `validateCompanyId`/`validateAccessKey` do Node, e mensagens na língua da audiência. Reutilizar o validador canônico de `add-client-core` evita duplicar a abstração em namespace incompatível. + +### D7. `consumer_invoices` é paridade-plus (NFC-e), com 3 ausências por lei fiscal +**Decisão**: `consumer_invoices` é implementado e exposto em `client.consumer_invoices`, mesmo o Node não o tendo. Fundamentação: `nf-consumidor-v2.yaml` cobre o lifecycle completo de NFC-e. Documentar como paridade-plus no cabeçalho da classe. + +O recurso **NÃO** replica 3 métodos do `product_invoices`: + +| Método ausente em NFC-e | Justificativa fiscal | +|---|---| +| `send_correction_letter` (CC-e) | Carta de correção é instrumento fiscal só do NF-e. | +| `download_epec_xml` | EPEC (Evento Prévio de Emissão em Contingência) só existe para NF-e. | +| `disable` por invoice | NFC-e suporta apenas inutilização coletiva via `disable_range`. | + +Essas ausências são propriedades da legislação fiscal brasileira, não limitações do SDK. Testar que esses métodos levantam `NoMethodError`. + +**Por quê**: paridade com o Node é o **piso**, não o teto. Quando a API oferece um recurso real e há demanda concreta (PoS, e-commerce que emite NFC-e), expor faz sentido. Paridade-plus documentada evita que mantenedores futuros confundam com phantom. Espelha a decisão D7 do PHP SDK. + +### D8. `ListResponse`/`ListPage` (de add-client-core) cobrem os dois shapes de paginação +**Decisão**: consumir os tipos já definidos em `add-client-core` (NÃO redefinir sob `Nfe::Util::`): + +```ruby +Nfe::ListPage = Data.define(:page_index, :page_count, :starting_after, :ending_before, :total) +Nfe::ListResponse = Data.define(:data, :page) # inclui Enumerable, each => data.each +``` + +O recurso preenche a metade relevante: service usa page-style (`page_index`/`page_count`); product/consumer usam cursor-style (`starting_after`/`ending_before`). O caller usa `result.data` igual nos dois casos e pode iterar direto (`result.each`). + +**Por quê**: um tipo só, amigável ao caller, reutilizado de `add-client-core`. `ListResponse` incluir `Enumerable` é idioma Ruby (vs forçar `result.data.each`). + +**Alternativa rejeitada**: dois tipos (`PageListResponse` + `CursorListResponse`). Mais "correto" mas força o caller a discriminar. + +### D9. `FlowStatus.terminal?` + polling manual; `create_and_wait`/`create_batch` diferidos +**Decisão**: NÃO implementar `create_and_wait` nem `create_batch`. Consumir `Nfe::FlowStatus.terminal?(status)` (de `add-client-core`; true para `Issued`, `Cancelled`, `IssueFailed`, `CancelFailed`) e documentar o loop manual no README: + +```ruby +result = client.service_invoices.create(company_id:, data:) +if result.pending? + loop do + sleep 2 + invoice = client.service_invoices.retrieve(company_id:, invoice_id: result.invoice_id) + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + end +end +``` + +**Por quê**: consistência com `add-client-core`. Quando um helper de polling chegar (release futura), `terminal?` já está pronto. O PHP SDK também diferiu ambos. + +### D10. `get_status` é derivado de `retrieve` (sem HTTP extra) +**Decisão**: `service_invoices.get_status` NÃO faz chamada HTTP própria — chama `retrieve` e computa o resultado (`status`, `invoice`, `complete?`, `failed?`) a partir do `flow_status`, via `FlowStatus.terminal?` e checagem de `IssueFailed`/`CancelFailed`. + +**Por quê**: paridade com o Node (que deriva de `retrieve()`). NOTA de divergência: a tabela do spec PHP promete um endpoint real `GET /status`; seguimos o Node (derivado) por ser o comportamento de produção observado. + +### D11. Manifestação inbound usa códigos numéricos `tpEvent` +**Decisão**: `inbound_product_invoices.manifest(tp_event: 210210)` aceita códigos numéricos: `210210` Ciência (default), `210220` Confirmação, `210240` Operação não Realizada. Expor constantes simbólicas no módulo (`MANIFEST_AWARENESS`, `MANIFEST_CONFIRMATION`, `MANIFEST_NOT_PERFORMED`). + +**Por quê**: paridade com o Node (`ManifestEventType` numérico). NOTA de divergência: o spec PHP usa labels string (Confirmation/Acknowledgement/Unknown/Refused); seguimos o Node numérico, que casa com o `tpEvent` real da SEFAZ. + +### D12. Onde colocam-se modelos hand-written quando o gerador for incompleto +**Decisão**: `lib/nfe/resources/dto/<...>.rb` (ex.: `lib/nfe/resources/dto/nfe_file_resource.rb`, `lib/nfe/resources/dto/service_invoice.rb`), separados de `lib/nfe/generated/`. + +**Por quê**: +- NÃO vai em `lib/nfe/generated/` (o guard de sync do gerador reclamaria; a decisão canônica proíbe hand-edit de gerados). +- `nf-servico-v1.yaml` tem 0 schemas de componente — o modelo de service-invoice é necessariamente derivado/hand-written. +- Fica visível como complemento hand-written, com RBS próprio em `sig/nfe/resources/dto/`. + +### D13. Idempotência e opções por chamada nos métodos de emissão (decisão de mantenedor) +**Decisão**: os métodos de emissão — `create` e `create_with_state_tax` de `service_invoices`, `product_invoices` e `consumer_invoices` — aceitam dois kwargs opcionais: + +```ruby +client.service_invoices.create(company_id:, data:, idempotency_key: nil, request_options: nil) +``` + +- `idempotency_key:` — quando fornecido, é enviado como header HTTP `Idempotency-Key`. O caller supre uma chave **estável** atrelada ao id de negócio (ex.: número do pedido). Documenta-se o padrão de retry seguro: após um timeout, o caller **repete a chamada com a MESMA chave**, evitando emitir um documento fiscal duplicado. O POST continua **não** sendo auto-retentado pelo transporte (a default de segurança de `add-http-transport` permanece). +- `request_options:` — aceita um `Nfe::RequestOptions` (de `add-client-core`, `Data.define(:api_key, :base_url, :timeout)`); a `AbstractResource` encaminha ao request e o transporte honra os overrides por chamada (habilita api_key multi-tenant por chamada sem instanciar um segundo `Client`). + +**Por quê**: emissão fiscal é a operação mais perigosa de duplicar — um documento emitido duas vezes vira passivo tributário. A chave de idempotência fornecida pelo caller é a única forma segura de tornar o retry de POST idempotente sem auto-retry cego. As opções por chamada destravam multi-tenancy sem o custo de um `Client` por tenant. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| Envelopes de resposta variam por endpoint sem padrão único (`{serviceInvoice:...}` vs `{serviceInvoices:[...]}` vs plano) | `Base#unwrap` por recurso; documentar o wrapper descoberto no comentário de cada método. | +| Modelos gerados podem não cobrir o shape de resposta (gerador cobre só `components.schemas`; `nf-servico-v1.yaml` tem 0) | Fallback para `Data.define` hand-written em `lib/nfe/resources/dto/`; documentar quais foram criados (tasks §9.2). | +| Regex de `access_key` (44 dígitos) é frouxa e aceita sequências inválidas | Aceitável — validação local é fail-fast para typo, não substitui validação server-side. | +| Paginação cursor-style (product/consumer) vs page-style (service) confunde o caller | Documentar em cada `list` qual shape de `ListPage` é preenchido; `ListResponse` aceita ambos e expõe `data` uniformemente. | +| `consumer_invoices` é paridade-plus sem referência cruzada no Node | Smoke test em sandbox antes do GA (tasks §13.5); fundamentação em `nf-consumidor-v2.yaml`. | +| `product_invoices.download_*` retorna URI, não bytes — viola a expectativa "downloads = bytes" | Modelo dedicado `NfeFileResource` + nota explícita no spec e no README; testar que o retorno é URI, não String binária. | +| Cancelamento pode ser async (202) em algum endpoint | service/consumer: tratado como síncrono (retorna modelo atualizado), conforme observado no Node; se a API mudar para 202, expandir via release menor aditiva. | + +## Resolved (durante recon — 2026-06-24) + +### R1. Modelo principal de service-invoice é hand-written +**Achado**: `nf-servico-v1.yaml` tem **0 schemas de componente** — o `ServiceInvoiceData` do Node é tratado como objeto aberto (`Record`). Não há DTO de resposta gerável. +**Decisão**: criar `lib/nfe/resources/dto/service_invoice.rb` (`Data.define`) com os campos que o SDK realmente acessa em produção (`id`, `flow_status`, `flow_message`, `status`, `environment`, `rps_number`, `rps_serial_number`, …). Tarefa em §9.2. + +### R2. Cancelamento de service é síncrono +**Achado**: `service-invoices.ts` faz `await this.http.delete(...)` e retorna `response.data` sem tratamento de 202 — confirmado HTTP 200 + modelo. +**Decisão**: `cancel` retorna o modelo de invoice atualizado (síncrono). Para `product_invoices`, `cancel` é async (204 enfileirado → recurso de cancelamento). + +### R3. Estados terminais cravados +**Achado**: `client-nodejs/src/core/types.ts` define exatamente `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed` como terminais; não-terminais: `PullFromCityHall`, `WaitingCalculateTaxes`, `WaitingDefineRpsNumber`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, `WaitingDownload`. +**Decisão**: `FlowStatus::TERMINAL` e `NON_TERMINAL` espelham essas listas; `terminal?` retorna true para exatamente os 4 valores. + +### R4. `product_invoices.list` exige `environment` +**Achado**: a `list` de product usa cursor (`starting_after`/`ending_before`/`limit`/`q`) e exige `environment` (`Production`/`Test`) — o Node levanta erro de validação se ausente. +**Decisão**: `environment:` é keyword obrigatória em `product_invoices.list`; ausência → `InvalidRequestError` antes do HTTP. + +### R5. Carta de correção valida tamanho client-side +**Achado**: `sendCorrectionLetter` valida `15 <= len <= 1000` (sem acentos) antes do HTTP. +**Decisão**: `send_correction_letter` valida o tamanho do `reason` client-side e levanta `InvalidRequestError` fora do range, antes do HTTP. Apenas em `product_invoices` (não existe em `consumer_invoices`). + +### R6. RTC fora de escopo +**Achado**: as specs RTC (`service-invoice-rtc-v1.yaml`, `product-invoice-rtc-v1.yaml`) são source-of-truth mas representam um modelo NOVO de emissão (grupos IBS/CBS/IS), com seleção por shape de payload. +**Decisão**: a emissão RTC fica em `add-rtc-invoice-emission`. Esta change implementa a emissão clássica e cruza-referência com aquela change; os padrões de 202/polling/host routing definidos aqui são reutilizados lá. diff --git a/openspec/changes/archive/2026-06-25-add-invoice-resources/proposal.md b/openspec/changes/archive/2026-06-25-add-invoice-resources/proposal.md new file mode 100644 index 0000000..e64cef6 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-invoice-resources/proposal.md @@ -0,0 +1,79 @@ +# add-invoice-resources + +## Why + +`add-client-core` entregou o `Nfe::Client`, o transporte `Net::HTTP`, o roteamento multi-base-URL via `Nfe::Configuration`, a hierarquia de erros tipados, o contrato de resposta discriminada 202 (`Pending`/`Issued`) e os acessores lazy snake_case dos 17 recursos. Esta change preenche os **cinco recursos de invoice** — o coração da plataforma NFE.io — com implementações reais. + +Quatro deles (service, product, transportation, inbound-product) são paritários 1:1 com o SDK Node.js em assinatura de método, ordem de parâmetros e categoria de retorno (modulo idiomas de linguagem: `Buffer` → `String` binário, `Promise`/async → retorno síncrono, `camelCase` → `snake_case`). O quinto (`consumer_invoices`, emissão NFC-e) é uma extensão **paridade-plus**: o SDK Node não expõe emissão de NFC-e, mas a API NFE.io a oferece nativamente desde a v2 via `nf-consumidor-v2.yaml`. + +Esses recursos são o **primeiro consumidor real** dos blocos montados em `add-client-core`: exercitam o contrato 202 (`service_invoices.create` e `consumer_invoices.create`), validam o roteamento multi-host (CT-e/NF-e moram em `api.nfse.io`, NFS-e em `api.nfe.io`), e fecham a pipeline `OpenAPI → modelos gerados → recurso → client → transporte`. + +> **Nota de escopo (RTC)**: a NOVA variante de emissão de NFS-e da Reforma Tributária (RTC, grupos IBS/CBS/IS) é tratada na change SEPARADA `add-rtc-invoice-emission`. Aqui implementamos a emissão **clássica** de service-invoice; o spec de RTC referencia esta change como base de padrões. + +## What Changes + +### Recursos implementados (5) + +| Recurso (acessor) | Padrão | Host (família) | Operações principais | +|---|---|---|---| +| `client.service_invoices` | Emissão NFS-e (CRUD + downloads + status) | `api.nfe.io` (main) | `create` (202 discriminado), `list` (page-style), `retrieve`, `cancel`, `send_email`, `download_pdf`, `download_xml`, `get_status` | +| `client.product_invoices` | Emissão NF-e (CRUD + eventos + cartas de correção + inutilização) | `api.nfse.io` (cte) | `create`, `create_with_state_tax`, `list` (cursor), `retrieve`, `cancel`, `list_items`, `list_events`, `download_pdf/xml/rejection_xml/epec_xml`, `send_correction_letter`, `download_correction_letter_pdf/xml`, `disable`, `disable_range` | +| `client.consumer_invoices` ⭐ | Emissão NFC-e (paridade-plus, além do Node) | `api.nfse.io` (cte) | `create`, `create_with_state_tax`, `list` (cursor), `retrieve`, `cancel`, `list_items`, `list_events`, `download_pdf/xml/rejection_xml`, `disable_range` | +| `client.transportation_invoices` | Inbound CT-e (settings + consulta) | `api.nfse.io` (cte) | `enable`, `disable`, `get_settings`, `retrieve` (por accessKey), `download_xml`, `get_event`, `download_event_xml` | +| `client.inbound_product_invoices` | Inbound NF-e de fornecedores (settings + consulta + manifestação) | `api.nfse.io` (cte) | `enable_auto_fetch`, `disable_auto_fetch`, `get_settings`, `get_details`, `get_product_invoice_details`, `get_event_details`, `get_product_invoice_event_details`, `get_xml`, `get_event_xml`, `get_pdf`, `get_json`, `manifest`, `reprocess_webhook` | + +> Host (família) `main` = `base_url_for(:main)` → `https://api.nfe.io`; o segmento `/v1` é fornecido pelo `api_version` do recurso (URL efetiva `https://api.nfe.io/v1/...`). + +### Adicionado (suporte) + +- `Nfe::Resources::ServiceInvoicePending` / `ServiceInvoiceIssued` — value objects `Data.define` para o contrato 202 de NFS-e (especialização concreta do contrato `Nfe::Pending`/`Nfe::Issued` de `add-client-core`). +- `Nfe::Resources::ProductInvoicePending` / `ProductInvoiceIssued`. +- `Nfe::Resources::ConsumerInvoicePending` / `ConsumerInvoiceIssued`. +- `Nfe::NfeFileResource` — value object `Data.define` que carrega a URI de download retornada por `product_invoices.download_*` (não bytes). +- DTOs de invoice hand-written sob `lib/nfe/resources/dto/` (ex.: `service_invoice.rb`, `consumer_invoice.rb`) onde o gerador OpenAPI não cobre o shape de resposta. + +- Idempotência + opções por chamada na emissão: `create`/`create_with_state_tax` de service/product/consumer aceitam `idempotency_key:` (enviado como header `Idempotency-Key`; retry seguro reutiliza a MESMA chave para não duplicar documento fiscal) e `request_options:` (`Nfe::RequestOptions` de `add-client-core`, override de api_key/base_url/timeout por chamada). Vide design D13. + +> Esta change **consome** (não redefine) as abstrações compartilhadas de `add-client-core`: `Nfe::IdValidator` (validação fail-fast de `company_id`/`invoice_id`/`access_key`/`state_tax_id`/`event_key`, levantando `Nfe::InvalidRequestError` em pt-BR), `Nfe::ListResponse`/`Nfe::ListPage` (os dois shapes de paginação), `Nfe::FlowStatus.terminal?`, e o helper de download binário de `Nfe::Resources::AbstractResource#download` (retorna `String` em `ASCII-8BIT`). + +### Diferenças de superfície NFC-e × NF-e (paridade-plus) + +`consumer_invoices` **NÃO** replica três métodos de `product_invoices`, por imposição da legislação fiscal brasileira (não por limitação do SDK): + +- `send_correction_letter` (CC-e) — carta de correção é instrumento fiscal apenas do NF-e. +- `download_epec_xml` — EPEC (Evento Prévio de Emissão em Contingência) só existe para NF-e. +- `disable` por invoice — NFC-e suporta apenas inutilização coletiva via `disable_range`. + +### Divergência de retorno de download (product_invoices) + +`product_invoices.download_pdf/xml/rejection_xml/epec_xml` retornam um **`NfeFileResource` (uma URI)**, não bytes crus — diferente de `service_invoices`, `consumer_invoices` e dos recursos inbound, que retornam bytes. Isso é comportamento da API e está documentado no spec. + +### Fora de escopo (diferido) + +- `create_and_wait` — helper de polling síncrono. Diferido (alinhado com `add-client-core`); o caller escreve loop manual com `FlowStatus.terminal?`. +- `create_batch` — açúcar concorrente; sem ganho real no modelo síncrono do SDK; diferido para release futura. +- Emissão RTC (IBS/CBS/IS) — coberta por `add-rtc-invoice-emission`. + +## Capabilities + +### New Capabilities +- `invoice-resources`: 5 recursos de invoice + classes de resposta discriminada por família (`*Pending`/`*Issued`) + `Nfe::NfeFileResource` + DTOs hand-written de invoice. Consome (não redefine) `Nfe::IdValidator`, `Nfe::ListResponse`/`Nfe::ListPage`, `Nfe::FlowStatus.terminal?` e os helpers de `Nfe::Resources::AbstractResource`, todos de `add-client-core`. + +### Modified Capabilities +- Nenhuma. Esta change apenas **consome** os contratos definidos em `add-client-core` (host map, contrato 202, acessores lazy, erros tipados); não os modifica. + +## Impact + +- **Affected code**: + - `lib/nfe/resources/service_invoices.rb`, `product_invoices.rb`, `consumer_invoices.rb`, `transportation_invoices.rb`, `inbound_product_invoices.rb` (substituem os stubs de `add-client-core`; herdam de `Nfe::Resources::AbstractResource`). + - `lib/nfe/resources/service_invoice_pending.rb`, `service_invoice_issued.rb`, e equivalentes product/consumer. + - `lib/nfe/resources/dto/nfe_file_resource.rb` + DTOs hand-written de invoice (`service_invoice.rb`, `consumer_invoice.rb`, …). + - `sig/nfe/resources/*.rbs` + `sig/nfe/resources/dto/*.rbs` (assinaturas RBS para Steep). + - `spec/nfe/resources/*_spec.rb` + `spec/nfe/models/*_spec.rb` (RSpec com WebMock). +- **Spec impact**: adiciona o capability `invoice-resources`. Não modifica nenhum capability existente. +- **Dependencies**: depende de `add-client-core` (transporte, `Configuration` com host map, erros, contrato `Pending`/`Issued`, acessores lazy). Cruza com `add-rtc-invoice-emission` (variante RTC da emissão de service-invoice). +- **Risks**: + - Envelopes de resposta (`{ serviceInvoices: [...] }`, `{ serviceInvoice: {...} }`) variam por endpoint — cada recurso desempacota o seu. + - Paginação page-style × cursor-style — `ListPage` acomoda ambos; documentado por método. + - `consumer_invoices` é paridade-plus sem referência cruzada no Node — smoke test em sandbox é essencial antes do GA. + - `product_invoices.download_*` retorna URI, não bytes — divergência de contrato documentada para não confundir com os demais downloads. diff --git a/openspec/changes/archive/2026-06-25-add-invoice-resources/specs/invoice-resources/spec.md b/openspec/changes/archive/2026-06-25-add-invoice-resources/specs/invoice-resources/spec.md new file mode 100644 index 0000000..4410c67 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-invoice-resources/specs/invoice-resources/spec.md @@ -0,0 +1,352 @@ +# invoice-resources — Delta + +## ADDED Requirements + +### Requirement: Five invoice resource classes are fully implemented +The SDK SHALL implement exactly five invoice resource classes under `Nfe::Resources` — `ServiceInvoices`, `ProductInvoices`, `ConsumerInvoices`, `TransportationInvoices`, and `InboundProductInvoices` — covering NFS-e, NF-e, NFC-e, inbound CT-e, and inbound supplier NF-e respectively. They SHALL be reachable through the lazy snake_case accessors `client.service_invoices`, `client.product_invoices`, `client.consumer_invoices`, `client.transportation_invoices`, and `client.inbound_product_invoices` defined by `add-client-core`. + +Four of the five (service, product, transportation, inbound-product) match the Node.js SDK 1:1 in method names, parameter set, and return-shape category, modulo Ruby idioms: `Buffer` becomes a binary `String`, `Promise`/async becomes a synchronous return, and `camelCase` becomes `snake_case`. The fifth (`ConsumerInvoices`) is a **parity-plus** addition: the Node SDK does not expose NFC-e emission, but the NFE.io API supports it natively via `nf-consumidor-v2.yaml`. + +The classic service-invoice emission lives in this capability. The new RTC (Reforma Tributária, IBS/CBS/IS) service-invoice and product-invoice emission models are out of scope here and are specified by the `add-rtc-invoice-emission` change. + +#### Scenario: Accessing invoice resources from the client +- **WHEN** a consumer reads any of `client.service_invoices`, `client.product_invoices`, `client.consumer_invoices`, `client.transportation_invoices`, or `client.inbound_product_invoices` +- **THEN** the accessor SHALL return a fully functional resource instance (not a stub that raises `NotImplementedError`) +- **AND** repeated reads of the same accessor SHALL return the same memoized instance + +#### Scenario: Parity with the Node SDK for the four shared resources +- **WHEN** comparing method names, parameter set, and return-shape category between this SDK and the Node SDK for `ServiceInvoices`, `ProductInvoices`, `TransportationInvoices`, or `InboundProductInvoices` +- **THEN** they SHALL be 1:1 equivalent, modulo Ruby idioms (binary `String` for downloads, synchronous returns, snake_case names) + +#### Scenario: NFC-e emission beyond Node parity +- **WHEN** a consumer calls any method on `client.consumer_invoices` +- **THEN** the resource SHALL execute against `https://api.nfse.io/v2/companies/{company_id}/consumerinvoices/*` paths defined in `nf-consumidor-v2.yaml`, even though the equivalent method does not exist in the Node SDK + +### Requirement: Invoice resources route to the host of their API family +Each invoice resource SHALL resolve its base URL through `Nfe::Configuration#base_url_for(family)` (provided by `add-client-core`) and SHALL NOT hard-code any host. `ServiceInvoices` SHALL use the `:main` family (`base_url_for(:main)` → host `https://api.nfe.io`, with the `/v1` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfe.io/v1/...`). `ProductInvoices`, `ConsumerInvoices`, `TransportationInvoices`, and `InboundProductInvoices` SHALL use the `:cte` family (`https://api.nfse.io`). + +#### Scenario: Service invoice routes to api.nfe.io +- **WHEN** any method of `ServiceInvoices` issues an HTTP request +- **THEN** the request host SHALL be `https://api.nfe.io` with the `/v1` base path segment + +#### Scenario: Product, consumer, transportation, and inbound route to api.nfse.io +- **WHEN** any method of `ProductInvoices`, `ConsumerInvoices`, `TransportationInvoices`, or `InboundProductInvoices` issues an HTTP request +- **THEN** the request host SHALL be `https://api.nfse.io`, distinct from the `https://api.nfe.io` host used by `ServiceInvoices` + +### Requirement: Service invoice creation supports the discriminated 202 contract +`ServiceInvoices#create(company_id:, data:)` SHALL accept a company ID and a request payload and SHALL return either a `Nfe::Resources::ServiceInvoicePending` (when the API responds HTTP 202 with a `Location` header) or a `Nfe::Resources::ServiceInvoiceIssued` (when the API responds HTTP 201 with the materialized invoice body). + +#### Scenario: Async invoice creation +- **WHEN** the consumer calls `client.service_invoices.create(company_id:, data:)` and the API responds HTTP 202 with `Location: /v1/companies/{id}/serviceinvoices/{invoice_id}` +- **THEN** the method SHALL return a `ServiceInvoicePending` whose `invoice_id` matches the final path segment (extracted via `%r{serviceinvoices/([a-z0-9-]+)}i`) and whose `location` matches the header value +- **AND** `pending?` SHALL be `true` and `issued?` SHALL be `false` + +#### Scenario: Immediate invoice creation +- **WHEN** the API responds HTTP 201 with the invoice body +- **THEN** the method SHALL return a `ServiceInvoiceIssued` whose `resource` is the typed invoice model hydrated from the response body +- **AND** `issued?` SHALL be `true` and `pending?` SHALL be `false` + +#### Scenario: Async response missing the Location header +- **WHEN** the API responds HTTP 202 but no `Location` header is present, or the invoice ID cannot be extracted from it +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` + +### Requirement: Emission methods accept an idempotency key and per-call request options +The emission methods — `create` and `create_with_state_tax` on `ServiceInvoices`, `ProductInvoices`, and `ConsumerInvoices` — SHALL accept two optional keyword arguments: `idempotency_key:` (default `nil`) and `request_options:` (default `nil`). + +When `idempotency_key:` is supplied, the SDK SHALL send it as the HTTP `Idempotency-Key` request header. The caller supplies a stable key tied to a business identifier. The SDK SHALL NOT auto-retry the POST; the documented safe-retry pattern is for the caller to re-invoke the same emission method with the SAME `idempotency_key:` after a timeout, so the server deduplicates and no duplicate fiscal document is issued. + +When `request_options:` is supplied, it SHALL be a `Nfe::RequestOptions` value object (provided by `add-client-core`) and `Nfe::Resources::AbstractResource` SHALL thread its `api_key`/`base_url`/`timeout` overrides into the request for that single call, without requiring a second `Client`. This capability SHALL NOT redefine `Nfe::RequestOptions`; it consumes it. + +#### Scenario: Idempotency key sent as a header +- **WHEN** `create(company_id:, data:, idempotency_key: 'order-42')` is called +- **THEN** the issued HTTP POST SHALL carry the header `Idempotency-Key: order-42` + +#### Scenario: Safe retry reuses the same key +- **WHEN** an emission call times out and the caller re-invokes the same method with the SAME `idempotency_key:` +- **THEN** the SDK SHALL send the identical `Idempotency-Key` header and SHALL NOT auto-retry the POST on its own, so the server can deduplicate and avoid issuing a duplicate fiscal document + +#### Scenario: Per-call request options override the client defaults +- **WHEN** `create(company_id:, data:, request_options: Nfe::RequestOptions.new(api_key: 'tenant-key', base_url: nil, timeout: nil))` is called +- **THEN** that single request SHALL authenticate with `tenant-key` instead of the `Client`'s default api_key, leaving the shared `Client` unchanged + +#### Scenario: Emission without the optional kwargs is unchanged +- **WHEN** `create(company_id:, data:)` is called without `idempotency_key:` or `request_options:` +- **THEN** the SDK SHALL issue the request with no `Idempotency-Key` header and using the `Client`'s default configuration + +### Requirement: Service invoice CRUD, email, downloads, and status +`ServiceInvoices` SHALL expose `create`, `list`, `retrieve`, `cancel`, `send_email`, `download_pdf`, `download_xml`, and `get_status`. Every method that takes a company ID or invoice ID SHALL validate it through `Nfe::IdValidator` (provided by `add-client-core`) before issuing the HTTP request. + +| Method | HTTP | Path | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | POST | `/companies/{company_id}/serviceinvoices` | +| `list(company_id:, **options)` | GET | `/companies/{company_id}/serviceinvoices` | +| `retrieve(company_id:, invoice_id:)` | GET | `/companies/{company_id}/serviceinvoices/{invoice_id}` | +| `cancel(company_id:, invoice_id:)` | DELETE | `/companies/{company_id}/serviceinvoices/{invoice_id}` | +| `send_email(company_id:, invoice_id:)` | PUT | `/companies/{company_id}/serviceinvoices/{invoice_id}/sendemail` | +| `download_pdf(company_id:, invoice_id: nil)` | GET | `.../{invoice_id}/pdf` or `.../serviceinvoices/pdf` (bulk) | +| `download_xml(company_id:, invoice_id: nil)` | GET | `.../{invoice_id}/xml` or `.../serviceinvoices/xml` (bulk) | +| `get_status(company_id:, invoice_id:)` | (derived) | derived from `retrieve` — no extra HTTP call | + +#### Scenario: Page-style listing +- **WHEN** `list(company_id:, page_index: 0, page_count: 20, issued_begin: '2026-01-01', issued_end: '2026-01-31')` is called +- **THEN** the SDK SHALL return a `Nfe::ListResponse` whose `page` carries `page_index`/`page_count` (cursor fields `nil`) and whose `data` is the unwrapped `serviceInvoices` array + +#### Scenario: Retrieve returns a typed model +- **WHEN** `retrieve(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a typed invoice model (a generated model, or a hand-written `Nfe::ServiceInvoice` value object where the generated tree does not cover the shape) hydrated from the response body + +#### Scenario: Retrieve not found +- **WHEN** `retrieve(company_id:, invoice_id:)` receives HTTP 404, or the response body is empty +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +#### Scenario: Cancel is synchronous +- **WHEN** `cancel(company_id:, invoice_id:)` succeeds +- **THEN** the SDK SHALL return the updated invoice model from the response body + +#### Scenario: Send email +- **WHEN** `send_email(company_id:, invoice_id:)` succeeds +- **THEN** the SDK SHALL issue a `PUT` to `.../sendemail` and return the send result carrying a `sent` flag + +#### Scenario: Bulk download with no invoice ID +- **WHEN** `download_pdf(company_id:)` is called with `invoice_id` omitted +- **THEN** the SDK SHALL request `.../serviceinvoices/pdf` and return the ZIP bytes as a binary `String` + +#### Scenario: Status derived without an HTTP call +- **WHEN** `get_status(company_id:, invoice_id:)` is called +- **THEN** the SDK SHALL call `retrieve` exactly once and SHALL return a value carrying `status`, `invoice`, `complete?` (via `FlowStatus.terminal?`), and `failed?` (true for `IssueFailed`/`CancelFailed`), making no separate status HTTP request + +### Requirement: Product invoice resource mirrors Node SDK breadth +`ProductInvoices` SHALL expose `create`, `create_with_state_tax`, `list`, `retrieve`, `cancel`, `list_items`, `list_events`, `download_pdf`, `download_xml`, `download_rejection_xml`, `download_epec_xml`, `send_correction_letter`, `download_correction_letter_pdf`, `download_correction_letter_xml`, `disable`, and `disable_range`, all under `/v2/companies/{company_id}/productinvoices*` on `https://api.nfse.io`. + +Pagination on `list`, `list_items`, and `list_events` uses cursor semantics (`starting_after`, `ending_before`, `limit`). The `environment` query parameter on `list` is required. + +Both `create` and `create_with_state_tax` SHALL accept the optional `idempotency_key:` and `request_options:` keyword arguments described in the dedicated emission-options requirement. + +#### Scenario: Discriminated creation +- **WHEN** `create(company_id:, data:)` is called and the API enqueues the invoice (HTTP 202) +- **THEN** the method SHALL return a `Nfe::Resources::ProductInvoicePending`; on HTTP 201 it SHALL return a `Nfe::Resources::ProductInvoiceIssued` + +#### Scenario: Creation scoped to a state tax registration +- **WHEN** `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` is called +- **THEN** the SDK SHALL route to `/v2/companies/{company_id}/statetaxes/{state_tax_id}/productinvoices` and SHALL validate `state_tax_id` via `IdValidator` before the request, forwarding `idempotency_key:` as the `Idempotency-Key` header when present + +#### Scenario: Cursor-style listing requires environment +- **WHEN** `list(company_id:, environment: 'Production', limit: 50)` is called +- **THEN** the SDK SHALL return a `ListResponse` whose `page` carries `starting_after`/`ending_before` cursors (not `page_index`) + +#### Scenario: Listing without environment is rejected +- **WHEN** `list(company_id:)` is called without an `environment` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without an HTTP request + +#### Scenario: Cancel forwards a reason +- **WHEN** `cancel(company_id:, invoice_id:, reason: 'Erro de digitação')` is called +- **THEN** the SDK SHALL issue `DELETE .../{invoice_id}?reason=...` and return the cancellation resource (the cancellation is asynchronous) + +#### Scenario: Product invoice downloads return a file URI, not bytes +- **WHEN** `download_pdf`, `download_xml`, `download_rejection_xml`, or `download_epec_xml` succeeds +- **THEN** the return value SHALL be a `Nfe::NfeFileResource` carrying a URI to the file — NOT raw bytes — distinguishing this resource from the byte-returning downloads on the other invoice resources + +#### Scenario: Correction letter length validation +- **WHEN** `send_correction_letter(company_id:, invoice_id:, reason:)` is called with a `reason` whose length is outside `15..1000` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without an HTTP request; with a valid length it SHALL `PUT .../correctionletter` with body `{ reason: }` + +#### Scenario: Per-invoice and range disablement +- **WHEN** `disable(company_id:, invoice_id:, reason:)` is called +- **THEN** the SDK SHALL `POST .../{invoice_id}/disablement?reason=...` +- **WHEN** `disable_range(company_id:, data:)` is called with `{ environment, serie, state, begin_number, last_number, reason? }` +- **THEN** the SDK SHALL `POST /v2/companies/{company_id}/productinvoices/disablement` + +### Requirement: Consumer invoice resource exposes the NFC-e emission lifecycle +`ConsumerInvoices` SHALL target `https://api.nfse.io` under v2 (`base_url_for(:cte)`) and SHALL expose the following methods backed by `nf-consumidor-v2.yaml`: + +| Method | HTTP | Path | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | POST | `/v2/companies/{company_id}/consumerinvoices` | +| `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` | POST | `.../statetaxes/{state_tax_id}/consumerinvoices` | +| `list(company_id:, **options)` | GET | `/v2/companies/{company_id}/consumerinvoices` | +| `retrieve(company_id:, invoice_id:)` | GET | `.../consumerinvoices/{invoice_id}` | +| `cancel(company_id:, invoice_id:)` | DELETE | `.../consumerinvoices/{invoice_id}` | +| `list_items(company_id:, invoice_id:)` | GET | `.../{invoice_id}/items` | +| `list_events(company_id:, invoice_id:)` | GET | `.../{invoice_id}/events` | +| `download_pdf(company_id:, invoice_id:)` | GET | `.../{invoice_id}/pdf` | +| `download_xml(company_id:, invoice_id:)` | GET | `.../{invoice_id}/xml` | +| `download_rejection_xml(company_id:, invoice_id:)` | GET | `.../{invoice_id}/xml/rejection` | +| `disable_range(company_id:, data:)` | POST | `.../consumerinvoices/disablement` | + +The resource SHALL NOT define `send_correction_letter` (CC-e applies only to NF-e by Brazilian fiscal law), `download_epec_xml` (no EPEC contingency exists for NFC-e), nor a per-invoice `disable` (NFC-e supports only collective inutilization via `disable_range`). + +#### Scenario: NFC-e discriminated creation +- **WHEN** `create(company_id:, data:)` is called and the API responds HTTP 202 with `Location` +- **THEN** the method SHALL return a `Nfe::Resources::ConsumerInvoicePending` whose `invoice_id` is extracted from the final path segment; on HTTP 201 it SHALL return a `Nfe::Resources::ConsumerInvoiceIssued` whose `resource` is a `Nfe::ConsumerInvoice` + +#### Scenario: NFC-e cancellation is synchronous +- **WHEN** `cancel(company_id:, invoice_id:)` is called +- **THEN** the SDK SHALL `DELETE .../consumerinvoices/{invoice_id}` and return the updated consumer-invoice model + +#### Scenario: NFC-e download returns bytes +- **WHEN** `download_pdf(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a binary `String` (the DANFE NFC-e PDF), unlike `ProductInvoices` which returns a URI + +#### Scenario: NFC-e collective inutilization only +- **WHEN** `disable_range(company_id:, data:)` is called +- **THEN** the SDK SHALL `POST .../consumerinvoices/disablement` + +#### Scenario: Methods absent by fiscal law +- **WHEN** consumer code calls `client.consumer_invoices.send_correction_letter(...)`, `download_epec_xml(...)`, or `disable(...)` +- **THEN** Ruby SHALL raise `NoMethodError`, because those instruments do not exist for NFC-e + +### Requirement: Transportation invoice resource (CT-e inbound) +`TransportationInvoices` SHALL manage inbound CT-e via the `:cte` family (`https://api.nfse.io`) and SHALL expose `enable`, `disable`, `get_settings`, `retrieve` (by access key), `download_xml`, `get_event`, and `download_event_xml`. + +| Method | HTTP | Path | +|---|---|---| +| `enable(company_id:, start_from_nsu: nil, start_from_date: nil)` | POST | `/v2/companies/{company_id}/inbound/transportationinvoices` | +| `disable(company_id:)` | DELETE | `.../inbound/transportationinvoices` | +| `get_settings(company_id:)` | GET | `.../inbound/transportationinvoices` | +| `retrieve(company_id:, access_key:)` | GET | `.../inbound/{access_key}` | +| `download_xml(company_id:, access_key:)` | GET | `.../inbound/{access_key}/xml` | +| `get_event(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}` | +| `download_event_xml(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}/xml` | + +#### Scenario: Enabling auto-fetch returns settings +- **WHEN** `enable(company_id:)` is called +- **THEN** the SDK SHALL `POST .../inbound/transportationinvoices` and return the inbound settings model + +#### Scenario: Access key normalisation +- **WHEN** `retrieve(company_id:, access_key:)` is called with a 44-digit key containing spaces or dots +- **THEN** `Nfe::IdValidator.access_key` SHALL strip non-digits and the request SHALL use the 44-digit value +- **AND** if the normalised value does not match `/\A\d{44}\z/` the SDK SHALL raise `Nfe::InvalidRequestError` before any HTTP request + +#### Scenario: XML downloads return strings +- **WHEN** `download_xml(company_id:, access_key:)` or `download_event_xml(company_id:, access_key:, event_key:)` succeeds +- **THEN** the return value SHALL be a `String` containing the raw XML + +### Requirement: Inbound product invoice resource manages supplier NF-e ingestion +`InboundProductInvoices` SHALL manage supplier-issued NF-e via the `:cte` family (`https://api.nfse.io`) and SHALL expose `enable_auto_fetch`, `disable_auto_fetch`, `get_settings`, `get_details`, `get_product_invoice_details`, `get_event_details`, `get_product_invoice_event_details`, `get_xml`, `get_event_xml`, `get_pdf`, `get_json`, `manifest`, and `reprocess_webhook`. + +The `manifest` method SHALL accept a numeric `tp_event` (default `210210`) and forward it as a query parameter. The module SHALL expose symbolic constants for the manifest event types: `210210` awareness (default), `210220` confirmation, `210240` operation not performed. + +| Method | HTTP | Path | +|---|---|---| +| `enable_auto_fetch(company_id:, **opts)` | POST | `/v2/companies/{company_id}/inbound/productinvoices` | +| `disable_auto_fetch(company_id:)` | DELETE | `.../inbound/productinvoices` | +| `get_settings(company_id:)` | GET | `.../inbound/productinvoices` | +| `get_details(company_id:, access_key:)` | GET | `.../inbound/{access_key}` | +| `get_product_invoice_details(company_id:, access_key:)` | GET | `.../inbound/productinvoice/{access_key}` | +| `get_event_details(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}` | +| `get_product_invoice_event_details(company_id:, access_key:, event_key:)` | GET | `.../inbound/productinvoice/{access_key}/events/{event_key}` | +| `get_xml(company_id:, access_key:)` | GET | `.../inbound/{access_key}/xml` | +| `get_event_xml(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}/xml` | +| `get_pdf(company_id:, access_key:)` | GET | `.../inbound/{access_key}/pdf` | +| `get_json(company_id:, access_key:)` | GET | `.../inbound/productinvoice/{access_key}/json` | +| `manifest(company_id:, access_key:, tp_event: 210210)` | POST | `.../inbound/{access_key}/manifest?tpEvent={tp_event}` | +| `reprocess_webhook(company_id:, access_key_or_nsu:)` | POST | `.../inbound/productinvoice/{access_key_or_nsu}/processwebhook` | + +#### Scenario: v1 versus v2 detail endpoints +- **WHEN** `get_details(company_id:, access_key:)` is called +- **THEN** the SDK SHALL request `.../inbound/{access_key}` (webhook v1 format) +- **WHEN** `get_product_invoice_details(company_id:, access_key:)` is called +- **THEN** the SDK SHALL request `.../inbound/productinvoice/{access_key}` (webhook v2 format) + +#### Scenario: Manifesting receipt with default event type +- **WHEN** `manifest(company_id:, access_key:)` is called without `tp_event` +- **THEN** the SDK SHALL `POST .../manifest?tpEvent=210210` (awareness) and return the result as a `String` + +#### Scenario: Manifesting receipt with explicit event type +- **WHEN** `manifest(company_id:, access_key:, tp_event: 210220)` is called +- **THEN** the SDK SHALL `POST .../manifest?tpEvent=210220` (confirmation) + +#### Scenario: PDF download returns bytes +- **WHEN** `get_pdf(company_id:, access_key:)` succeeds +- **THEN** the return value SHALL be a binary `String` (the PDF bytes) + +#### Scenario: Reprocess accepts key or NSU +- **WHEN** `reprocess_webhook(company_id:, access_key_or_nsu:)` is called with either a 44-digit access key or a numeric NSU +- **THEN** the SDK SHALL `POST .../inbound/productinvoice/{access_key_or_nsu}/processwebhook` and SHALL NOT reject a numeric NSU as an invalid access key + +### Requirement: Discriminated response value objects for invoice creation +The SDK SHALL provide the following immutable `Data.define` value objects under `Nfe::Resources`, each exposing `pending?` and `issued?` predicate methods: + +- `ServiceInvoicePending(:invoice_id, :location)` and `ServiceInvoiceIssued(:resource)` +- `ProductInvoicePending(:invoice_id, :location)` and `ProductInvoiceIssued(:resource)` +- `ConsumerInvoicePending(:invoice_id, :location)` and `ConsumerInvoiceIssued(:resource)` + +These implement the `Pending`/`Issued` contract introduced by `add-client-core`. + +#### Scenario: Discriminating with a predicate +- **WHEN** a consumer writes `result.pending? ? handle_pending(result) : handle_issued(result)` +- **THEN** a `*Pending` value SHALL answer `pending?` with `true` and expose `invoice_id`/`location`, and a `*Issued` value SHALL answer `issued?` with `true` and expose `resource` + +#### Scenario: Discriminating with pattern matching +- **WHEN** a consumer writes `case result; in Nfe::Resources::ServiceInvoicePending; ...; in Nfe::Resources::ServiceInvoiceIssued; ...; end` +- **THEN** Ruby `Data` pattern matching SHALL select the correct branch for the returned value object + +### Requirement: Invoice resources validate IDs and access keys before HTTP +Every invoice resource method that takes an identifier SHALL validate it through the `Nfe::IdValidator` module provided by `add-client-core` — calling `company_id`, `invoice_id`, `state_tax_id`, `event_key`, or `access_key` — before issuing the HTTP request. This capability SHALL NOT redefine the validator; it consumes the one defined by `add-client-core`. + +`Nfe::IdValidator.access_key` accepts formatted input (with spaces, dots, dashes), strips non-digit characters, validates that the result has exactly 44 digits (`/\A\d{44}\z/`), and returns the normalised string. + +#### Scenario: Empty company ID rejected before HTTP +- **WHEN** any resource method receives an empty or whitespace-only company ID +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously, with a Portuguese-language message naming the invalid argument, and SHALL make no HTTP request + +#### Scenario: Access key with formatting is normalised +- **WHEN** a resource method receives a 44-digit access key with separators and calls `Nfe::IdValidator.access_key` +- **THEN** the validator SHALL return a 44-character digit-only `String` and SHALL NOT raise + +#### Scenario: Access key of wrong length rejected +- **WHEN** a resource method receives an access key that normalises to fewer than 44 digits +- **THEN** `Nfe::IdValidator.access_key` SHALL raise `Nfe::InvalidRequestError` before any HTTP request + +### Requirement: Invoice listings use the shared ListResponse pagination type +Every invoice resource `list`/`list_items`/`list_events` method SHALL return the `Nfe::ListResponse` value object provided by `add-client-core` (carrying `data` and a `Nfe::ListPage`), populating only the half of `ListPage` (`page_index`/`page_count` for page-style, or `starting_after`/`ending_before` for cursor-style) relevant to its endpoint. This capability SHALL NOT redefine `ListResponse`/`ListPage`; it consumes them. + +#### Scenario: Page-style listing +- **WHEN** a resource paginates with `page_index`/`page_count` (e.g., service invoices) +- **THEN** the returned `ListResponse.page` SHALL have `page_index` and `page_count` set and cursor fields `nil` + +#### Scenario: Cursor-style listing +- **WHEN** a resource paginates with `starting_after`/`ending_before` (e.g., product or consumer invoices) +- **THEN** the returned `ListResponse.page` SHALL have the cursor fields set and `page_index` `nil` + +#### Scenario: Iterating a list response +- **WHEN** a consumer calls `result.each { |item| ... }` or `result.map { ... }` on a `ListResponse` +- **THEN** the iteration SHALL traverse the underlying `data` array via the `Enumerable` included by `add-client-core` + +### Requirement: Invoice status checks use the shared FlowStatus helper +Manual polling and `ServiceInvoices#get_status` SHALL determine terminal state through `Nfe::FlowStatus.terminal?(status)` provided by `add-client-core`, which returns `true` for `Issued`, `Cancelled`, `IssueFailed`, and `CancelFailed`, and `false` otherwise. This capability SHALL NOT redefine `FlowStatus`; it consumes it. + +#### Scenario: Terminal status +- **WHEN** `Nfe::FlowStatus.terminal?('Issued')`, `'Cancelled'`, `'IssueFailed'`, or `'CancelFailed'` is called +- **THEN** the method SHALL return `true` + +#### Scenario: Non-terminal status +- **WHEN** `Nfe::FlowStatus.terminal?('WaitingDefineRpsNumber')` or any other non-terminal value is called +- **THEN** the method SHALL return `false` + +### Requirement: Byte downloads return binary-safe strings +The byte-returning download methods — `ServiceInvoices#download_pdf`/`download_xml`, `ConsumerInvoices#download_pdf`/`download_xml`/`download_rejection_xml`, `TransportationInvoices#download_xml`/`download_event_xml`, and `InboundProductInvoices#get_xml`/`get_event_xml`/`get_pdf` — SHALL return a Ruby `String` containing the raw response bytes with encoding forced to `Encoding::ASCII_8BIT`. They SHALL set the appropriate `Accept` header (`application/pdf` or `application/xml`) and SHALL NOT attempt to parse the body as JSON. + +This requirement does NOT apply to `ProductInvoices` download methods, which return a `Nfe::NfeFileResource` (URI) instead of bytes. + +#### Scenario: PDF download bytes +- **WHEN** any covered `download_pdf`/`get_pdf` method succeeds +- **THEN** the return value SHALL be an `ASCII-8BIT` `String` whose first four bytes are `%PDF` + +#### Scenario: XML download bytes +- **WHEN** any covered `download_xml`/`get_xml` method succeeds +- **THEN** the return value SHALL be an `ASCII-8BIT` `String` whose first non-BOM character is `<` + +### Requirement: create_and_wait and create_batch are deferred +The SDK v1.0 SHALL NOT implement `create_and_wait` or `create_batch` on any invoice resource. The discriminated `Pending`/`Issued` contract plus `FlowStatus.terminal?` are sufficient for manual polling loops in CLI/worker contexts. Both helpers are explicitly deferred to a future minor release. + +#### Scenario: Looking for create_and_wait +- **WHEN** consumer code calls `client.service_invoices.create_and_wait(...)` against v1.0 +- **THEN** Ruby SHALL raise `NoMethodError`, since the method is not defined + +### Requirement: RTC emission is delegated to a separate change +This capability SHALL implement only the classic service-invoice and product-invoice emission. The RTC (Reforma Tributária do Consumo) emission models — adding the IBS, CBS, and IS tax groups — SHALL NOT be implemented here; they are specified by the `add-rtc-invoice-emission` change, which reuses the 202 contract, host routing, and validators defined in this capability. + +#### Scenario: Classic emission only +- **WHEN** a consumer issues a service or product invoice through this capability's `create` methods +- **THEN** the SDK SHALL send the classic (non-RTC) payload shape, and any IBS/CBS/IS handling SHALL be provided by the dedicated RTC resources from `add-rtc-invoice-emission` diff --git a/openspec/changes/archive/2026-06-25-add-invoice-resources/tasks.md b/openspec/changes/archive/2026-06-25-add-invoice-resources/tasks.md new file mode 100644 index 0000000..ee3f0f7 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-invoice-resources/tasks.md @@ -0,0 +1,164 @@ +# Tasks — add-invoice-resources + +> Planejamento greenfield. Todos os itens estão `[ ]` (não implementados). Depende de `add-client-core` (transporte `Net::HTTP`, `Nfe::Configuration` com host map, erros tipados, contrato `Pending`/`Issued`, acessores lazy). A emissão RTC fica em `add-rtc-invoice-emission`. + +## 1. Suporte consumido de add-client-core (validators, ListResponse, FlowStatus) + +> NÃO recriar estas abstrações — `add-client-core` já as define. Esta seção apenas confirma o contrato consumido e cobre as integrações. + +- [x] 1.1 Consumir `Nfe::IdValidator` (de `add-client-core`) — métodos de módulo `company_id`, `invoice_id`, `state_tax_id`, `event_key`, e `access_key` (normaliza removendo não-dígitos, valida `/\A\d{44}\z/`, retorna a String normalizada). Cada método levanta `Nfe::InvalidRequestError` com mensagem em pt-BR identificando o argumento inválido. NÃO criar `Nfe::Util::IdValidator`. +- [x] 1.2 Consumir `Nfe::ListPage = Data.define(:page_index, :page_count, :starting_after, :ending_before, :total)` (de `add-client-core`) com defaults `nil`. NÃO recriar. +- [x] 1.3 Consumir `Nfe::ListResponse = Data.define(:data, :page)` (de `add-client-core`); `data` é `Array`, `page` é `Nfe::ListPage`; já inclui `Enumerable` (delega `each` para `data`). NÃO recriar. +- [x] 1.4 Consumir `Nfe::FlowStatus.terminal?(status)` (de `add-client-core`) — `true` para `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`; `false` para os demais. NÃO recriar `Nfe::Util::FlowStatus`. +- [x] 1.5 Confirmar que as assinaturas RBS de `Nfe::IdValidator`, `Nfe::ListPage`, `Nfe::ListResponse`, `Nfe::FlowStatus` (de `add-client-core`) cobrem o uso desta change; nenhum RBS novo para estes tipos aqui. +- [x] 1.6 Tests de integração: exercitar `Nfe::IdValidator` (vazio → erro; access_key com separadores → 44 dígitos; comprimento errado → erro), `Nfe::FlowStatus.terminal?` (4 terminais → true; não-terminais → false) e `Nfe::ListResponse` (Enumerable, shapes page e cursor) nos specs dos recursos que os consomem. + +## 2. Helpers de download/unwrapping no recurso-base (AbstractResource de add-client-core) + +> `Nfe::Resources::AbstractResource` (de `add-client-core`) já provê `download`, `hydrate`, `hydrate_list`, `handle_async_response` e `get/post/put/delete`. Esta seção só confirma o consumo e cobre a lacuna específica de invoice (unwrapping de envelope). + +- [x] 2.1 Consumir `Nfe::Resources::AbstractResource#download(path)` (de `add-client-core`) para os downloads de bytes — GET com `Accept` apropriado, retorna `response.body` como `String` em `Encoding::ASCII_8BIT` (binary-safe), sem decodificar como JSON. +- [x] 2.2 Adicionar `Nfe::Resources::AbstractResource#unwrap(payload, *keys)` (protegido) — desempacota envelopes do tipo `{ "serviceInvoice" => {...} }` retornando o primeiro `key` presente, ou `payload` se nenhum existir. (Extensão aditiva à base, se ainda não existir.) +- [x] 2.3 Consumir `Nfe::Resources::AbstractResource#hydrate_list(klass, payload, wrapper_key:)` (de `add-client-core`) — desempacota `{ => [...] }`, hidrata cada item, detecta o shape de paginação (page-style vs cursor-style) e devolve `Nfe::ListResponse` com `Nfe::ListPage` preenchido na metade correta. +- [x] 2.4 Garantir que cada recurso declara sua `api_family` (`:main` para service; `:cte` para product/consumer/transportation/inbound), resolvida via `Nfe::Configuration#base_url_for(family)` (de `add-client-core`). +- [x] 2.5 RBS: atualizar `sig/nfe/resources/abstract_resource.rbs` apenas se `unwrap` for adicionado; demais assinaturas já vêm de `add-client-core`. +- [x] 2.6 Tests: cobrir `unwrap` (desempacota e cai no fallback) nos specs dos recursos; `download`/`hydrate_list` já são cobertos por `add-client-core`. + +## 3. Response value objects (Pending + Issued) + +- [x] 3.1 `lib/nfe/resources/service_invoice_pending.rb` — `Nfe::Resources::ServiceInvoicePending = Data.define(:invoice_id, :location)`; método `pending?` → `true`, `issued?` → `false`. +- [x] 3.2 `lib/nfe/resources/service_invoice_issued.rb` — `Nfe::Resources::ServiceInvoiceIssued = Data.define(:resource)` onde `resource` é o modelo de invoice hidratado; `pending?` → `false`, `issued?` → `true`. +- [x] 3.3 `lib/nfe/resources/product_invoice_pending.rb` + `product_invoice_issued.rb`. +- [x] 3.4 `lib/nfe/resources/consumer_invoice_pending.rb` + `consumer_invoice_issued.rb`. +- [x] 3.5 Helper de extração de `invoice_id` a partir do header `Location` (regex `%r{serviceinvoices/([a-z0-9-]+)}i` para service; `%r{(?:product|consumer)invoices/([a-z0-9-]+)}i` para os demais). Levantar `Nfe::InvoiceProcessingError` se 202 vier sem `Location` ou se o ID não for extraível. +- [x] 3.6 RBS para cada par Pending/Issued em `sig/nfe/resources/`. +- [x] 3.7 Tests: `spec/nfe/resources/invoice_response_spec.rb` — `pending?`/`issued?`, extração de `invoice_id` do `Location`, erro quando `Location` ausente. + +## 4. service_invoices (NFS-e — recurso canônico, host main → api.nfe.io; `/v1` via api_version, URL efetiva api.nfe.io/v1) + +- [x] 4.1 `lib/nfe/resources/service_invoices.rb` — classe `Nfe::Resources::ServiceInvoices < Nfe::Resources::AbstractResource`, `api_family :main`. +- [x] 4.2 `create(company_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /companies/{company_id}/serviceinvoices`. Se 202 → `ServiceInvoicePending` (extrai `invoice_id` do `Location`); se 201 → `ServiceInvoiceIssued` (hidrata o body). Levanta `InvoiceProcessingError` se 202 sem `Location`. `idempotency_key:` vira header `Idempotency-Key`; `request_options:` (`Nfe::RequestOptions`) é encaminhado ao request (vide design D13). +- [x] 4.3 `list(company_id:, **options)` — `GET /companies/{company_id}/serviceinvoices` com query `page_index`, `page_count`, `issued_begin`, `issued_end`, `created_begin`, `created_end`, `has_totals` (page-style). Devolve `ListResponse` com `ListPage` page-style (wrapper `serviceInvoices`). +- [x] 4.4 `retrieve(company_id:, invoice_id:)` — `GET .../{invoice_id}`. Levanta `Nfe::NotFoundError` se corpo vazio/404. +- [x] 4.5 `cancel(company_id:, invoice_id:)` — `DELETE .../{invoice_id}`; retorna o modelo de invoice atualizado (síncrono). +- [x] 4.6 `send_email(company_id:, invoice_id:)` — `PUT .../{invoice_id}/sendemail`; retorna `{ sent:, message: }` (sem argumento de lista de e-mails — paridade Node). +- [x] 4.7 `download_pdf(company_id:, invoice_id: nil)` — `GET .../{invoice_id}/pdf` ou, se `invoice_id` nil, `GET .../serviceinvoices/pdf` (download em lote → ZIP). `Accept: application/pdf`. Retorna `String` binária. +- [x] 4.8 `download_xml(company_id:, invoice_id: nil)` — `GET .../{invoice_id}/xml` ou em lote `.../serviceinvoices/xml`. `Accept: application/xml`. Retorna `String` binária. +- [x] 4.9 `get_status(company_id:, invoice_id:)` — DERIVADO de `retrieve` (sem chamada HTTP extra, paridade Node). Retorna `Data.define(:status, :invoice, :complete?, :failed?)` usando `FlowStatus.terminal?` e checagem de `IssueFailed`/`CancelFailed`. +- [x] 4.10 Validar `company_id`/`invoice_id` via `IdValidator` no início de cada método. +- [x] 4.11 RBS: `sig/nfe/resources/service_invoices.rbs`. +- [x] 4.12 Tests `spec/nfe/resources/service_invoices_spec.rb` (WebMock): 202→Pending, 201→Issued, 202-sem-Location→erro, list page-style, retrieve, retrieve 404→NotFoundError, cancel, send_email, download_pdf bytes começam com `%PDF`, download_xml começa com `<`, download em lote (invoice_id nil), get_status derivado, IDs inválidos→InvalidRequestError sem HTTP, `idempotency_key:` enviado como header `Idempotency-Key`, `request_options:` (api_key por chamada) sobrescrevendo o default sem mutar o `Client`. + +## 5. product_invoices (NF-e — host cte / api.nfse.io) + +- [x] 5.1 `lib/nfe/resources/product_invoices.rb` — `Nfe::Resources::ProductInvoices < Nfe::Resources::AbstractResource`, `api_family :cte`. +- [x] 5.2 `create(company_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /v2/companies/{company_id}/productinvoices`; resposta discriminada `ProductInvoicePending|ProductInvoiceIssued` (async 202 enfileirado, conclusão via webhook). `idempotency_key:`/`request_options:` conforme design D13. +- [x] 5.3 `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /v2/companies/{company_id}/statetaxes/{state_tax_id}/productinvoices`; valida `state_tax_id`. `idempotency_key:`/`request_options:` conforme design D13. +- [x] 5.4 `list(company_id:, environment:, **options)` — `GET /v2/companies/{company_id}/productinvoices` (cursor: `starting_after`, `ending_before`, `limit`, `q`). `environment` (`"Production"`/`"Test"`) é OBRIGATÓRIO → `InvalidRequestError` se ausente. Devolve `ListResponse` cursor-style. +- [x] 5.5 `retrieve(company_id:, invoice_id:)` — `GET .../{invoice_id}`. +- [x] 5.6 `cancel(company_id:, invoice_id:, reason: nil)` — `DELETE .../{invoice_id}?reason={reason}`; retorna recurso de cancelamento (async 204 enfileirado). +- [x] 5.7 `list_items(company_id:, invoice_id:, limit: nil, starting_after: nil)` — `GET .../{invoice_id}/items` (cursor). +- [x] 5.8 `list_events(company_id:, invoice_id:, limit: nil, starting_after: nil)` — `GET .../{invoice_id}/events` (cursor). +- [x] 5.9 `download_pdf(company_id:, invoice_id:, force: nil)` — `GET .../{invoice_id}/pdf?force={force}`; retorna `NfeFileResource` (URI, NÃO bytes). Documentar a divergência. +- [x] 5.10 `download_xml(company_id:, invoice_id:)` — `GET .../{invoice_id}/xml`; retorna `NfeFileResource` (URI). +- [x] 5.11 `download_rejection_xml(company_id:, invoice_id:)` — `GET .../{invoice_id}/xml-rejection`; retorna `NfeFileResource` (URI). (Path Node `/xml-rejection`.) +- [x] 5.12 `download_epec_xml(company_id:, invoice_id:)` — `GET .../{invoice_id}/xml-epec`; retorna `NfeFileResource` (URI). (XML de contingência EPEC.) +- [x] 5.13 `send_correction_letter(company_id:, invoice_id:, reason:)` — `PUT .../{invoice_id}/correctionletter`; valida `15 <= reason.length <= 1000` (sem acentos) client-side antes do HTTP; body `{ reason: }`. Retorna recurso de cancelamento (CC-e async). +- [x] 5.14 `download_correction_letter_pdf(company_id:, invoice_id:)` — `GET .../{invoice_id}/correctionletter/pdf`; `NfeFileResource`. +- [x] 5.15 `download_correction_letter_xml(company_id:, invoice_id:)` — `GET .../{invoice_id}/correctionletter/xml`; `NfeFileResource`. +- [x] 5.16 `disable(company_id:, invoice_id:, reason: nil)` — `POST .../{invoice_id}/disablement?reason={reason}` (inutilização por invoice, async). +- [x] 5.17 `disable_range(company_id:, data:)` — `POST /v2/companies/{company_id}/productinvoices/disablement` com `{ environment, serie, state, begin_number, last_number, reason? }` (faixa; número único = mesmo begin/last). +- [x] 5.18 Validar IDs via `IdValidator`; validar tamanho da carta de correção. +- [x] 5.19 RBS: `sig/nfe/resources/product_invoices.rbs`. +- [x] 5.20 Tests `spec/nfe/resources/product_invoices_spec.rb`: routing para `api.nfse.io`, create discriminado, create_with_state_tax, list cursor + environment obrigatório, retrieve, cancel com reason em query, list_items/list_events, download_* retornam URI (NfeFileResource), correction letter (15-1000 chars + erro fora do range), disable, disable_range. + +## 6. consumer_invoices (NFC-e — paridade-plus, host cte / api.nfse.io) + +> Recurso ALÉM da paridade Node (Node não expõe emissão de NFC-e). Fundamentado em `nf-consumidor-v2.yaml`. Documentar paridade-plus + 3 ausências por lei fiscal (vide design D7). + +- [x] 6.1 `lib/nfe/resources/consumer_invoices.rb` — `Nfe::Resources::ConsumerInvoices < Nfe::Resources::AbstractResource`, `api_family :cte`. Comentário de cabeçalho documentando "paridade-plus" e as 3 ausências. +- [x] 6.2 `create(company_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /v2/companies/{company_id}/consumerinvoices`; discriminado `ConsumerInvoicePending|ConsumerInvoiceIssued` (202/201). `idempotency_key:`/`request_options:` conforme design D13. +- [x] 6.3 `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /v2/companies/{company_id}/statetaxes/{state_tax_id}/consumerinvoices`. `idempotency_key:`/`request_options:` conforme design D13. +- [x] 6.4 `list(company_id:, **options)` — `GET .../consumerinvoices` (cursor; wrapper `consumerInvoices`). +- [x] 6.5 `retrieve(company_id:, invoice_id:)` — `GET .../{invoice_id}`. +- [x] 6.6 `cancel(company_id:, invoice_id:)` — `DELETE .../{invoice_id}` (síncrono); retorna o modelo atualizado. +- [x] 6.7 `list_items(company_id:, invoice_id:)` — `GET .../{invoice_id}/items`. +- [x] 6.8 `list_events(company_id:, invoice_id:)` — `GET .../{invoice_id}/events`. +- [x] 6.9 `download_pdf(company_id:, invoice_id:)` — `GET .../{invoice_id}/pdf`; retorna `String` binária (DANFE NFC-e, ao contrário do product). `Accept: application/pdf`. +- [x] 6.10 `download_xml(company_id:, invoice_id:)` — `GET .../{invoice_id}/xml`; retorna `String` binária. +- [x] 6.11 `download_rejection_xml(company_id:, invoice_id:)` — `GET .../{invoice_id}/xml/rejection`; retorna `String` binária. +- [x] 6.12 `disable_range(company_id:, data:)` — `POST .../consumerinvoices/disablement` (inutilização SOMENTE coletiva). +- [x] 6.13 NÃO definir `send_correction_letter`, `download_epec_xml`, nem `disable` por invoice (verificar via teste que esses métodos não respondem). +- [x] 6.14 Validar IDs via `IdValidator`. +- [x] 6.15 RBS: `sig/nfe/resources/consumer_invoices.rbs`. +- [x] 6.16 Tests `spec/nfe/resources/consumer_invoices_spec.rb`: routing `api.nfse.io`, create discriminado 202/201, create_with_state_tax, list cursor, retrieve, cancel síncrono, downloads (bytes), disable_range, e asserções de que os 3 métodos ausentes levantam `NoMethodError`. + +## 7. transportation_invoices (CT-e — inbound, host cte / api.nfse.io) + +- [x] 7.1 `lib/nfe/resources/transportation_invoices.rb` — `Nfe::Resources::TransportationInvoices < Nfe::Resources::AbstractResource`, `api_family :cte`. +- [x] 7.2 `enable(company_id:, start_from_nsu: nil, start_from_date: nil)` — `POST /v2/companies/{company_id}/inbound/transportationinvoices`; habilita busca automática de CT-e via Distribuição DFe; retorna settings. +- [x] 7.3 `disable(company_id:)` — `DELETE /v2/companies/{company_id}/inbound/transportationinvoices`; retorna settings. +- [x] 7.4 `get_settings(company_id:)` — `GET /v2/companies/{company_id}/inbound/transportationinvoices`; retorna settings. +- [x] 7.5 `retrieve(company_id:, access_key:)` — `GET /v2/companies/{company_id}/inbound/{access_key}`; valida `access_key` (44 dígitos); retorna metadata. +- [x] 7.6 `download_xml(company_id:, access_key:)` — `GET .../inbound/{access_key}/xml`; retorna `String` (XML). +- [x] 7.7 `get_event(company_id:, access_key:, event_key:)` — `GET .../inbound/{access_key}/events/{event_key}`; retorna metadata. +- [x] 7.8 `download_event_xml(company_id:, access_key:, event_key:)` — `GET .../inbound/{access_key}/events/{event_key}/xml`; retorna `String` (XML). +- [x] 7.9 Validar `company_id`/`access_key`/`event_key` via `IdValidator`. +- [x] 7.10 RBS: `sig/nfe/resources/transportation_invoices.rbs`. +- [x] 7.11 Tests `spec/nfe/resources/transportation_invoices_spec.rb`: routing `api.nfse.io`, enable/disable/get_settings, retrieve com normalização de access_key (espaços/pontos → 44 dígitos), access_key inválida→InvalidRequestError, download_xml, get_event, download_event_xml. + +## 8. inbound_product_invoices (NF-e recebida de fornecedores, host cte / api.nfse.io) + +- [x] 8.1 `lib/nfe/resources/inbound_product_invoices.rb` — `Nfe::Resources::InboundProductInvoices < Nfe::Resources::AbstractResource`, `api_family :cte`. +- [x] 8.2 `enable_auto_fetch(company_id:, start_from_nsu: nil, start_from_date: nil, environment_sefaz: nil, automatic_manifesting: nil, webhook_version: nil)` — `POST /v2/companies/{company_id}/inbound/productinvoices`; retorna settings. +- [x] 8.3 `disable_auto_fetch(company_id:)` — `DELETE .../inbound/productinvoices`; retorna settings. +- [x] 8.4 `get_settings(company_id:)` — `GET .../inbound/productinvoices`; retorna settings. +- [x] 8.5 `get_details(company_id:, access_key:)` — `GET .../inbound/{access_key}`; metadata genérica NF-e/CT-e (webhook v1). +- [x] 8.6 `get_product_invoice_details(company_id:, access_key:)` — `GET .../inbound/productinvoice/{access_key}`; metadata v2 recomendada (+`productInvoices[]`). +- [x] 8.7 `get_event_details(company_id:, access_key:, event_key:)` — `GET .../inbound/{access_key}/events/{event_key}`. +- [x] 8.8 `get_product_invoice_event_details(company_id:, access_key:, event_key:)` — `GET .../inbound/productinvoice/{access_key}/events/{event_key}`. +- [x] 8.9 `get_xml(company_id:, access_key:)` — `GET .../inbound/{access_key}/xml`; retorna `String` (XML). +- [x] 8.10 `get_event_xml(company_id:, access_key:, event_key:)` — `GET .../inbound/{access_key}/events/{event_key}/xml`; retorna `String`. +- [x] 8.11 `get_pdf(company_id:, access_key:)` — `GET .../inbound/{access_key}/pdf`; retorna `String` binária (bytes do PDF). +- [x] 8.12 `get_json(company_id:, access_key:)` — `GET .../inbound/productinvoice/{access_key}/json`; retorna metadata estruturada (Hash hidratado). +- [x] 8.13 `manifest(company_id:, access_key:, tp_event: 210210)` — `POST .../inbound/{access_key}/manifest?tpEvent={tp_event}`. Aceitar código numérico (`210210` Ciência (default), `210220` Confirmação, `210240` Operação não Realizada). Expor constantes simbólicas no módulo (`MANIFEST_AWARENESS = 210210`, etc.). Retorna `String`. +- [x] 8.14 `reprocess_webhook(company_id:, access_key_or_nsu:)` — `POST .../inbound/productinvoice/{access_key_or_nsu}/processwebhook`; aceita chave de 44 dígitos OU número NSU. +- [x] 8.15 Validar IDs via `IdValidator` (access_key 44 dígitos; `reprocess_webhook` tolera NSU numérico). +- [x] 8.16 RBS: `sig/nfe/resources/inbound_product_invoices.rbs`. +- [x] 8.17 Tests `spec/nfe/resources/inbound_product_invoices_spec.rb`: routing `api.nfse.io`, enable/disable/get_settings, get_details vs get_product_invoice_details (v1 vs v2 path), eventos, get_xml/get_event_xml (string), get_pdf (bytes), get_json (Hash), manifest com tpEvent default e explícito, reprocess_webhook com access_key e com NSU. + +## 9. Modelos gerados (DTOs de invoice) + +- [x] 9.1 Confirmar quais modelos de invoice o gerador OpenAPI cobre (de `nf-servico-v1.yaml`, `nf-produto-v2.yaml`, `nf-consumidor-v2.yaml`, `consulta-cte-v2.yaml`, `consulta-nfe-distribuicao-v1.yaml`). NOTA: `nf-servico-v1.yaml` tem 0 schemas de componente — o modelo de service-invoice é derivado das operações. +- [x] 9.2 Onde o gerador não cobrir o shape de resposta, criar value objects `Data.define` hand-written sob `lib/nfe/resources/dto/` (NÃO em `lib/nfe/generated/`, para não conflitar com o sync do gerador) com os campos que o SDK realmente acessa (`id`, `flow_status`, `flow_message`, `status`, `environment`, `rps_number`, `rps_serial_number`, etc.). Documentar quais foram hand-written. +- [x] 9.3 `Nfe::NfeFileResource = Data.define(:uri, ...)` — modelo de retorno dos downloads de `product_invoices` (URI, não bytes). +- [x] 9.4 RBS para os modelos hand-written em `sig/nfe/resources/dto/`. + +## 10. Integração no Client + +- [x] 10.1 Confirmar que os acessores lazy `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices` em `Nfe::Client` (de `add-client-core`) agora instanciam as classes reais (não stubs) passando o transporte/config correto por família. +- [x] 10.2 Confirmar roteamento de host: service → `:main` (host `api.nfe.io`; `/v1` via api_version, URL efetiva `api.nfe.io/v1`); os outros 4 → `:cte` (api.nfse.io). +- [x] 10.3 Tests `spec/nfe/client_spec.rb` — cada acessor devolve a classe concreta esperada e é memoizado (mesma instância em chamadas repetidas). + +## 11. Validação e qualidade + +- [x] 11.1 `bundle exec rspec` — cobertura SimpleCov >= 80%. +- [x] 11.2 `bundle exec steep check` — 0 erros de tipo nos novos arquivos (`lib/nfe/resources/`, `lib/nfe/resources/dto/`). +- [x] 11.3 `bundle exec rubocop` — sem offenses; todo `.rb` começa com `# frozen_string_literal: true`. +- [x] 11.4 `openspec validate add-invoice-resources` — passa. +- [x] 11.5 CI matrix Ruby 3.2 / 3.3 / 3.4 verde. + +## 12. Documentação + +- [x] 12.1 YARD/comentários em cada método público (paridade com o JSDoc Node + notas pt-BR onde fizer sentido). +- [x] 12.2 README — tabela com os 5 recursos + exemplo 1-liner de emissão de service invoice e de leitura do retorno discriminado (`case result; in ServiceInvoicePending => p ...`). +- [x] 12.3 Documentar no README: downloads de `product_invoices` retornam URI (NfeFileResource), os demais retornam bytes; `consumer_invoices` é paridade-plus; `create_and_wait`/`create_batch` diferidos (mostrar loop manual com `FlowStatus.terminal?`); cross-reference para `add-rtc-invoice-emission`. + +## 13. Smoke test manual (opt-in, fora do CI) + +- [ ] 13.1 NFS-e ponta-a-ponta: emissão + polling manual até estado terminal (precisa chave sandbox + company cadastrada). +- [ ] 13.2 `download_pdf` retornando bytes que começam com `%PDF`; `download_xml` começando com `<`. +- [ ] 13.3 Listagem com paginação real (page-style em service, cursor em product/consumer). +- [ ] 13.4 CT-e: configurar auto-fetch + consultar por access_key. +- [ ] 13.5 NFC-e: emissão paridade-plus em sandbox antes do GA. +- [ ] 13.6 Registrar resultados em `.notes/invoice-smoke-results.md`. diff --git a/openspec/changes/archive/2026-06-25-add-lookup-resources/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-lookup-resources/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-lookup-resources/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-lookup-resources/README.md b/openspec/changes/archive/2026-06-25-add-lookup-resources/README.md new file mode 100644 index 0000000..d878e54 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-lookup-resources/README.md @@ -0,0 +1,3 @@ +# add-lookup-resources + +Os 8 recursos de lookup/consulta/dados auxiliares do SDK Ruby v1 — addresses (CEP), legal_entity_lookup (CNPJ), natural_person_lookup (CPF), product_invoice_query + consumer_invoice_query (consulta por chave de acesso), tax_calculation, tax_codes e state_taxes — cada um roteado ao seu host correto pelo host map de `Nfe::Configuration`. diff --git a/openspec/changes/archive/2026-06-25-add-lookup-resources/design.md b/openspec/changes/archive/2026-06-25-add-lookup-resources/design.md new file mode 100644 index 0000000..53fb472 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-lookup-resources/design.md @@ -0,0 +1,227 @@ +# Design — add-lookup-resources + +## Context + +Os 8 recursos cobertos por esta change têm a personalidade mais variada do SDK Ruby v1: + +- **CEP lookup** (`addresses`) é trivialmente um GET por código, com normalização de hífen. +- **CNPJ/CPF lookup** (`legal_entity_lookup`, `natural_person_lookup`) é GET por número com normalização forte de entrada (aceita `12.345.678/0001-90` e `12345678000190`) + validação de UF. +- **Tax calculation** (`tax_calculation`) é POST com payload denso item-a-item; a resposta é um breakdown de impostos por item (ICMS/ICMS-ST/PIS/COFINS/IPI/II + CFOP). +- **State taxes** (`state_taxes`) é CRUD completo por empresa. +- **Invoice queries** (`product_invoice_query`, `consumer_invoice_query`) são read-only por chave de acesso (44 dígitos), sem escopo de empresa. + +Esta change é o **principal consumidor do host map** de `add-client-core`: 6 das 8 famílias batem em hosts dedicados fora de `api.nfe.io`. O foco do design é **fail-fast validation** na borda + **roteamento multi-host correto e travado por teste**. + +Tudo é adaptado para Ruby idiomático: value objects são `Data.define` imutáveis; argumentos são keyword args com `snake_case`; downloads retornam `String` binária (`force_encoding(Encoding::ASCII_8BIT)`); o que no Node é `Promise`/`Buffer` vira retorno síncrono/`String`; erros são `raise` de classes tipadas (`Nfe::InvalidRequestError`, `Nfe::NotFoundError`, etc., definidas em `add-client-core`). + +## Goals / Non-Goals + +**Goals** +- 8 recursos com paridade método-por-método com o Node SDK (e PHP), adaptados a snake_case. +- Aceitar entrada formatada (CNPJ/CPF com pontuação, CEP com hífen, UF minúscula) e **normalizar antes do HTTP**, retornando o valor normalizado dos validadores. +- Confirmar roteamento multi-host: cada spec de recurso assertiona o host de saída via transporte mockado. +- Value objects gerados (`lib/nfe/generated/`) onde o gerador OpenAPI cobrir; hand-written em `lib/nfe/resources/dto//` onde o gen for esparso. NUNCA editar arquivos gerados à mão. +- `Nfe::DateNormalizer` para parâmetros de data: aceita `String` ISO ou objetos `Date`/`Time`/`DateTime`. +- Downloads (PDF/XML) retornam `String` binária crua, via o helper de download de `Nfe::Resources::AbstractResource`. + +**Non-Goals** +- Validação de dígito verificador (Module-11) de CNPJ/CPF — o servidor valida; complexidade != ganho. +- CNPJ alfanumérico (v3) — fora do escopo v1 desta change; registrado como risco/evolução (R7). +- Builder fluente para o payload de `calculate` — `Hash` é suficiente; quem quer tipo usa o value object gerado. +- Caching de respostas de lookup — o caller decide; o SDK não tem camada de cache. +- Parser de OData `$filter` em `addresses.search` — repassado opaco como string para a API; sem parser local. +- Auto-paginação (`list_all`/iterator) em `state_taxes`/`tax_codes` — o caller escreve o loop; `ListResponse` carrega os cursores/páginas para isso. + +## Decisions + +### D1. Cada recurso valida no boundary, antes do HTTP, e usa o valor normalizado +**Decisão**: todo método público chama o validador apropriado (`Nfe::IdValidator.cnpj`, `.cpf`, `.cep`, `.state`, `.access_key`, `.company_id`, `.state_tax_id`) como primeira instrução. O validador **retorna a versão normalizada** (dígitos puros para tax numbers/CEP, UF maiúscula para estados) e é esse valor normalizado que entra no path. + +```ruby +def get_basic_info(federal_tax_number, update_address: nil, update_city_code: nil) + cnpj = Nfe::IdValidator.cnpj(federal_tax_number) # normaliza + valida 14 dígitos + query = {} + query[:updateAddress] = update_address unless update_address.nil? + query[:updateCityCode] = update_city_code unless update_city_code.nil? + hydrate(LegalEntityBasicInfoResponse, get("/v2/legalentities/basicInfo/#{cnpj}", query: query)) +end +``` + +**Por quê**: paridade com Node + fail-fast com mensagem clara em pt-BR. Não confiamos em strings de entrada do usuário; erros de digitação falham localmente sem queimar uma chamada paga à API. + +**Por quê retornar o normalizado** (e não só validar in-place): evita esquecer de normalizar e mandar `12.345.678/0001-90` no path. O validador é a única fonte da verdade da forma normalizada. + +### D2. `Nfe::DateNormalizer` para inputs de data +**Decisão**: `Nfe::DateNormalizer.to_iso_date(input) -> String` retorna `"YYYY-MM-DD"`. Aceita: +- `String` que casa `/\A\d{4}-\d{2}-\d{2}\z/` **e** sobrevive a um roundtrip via `Date.iso8601` (rejeita `2026-13-45`); +- `Date`, `Time`, `DateTime` (via `.strftime("%Y-%m-%d")`, descartando o componente de hora). + +Qualquer outra coisa (formato `15/01/1990`, mês/dia fora de faixa, tipo inesperado) levanta `Nfe::InvalidRequestError`. + +```ruby +def get_status(federal_tax_number, birth_date) + cpf = Nfe::IdValidator.cpf(federal_tax_number) + date = Nfe::DateNormalizer.to_iso_date(birth_date) + hydrate(NaturalPersonStatusResponse, get("/v1/naturalperson/status/#{cpf}/#{date}")) +end +``` + +**Por quê**: devs Ruby alternam entre string ISO e objetos de data conforme o contexto; aceitar ambos elimina conversão na borda. Espelha o `string | Date` do Node e o `DateNormalizer::toIsoDate` do PHP. + +**Alternativa rejeitada**: aceitar só `String`. Força o caller a formatar `Date` na mão — atrito desnecessário em Ruby, onde `date`/`time` são stdlib. + +### D3. Hosts dedicados confirmados por teste (esta change é o exercitador do host map) +**Decisão**: cada spec de método em `legal_entity_lookup`, `natural_person_lookup`, `addresses`, `product_invoice_query`, `consumer_invoice_query`, `tax_calculation`, `tax_codes`, `state_taxes` assertiona que o host capturado pelo transporte mockado é o esperado. + +```ruby +client = Nfe::Client.new(api_key: "k", transport: mock) +client.legal_entity_lookup.get_basic_info("12345678000190") +expect(mock.last_request.uri.to_s).to start_with("https://legalentity.api.nfe.io/v2/legalentities/basicInfo/") +``` + +Mapa de hosts (single source of truth em `Nfe::Configuration`, entregue por **add-client-core**): + +| Família (`api_family`) | Host | Recursos desta change | +|---|---|---| +| `addresses` | `https://address.api.nfe.io/v2` (versão na base URL) | `addresses` | +| `legal-entity` | `https://legalentity.api.nfe.io` | `legal_entity_lookup` | +| `natural-person` | `https://naturalperson.api.nfe.io` | `natural_person_lookup` | +| `nfe-query` | `https://nfe.api.nfe.io` | `product_invoice_query` (v2), `consumer_invoice_query` (v1) | +| `cte` | `https://api.nfse.io` | `tax_calculation`, `tax_codes`, `state_taxes` | + +**Por quê**: o multi-base-URL routing é um pilar de `add-client-core`; esta change é o consumidor mais agressivo. Travar o host no teste impede que um refactor do mapa quebre o roteamento silenciosamente. + +### D4. `addresses` usa base URL com `/v2` embutido; `api_version` vazia +**Decisão**: a família `addresses` aponta para `https://address.api.nfe.io/v2`, então o `/v2` é parte da base URL — **não** do path. `AddressesResource#api_version` retorna `""` (string vazia) e os paths internos são `/addresses/...`. O `AbstractResource` (de `add-client-core`) compõe o full path tolerando `api_version` vazia sem gerar `//addresses`. + +**Por quê**: espelha o `ADDRESS_API_BASE_URL = 'https://address.api.nfe.io/v2'` do Node. O recurso não deve hard-codear `/v2` no path porque isso duplicaria a versão. + +### D5. `product_invoice_query` usa v2; `consumer_invoice_query` usa v1 + `/coupon/` — mesmo host +**Decisão**: ambos roteiam para `https://nfe.api.nfe.io` (família `nfe-query`), mas com paths divergentes confirmados no Node: + +| Recurso | Path de retrieve | Path de download | +|---|---|---| +| `product_invoice_query` | `GET /v2/productinvoices/{access_key}` | `/v2/productinvoices/{access_key}.pdf` e `.xml`; eventos em `/v2/productinvoices/events/{access_key}` | +| `consumer_invoice_query` | `GET /v1/consumerinvoices/coupon/{access_key}` | `/v1/consumerinvoices/coupon/{access_key}.xml` | + +Downloads de query usam o sufixo `.pdf` / `.xml` no path (não um sub-recurso) e devem mandar o header `Accept` correto (`application/pdf` / `application/xml`). + +**Por quê**: os dois recursos compartilham host mas versões de API distintas. Hard-codear o path por recurso (em vez de um `api_version` único) é o caminho honesto, porque a versão **não** é uniforme por host aqui. + +**Cross-reference**: `consumer_invoice_query.retrieve` devolve um `TaxCoupon` (CFe-SAT) — é **consulta** por chave. Não confundir com `consumer_invoices.create` (emissão NFC-e) de **add-invoice-resources**, que é escopado por empresa e vive em `api.nfse.io`. + +### D6. Value objects: gerados quando possível, hand-written quando o gen for esparso +**Decisão**: para cada resposta, primeiro checar se o gerador OpenAPI emitiu o value object sob `lib/nfe/generated//`. Se sim, hidratar contra ele. Se o gen for esparso (specs de query/CPF costumam ser), criar `Data.define` hand-written em `lib/nfe/resources/dto//`. + +Candidatos prováveis a hand-written (confirmar `ls lib/nfe/generated/` antes): +- `Nfe::Resources::Dto::Addresses::AddressLookupResponse` (`consulta-endereco` pode cobrir). +- `Nfe::Resources::Dto::NaturalPersonLookup::NaturalPersonStatusResponse` (spec de CPF é esparso). +- `Nfe::Resources::Dto::TaxCodes::TaxCodePaginatedResponse` (paginação 1-based: `current_page`, `total_pages`, `total_count`, `items`). +- `Nfe::Resources::Dto::ConsumerInvoiceQuery::TaxCoupon` + sub-objetos (`CouponIssuer`, `CouponBuyer`, `CouponTotal`, `CouponItem`, `CouponPayment`, etc.). +- `Nfe::Resources::Dto::StateTaxes::NfeStateTax`. +- `Nfe::Resources::Dto::LegalEntityLookup::*` (basicInfo / stateTax / stateTaxForInvoice). + +Todos imutáveis via `Data.define`. **NUNCA** editar arquivos sob `lib/nfe/generated/` à mão (CI sync guard reclama). + +**Por quê**: paralelo direto da decisão do PHP (DTOs hand-written em `src/Resource/Dto/`). Mantém os gerados puros e os complementos visíveis. + +### D7. `tax_calculation.calculate` aceita `Hash` opaco; value object gerado é opcional +**Decisão**: `calculate(tenant_id, request)` aceita `request` como `Hash`. Validação local mínima: `tenant_id` não vazio, `request[:operation_type]`/`:operationType` presente, `request[:items]` array não vazio. PHPDoc/RBS recomendam construir `Nfe::Generated::CalculoImpostosV1::CalculateRequest` e passar `.to_h` para type-safety. + +O `tenant_id` é URL-encodado no path: `POST /tax-rules/{tenant_id}/engine/calculate`. Host: `https://api.nfse.io` (família `cte`). + +**Por quê**: paridade com Node (aceita objeto literal). O motor de cálculo evolui (RTC/IBS/CBS); forçar shape no cliente seria frágil. O SDK passa adiante e devolve o breakdown. + +**Nota de validação**: o Node valida `issuer` e `recipient` obrigatórios; o PHP valida só `tenantId` + `items` + `operationType`. Adotamos o conjunto **mínimo do PHP** (tenant + operation_type + items não vazio) para não bloquear payloads válidos que o motor aceita — `issuer`/`recipient` ausentes viram 400 server-side com mensagem clara. + +### D8. `tax_codes` é paginação page-style 1-based (distinta do cursor) +**Decisão**: os 4 métodos `list_*` aceitam `page_index:` (1-based, default da API se omitido) e `page_count:` (default 50 na API). A resposta carrega `current_page`, `total_pages`, `total_count`, `items`. Isso é **distinto** do cursor-style (`starting_after`/`ending_before`/`limit`) usado por `state_taxes` e pelos invoice resources. + +**Por quê**: confirmado no Node (`TaxCodeListOptions { pageIndex, pageCount }`). Documentar em RBS/comentário que `tax_codes` é 1-based page-style — para o caller não confundir com o cursor das outras listas. + +### D9. `state_taxes` é o único CRUD; envelopa o body como `{ state_tax: data }` +**Decisão**: `state_taxes` expõe `list` (cursor-style), `create`, `retrieve`, `update`, `delete`. `create` e `update` envolvem o body como `{ stateTax: }` antes do POST/PUT (envelope canônico do Node `state-taxes.ts`). `delete` retorna `nil` (HTTP 200/204 sem corpo significativo). Host: `https://api.nfse.io` (família `cte`), paths `v2`. + +Validação via `Nfe::IdValidator.company_id` + `Nfe::IdValidator.state_tax_id` (ambos de **add-client-core**). + +**Por quê**: paridade exata com o Node. O envelope `{ stateTax: ... }` é aplicado pelo SDK — o caller passa só os campos. + +### D10. `addresses.search` repassa `$filter` OData opaco +**Decisão**: `search(filter: nil)` repassa `filter` direto na query string como `$filter=...`. O SDK não parseia nem valida a expressão; o caller é responsável por montá-la e por escapar valores. URL-encoding da query é feito pelo transporte. + +```ruby +client.addresses.search(filter: "city eq 'São Paulo'") +# => GET https://address.api.nfe.io/v2/addresses?$filter=city%20eq%20%27S%C3%A3o%20Paulo%27 +``` + +**Por quê**: paridade com Node. Implementar parser OData seria over-reach. Filtro mal formado → 400 → `Nfe::InvalidRequestError` com payload, e o caller depura. + +### D11. Downloads retornam `String` binária; usam o helper de `AbstractResource` +**Decisão**: `product_invoice_query.download_pdf` / `download_xml` e `consumer_invoice_query.download_xml` retornam `String` binária crua (`force_encoding(Encoding::ASCII_8BIT)`), via o helper `download(path, accept:)` de `Nfe::Resources::AbstractResource` (entregue por **add-client-core**). O helper manda o header `Accept` apropriado e devolve o corpo cru após validar 200. + +**Por quê**: Ruby `String` é binary-safe; é o análogo natural do `Buffer` do Node. O caller decide se grava em disco (`File.binwrite`) ou faz stream. Mesma decisão dos downloads de invoice em **add-invoice-resources**. + +**Dependência**: o helper `download` é compartilhado e vem de **add-client-core**. + +### D12. Extensão de `IdValidator` (cep/state/cnpj/cpf) coexiste com a base +**Decisão**: `Nfe::IdValidator` (módulo de funções de módulo / métodos de classe, em **add-client-core**) ganha 4 validadores nesta change: +- `cep(value) -> String` — normaliza para 8 dígitos; rejeita comprimento != 8. +- `state(value) -> String` — UF maiúscula; aceita as 29 (27 UFs + `EX` + `NA`); rejeita o resto. +- `cnpj(value) -> String` — 14 dígitos numéricos (v1). +- `cpf(value) -> String` — 11 dígitos numéricos. + +`access_key`, `company_id`, `state_tax_id` já existem em **add-client-core** e são reusados. **add-invoice-resources** adiciona `invoice_id`/`event_key` em métodos disjuntos — sem conflito de arquivo se ambas as changes editarem `id_validator.rb` (métodos distintos). + +**Por quê**: centraliza toda normalização de identificador fiscal num único módulo testável. Mensagens em pt-BR. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| Hosts dedicados mudam (`legalentity.api.nfe.io` → outro) | `Nfe::Configuration` host map é o único ponto a ajustar; specs travam o host esperado por recurso; smoke test pega antes do GA | +| Specs OpenAPI esparsos não cobrem respostas críticas (CPF, query, coupon) | Value objects hand-written em `lib/nfe/resources/dto//`; documentar quais foram hand-written; migrar quando o gen evoluir | +| Payload de `calculate` muda no servidor (RTC/IBS/CBS) | Aceitamos `Hash` opaco — SDK não força shape no cliente, só repassa; risco fica com o caller; RBS recomenda o value object gerado | +| OData `$filter` mal formado quebra `addresses.search` | API retorna 400 → `Nfe::InvalidRequestError` com payload; caller depura | +| Rate limit / cobrança por chamada em lookup CNPJ/CPF esgota billing | Retry de `add-client-core` honra `Retry-After`; comentário/RBS avisam do custo | +| `DateNormalizer` frouxo aceita data inválida (`2026-13-45`) | Regex estrita `/\A\d{4}-\d{2}-\d{2}\z/` + roundtrip `Date.iso8601` que rejeita mês/dia fora de faixa | +| Confusão entre `consumer_invoice_query` (consulta) e `consumer_invoices` (emissão) | Documentado em proposal + spec + cross-reference a **add-invoice-resources**; hosts e versões distintos deixam claro | +| CNPJ alfanumérico (jul/2026) incompatível com `IdValidator::cnpj` numérico v1 | v1 desta change é numérico-only por design (endpoints v1/v2 não mudam); alfanumérico vive em v3 — evolução futura (R7), não coagir para Integer | + +## Resolved (durante recon — grounding nos arquivos do Node SDK) + +### R1. Hosts canônicos confirmados; specs PHP divergentes ignorados +**Achado**: os arquivos do Node SDK definem os hosts canônicos em constantes: +- `addresses.ts:17` → `ADDRESS_API_BASE_URL = 'https://address.api.nfe.io/v2'` +- `legal-entity-lookup.ts:29` → `LEGAL_ENTITY_API_BASE_URL = 'https://legalentity.api.nfe.io'` +- `natural-person-lookup.ts:20` → `NATURAL_PERSON_API_BASE_URL = 'https://naturalperson.api.nfe.io'` +- `product-invoice-query.ts:21` → `NFE_QUERY_API_BASE_URL = 'https://nfe.api.nfe.io'` +- `tax-calculation.ts` / `tax-codes.ts` / `state-taxes.ts` → host `api.nfse.io` (família `cte`) + +As deltas de spec do PHP listavam `api-legalentity.nfe.io` / `api-naturalperson.nfe.io` — **divergência conhecida e incorreta**. O `client-core` spec do PHP e o Node concordam no `*.api.nfe.io`. **Decisão**: usar `legalentity.api.nfe.io` e `naturalperson.api.nfe.io`. + +### R2. `product_invoice_query` usa v2; `consumer_invoice_query` usa v1 + `/coupon/` +**Achado** (paths exatos do Node): +- `product-invoice-query.ts:108` → `/v2/productinvoices/{accessKey}`; `:133` → `.pdf`; `:159` → `.xml`; `:189` → `/v2/productinvoices/events/{accessKey}` +- `consumer-invoice-query.ts:100` → `/v1/consumerinvoices/coupon/{accessKey}`; `:125` → `.xml` + +**Decisão**: paths hard-coded por recurso (D5). `consumer_invoice_query.retrieve` devolve `TaxCoupon`. + +### R3. `tax_codes` é page-style 1-based +**Achado**: `tax-codes.ts:25-39` monta `pageIndex`/`pageCount` na query; doc diz "1-based, default 1" e "default 50". Resposta com `currentPage`/`totalPages`/`totalCount`/`items`. Distinto do cursor de `state-taxes`. +**Decisão**: D8. + +### R4. `state_taxes.create`/`update` envelopam `{ stateTax: data }` +**Achado**: `state-taxes.ts:169` (`{ stateTax: data }` no POST) e `:237` (idem no PUT). `list` usa `startingAfter`/`endingBefore`/`limit` (cursor). `delete` retorna void. +**Decisão**: D9. + +### R5. `tax_calculation.calculate` — validação do Node vs PHP +**Achado**: `tax-calculation.ts:37-57` valida `issuer`, `recipient`, `operationType`, `items` não vazio + `tenantId` não vazio. O PHP valida só `tenantId` + `operationType` + `items`. Path: `/tax-rules/{tenantId}/engine/calculate` com `tenantId` URL-encodado (`:178`). +**Decisão**: D7 — adotar o conjunto mínimo do PHP (tenant + operation_type + items), deixando issuer/recipient para o servidor validar. + +### R6. `IdValidator::state` aceita 29 valores (27 UFs + EX + NA) +**Achado**: `legal-entity-lookup.ts:32-37` define o `Set` com `AC..TO` + `EX` + `NA` (29 valores). `validateState` normaliza para uppercase e rejeita fora do set. `validateFederalTaxNumber` exige 14 dígitos após `replace(/\D/g,'')`; `validateCpf` exige 11. +**Decisão**: D12 — `IdValidator.state` aceita os 29; `cnpj` 14 dígitos; `cpf` 11 dígitos; `cep` 8 dígitos. + +### R7. CNPJ alfanumérico é v3 — fora do escopo v1 +**Achado**: a IN RFB 2.229/2024 (vigente jul/2026) permite letras nas 12 primeiras posições do CNPJ; entregue via APIs **v3** (`consulta-cnpj-v3` etc.). As famílias v1/v2 desta change permanecem numéricas. +**Decisão**: `IdValidator::cnpj` v1 valida 14 dígitos numéricos. Não coagir para Integer (deixar como `String` desde já evita a armadilha do Node `validateCNPJ`), mas o suporte alfanumérico real fica para uma evolução sobre endpoints v3. Registrado como risco. diff --git a/openspec/changes/archive/2026-06-25-add-lookup-resources/proposal.md b/openspec/changes/archive/2026-06-25-add-lookup-resources/proposal.md new file mode 100644 index 0000000..6268b4b --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-lookup-resources/proposal.md @@ -0,0 +1,63 @@ +# add-lookup-resources + +## Why + +Os recursos de **lookup, consulta (query) e dados auxiliares** completam a superfície de 17 acessores do `Nfe::Client` e fecham a paridade-plus com os SDKs Node e PHP. Eles têm um perfil distinto dos recursos de invoice (de `add-invoice-resources`) e de entidade (companies/people/webhooks): + +- **Read-only na maior parte**: devolvem dados normalizados (endereço por CEP, situação cadastral de CNPJ/CPF, eventos de NF-e, etc.). Nunca retornam o contrato 202 — respostas são sempre síncronas. +- **Multi-host agressivo**: esta change é o **principal exercitador do host map** definido em `add-client-core`. Seis das oito famílias vivem em hosts dedicados, fora do `https://api.nfe.io` padrão. Se o host map estiver errado, ~6 recursos retornam 404 ou batem no host errado. +- **`tax_calculation` é write-style** (POST com payload denso item-a-item) mas read-only no efeito — é um motor de cálculo, não persiste documento fiscal. +- **`state_taxes` é o único CRUD completo** desta change (list/create/retrieve/update/delete de Inscrições Estaduais por empresa). + +Esta change implementa os 8 recursos como classes Ruby idiomáticas (`Data.define` para value objects imutáveis, keyword args, snake_case, `raise` de erros tipados), reutilizando `Nfe::Resources::AbstractResource`, `Nfe::IdValidator`, `Nfe::ListResponse` e o host map de `Nfe::Configuration` — todos entregues por **add-client-core** (dependência). + +## What Changes (high-level) + +### Recursos implementados (8) + +| Recurso (acessor snake_case) | Família / host (via Configuration) | Operações | +|---|---|---| +| `addresses` | `addresses` → `https://address.api.nfe.io/v2` (o `/v2` é parte da base URL) | `lookup_by_postal_code`, `search`, `lookup_by_term` | +| `legal_entity_lookup` | `legal-entity` → `https://legalentity.api.nfe.io` | `get_basic_info`, `get_state_tax_info`, `get_state_tax_for_invoice`, `get_suggested_state_tax_for_invoice` | +| `natural_person_lookup` | `natural-person` → `https://naturalperson.api.nfe.io` | `get_status` | +| `product_invoice_query` | `nfe-query` → `https://nfe.api.nfe.io` (paths `v2`) | `retrieve`, `download_pdf`, `download_xml`, `list_events` | +| `consumer_invoice_query` | `nfe-query` → `https://nfe.api.nfe.io` (paths `v1` + `/coupon/`) | `retrieve`, `download_xml` | +| `tax_calculation` | `cte` → `https://api.nfse.io` | `calculate` | +| `tax_codes` | `cte` → `https://api.nfse.io` | `list_operation_codes`, `list_acquisition_purposes`, `list_issuer_tax_profiles`, `list_recipient_tax_profiles` | +| `state_taxes` | `cte` → `https://api.nfse.io` (paths `v2`) | `list`, `create`, `retrieve`, `update`, `delete` | + +### Adicionado (suporte) + +- **Extensão de `Nfe::IdValidator`** (a classe base vive em `add-client-core`): adiciona `cep`, `state` (UF de 2 letras + `EX` + `NA`), `cnpj` e `cpf`. Cada validador aceita entrada formatada (com pontos/hífens), normaliza para dígitos puros (ou UF maiúscula) e retorna o valor normalizado; `access_key` (44 dígitos) já existe em `add-client-core` e é reusado aqui. +- **`Nfe::DateNormalizer`** — `to_iso_date(input)` converte `String` (ISO `YYYY-MM-DD`) **ou** `Date`/`Time`/`DateTime` para uma string `YYYY-MM-DD`. Usado por `natural_person_lookup.get_status`. (Node aceita `string | Date`; em Ruby aceitamos `String` e os tipos de data da stdlib `date`/`time`.) +- **Value objects gerados/hand-written** em `lib/nfe/generated/` (quando o gerador OpenAPI cobre o schema) ou em `lib/nfe/resources/dto//` (hand-written quando o gen for esparso): `AddressLookupResponse`, `LegalEntityBasicInfoResponse`, `LegalEntityStateTaxResponse`, `LegalEntityStateTaxForInvoiceResponse`, `NaturalPersonStatusResponse`, `CalculateResponse`, `TaxCodePaginatedResponse`, `ProductInvoiceDetails`, `ProductInvoiceEventsResponse`, `TaxCoupon` (e sub-objetos), `NfeStateTax`. Todos `Data.define` imutáveis. + +### Não inclui (fora de escopo desta release) + +- **Validação de dígito verificador (Module-11) de CNPJ/CPF** — Node tem helpers; o servidor já valida. A validação local é fail-fast contra typo (comprimento/forma), não substitui a validação fiscal. Replicar Module-11 é custo sem ganho real. +- **CNPJ alfanumérico (IN RFB 2.229/2024, vigente jul/2026)** — vive nas APIs **v3** (`consulta-cnpj-v3`). As famílias v1/v2 desta change continuam numéricas. `IdValidator::cnpj` v1 valida 14 dígitos numéricos; suporte alfanumérico (não coagir para Integer) é uma evolução futura sobre endpoints v3, registrada como risco em `design.md`. +- **Builder fluente para o payload de `tax_calculation.calculate`** — aceitamos `Hash`; quem quer type-safety constrói o value object gerado `Nfe::Generated::CalculoImpostosV1::CalculateRequest` e passa via `to_h`. +- **Parser de OData `$filter`** em `addresses.search` — o filtro é repassado opaco para a query string; o caller é responsável por montá-lo. +- **Camada de cache** das respostas de lookup — o caller decide. + +## Capabilities + +### New Capabilities +- `lookup-resources`: os 8 recursos de lookup/query/state-tax + `Nfe::DateNormalizer` + a extensão dos validadores de `IdValidator` (cep/state/cnpj/cpf) + os value objects de resposta. + +### Modified Capabilities +- (nenhuma) — o host map e os blocos compartilhados (`Nfe::Resources::AbstractResource`, `IdValidator` base, `ListResponse`, lazy accessors) pertencem a **add-client-core**; esta change apenas os consome. + +## Impact + +- **Affected code**: `lib/nfe/resources/{addresses,legal_entity_lookup,natural_person_lookup,product_invoice_query,consumer_invoice_query,tax_calculation,tax_codes,state_taxes}.rb` (cada um herda de `Nfe::Resources::AbstractResource`), `lib/nfe/date_normalizer.rb`, `lib/nfe/id_validator.rb` (extensão cep/state/cnpj/cpf), value objects sob `lib/nfe/generated/**` ou `lib/nfe/resources/dto/**`. +- **Signatures**: `sig/nfe/resources/*.rbs` para cada recurso, `sig/nfe/date_normalizer.rbs`, e `sig/nfe/id_validator.rbs` (assinaturas dos novos validadores). Type-check com Steep, lint com RuboCop. +- **Tests**: `spec/nfe/resources/*_spec.rb` por recurso, mais `spec/nfe/date_normalizer_spec.rb` e cobertura dos novos validadores em `spec/nfe/id_validator_spec.rb`. Cada spec de recurso **assertiona o host de saída** (`https://address.api.nfe.io/v2`, `https://legalentity.api.nfe.io`, `https://naturalperson.api.nfe.io`, `https://nfe.api.nfe.io`, `https://api.nfse.io`) via transporte mockado. Cobertura >= 80% via SimpleCov. +- **Spec impact**: adiciona a capability `lookup-resources`; não modifica outras capabilities. +- **Dependencies**: **depende de add-client-core** (host map em `Nfe::Configuration`, `Nfe::Resources::AbstractResource`, `Nfe::IdValidator` base com `access_key`, `Nfe::ListResponse`, accessores lazy no `Nfe::Client`) e transitivamente de **add-ruby-foundation** (gem, namespace, RBS/Steep/RuboCop/RSpec, `frozen_string_literal`). Pode ser implementada em paralelo com **add-invoice-resources** — não há sobreposição de arquivos (ambas estendem `IdValidator`, mas em métodos distintos: invoice usa `company_id`/`invoice_id`/`access_key`/`state_tax_id`/`event_key`; lookup adiciona `cep`/`state`/`cnpj`/`cpf`). +- **Cross-reference**: `consumer_invoice_query` é a **consulta de NFC-e por chave de acesso** (read-only, sem escopo de empresa, host `nfe.api.nfe.io`). É distinto de `consumer_invoices` (emissão de NFC-e, escopada por empresa, host `api.nfse.io`), que pertence a **add-invoice-resources**. Os dois recursos coexistem no `Nfe::Client` e não devem ser confundidos. +- **Risks**: + - Hosts dedicados (`legalentity.api.nfe.io`, `naturalperson.api.nfe.io`) podem mudar; o `Nfe::Configuration` centraliza o mapa (único ponto a ajustar) e os specs travam o host esperado por recurso. Os specs do PHP listavam por engano `api-legalentity.nfe.io`/`api-naturalperson.nfe.io` — o host canônico (confirmado no Node SDK) é `*.api.nfe.io`. Esta change usa o canônico. + - Rate limits / cobrança por chamada agressivos em lookup de CNPJ/CPF (cobrado pela NFE.io). A política de retry de `add-client-core` honra `Retry-After`; o caller deve estar ciente do custo. + - O payload de `tax_calculation.calculate` é denso; risco de divergência entre o shape aceito pelo motor e o que o gerador produz. Mitigado por aceitar `Hash` opaco (SDK não força shape). + - `consumer_invoice_query` usa paths **v1** + `/coupon/` enquanto `product_invoice_query` usa **v2** — mesmo host (`nfe.api.nfe.io`), versões diferentes. Risco de troca de versão; coberto por specs explícitos de path. diff --git a/openspec/changes/archive/2026-06-25-add-lookup-resources/specs/lookup-resources/spec.md b/openspec/changes/archive/2026-06-25-add-lookup-resources/specs/lookup-resources/spec.md new file mode 100644 index 0000000..5218878 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-lookup-resources/specs/lookup-resources/spec.md @@ -0,0 +1,261 @@ +# lookup-resources — Delta + +## ADDED Requirements + +### Requirement: Eight lookup, query, and state-tax resources are fully implemented +The SDK SHALL implement eight resource classes under `Nfe::Resources` — `Addresses`, `LegalEntityLookup`, `NaturalPersonLookup`, `ProductInvoiceQuery`, `ConsumerInvoiceQuery`, `TaxCalculation`, `TaxCodes`, and `StateTaxes` — each extending `Nfe::Resources::AbstractResource` (from `add-client-core`) and exposed as a lazy snake_case accessor on `Nfe::Client`. Method names, parameter order, and behavior SHALL match the NFE.io Node.js SDK 1:1, adapted to Ruby idioms (snake_case methods, keyword arguments, `Buffer`→binary `String`, `Promise`→synchronous return, `Date`/`Time`/`DateTime` accepted alongside `String` for date inputs). + +This change depends on `add-client-core`, which owns the `Nfe::Configuration` host map, `Nfe::Resources::AbstractResource`, the base `Nfe::IdValidator` (`company_id`, `state_tax_id`, `access_key`), `Nfe::ListResponse`/`Nfe::ListPage`, the typed error classes, and the lazy resource accessors on `Nfe::Client`. + +#### Scenario: Parity with the Node SDK +- **WHEN** comparing method signatures between this Ruby SDK and the Node SDK for any of the eight resources +- **THEN** they SHALL be 1:1 equivalent modulo Ruby idioms (e.g., `lookupByPostalCode` ⇄ `lookup_by_postal_code`, `Date`/`Time` accepted alongside ISO `String`) + +#### Scenario: Accessing lookup resources from Client +- **WHEN** consumer code reads any of `client.addresses`, `client.legal_entity_lookup`, `client.natural_person_lookup`, `client.product_invoice_query`, `client.consumer_invoice_query`, `client.tax_calculation`, `client.tax_codes`, `client.state_taxes` +- **THEN** each accessor SHALL return a fully functional resource instance (not a stub that raises `NoMethodError`) + +### Requirement: Multi-host routing for lookup endpoints +The SDK SHALL route each resource to its correct host as resolved by `Nfe::Configuration` from the resource's `api_family`. No resource SHALL hard-code a host. Six families exercised by this change resolve to dedicated hosts distinct from the default `https://api.nfe.io`: + +| Resource | api_family | Host | +|---|---|---| +| `Addresses` | `addresses` | `https://address.api.nfe.io/v2` (the `/v2` is part of the base URL) | +| `LegalEntityLookup` | `legal-entity` | `https://legalentity.api.nfe.io` | +| `NaturalPersonLookup` | `natural-person` | `https://naturalperson.api.nfe.io` | +| `ProductInvoiceQuery` | `nfe-query` | `https://nfe.api.nfe.io` (paths use `v2`) | +| `ConsumerInvoiceQuery` | `nfe-query` | `https://nfe.api.nfe.io` (paths use `v1` + `/coupon/`) | +| `TaxCalculation`, `TaxCodes`, `StateTaxes` | `cte` | `https://api.nfse.io` | + +#### Scenario: Address lookup routes to the address host with embedded version +- **WHEN** any method of `Nfe::Resources::Addresses` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://address.api.nfe.io/v2/addresses` and SHALL NOT contain a duplicated version segment (no `/v2/v2`) + +#### Scenario: Legal entity lookup routes to its dedicated host +- **WHEN** any method of `Nfe::Resources::LegalEntityLookup` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://legalentity.api.nfe.io` + +#### Scenario: Natural person lookup routes to its dedicated host +- **WHEN** any method of `Nfe::Resources::NaturalPersonLookup` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://naturalperson.api.nfe.io` + +#### Scenario: Both invoice queries share the nfe-query host +- **WHEN** a method of `Nfe::Resources::ProductInvoiceQuery` or `Nfe::Resources::ConsumerInvoiceQuery` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://nfe.api.nfe.io` + +#### Scenario: Tax and state-tax resources route to nfse.io +- **WHEN** a method of `Nfe::Resources::TaxCalculation`, `Nfe::Resources::TaxCodes`, or `Nfe::Resources::StateTaxes` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://api.nfse.io` + +### Requirement: Address lookup by postal code, search, and term +`Nfe::Resources::Addresses` SHALL expose: + +- `lookup_by_postal_code(postal_code)` — accepts a CEP with or without hyphen; normalises to 8 digits via `Nfe::IdValidator.cep`; issues `GET /addresses/{cep}` +- `search(filter: nil)` — accepts an opaque OData `$filter` string forwarded verbatim as the `$filter` query parameter +- `lookup_by_term(term)` — accepts a non-empty search term; URL-encodes it; issues `GET /addresses/{encoded_term}` + +Each method SHALL return an `AddressLookupResponse` value object. + +#### Scenario: CEP with hyphen normalised +- **WHEN** `lookup_by_postal_code("01310-100")` is called +- **THEN** the request SHALL be issued to `/addresses/01310100` (digits only) + +#### Scenario: CEP with invalid length rejected before HTTP +- **WHEN** `lookup_by_postal_code("123")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Search with OData filter forwarded opaquely +- **WHEN** `search(filter: "city eq 'São Paulo'")` is called +- **THEN** the SDK SHALL issue `GET /addresses` with the `$filter` query parameter set to the given expression (URL-encoded by the transport), without parsing or validating the expression + +#### Scenario: Empty search term rejected +- **WHEN** `lookup_by_term("")` or `lookup_by_term(" ")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +### Requirement: Legal entity (CNPJ) lookup with four query methods +`Nfe::Resources::LegalEntityLookup` SHALL expose `get_basic_info(federal_tax_number, update_address: nil, update_city_code: nil)`, `get_state_tax_info(state, federal_tax_number)`, `get_state_tax_for_invoice(state, federal_tax_number)`, and `get_suggested_state_tax_for_invoice(state, federal_tax_number)`. + +Each method SHALL normalise its inputs before issuing the request: CNPJ via `Nfe::IdValidator.cnpj` (14 digits, non-digits stripped) and state via `Nfe::IdValidator.state` (uppercase, validated against the 29-value set of 27 Brazilian UFs plus `EX` and `NA`). + +#### Scenario: CNPJ with punctuation normalised +- **WHEN** `get_basic_info("12.345.678/0001-90")` is called +- **THEN** the SDK SHALL normalise to `12345678000190` and issue `GET /v2/legalentities/basicInfo/12345678000190` + +#### Scenario: State in lowercase normalised to uppercase +- **WHEN** `get_state_tax_info("sp", "12345678000190")` is called +- **THEN** the SDK SHALL normalise the state to `SP` and issue `GET /v2/legalentities/stateTaxInfo/SP/12345678000190` + +#### Scenario: Invalid state code rejected before HTTP +- **WHEN** `get_state_tax_info("XX", "12345678000190")` is called with a code outside the 29-value set +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Optional query parameters forwarded +- **WHEN** `get_basic_info("12345678000190", update_address: false, update_city_code: true)` is called +- **THEN** the SDK SHALL send `updateAddress=false` and `updateCityCode=true` as query parameters, and SHALL omit any option left at its default `nil` + +#### Scenario: Suggested state tax uses the dedicated path +- **WHEN** `get_suggested_state_tax_for_invoice("SP", "12345678000190")` is called +- **THEN** the SDK SHALL issue `GET /v2/legalentities/stateTaxSuggestedForInvoice/SP/12345678000190` + +### Requirement: Natural person (CPF) lookup with date normalisation +`Nfe::Resources::NaturalPersonLookup` SHALL expose `get_status(federal_tax_number, birth_date)` returning a `NaturalPersonStatusResponse`. The CPF SHALL be normalised via `Nfe::IdValidator.cpf` (11 digits). The `birth_date` SHALL accept either an ISO `String` (`YYYY-MM-DD`) or a `Date`/`Time`/`DateTime` object, normalised to `YYYY-MM-DD` via `Nfe::DateNormalizer.to_iso_date`. The request SHALL be `GET /v1/naturalperson/status/{cpf}/{birth_date}`. + +#### Scenario: String birth date +- **WHEN** `get_status("12345678901", "1990-01-15")` is called +- **THEN** the SDK SHALL issue `GET /v1/naturalperson/status/12345678901/1990-01-15` + +#### Scenario: Date object birth date and formatted CPF +- **WHEN** `get_status("123.456.789-01", Date.new(1990, 1, 15))` is called +- **THEN** the SDK SHALL normalise the CPF to `12345678901`, format the date as `1990-01-15`, and issue the same request as the string-date case + +#### Scenario: Invalid birth date format rejected +- **WHEN** `get_status("12345678901", "15/01/1990")` is called (non-ISO format) +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Out-of-range birth date rejected +- **WHEN** `get_status("12345678901", "2026-13-45")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` (month 13 / day 45 fail the roundtrip) + +### Requirement: Product invoice query by access key with downloads +`Nfe::Resources::ProductInvoiceQuery` SHALL expose `retrieve(access_key)`, `download_pdf(access_key)`, `download_xml(access_key)`, and `list_events(access_key)`, all keyed by a 44-digit access key normalised via `Nfe::IdValidator.access_key` and routed to `https://nfe.api.nfe.io` under API version `v2`. No company scope is required (read-only SEFAZ query). Download methods SHALL return raw bytes as a binary `String`. + +#### Scenario: Retrieve by access key +- **WHEN** `retrieve("35261234...44 digits...")` is called with a valid access key +- **THEN** the SDK SHALL issue `GET https://nfe.api.nfe.io/v2/productinvoices/{access_key}` and return a `ProductInvoiceDetails` value object hydrated from the response + +#### Scenario: Download PDF returns binary bytes +- **WHEN** `download_pdf(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v2/productinvoices/{access_key}.pdf` with `Accept: application/pdf` and return a binary `String` whose first four bytes are `%PDF` + +#### Scenario: Download XML returns binary bytes +- **WHEN** `download_xml(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v2/productinvoices/{access_key}.xml` with `Accept: application/xml` and return a binary `String` whose first non-BOM character is `<` + +#### Scenario: List events uses the events path +- **WHEN** `list_events(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v2/productinvoices/events/{access_key}` and return a `ProductInvoiceEventsResponse` + +#### Scenario: Access key with formatting normalised +- **WHEN** an access key is passed with spaces or dots +- **THEN** the SDK SHALL strip non-digit characters and validate the result has exactly 44 digits, raising `Nfe::InvalidRequestError` otherwise + +### Requirement: Consumer invoice query by access key +`Nfe::Resources::ConsumerInvoiceQuery` SHALL expose `retrieve(access_key)` returning a `TaxCoupon` and `download_xml(access_key)` returning a binary `String`, routed to `https://nfe.api.nfe.io` under API version `v1` with the `/coupon/` path segment. This resource is the **read-only NFC-e/CFe-SAT lookup by access key** and is distinct from the `consumer_invoices` emission resource defined in `add-invoice-resources` (which is company-scoped and routes to `https://api.nfse.io`). + +#### Scenario: Tax coupon retrieval +- **WHEN** `retrieve(access_key)` is called with a valid 44-digit access key +- **THEN** the SDK SHALL issue `GET https://nfe.api.nfe.io/v1/consumerinvoices/coupon/{access_key}` and return a `TaxCoupon` value object whose shape matches the Node SDK's canonical `TaxCoupon` (optional fields including `current_status`, `number`, `access_key`, `issued_on`, `issuer`, `buyer`, `totals`, `items`, `payment`) + +#### Scenario: Tax coupon XML download +- **WHEN** `download_xml(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v1/consumerinvoices/coupon/{access_key}.xml` with `Accept: application/xml` and return the raw XML bytes as a binary `String` + +#### Scenario: Distinct from consumer invoice emission +- **WHEN** a consumer needs to emit an NFC-e rather than query one +- **THEN** they SHALL use `client.consumer_invoices` (from `add-invoice-resources`, host `https://api.nfse.io`), NOT `client.consumer_invoice_query` (host `https://nfe.api.nfe.io`) + +### Requirement: Tax calculation with opaque request payload +`Nfe::Resources::TaxCalculation` SHALL expose `calculate(tenant_id, request)` returning a `CalculateResponse`. It SHALL `POST` to `/tax-rules/{tenant_id}/engine/calculate` (with `tenant_id` URL-encoded) on host `https://api.nfse.io`, forwarding `request` (a `Hash`) as the JSON body. The SDK SHALL validate only that `tenant_id` is non-empty, that `request` carries an `operation_type` (or `operationType`) field, and that `request[:items]` is a non-empty array; it SHALL NOT otherwise validate the request shape. + +#### Scenario: Minimal calculation request +- **WHEN** `calculate("tenant-123", { operation_type: "Outgoing", issuer: {...}, recipient: {...}, items: [{ id: "1", ... }] })` is called +- **THEN** the SDK SHALL POST the body as JSON to `/tax-rules/tenant-123/engine/calculate` and hydrate the response into a `CalculateResponse` + +#### Scenario: Empty items array rejected +- **WHEN** `calculate("tenant", { operation_type: "Outgoing", items: [] })` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Empty tenant id rejected +- **WHEN** `calculate("", request)` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +### Requirement: Tax codes listing with page-style pagination +`Nfe::Resources::TaxCodes` SHALL expose four parallel listing methods — `list_operation_codes`, `list_acquisition_purposes`, `list_issuer_tax_profiles`, and `list_recipient_tax_profiles` — each accepting `page_index:` (1-based) and `page_count:` keyword arguments, distinct from the cursor-style pagination used by `StateTaxes`. Each SHALL return a `TaxCodePaginatedResponse` carrying `current_page`, `total_pages`, `total_count`, and `items`. The paths SHALL be `/tax-codes/operation-code`, `/tax-codes/acquisition-purpose`, `/tax-codes/issuer-tax-profile`, and `/tax-codes/recipient-tax-profile` respectively, on host `https://api.nfse.io`. + +#### Scenario: Default pagination defers to the API +- **WHEN** `list_operation_codes` is called with no arguments +- **THEN** the request SHALL omit `pageIndex` and `pageCount`, deferring to the API defaults + +#### Scenario: Explicit 1-based pagination preserved +- **WHEN** `list_operation_codes(page_index: 2, page_count: 20)` is called +- **THEN** the request SHALL include `pageIndex=2` and `pageCount=20` (1-based preserved as the API expects) + +#### Scenario: Each method targets its own path +- **WHEN** `list_acquisition_purposes`, `list_issuer_tax_profiles`, or `list_recipient_tax_profiles` is called +- **THEN** the SDK SHALL issue the request to `/tax-codes/acquisition-purpose`, `/tax-codes/issuer-tax-profile`, or `/tax-codes/recipient-tax-profile` respectively + +### Requirement: State taxes full CRUD with body envelope +`Nfe::Resources::StateTaxes` SHALL expose `list`, `create`, `retrieve`, `update`, and `delete` for company state tax registrations (Inscrições Estaduais), routed to `https://api.nfse.io` under API version `v2`. `list` SHALL use cursor-style pagination (`starting_after:`, `ending_before:`, `limit:`). Both `create` and `update` SHALL wrap the request body as `{ stateTax: }` to match the canonical Node SDK envelope. `company_id` and `state_tax_id` SHALL be validated via `Nfe::IdValidator`. + +#### Scenario: Creating a state tax registration wraps the body +- **WHEN** `create(company_id, { tax_number: "123456789", serie: 1, number: 1, code: "SP" })` is called +- **THEN** the SDK SHALL `POST` to `https://api.nfse.io/v2/companies/{company_id}/statetaxes` with the body `{"stateTax": {"tax_number": "123456789", "serie": 1, ...}}` and return the created `NfeStateTax` + +#### Scenario: Updating wraps the body the same way +- **WHEN** `update(company_id, state_tax_id, { serie: 2 })` is called +- **THEN** the SDK SHALL `PUT` to `/v2/companies/{company_id}/statetaxes/{state_tax_id}` with body `{"stateTax": {"serie": 2}}` + +#### Scenario: Listing with cursor pagination +- **WHEN** `list(company_id, limit: 20)` is called +- **THEN** the SDK SHALL issue the `GET` and return an `Nfe::ListResponse` whose `page` carries the cursor metadata (`starting_after`/`ending_before`) and not `page_index` + +#### Scenario: Deletion returns nil +- **WHEN** `delete(company_id, state_tax_id)` succeeds against HTTP 200 or 204 +- **THEN** the method SHALL return `nil` without raising + +#### Scenario: Empty company id rejected before HTTP +- **WHEN** any `StateTaxes` method receives an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +### Requirement: DateNormalizer helper +The SDK SHALL provide `Nfe::DateNormalizer` with a `to_iso_date(input)` method returning a `YYYY-MM-DD` `String`. It SHALL accept ISO date strings and `Date`/`Time`/`DateTime` objects, dropping any time component, and SHALL raise `Nfe::InvalidRequestError` for malformed or out-of-range inputs and for unsupported types. It SHALL depend only on the Ruby standard library (`date`, `time`). + +#### Scenario: ISO string passthrough +- **WHEN** `Nfe::DateNormalizer.to_iso_date("1990-01-15")` is called +- **THEN** the method SHALL return `"1990-01-15"` + +#### Scenario: Date/Time object conversion drops the time +- **WHEN** `Nfe::DateNormalizer.to_iso_date(Time.new(1990, 1, 15, 12, 34, 56))` is called +- **THEN** the method SHALL return `"1990-01-15"` + +#### Scenario: Invalid format rejected +- **WHEN** `Nfe::DateNormalizer.to_iso_date("15/01/1990")` is called +- **THEN** the method SHALL raise `Nfe::InvalidRequestError` + +#### Scenario: Out-of-range string rejected +- **WHEN** `Nfe::DateNormalizer.to_iso_date("2026-13-45")` is called +- **THEN** the method SHALL raise `Nfe::InvalidRequestError` + +### Requirement: ID validators cover the lookup surface +`Nfe::IdValidator` SHALL expose `cep(value)`, `state(value)`, `cnpj(value)`, and `cpf(value)` validators in addition to the `company_id`, `state_tax_id`, and `access_key` validators provided by `add-client-core`. Each SHALL strip non-digit characters where appropriate, validate length (or membership for `state`), and return the normalised value, raising `Nfe::InvalidRequestError` (with a Portuguese-language message) on failure. + +#### Scenario: CEP normalisation +- **WHEN** `Nfe::IdValidator.cep("01310-100")` is called +- **THEN** the method SHALL return `"01310100"` (8 digits) + +#### Scenario: State validation rejects unknown codes +- **WHEN** `Nfe::IdValidator.state("ZZ")` is called with a code outside the 29-value set (27 UFs plus `EX` and `NA`) +- **THEN** the method SHALL raise `Nfe::InvalidRequestError` + +#### Scenario: Special state codes EX and NA accepted +- **WHEN** `Nfe::IdValidator.state("ex")` or `Nfe::IdValidator.state("na")` is called +- **THEN** the method SHALL return the uppercase code (`"EX"` / `"NA"`) without raising + +#### Scenario: CNPJ normalisation +- **WHEN** `Nfe::IdValidator.cnpj("12.345.678/0001-90")` is called +- **THEN** the method SHALL return `"12345678000190"` (14 digits) + +#### Scenario: CPF normalisation +- **WHEN** `Nfe::IdValidator.cpf("123.456.789-01")` is called +- **THEN** the method SHALL return `"12345678901"` (11 digits) + +### Requirement: Lookup responses are immutable value objects +Every response returned by a lookup resource (`AddressLookupResponse`, `LegalEntityBasicInfoResponse`, `LegalEntityStateTaxResponse`, `LegalEntityStateTaxForInvoiceResponse`, `NaturalPersonStatusResponse`, `ProductInvoiceDetails`, `ProductInvoiceEventsResponse`, `TaxCoupon`, `CalculateResponse`, `TaxCodePaginatedResponse`, `NfeStateTax`) SHALL be an immutable `Data.define` value object, hydrated from the response body. Where the OpenAPI generator covers the schema, the resource SHALL hydrate against the generated value object under `lib/nfe/generated/`; otherwise the SDK SHALL provide a hand-written value object under `lib/nfe/resources/dto//`. Generated files SHALL NOT be hand-edited. + +#### Scenario: Hydrating a retrieve response +- **WHEN** `Nfe::Resources::ProductInvoiceQuery#retrieve` succeeds against the API +- **THEN** the return value SHALL be an immutable `Data.define` value object (generated or hand-written) whose attributes are populated from the response body + +#### Scenario: Immutability of returned value objects +- **WHEN** consumer code attempts to mutate a returned value object's attribute +- **THEN** the attempt SHALL fail, because the value object is a frozen `Data.define` instance diff --git a/openspec/changes/archive/2026-06-25-add-lookup-resources/tasks.md b/openspec/changes/archive/2026-06-25-add-lookup-resources/tasks.md new file mode 100644 index 0000000..42c8c70 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-lookup-resources/tasks.md @@ -0,0 +1,131 @@ +# Tasks — add-lookup-resources + +> Plano greenfield para o SDK Ruby v1 (gem `nfe-io` 1.0.0). Todos os itens estão UNCHECKED. +> **Depende de add-client-core**: `Nfe::Configuration` (host map), `Nfe::Resources::AbstractResource` (`get`/`post`/`put`/`delete`/`download`/`hydrate`), `Nfe::IdValidator` base (`company_id`, `state_tax_id`, `access_key`), `Nfe::ListResponse`/`Nfe::ListPage`, accessores lazy no `Nfe::Client`, classes de erro (`Nfe::InvalidRequestError`, `Nfe::NotFoundError`, etc.). Transitivamente depende de **add-ruby-foundation**. +> Convenções: todo `.rb` começa com `# frozen_string_literal: true`; value objects são `Data.define`; keyword args; snake_case; zero dependências de runtime (só stdlib). Arquivos sob `lib/nfe/generated/` NUNCA são editados à mão. + +## 1. Suporte: extensão do IdValidator + DateNormalizer + +- [x] 1.1 Estender `lib/nfe/id_validator.rb` (módulo base de add-client-core) com `cep(value) -> String` — normaliza removendo não-dígitos, valida exatamente 8 dígitos; `raise Nfe::InvalidRequestError` com mensagem pt-BR se vazio ou comprimento != 8. +- [x] 1.2 Adicionar `state(value) -> String` — `strip` + `upcase`; valida contra o conjunto das 29 UFs (`AC AL AM AP BA CE DF ES GO MA MG MS MT PA PB PE PI PR RJ RN RO RR RS SC SE SP TO` + `EX` + `NA`); retorna a UF maiúscula; `raise` para qualquer outro código. +- [x] 1.3 Adicionar `cnpj(value) -> String` — remove não-dígitos, valida 14 dígitos; retorna normalizado; `raise` se vazio/comprimento errado. +- [x] 1.4 Adicionar `cpf(value) -> String` — remove não-dígitos, valida 11 dígitos; retorna normalizado; `raise` se vazio/comprimento errado. +- [x] 1.5 Confirmar reuso de `access_key` (44 dígitos), `company_id`, `state_tax_id` de add-client-core — não redefinir; só consumir. +- [x] 1.6 Criar `lib/nfe/date_normalizer.rb` — módulo `Nfe::DateNormalizer` com `to_iso_date(input) -> String`: aceita `String` (regex `/\A\d{4}-\d{2}-\d{2}\z/` + roundtrip `Date.iso8601` que rejeita mês/dia fora de faixa) e `Date`/`Time`/`DateTime` (via `strftime("%Y-%m-%d")`, descartando hora); `raise Nfe::InvalidRequestError` para formato inválido, data fora de faixa ou tipo inesperado. `require "date"`/`"time"` da stdlib. +- [x] 1.7 Assinaturas RBS: `sig/nfe/id_validator.rbs` (cep/state/cnpj/cpf) e `sig/nfe/date_normalizer.rbs` (`to_iso_date: (String | Date | Time | DateTime) -> String`). +- [x] 1.8 Specs: `spec/nfe/date_normalizer_spec.rb` (string passthrough, conversão de `Date`/`Time`, formato inválido `15/01/1990`, fora de faixa `2026-13-45`, tipo inesperado) + estender `spec/nfe/id_validator_spec.rb` (cep com/sem hífen, comprimento errado, state lower→upper, `EX`/`NA` aceitos, `ZZ` rejeitado, cnpj/cpf com pontuação normalizados). + +## 2. AddressesResource + +- [x] 2.1 Criar `lib/nfe/resources/addresses.rb` — `class Nfe::Resources::Addresses < Nfe::Resources::AbstractResource`; `api_family` → `:addresses`; `api_version` → `""` (o `/v2` está na base URL `address.api.nfe.io/v2`). +- [x] 2.2 `lookup_by_postal_code(postal_code) -> AddressLookupResponse` — `cep = Nfe::IdValidator.cep(postal_code)`; `GET /addresses/#{cep}`. +- [x] 2.3 `search(filter: nil) -> AddressLookupResponse` — `GET /addresses` com query `{ "$filter" => filter }` quando `filter` presente; repassa opaco (sem parser OData). +- [x] 2.4 `lookup_by_term(term) -> AddressLookupResponse` — rejeita `term` vazio/whitespace (`raise Nfe::InvalidRequestError`); `GET /addresses/#{CGI.escape(term.strip)}`. +- [x] 2.5 Value object `AddressLookupResponse` — checar `lib/nfe/generated/` (spec `consulta-endereco`); se ausente, criar `Data.define` hand-written em `lib/nfe/resources/dto/addresses/address_lookup_response.rb` (`addresses:` lista de `Address` com `street`, `street_suffix`, `postal_code`, `city`, `state`, etc.). +- [x] 2.6 RBS `sig/nfe/resources/addresses.rbs`. +- [x] 2.7 Spec `spec/nfe/resources/addresses_spec.rb` — assertiona host de saída `https://address.api.nfe.io/v2`; CEP com hífen → path `/addresses/01310100`; CEP comprimento inválido → `Nfe::InvalidRequestError` sem HTTP; `search` repassa `$filter`; term vazio rejeitado. + +## 3. LegalEntityLookupResource + +- [x] 3.1 Criar `lib/nfe/resources/legal_entity_lookup.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:legal_entity` (host `https://legalentity.api.nfe.io`); paths usam `/v2/legalentities/...`. +- [x] 3.2 `get_basic_info(federal_tax_number, update_address: nil, update_city_code: nil) -> LegalEntityBasicInfoResponse` — `cnpj = Nfe::IdValidator.cnpj(...)`; monta query só com os opts não-nil; `GET /v2/legalentities/basicInfo/#{cnpj}`. +- [x] 3.3 `get_state_tax_info(state, federal_tax_number) -> LegalEntityStateTaxResponse` — `state = Nfe::IdValidator.state(...)`, `cnpj = Nfe::IdValidator.cnpj(...)`; `GET /v2/legalentities/stateTaxInfo/#{state}/#{cnpj}`. +- [x] 3.4 `get_state_tax_for_invoice(state, federal_tax_number) -> LegalEntityStateTaxForInvoiceResponse` — `GET /v2/legalentities/stateTaxForInvoice/#{state}/#{cnpj}`. +- [x] 3.5 `get_suggested_state_tax_for_invoice(state, federal_tax_number) -> LegalEntityStateTaxForInvoiceResponse` — `GET /v2/legalentities/stateTaxSuggestedForInvoice/#{state}/#{cnpj}`. +- [x] 3.6 Value objects — checar `lib/nfe/generated/` (spec `consulta-cnpj`); hand-written em `lib/nfe/resources/dto/legal_entity_lookup/` onde o gen não cobrir (`LegalEntityBasicInfoResponse { legal_entity: ... }`, `LegalEntityStateTaxResponse`, `LegalEntityStateTaxForInvoiceResponse`). +- [x] 3.7 RBS `sig/nfe/resources/legal_entity_lookup.rbs`. +- [x] 3.8 Spec `spec/nfe/resources/legal_entity_lookup_spec.rb` — host de saída `https://legalentity.api.nfe.io`; CNPJ com pontuação `12.345.678/0001-90` → `12345678000190`; state lower `sp` → `SP` no path; state inválido `XX` → `Nfe::InvalidRequestError` sem HTTP; opts `update_address`/`update_city_code` viram query params. + +## 4. NaturalPersonLookupResource + +- [x] 4.1 Criar `lib/nfe/resources/natural_person_lookup.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:natural_person` (host `https://naturalperson.api.nfe.io`); paths `/v1/naturalperson/...`. +- [x] 4.2 `get_status(federal_tax_number, birth_date) -> NaturalPersonStatusResponse` — `cpf = Nfe::IdValidator.cpf(...)`, `date = Nfe::DateNormalizer.to_iso_date(birth_date)` (aceita `String`|`Date`|`Time`|`DateTime`); `GET /v1/naturalperson/status/#{cpf}/#{date}`. +- [x] 4.3 Value object `NaturalPersonStatusResponse` — hand-written `Data.define` em `lib/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rb` (`name`, `federal_tax_number`, `birth_on`, `status`, `created_on`, todos opcionais) — spec de CPF é esparso. +- [x] 4.4 RBS `sig/nfe/resources/natural_person_lookup.rbs`. +- [x] 4.5 Spec `spec/nfe/resources/natural_person_lookup_spec.rb` — host `https://naturalperson.api.nfe.io`; CPF formatado `123.456.789-01` → digits-only; `birth_date` como `String` ISO e como `Date` produzem o mesmo path; formato inválido `15/01/1990` → `Nfe::InvalidRequestError`; data fora de faixa `2026-13-45` → `Nfe::InvalidRequestError`. + +## 5. ProductInvoiceQueryResource + +- [x] 5.1 Criar `lib/nfe/resources/product_invoice_query.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:nfe_query` (host `https://nfe.api.nfe.io`); paths internos com prefixo `/v2/productinvoices`. +- [x] 5.2 `retrieve(access_key) -> ProductInvoiceDetails` — `key = Nfe::IdValidator.access_key(...)`; `GET /v2/productinvoices/#{key}`. +- [x] 5.3 `download_pdf(access_key) -> String` — `download("/v2/productinvoices/#{key}.pdf", accept: "application/pdf")`; retorna `String` binária (`%PDF...`). +- [x] 5.4 `download_xml(access_key) -> String` — `download("/v2/productinvoices/#{key}.xml", accept: "application/xml")`; retorna `String` binária (`<...`). +- [x] 5.5 `list_events(access_key) -> ProductInvoiceEventsResponse` — `GET /v2/productinvoices/events/#{key}`. +- [x] 5.6 Value objects — checar `lib/nfe/generated/` (spec `consulta-nf`); hand-written `ProductInvoiceDetails` e `ProductInvoiceEventsResponse { events:, created_on: }` em `lib/nfe/resources/dto/product_invoice_query/` se o gen não cobrir. +- [x] 5.7 RBS `sig/nfe/resources/product_invoice_query.rbs`. +- [x] 5.8 Spec `spec/nfe/resources/product_invoice_query_spec.rb` — host `https://nfe.api.nfe.io`; access key com espaços/pontos → 44 dígitos; `123` → `Nfe::InvalidRequestError`; download manda `Accept` correto e retorna bytes; path de download usa sufixo `.pdf`/`.xml`. + +## 6. ConsumerInvoiceQueryResource + +> Consulta de NFC-e por chave de acesso (CFe-SAT). **Distinto** de `consumer_invoices` (emissão NFC-e) de **add-invoice-resources** — host e versão diferentes. Cross-reference no comentário/RBS. + +- [x] 6.1 Criar `lib/nfe/resources/consumer_invoice_query.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:nfe_query` (mesmo host `https://nfe.api.nfe.io` que product query, mas paths `v1` + `/coupon/`). +- [x] 6.2 `retrieve(access_key) -> TaxCoupon` — `key = Nfe::IdValidator.access_key(...)`; `GET /v1/consumerinvoices/coupon/#{key}`. +- [x] 6.3 `download_xml(access_key) -> String` — `download("/v1/consumerinvoices/coupon/#{key}.xml", accept: "application/xml")`; retorna `String` binária. +- [x] 6.4 Value object `TaxCoupon` hand-written em `lib/nfe/resources/dto/consumer_invoice_query/tax_coupon.rb` — campos canônicos do Node (`current_status`, `number`, `sat_serie`, `software_version`, `software_federal_tax_number`, `access_key`, `cashier`, `issued_on`, `created_on`, `xml_version`, `issuer`, `buyer`, `totals`, `delivery`, `additional_information`, `items`, `payment`), todos opcionais. Sub-objetos (`CouponIssuer`, `CouponBuyer`, `CouponTotal`, `CouponDelivery`, `CouponAdditionalInformation`, `CouponItem`, `CouponPayment`) como `Data.define` aninhados quando referenciados. +- [x] 6.5 RBS `sig/nfe/resources/consumer_invoice_query.rbs`. +- [x] 6.6 Spec `spec/nfe/resources/consumer_invoice_query_spec.rb` — host `https://nfe.api.nfe.io`; path `v1` + `/coupon/`; access key normalizada; `download_xml` usa `.xml` no path e retorna bytes. + +## 7. TaxCalculationResource + +- [x] 7.1 Criar `lib/nfe/resources/tax_calculation.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:cte` (host `https://api.nfse.io`); `api_version` → `""` (paths começam em `/tax-rules`). +- [x] 7.2 `calculate(tenant_id, request) -> CalculateResponse` — validação local: `tenant_id` não vazio, `request` com `operation_type`/`operationType` presente e `items` array não vazio; `raise Nfe::InvalidRequestError` senão; `POST /tax-rules/#{CGI.escape(tenant_id.strip)}/engine/calculate` com `request` como body JSON. +- [x] 7.3 `request` aceita `Hash`; comentário/RBS recomendam `Nfe::Generated::CalculoImpostosV1::CalculateRequest#to_h` para type-safety. +- [x] 7.4 Value object `CalculateResponse` — checar `lib/nfe/generated/` (spec `calculo-impostos`); hand-written em `lib/nfe/resources/dto/tax_calculation/calculate_response.rb` se ausente (`items:` com breakdown ICMS/PIS/COFINS/IPI/II + `cfop`). +- [x] 7.5 RBS `sig/nfe/resources/tax_calculation.rbs`. +- [x] 7.6 Spec `spec/nfe/resources/tax_calculation_spec.rb` — host `https://api.nfse.io`; path `/tax-rules/{tenant}/engine/calculate` com tenant URL-encodado; `tenant_id` vazio → `Nfe::InvalidRequestError` sem HTTP; `items: []` → `Nfe::InvalidRequestError`; body enviado como JSON. + +## 8. TaxCodesResource + +- [x] 8.1 Criar `lib/nfe/resources/tax_codes.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:cte` (host `https://api.nfse.io`); `api_version` → `""` (paths `/tax-codes/...`). +- [x] 8.2 `list_operation_codes(page_index: nil, page_count: nil) -> TaxCodePaginatedResponse` — `GET /tax-codes/operation-code` com query 1-based (`pageIndex`/`pageCount`) só quando presentes. +- [x] 8.3 `list_acquisition_purposes(page_index: nil, page_count: nil)` — `GET /tax-codes/acquisition-purpose`. +- [x] 8.4 `list_issuer_tax_profiles(page_index: nil, page_count: nil)` — `GET /tax-codes/issuer-tax-profile`. +- [x] 8.5 `list_recipient_tax_profiles(page_index: nil, page_count: nil)` — `GET /tax-codes/recipient-tax-profile`. +- [x] 8.6 Value object `TaxCodePaginatedResponse` hand-written em `lib/nfe/resources/dto/tax_codes/tax_code_paginated_response.rb` (`current_page`, `total_pages`, `total_count`, `items` de `TaxCode { code, description }`). Page-style 1-based — documentar que difere do cursor das outras listas. +- [x] 8.7 RBS `sig/nfe/resources/tax_codes.rbs`. +- [x] 8.8 Spec `spec/nfe/resources/tax_codes_spec.rb` — host `https://api.nfse.io`; default omite `pageIndex`/`pageCount`; explícito `page_index: 2, page_count: 20` aparece na query (1-based preservado); os 4 paths corretos. + +## 9. StateTaxesResource (CRUD) + +- [x] 9.1 Criar `lib/nfe/resources/state_taxes.rb` — `< Nfe::Resources::AbstractResource`; `api_family` → `:cte` (host `https://api.nfse.io`); base path `/v2/companies/#{company_id}/statetaxes`. +- [x] 9.2 `list(company_id, starting_after: nil, ending_before: nil, limit: nil) -> Nfe::ListResponse` — `Nfe::IdValidator.company_id(...)`; cursor-style; `GET` base path com query dos cursores presentes; `ListPage` carrega cursores (não `page_index`). +- [x] 9.3 `create(company_id, data) -> NfeStateTax` — envelopa body como `{ stateTax: data }`; `POST` base path. +- [x] 9.4 `retrieve(company_id, state_tax_id) -> NfeStateTax` — `Nfe::IdValidator.state_tax_id(...)`; `GET base/#{state_tax_id}`. +- [x] 9.5 `update(company_id, state_tax_id, data) -> NfeStateTax` — envelopa `{ stateTax: data }`; `PUT base/#{state_tax_id}`. +- [x] 9.6 `delete(company_id, state_tax_id) -> nil` — `DELETE base/#{state_tax_id}`; retorna `nil` (200/204). +- [x] 9.7 Value object `NfeStateTax` — checar `lib/nfe/generated/` (spec `contribuintes-v2`/`nf-produto-v2`); hand-written em `lib/nfe/resources/dto/state_taxes/nfe_state_tax.rb` se ausente (`id`, `tax_number`, `serie`, `number`, `code`, `environment_type`, `type`, `status`). +- [x] 9.8 RBS `sig/nfe/resources/state_taxes.rbs`. +- [x] 9.9 Spec `spec/nfe/resources/state_taxes_spec.rb` — host `https://api.nfse.io`; `create` envia `{"stateTax": {...}}`; `update` idem; `list` cursor-style (`ListPage` com cursores); `delete` retorna `nil`; validação de `company_id`/`state_tax_id` vazios → `Nfe::InvalidRequestError` sem HTTP. + +## 10. Integração com o Client (accessores lazy) + +- [x] 10.1 Confirmar que os 8 accessores snake_case estão registrados no `Nfe::Client` (definidos em add-client-core): `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `product_invoice_query`, `consumer_invoice_query`, `tax_calculation`, `tax_codes`, `state_taxes`. Esta change só provê as classes que esses accessores instanciam lazy. +- [x] 10.2 `require` dos 8 arquivos de recurso + `date_normalizer` no autoload de `lib/nfe.rb` (ou no manifesto que add-client-core usa). +- [x] 10.3 Spec de fumaça em `spec/nfe/client_spec.rb` (estende o de add-client-core): cada um dos 8 accessores devolve a classe correta e roteia para o host esperado quando um método é chamado com transporte mockado. + +## 11. Type-check, lint e cobertura + +- [x] 11.1 `steep check` — 0 erros para os arquivos novos (`lib/nfe/resources/*.rb`, `date_normalizer.rb`, extensão de `id_validator.rb` + RBS correspondentes). +- [x] 11.2 `rubocop` — sem ofensas; todo `.rb` com `# frozen_string_literal: true`. +- [x] 11.3 `rspec` — todos os specs desta change verdes. +- [x] 11.4 SimpleCov — cobertura >= 80% mantida com os novos arquivos. +- [x] 11.5 `openspec validate add-lookup-resources` — passa. + +## 12. Documentação + +- [x] 12.1 README — adicionar os 8 recursos à tabela de acessores com 1-liner cada (pt-BR), destacando a seção "Roteamento multi-host" (hosts dedicados). +- [x] 12.2 Comentários/YARD em cada método público com exemplo idiomático Ruby (paridade com o JSDoc do Node, em pt-BR onde fizer sentido). +- [x] 12.3 Nota explícita de cross-reference: `consumer_invoice_query` (consulta por chave) vs `consumer_invoices` (emissão, de add-invoice-resources). + +## 13. Smoke test manual (opt-in, fora do CI) + +- [ ] 13.1 CEP lookup `01310-100` retorna Av. Paulista — DEFERRED (precisa chave de dados). +- [ ] 13.2 CNPJ basicInfo lookup — DEFERRED. +- [ ] 13.3 CPF status (cpf + birth_date) — DEFERRED. +- [ ] 13.4 Tax calculation operação simples — DEFERRED. +- [ ] 13.5 Tax codes paginação 1-based — DEFERRED. +- [ ] 13.6 Product invoice query + download_pdf (bytes `%PDF`) — DEFERRED. +- [ ] 13.7 Consumer invoice query (coupon) + download_xml — DEFERRED. +- [ ] 13.8 State taxes CRUD end-to-end — DEFERRED. +- [ ] 13.9 Registrar resultados em `.notes/lookup-smoke-results.md` — DEFERRED. diff --git a/openspec/changes/archive/2026-06-25-add-openapi-pipeline/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-openapi-pipeline/README.md b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/README.md new file mode 100644 index 0000000..370cd24 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/README.md @@ -0,0 +1,3 @@ +# add-openapi-pipeline + +Pipeline de codegen Ruby (stdlib + dev-only) que lê os specs OpenAPI sincronizados do nfeio-docs e emite value objects `Data.define` imutáveis em `lib/nfe/generated/` mais assinaturas `.rbs` em `sig/nfe/generated/`, com banner anti-edição, validação de spec e guarda de sincronia em CI (`rake generate` / `generate:check`). diff --git a/openspec/changes/archive/2026-06-25-add-openapi-pipeline/design.md b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/design.md new file mode 100644 index 0000000..b31106b --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/design.md @@ -0,0 +1,247 @@ +# Design — add-openapi-pipeline + +## Context + +A NFE.io publica os contratos da API como specs OpenAPI versionados em `nfeio-docs` (`docs/static/api/*.yaml`). Esse é o **source-of-truth** para o comportamento da API. Os SDKs irmãos já resolveram a geração de tipos a partir desses specs: + +- **Node**: `scripts/generate-types.ts` usa `openapi-typescript` (gera só types, não services) e escreve em `src/generated/`, um arquivo por spec, com banner anti-edição e namespace derivado do filename (`nf-servico-v1` → `NfServico`). +- **PHP**: `scripts/generate.php` + `scripts/Generator/*` é um codegen custom (deps dev-only `symfony/yaml` + `nikic/php-parser`) que emite `final readonly class` em `src/Generated//`, com `composer generate` / `generate:check` e job de CI `openapi-sync`. Gerou **415 arquivos em 10 namespaces** na execução real. + +Esta change traz o mesmo conceito para Ruby, adaptado a duas restrições herdadas de `add-ruby-foundation`: + +1. **Zero dependências de runtime** — o gem publicado (`nfe-io` 1.0.0) só pode depender da stdlib (`net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`). Logo o código gerado tem de ser Ruby puro de stdlib (`Data.define`), e as deps de geração ficam confinadas a um grupo dev-only do Gemfile. +2. **Rigor de tipo paralelo a Node (.d.ts) e PHP (PHPStan L8)** — o SDK Ruby entrega assinaturas RBS e checa com Steep no CI. Portanto o gerador precisa emitir **`.rb` E `.rbs` no mesmo passo**, não só os value objects. + +A decisão estratégica é a mesma de Node/PHP: **gerar tipos, não serviços**. A superfície hand-written (`Nfe::Client` Stripe-style com accessors lazy snake_case, polling de 202, paginadores, helpers de webhook, hidratação) é escrita à mão nas changes de recursos (`add-invoice-resources` e irmãs). O codegen entrega apenas os DTOs/enums tipados como matéria-prima. + +Caveat de recon importante: alguns specs são "esparsos" — `nf-servico-v1` deriva o `ServiceInvoice` de `operations[...]` (0 component schemas) e `cpf-api` não tem `components.schemas`. Esses não produzem namespace gerado; os DTOs faltantes ficam hand-written nas changes de recursos (mesmo padrão que o PHP adotou para `cpf-api-v3`). + +## Goals / Non-Goals + +**Goals** +- `scripts/generate.rb` ergonômico, idempotente, rápido, rodável com `ruby scripts/generate.rb` (sem Java, sem Node). +- Saída em `lib/nfe/generated//.rb` (value objects `Data.define` imutáveis) E `sig/nfe/generated//.rbs` (assinaturas espelhadas), 1 schema por arquivo. +- Banner `# AUTO-GENERATED — do not edit` + spec de origem + hash SHA-256 em todo arquivo gerado; primeira linha sempre `# frozen_string_literal: true`. +- Suporte a: `object` schemas, `enum`, `$ref` locais, `nullable`, `oneOf`/`allOf` simples, formatos básicos (`string`, `integer`, `number`, `boolean`, `date-time`). +- Namespaces nomeados pelas famílias de spec, mecanicamente (`NfServicoV1`, `NfProdutoV2`, `ConsultaCteV2`, `CalculoImpostosV1`, `ServiceInvoiceRtcV1`, `ProductInvoiceRtcV1`, etc.). +- Saída **determinística** — regenerar duas vezes produz bytes idênticos (pré-requisito do guard de CI). +- `rake generate` / `rake generate:check`; job de CI `openapi-sync` que falha PRs com drift. +- Mecanismo de sync-from-docs documentado (`rake openapi:sync` + seção no CONTRIBUTING.md). +- Zero dep de runtime: deps de geração só no grupo `:codegen` do Gemfile. + +**Non-Goals** +- Gerar clients, recursos, factories, polling, paginação ou HTTP — tudo hand-written nas changes de recursos. +- Gerar request/response builders mágicos. +- Suportar features avançadas de OpenAPI 3.1 (JSON Schema 2020-12 dialect completo). +- Fetch automático de specs da web — specs são versionados no repo após revisão manual. +- Watch mode de codegen. +- Resolver `$ref` cross-file — cada spec é self-contained. +- Conversão automática de `date-time` → `Time` no DTO (fica em helpers da camada de recursos). + +## Decisions + +### D1. Codegen custom em Ruby, não Java/Node +**Decisão**: `scripts/generate.rb` é Ruby puro, rodável com `ruby scripts/generate.rb`. + +**Por quê**: o desenvolvedor que pega este SDK conhece Ruby. Exigir Node (como o gerador do Node SDK exige) ou Java (openapi-generator-cli) só para regenerar tipos é hostil e quebra o "closed loop" — Ruby gera Ruby. Espelha a decisão do PHP (PHP gera PHP). + +**Alternativa rejeitada**: reaproveitar `openapi-typescript` + um transpiler. Acopla a toolchain Ruby a Node; descartado. + +### D2. Parser YAML: `psych` (stdlib), não gem externa +**Decisão**: usar `psych` (`require "psych"`), que é stdlib em Ruby 3.2+, como parser primário. + +**Por quê**: evita até a dependência dev-only de YAML que o PHP precisou (`symfony/yaml`). Psych é maduro, embarcado, suficiente para OpenAPI 3.x. Mantém o footprint de build mínimo. + +**Por quê não uma gem (ex.: `oas_parser`, `openapi3_parser`)**: deps pesadas e barrocas; o escopo é pequeno (objects, enums, refs); custom dá controle total. Espelha a rejeição do PHP a `jane-php/open-api` e `openapi-generator-cli`. + +**Risco**: alguns specs do docs vêm como `.json` (ex.: `consumer-invoice.json`, `contribuintes-v2.json`). Mitigação: normalizar JSON→YAML no `rake openapi:sync` OU o `SpecLoader` aceita ambos (`JSON.parse` para `.json`). Registrado em tasks §2.3. + +### D3. Emissão de código: template determinístico, não AST pesado +**Decisão**: emitir `.rb` e `.rbs` via template-string com normalização determinística (indentação fixa, ordenação estável). Avaliar `prism` (parser/emitter oficial Ruby 3.3+, dev-only) como reforço de formatação, mas a saída-alvo (`Data.define` anêmico + `module` de enum) é simples o bastante para template controlado. + +**Por quê**: o PHP precisou de `nikic/php-parser` porque emitir PHP com escapes/visibilidade/promotion à mão é frágil. O alvo Ruby aqui é muito mais simples — uma linha `Const = Data.define(:a, :b)` e constantes congeladas. Um template determinístico e bem testado é menos dependência e mais legível. A formatação consistente é garantida por testes de snapshot + idempotência. + +**Alternativa rejeitada**: gerar via `RuboCop -a` pós-emissão. Acopla a saída ao RuboCop e introduz não-determinismo entre versões; descartado. + +### D4. Saída dupla `.rb` + `.rbs` no mesmo passo +**Decisão**: cada schema gera DOIS arquivos — `lib/nfe/generated//.rb` (o `Data.define`) e `sig/nfe/generated//.rbs` (a assinatura). Ambos saem do mesmo modelo interno (`SchemaCompiler`) num único `generate`. + +**Por quê**: +- `add-ruby-foundation` exige RBS + Steep no CI; o tipo de um value object gerado precisa de assinatura RBS para a camada hand-written tipar contra ele. +- Gerar os dois do mesmo modelo elimina drift entre código e assinatura. +- O `generate:check` cobre os dois diretórios, então o CI pega divergência de qualquer um. + +**Alternativa rejeitada**: gerar só `.rb` e deixar RBS para `rbs prototype rb`. O protótipo do `rbs` produz `untyped` em massa (perde a riqueza do spec); descartado. + +### D5. Layout: módulo por família de spec, não por entidade +**Decisão**: +``` +lib/nfe/generated/nf_servico_v1/.rb -> Nfe::Generated::NfServicoV1:: +lib/nfe/generated/nf_produto_v2/.rb -> Nfe::Generated::NfProdutoV2:: +``` +em vez de achatar todos os schemas num único namespace. + +**Por quê**: schemas com nomes iguais aparecem em specs diferentes (`Address`, `Borrower`, `Company`). Módulo por família evita colisão. O nome do módulo vem do filename do spec (kebab→PascalCase + versão): `service-invoice-rtc-v1.yaml` → `ServiceInvoiceRtcV1`; o diretório usa snake_case (`service_invoice_rtc_v1`). Espelha a decisão D4 do PHP. + +### D6. `object` schema → `Data.define` imutável com keyword args +**Decisão**: cada schema `object` vira `Const = Data.define(:attr_a, :attr_b, ...)`. A hidratação (camada de recursos) constrói via keyword args. + +```ruby +# frozen_string_literal: true +# AUTO-GENERATED — do not edit +# Source: openapi/nf-servico-v1.yaml +# Hash: sha256:abcd... + +module Nfe + module Generated + module NfServicoV1 + # borrower (original: Borrower) + Borrower = Data.define( + :name, # String + :federal_tax_number, # Integer? (original: federalTaxNumber) + :email, # String? + ) do + # Hidrata a partir do payload da API: mapeia camelCase→snake_case, + # descarta chaves desconhecidas, recursa em refs aninhados. + def self.from_api(payload) + return nil if payload.nil? + new( + name: payload["name"], + federal_tax_number: payload["federalTaxNumber"], + email: payload["email"], + ) + end + end + end + end +end +``` + +**Por quê**: decisão canônica do projeto — "immutable Data.define value objects". `Data.define` é frozen por construção, gera `==`/`hash`/`deconstruct` de graça, e é stdlib puro (zero dep). Modelos anêmicos: sem lógica de negócio — o único método gerado é `from_api`, a hidratação determinística do payload (camel→snake, drop de chaves desconhecidas, recursão em objetos/arrays `$ref` via o `from_api` do DTO referenciado). A camada hand-written de recursos chama `klass.from_api(payload)`; o produtor do método e do `.rbs` correspondente é esta pipeline (GAP#7). + +**Alternativa rejeitada**: `Struct` mutável ou classe à mão com `attr_reader`. `Struct` é mutável (viola imutabilidade); classe à mão é verbosa. `Data.define` é o idioma Ruby 3.2+ correto. + +### D7. `enum` → módulo de constantes congeladas +**Decisão**: schema com `enum: [...]` vira um `module` de constantes: +```ruby +module FlowStatus + Issued = "Issued" + IssueFailed = "IssueFailed" + Cancelled = "Cancelled" + CancelFailed = "CancelFailed" + ALL = [Issued, IssueFailed, Cancelled, CancelFailed].freeze +end +``` + +**Por quê**: Ruby não tem enum nativo como PHP 8.1. Um módulo de constantes congeladas é zero-dep, idiomático, e dá `ALL` para iteração/validação. A camada de recursos (ex.: `FlowStatus` terminal-state helper de `add-invoice-resources`) consome essas constantes. + +**Alternativa rejeitada**: gem de enum (`ruby-enum`) — viola zero-dep. Símbolos soltos — perdem a lista canônica e o backing value. + +### D8. `nullable`/opcional → keyword arg com default `nil` + tipo RBS `T?` +**Decisão**: campo `nullable: true` ou não listado em `required` → tipo RBS `T?` e, no `Data.define`, o atributo aceita `nil` (a hidratação passa keyword default `nil`). Campos em `required: [...]` são tratados como obrigatórios na assinatura RBS. + +**Por quê**: nullability explícita; Steep pega quem esquecer. Fiel ao spec. + +**Nota**: `Data.define` em si não impõe required/optional em runtime; o rigor vive na assinatura RBS + na hidratação. O DTO gerado é anêmico e permissivo por construção; a tipagem estática é a guarda. + +### D9. `format: date-time` → `String`, não `Time` +**Decisão**: representar `date-time`/`date` como `String` no DTO gerado; a conversão para `Time` fica em helpers da camada de recursos. + +**Por quê**: a API retorna ISO 8601 timezone-aware. Auto-converter no DTO acopla parsing à geração e perde o wire format. Espelha a decisão D9 do PHP (lá: `string`, não `DateTimeImmutable`). `time` é stdlib, então o helper de cima fica trivial sem dep. + +### D10. `oneOf` simples → union RBS; complexo → `untyped` +**Decisão**: `oneOf` entre primitivos (`[integer, string]`) → union RBS `Integer | String` (o keyword arg Ruby aceita ambos naturalmente). `oneOf`/`anyOf` entre objetos, sem discriminator confiável → `untyped` com comentário `# oneOf: A | B`. + +**Por quê**: os specs da NFE.io raramente trazem `discriminator` confiável. Conservador por design: em dúvida, `untyped` em vez de quebrar o gerador. Espelha D8 do PHP (`mixed` para `oneOf` complexo). `allOf` faz merge raso das propriedades (composição). + +### D11. CI guard via `rake generate:check` +**Decisão**: `--check` gera em memória, compara com o checked-in em `lib/nfe/generated/` E `sig/nfe/generated/`, e sai com código não-zero se houver `added`/`removed`/`changed`. Job `openapi-sync` no CI roda isso. + +**Por quê**: PR que toca `openapi/*.yaml` sem regenerar não passa — força sincronia. Espelha D10 do PHP. O determinismo (D12) é o que torna o diff confiável. + +### D12. Saída determinística +**Decisão**: ordenar schemas e propriedades por nome; sem timestamp dentro do corpo comparado (o `generated_marker.rb` isola o `generated_at` e ele é normalizado/ignorado no check); ordenação de Hash explícita (não dependente de inserção do YAML). + +**Por quê**: o guard de CI só é confiável se "gerar duas vezes" produzir bytes idênticos. Qualquer não-determinismo gera falsos positivos de drift. + +### D13. Mapeamento de nome de spec → namespace +**Decisão**: kebab-case + sufixo de versão → PascalCase para o módulo, snake_case para o diretório/arquivo: +- `service-invoice-rtc-v1.yaml` → módulo `ServiceInvoiceRtcV1`, dir `service_invoice_rtc_v1` +- `consulta-cnpj-v3.yaml` → `ConsultaCnpjV3` / `consulta_cnpj_v3` +- `calculo-impostos-v1.yaml` → `CalculoImpostosV1` / `calculo_impostos_v1` + +**Por quê**: mecânico, determinístico, sem ambiguidade. Português nos nomes de spec é OK — tradução pt→en perderia info (specs originais são em pt). Espelha D12 do PHP. **Divergência consciente vs Node**: o Node SDK remove o sufixo de versão (`nf-servico-v1` → `NfServico`); aqui PRESERVAMOS a versão (`NfServicoV1`) para conviver com famílias multi-versão (v1/v2/v3 do mesmo domínio coexistem — ex.: `consulta-cnpj` numérico e `consulta-cnpj-v3` alfanumérico). + +### D14. Deps de geração isoladas em grupo dev-only do Gemfile +**Decisão**: tudo que a geração usa fica em `group :codegen do ... end` no Gemfile; `nfe-io.gemspec` não declara nenhum `add_dependency`. `bundle install --without codegen` produz ambiente de runtime limpo. + +**Por quê**: a regra canônica é zero dep de runtime. A geração é build-time. Confinar ao grupo `:codegen` garante que o gem publicado não arrasta nada. Como o parser preferido é `psych` (stdlib), o grupo `:codegen` pode até ficar quase vazio. + +### D15. Onde ficam DTOs não cobertos pelo gerador +**Decisão**: specs sem `components.schemas` (ex.: `nf-servico-v1` deriva de `operations[...]`, `cpf-api` sem schemas) não produzem namespace gerado. Os DTOs de response correspondentes ficam **hand-written** nas changes de recursos, em `lib/nfe/resources/dto//` (separado de `lib/nfe/generated/` para não conflitar com o guard de sincronia). + +**Por quê**: o gerador lê `components.schemas`; o que não está lá não é gerável. Forçar geração a partir de `operations[...]` (como o Node faz para derivar tipos de operação) é fora de escopo desta pipeline (que gera só DTOs de schema). Espelha a nota do PHP sobre `cpf-api-v3`. Registrado em tasks §10.7. + +### D16. Sync-from-docs é manual e revisado +**Decisão**: `rake openapi:sync` copia `nfeio-docs/static/api/*.{yaml,json}` para `openapi/`, mas NÃO faz commit nem regenera. O fluxo no CONTRIBUTING.md é: `sync` → revisar diff → `generate` → revisar `.rb`/`.rbs` → commit dos três juntos. + +**Por quê**: specs imperfeitos não podem entrar no SDK sem revisão humana. Fetch automático em build introduziria specs "broken" silenciosamente. Espelha a escolha do PHP ("não há fetch automático — escolha consciente"). O source-of-truth é nfeio-docs; o Node SDK está atrás dos docs (RTC e v3 ainda não estão no spec dir dele), então o Ruby sincroniza direto da fonte. + +### D17. Template RBS fixo para DTOs gerados + loader por `require_relative` explícito +**Decisão**: o `.rbs` de cada DTO segue um template fixo — `class < Data` com atributos tipados (reader por atributo), assinatura de construtor por keyword args, e a assinatura de `from_api`: +```rbs +# AUTO-GENERATED — do not edit +# Source: openapi/nf-servico-v1.yaml +# Hash: sha256:abcd... +module Nfe + module Generated + module NfServicoV1 + class Borrower < Data + attr_reader name: String + attr_reader federal_tax_number: Integer? + attr_reader email: String? + def self.new: (?name: String, ?federal_tax_number: Integer?, ?email: String?) -> instance + def self.from_api: (Hash[String, untyped] payload) -> instance + end + end + end +end +``` +O carregamento da árvore gerada é por **`require_relative` explícito**: o gerador emite, junto com a árvore, um arquivo `lib/nfe/generated.rb` que faz `require_relative` de cada arquivo gerado em ordem estável (refs antes dos consumidores quando possível; `Data.define` tolera referência tardia pois `from_api` só resolve no call-time). Sem autoload mágico. + +**Por quê**: o template RBS fixo garante que o `.rbs` espelha exatamente o `.rb` (mesmo modelo interno, D4), inclusive a assinatura de `from_api` (GAP#7), e mantém o output determinístico (D12). `require_relative` explícito é zero-dep, previsível, e amigável ao `generate:check` (a lista de requires é ela própria determinística e versionada); autoload (`Zeitwerk`/`autoload`) acoplaria carregamento a convenções de path e arriscaria não-determinismo no boot. + +**Alternativa rejeitada**: autoload via `Zeitwerk`. Adiciona dependência/convenção e esconde a ordem de carga; descartado em favor de `require_relative` explícito gerado. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| Codegen custom é manutenção própria | Escopo mínimo (objects, enums, refs, nullable, oneOf/allOf simples). Documentar patterns suportados no CONTRIBUTING.md | +| Specs OpenAPI da NFE.io são imperfeitos (`nullable` ausente, `oneOf` sem discriminator) | Gerador tolerante: em dúvida, `untyped` + comentário; nunca quebrar o pipeline silenciosamente | +| Specs sem `components.schemas` (`nf-servico-v1`, `cpf-api`) não geram DTOs | DTOs faltantes ficam hand-written em `lib/nfe/resources/dto/`; listados em `openapi/README.md` | +| Drift entre `.rb` e `.rbs` | Gerar ambos do mesmo modelo num único passo; `generate:check` cobre os dois diretórios | +| Não-determinismo na saída gera falso drift no CI | Ordenação estável + isolamento do `generated_at` no marker; teste de idempotência (gerar 2x → bytes idênticos) | +| Specs em `.json` (ex.: `contribuintes-v2.json`) | Normalizar JSON→YAML no sync OU `SpecLoader` aceita ambos via `JSON.parse` | +| Bytes commitados de `lib/nfe/generated/` poluem diffs de PR | `.gitattributes` `linguist-generated=true` em `lib/nfe/generated/**` e `sig/nfe/generated/**` | +| Nomes de schema em camelCase vindos do spec | `NameMapper#class_name`/`#attr_name` normaliza para idioma Ruby; nome original preservado em comentário para rastreabilidade | +| Cross-file `$ref` (não suportado) | Cada spec é self-contained; `$ref` externo → warning + `untyped`; não é caso real nos specs atuais | +| `Data.define` não impõe required em runtime | O rigor required/optional vive na assinatura RBS + Steep; o DTO gerado é anêmico por design | + +## Resolved (durante recon — 2026-06-24) + +### R1. Specs vivem em nfeio-docs `static/api/` +**Achado**: o conjunto de specs está em `docs/static/api/*.yaml` (símlink `client-ruby/nfeio-docs`), incluindo RTC (`service-invoice-rtc-v1.yaml`, `product-invoice-rtc-v1.yaml`) e Contribuintes v2 — exatamente o source-of-truth, à frente do spec dir do Node SDK. +**Decisão**: `rake openapi:sync` puxa daí; conjunto-base listado em tasks §2.2. + +### R2. Alguns specs não têm `components.schemas` +**Achado**: `nf-servico-v1.yaml` tem 0 component schemas (ServiceInvoice é derivado de `operations[...]`); `cpf-api.yaml` idem. O PHP marcou isso para `cpf-api-v3` (DTOs hand-written em c07). +**Decisão**: esses não geram namespace; DTOs faltantes ficam hand-written nas changes de recursos (D15). Registrado em tasks §2.4 e §10.7. + +### R3. PHP gerou 415 arquivos em 10 namespaces +**Achado**: a execução real do PHP (`composer generate`) produziu 415 arquivos em `CalculoImpostosV1`, `ConsultaCnpjV3`, `ConsultaCteV2`, `ConsultaDfeDistribuicaoV2`, `ConsultaNfConsumidorV3`, `ConsumerInvoiceV3`, `ContribuintesV2`, `ProductInvoiceRtcV1`, `ProductRegisterPtBrV1`, `ServiceInvoiceRtcV1`. +**Decisão**: ordem de grandeza esperada para o Ruby também (×2 por causa dos `.rbs`). Confirma a necessidade de `linguist-generated=true` e exclusão no RuboCop/Steep. + +### R4. Preservar sufixo de versão no namespace (vs Node) +**Achado**: o Node remove a versão (`NfServico`); famílias multi-versão coexistem (`consulta-cnpj` numérico + `consulta-cnpj-v3` alfanumérico do CNPJ alfanumérico de jul/2026). +**Decisão**: preservar versão (`NfServicoV1`, `ConsultaCnpjV3`) como o PHP faz, para evitar colisão entre versões do mesmo domínio (D13). diff --git a/openspec/changes/archive/2026-06-25-add-openapi-pipeline/proposal.md b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/proposal.md new file mode 100644 index 0000000..537eb44 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/proposal.md @@ -0,0 +1,66 @@ +# add-openapi-pipeline + +## Why + +A NFE.io é a **fonte da verdade** para o comportamento da API e publica os contratos como specs OpenAPI versionados em `nfeio-docs` (`docs/static/api/*.yaml`). Os SDKs Node (via `openapi-typescript`) e PHP (via codegen custom em `scripts/generate.php`) já provaram o conceito: **gerar tipos a partir dos specs, não escrever DTOs à mão**. Replicar dezenas de schemas manualmente em Ruby seria trabalho repetido e fonte garantida de divergência silenciosa quando a API evolui (RTC, CNPJ alfanumérico v3, Contribuintes v2, etc.). + +Esta change estabelece a pipeline de geração de código do SDK Ruby v1. Ela depende de `add-ruby-foundation` (que fixa gem `nfe-io` 1.0.0, namespace `Nfe`, piso Ruby 3.2, zero dependências de runtime, RBS/Steep/RuboCop/RSpec e a CI matrix 3.2/3.3/3.4). A pipeline produz a matéria-prima — value objects `Data.define` imutáveis e suas assinaturas `.rbs` — que os recursos hand-written (`add-invoice-resources` e changes irmãs) consomem. + +A escolha é deliberada e espelha Node e PHP: **gerar tipos, não serviços**. Os recursos (`Nfe::Client` + accessors lazy, polling de 202, paginadores, helpers de webhook) são hand-written para garantir ergonomia Stripe-like. O codegen entrega apenas os DTOs tipados. + +Restrição central herdada de `add-ruby-foundation`: **zero dependências de runtime**. O código gerado é Ruby puro de stdlib (`Data.define`); a geração em si é uma preocupação de **dev/build-time** e pode usar dependências dev-only confinadas a um grupo do Gemfile que nunca entra no gem publicado. + +## What Changes + +- **`scripts/generate.rb`** — script Ruby (não bash, não Java, não Node) que lê `openapi/*.yaml` e emite código em `lib/nfe/generated/` mais assinaturas em `sig/nfe/generated/`. Roda via `rake generate`. +- **Inventário de specs sincronizado do nfeio-docs** em `openapi/` deste repo — o mesmo conjunto de famílias que Node/PHP usam (NFS-e, NF-e, NFC-e, consultas, distribuição, CNPJ, CPF, endereço, cálculo de impostos, RTC, Contribuintes v2). Specs são versionados no repo; não há fetch automático em build. +- **Dev deps build-time** confinadas ao grupo `:codegen` do Gemfile (nunca em `add_dependency` do `.gemspec`): + - parser de YAML maduro — preferência por `psych` (já é stdlib em Ruby 3.2+ via `require "psych"`), eliminando dependência externa quando possível; fallback documentado para uma gem dev-only se um spec exigir features de YAML que o Psych não cobre. + - `prism` ou template-string com normalização determinística para emissão de Ruby legível (decisão registrada em design.md). +- **Layout de saída**: + ``` + lib/nfe/generated/ + nf_servico_v1/ + .rb # 1 Data.define por arquivo + nf_produto_v2/ + nf_consumidor_v2/ + consulta_cte_v2/ + ... # 1 módulo Ruby por família de spec + generated_marker.rb # constante com timestamp + hash dos specs de origem + sig/nfe/generated/ + nf_servico_v1/ + .rbs # assinatura RBS espelhando cada Data.define + ... + ``` +- **Namespaces nomeados pelas famílias de spec** (PascalCase a partir do filename kebab-case + sufixo de versão): `NfServicoV1`, `NfProdutoV2`, `NfConsumidorV2`, `ConsultaCteV2`, `ConsultaDfeDistribuicaoV2`, `CalculoImpostosV1`, `ConsultaCnpjV3`, `ServiceInvoiceRtcV1`, `ProductInvoiceRtcV1`, etc. Mapeamento mecânico e determinístico, sem tradução pt→en. +- **Banner anti-edição**: todo arquivo gerado (`.rb` e `.rbs`) começa com `# frozen_string_literal: true` seguido de `# AUTO-GENERATED — do not edit` + spec de origem + hash SHA-256. +- **Mapeamento de schema → Ruby idiomático**: `object` → `Data.define` imutável com keyword args; `enum` → módulo de constantes congeladas (`module X; A = "a"; ALL = [A].freeze; end`); `$ref` local → referência de classe na mesma família; `nullable`/opcional → keyword arg com default `nil`; `oneOf`/`allOf` mapeados conservadoramente (union de primitivos quando expressável, senão `Object`/`untyped` com comentário). +- **Hidratação `from_api` (GAP#7)**: cada `Data.define` gerado recebe um método de classe `from_api(payload)` que mapeia chaves camelCase→membros snake_case, descarta chaves desconhecidas e recursa em atributos `$ref` (objeto → `from_api` do DTO referenciado; array de `$ref` → `map` elemento a elemento). É o único método gerado no value object (modelo segue anêmico). O `.rbs` correspondente declara `def self.from_api`. O call site (`klass.from_api(payload)`) vive na camada hand-written de recursos, mas o produtor é esta pipeline. +- **Validação de spec**: o `SpecLoader` valida o YAML (parse OK, versão OpenAPI presente, `components.schemas` é mapa) e falha alto em spec quebrado em vez de emitir código corrompido. +- **Saída determinística**: ordenação estável de schemas e propriedades, banner sem timestamp variável dentro do corpo comparado, de modo que regenerar duas vezes produz bytes idênticos (pré-requisito para o guard de CI). +- **Rake tasks**: `rake generate` (escreve `lib/nfe/generated/` + `sig/nfe/generated/`) e `rake generate:check` (gera em memória/tmp, faz diff contra o checked-in, sai com código não-zero se houver drift). +- **Guard de CI "out-of-sync"**: job que roda `rake generate:check` e falha o PR se `openapi/*.yaml` mudou sem regenerar a saída. +- **Mecanismo de sync documentado**: `rake openapi:sync` (ou script equivalente) que copia/atualiza os YAMLs de `nfeio-docs` (`docs/static/api/`) para `openapi/` deste repo, mais a seção em `CONTRIBUTING.md` explicando o fluxo manual (revisão antes do commit). +- **RuboCop/Steep ignoram `lib/nfe/generated/` e `sig/nfe/generated/`** para análise estrita (gerado tolera shapes amplos), mantendo o rigor de tipo de `add-ruby-foundation` na superfície hand-written. +- **NÃO gera** clients, recursos, factories, polling, paginação ou qualquer surface acima de DTOs/enums — esses são hand-written nas changes de recursos. + +## Capabilities + +### New Capabilities +- `openapi-pipeline`: contrato de geração de value objects `Data.define` + enums + assinaturas RBS a partir dos specs OpenAPI sincronizados do nfeio-docs; layout `lib/nfe/generated/` + `sig/nfe/generated/`; política de não-edição manual; saída determinística; rake tasks `generate`/`generate:check`; guard de sincronia em CI; mecanismo de sync-from-docs documentado. + +### Modified Capabilities +- (nenhuma) — depende de `add-ruby-foundation`, mas não modifica sua spec; apenas a consome (toolchain RBS/Steep/RuboCop/CI matrix). + +## Impact + +- **Affected code**: `scripts/generate.rb` + `scripts/generator/*.rb` (loader, name_mapper, type_mapper, schema_compiler, enum_compiler, rbs_emitter, ruby_emitter, check_mode); `lib/nfe/generated/**` (gerado); `sig/nfe/generated/**` (gerado); `Rakefile` (tasks `generate`, `generate:check`, `openapi:sync`); `Gemfile` (grupo dev-only `:codegen`); `.github/workflows/ci.yml` (job `openapi-sync`); `openapi/*.yaml` (specs sincronizados); `CONTRIBUTING.md` (fluxo de sync); `.rubocop.yml` e `Steepfile` (exclusões de `lib/nfe/generated/`). +- **Build-time deps**: confinadas ao grupo `:codegen` do Gemfile; preferência por stdlib (`psych`, `digest`, `fileutils`). **Runtime deps: zero** — `lib/nfe/generated/**` é Ruby puro de stdlib (`Data.define`), sem `require` de gem externa. +- **Source of truth**: `nfeio-docs` (`docs/static/api/*.yaml`). `openapi/*.yaml` neste repo é uma cópia versionada e revisada (sync manual via `rake openapi:sync`), não um download automático em build. +- **Downstream**: `add-invoice-resources` e demais changes de recursos importam tipos de `Nfe::Generated::*` quando precisam de DTOs tipados; hidratam os `Data.define` a partir das respostas HTTP. +- **Spec impact**: adiciona a capability `openapi-pipeline`; não modifica `ruby-foundation`. +- **Dependencies**: depende de `add-ruby-foundation` (toolchain, namespace, piso Ruby, regra zero-dep, RBS/Steep/RuboCop/CI). +- **Risks**: + - Codegen custom é manutenção própria. Mitigação: escopo mínimo (objects, enums, refs, nullable, oneOf/allOf simples); quando em dúvida, gerar tipo amplo em vez de quebrar. + - Specs OpenAPI da NFE.io são imperfeitos (`nullable` ausente, `oneOf` sem discriminator, alguns sem `components.schemas` — ex.: `nf-servico-v1` deriva o ServiceInvoice de `operations[...]`, e `cpf-api` não tem schemas). O gerador deve ser tolerante e os DTOs faltantes ficam hand-written nas changes de recursos. + - Drift entre `lib/nfe/generated/` e `sig/nfe/generated/` — mitigado por gerar ambos no mesmo passo e cobrir os dois no `generate:check`. diff --git a/openspec/changes/archive/2026-06-25-add-openapi-pipeline/specs/openapi-pipeline/spec.md b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/specs/openapi-pipeline/spec.md new file mode 100644 index 0000000..15df45f --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/specs/openapi-pipeline/spec.md @@ -0,0 +1,215 @@ +# openapi-pipeline — Delta + +## ADDED Requirements + +### Requirement: A Ruby code generator reads OpenAPI specs and emits typed value objects +The SDK SHALL provide `scripts/generate.rb`, a Ruby script runnable as `ruby scripts/generate.rb` (no Node, Java, or external generator), that discovers every `*.yaml`/`*.json` spec under `openapi/`, loads each, compiles its `components.schemas`, and emits Ruby code under `lib/nfe/generated/` and matching RBS signatures under `sig/nfe/generated/`. + +The generator SHALL emit **types only** — value objects and enums — and SHALL NOT emit clients, resources, factories, HTTP code, polling, or pagination. Those are hand-written by the resource changes (depende de `add-ruby-foundation`; consumed by `add-invoice-resources`). + +#### Scenario: Running the generator +- **WHEN** a developer runs `ruby scripts/generate.rb` (or `rake generate`) against the `openapi/` directory +- **THEN** the generator SHALL write one `.rb` file per `object`/`enum` schema under `lib/nfe/generated//` and one matching `.rbs` file under `sig/nfe/generated//`, and SHALL print the count of files written + +#### Scenario: Types only, no service surface +- **WHEN** the generator finishes +- **THEN** no client, resource, factory, HTTP, polling, or pagination code SHALL appear under `lib/nfe/generated/` — only `Data.define` value objects, enum constant modules, and the generated marker + +### Requirement: Generation has zero runtime dependencies +The generated code under `lib/nfe/generated/` SHALL be pure Ruby standard library (`Data.define`, frozen constants) with no `require` of any external gem. All generation-time dependencies SHALL be confined to a dev-only `:codegen` Gemfile group and SHALL NOT appear as `add_dependency` in `nfe-io.gemspec`. + +#### Scenario: Published gem carries no codegen dependency +- **WHEN** the gem is installed for runtime use (e.g., `bundle install --without codegen`) +- **THEN** the generated value objects SHALL load and function with only the Ruby standard library, and no codegen dependency SHALL be present + +#### Scenario: YAML parsing uses the standard library +- **WHEN** the generator parses a spec file +- **THEN** it SHALL use `psych` from the Ruby standard library (Ruby 3.2+) as the primary YAML parser, avoiding an external YAML gem + +### Requirement: Generated value objects are immutable Data.define classes +Each OpenAPI `object` schema SHALL be emitted as an immutable `Data.define` value object in the namespace `Nfe::Generated::`, with one attribute per schema property and snake_case attribute names. Generated models SHALL be anemic — attributes only, no business logic. + +#### Scenario: Object schema becomes a Data.define +- **WHEN** the generator processes an `object` schema named `Borrower` with properties `name` and `federalTaxNumber` +- **THEN** it SHALL emit `Nfe::Generated::::Borrower = Data.define(:name, :federal_tax_number, ...)` whose instances are frozen, with the original property name preserved in a comment + +#### Scenario: camelCase property maps to snake_case attribute +- **WHEN** a property is named `federalTaxNumber` in the spec +- **THEN** the generated `Data.define` attribute SHALL be `:federal_tax_number` and the original `federalTaxNumber` SHALL be recorded in a comment for hydration traceability + +### Requirement: Enum schemas become frozen constant modules +Each schema declaring `enum: [...]` SHALL be emitted as a Ruby `module` of frozen constants plus an `ALL` array, rather than loose symbols or an external enum gem. The generator SHALL support both String-backed and Integer-backed enums. + +#### Scenario: String enum +- **WHEN** the generator processes a schema with `enum: ["Issued", "Cancelled"]` +- **THEN** it SHALL emit a module exposing `Issued = "Issued"`, `Cancelled = "Cancelled"`, and `ALL = [Issued, Cancelled].freeze` + +#### Scenario: Non-enum schema returns no enum +- **WHEN** the enum compiler is given an `object` schema with no `enum` key +- **THEN** it SHALL return `nil` (the schema is compiled as a `Data.define` instead) + +### Requirement: Generator emits matching RBS signatures alongside Ruby code +For every generated `.rb` value object or enum module, the generator SHALL emit a matching `.rbs` signature under `sig/nfe/generated//` in the same pass, derived from the same internal model, so the hand-written surface can type-check against generated types with Steep (per `add-ruby-foundation`). + +#### Scenario: RBS mirrors the value object +- **WHEN** the generator emits `Nfe::Generated::NfServicoV1::Borrower = Data.define(...)` +- **THEN** it SHALL also emit `sig/nfe/generated/nf_servico_v1/borrower.rbs` declaring the class, its typed attributes, and the constructor signature + +#### Scenario: No drift between code and signature +- **WHEN** a property's type or nullability changes in the spec and the generator is re-run +- **THEN** both the `.rb` attribute and the `.rbs` type SHALL update together (single internal model), with no manual `.rbs` edit required + +### Requirement: Each generated DTO carries a from_api hydration class method +The generator SHALL emit a `from_api(payload)` class method on every generated `Data.define` value object. `from_api` SHALL map camelCase JSON keys from the API payload to the value object's snake_case members, SHALL drop unknown keys (keys with no matching member), and SHALL recurse into nested object and array attributes — hydrating each referenced (`$ref`) object into its own DTO via that DTO's `from_api`, and each element of a `$ref` array into the item DTO. Primitive and free-form (`Hash`) attributes SHALL be assigned as-is. `from_api` SHALL be the only generated method on the otherwise anemic value object (no business logic). The generator SHALL emit a matching `.rbs` signature for `from_api`. + +The `from_api` call site lives in the hand-written resource/client layer (`klass.from_api(payload)`), but the producer of the method and its `.rbs` is this pipeline. + +#### Scenario: camelCase payload keys map to snake_case members +- **WHEN** `from_api({"federalTaxNumber" => 123, "name" => "Acme"})` is called on a DTO with members `:federal_tax_number` and `:name` +- **THEN** it SHALL return an instance with `federal_tax_number == 123` and `name == "Acme"` + +#### Scenario: Unknown payload fields are dropped +- **WHEN** the payload contains a key with no matching value-object member (e.g., a field the spec did not declare) +- **THEN** `from_api` SHALL ignore that key and construct the instance without raising, so payloads with extra/forward-compatible fields hydrate cleanly + +#### Scenario: Nested object attribute is hydrated into its DTO +- **WHEN** a DTO has an attribute typed as a `$ref` to another generated DTO and the payload supplies a nested object for it +- **THEN** `from_api` SHALL recurse, calling the referenced DTO's `from_api` on the nested object, so the attribute holds a hydrated DTO instance rather than a raw `Hash` + +#### Scenario: Nested array of refs is hydrated element-by-element +- **WHEN** a DTO has an attribute typed as an array of a `$ref` item type and the payload supplies an array of objects +- **THEN** `from_api` SHALL map each element through the item DTO's `from_api`, yielding an `Array` of hydrated DTO instances + +#### Scenario: from_api signature is emitted in RBS +- **WHEN** the generator emits a value object with `from_api` +- **THEN** the matching `.rbs` SHALL declare a `def self.from_api: (Hash[String, untyped] payload) -> instance` signature so the hand-written layer type-checks the hydration call + +### Requirement: Type mapping translates OpenAPI types to idiomatic Ruby and RBS +The generator SHALL map OpenAPI schema fragments to Ruby attributes and RBS types as follows: `string`→`String`, `integer`→`Integer`, `number`→`Float`, `boolean`→`bool`, free-form `object`→`Hash[String, untyped]`, `array` with `items`→`Array[ItemType]`, local `$ref`→the referenced class name in the same family, `format: date-time`/`date`→`String`. When a schema is ambiguous, the generator SHALL fall back to `untyped` rather than fail. + +#### Scenario: Primitive and array mapping +- **WHEN** a property has `type: array` with `items: {type: string}` +- **THEN** the RBS type SHALL be `Array[String]` + +#### Scenario: Local ref resolution +- **WHEN** a property is `{$ref: "#/components/schemas/Address"}` +- **THEN** the type SHALL resolve to `Address` within the same family namespace + +#### Scenario: date-time stays a string +- **WHEN** a property has `format: date-time` +- **THEN** the generated type SHALL be `String` (conversion to `Time` is left to the resource layer) + +#### Scenario: Cross-file ref is unsupported +- **WHEN** a `$ref` points outside the current spec document +- **THEN** the generator SHALL emit `untyped` with a comment and a warning, never raising + +### Requirement: Nullable and optional properties produce nullable RBS types and nil defaults +A property marked `nullable: true`, or any property absent from the schema's `required` list, SHALL be emitted with an RBS type suffixed `?` and SHALL accept `nil`. Properties listed in `required: [...]` SHALL be typed as non-nullable in RBS. + +#### Scenario: Optional property +- **WHEN** a property `email` is not in `required` (or is `nullable: true`) +- **THEN** its RBS type SHALL be `String?` and the value object SHALL accept `nil` for it + +#### Scenario: Required property +- **WHEN** a property `name` is listed in `required` +- **THEN** its RBS type SHALL be non-nullable (`String`) + +### Requirement: oneOf and allOf are mapped conservatively +`oneOf` between primitive types SHALL be emitted as an RBS union (e.g., `Integer | String`). `oneOf`/`anyOf` between object types, lacking a reliable discriminator, SHALL be emitted as `untyped` with an explanatory comment. `allOf` SHALL be a shallow merge of the member schemas' properties. + +#### Scenario: oneOf of primitives +- **WHEN** a property has `oneOf: [{type: integer}, {type: string}]` +- **THEN** the RBS type SHALL be `Integer | String` + +#### Scenario: oneOf of objects +- **WHEN** a property has `oneOf` between two object schemas +- **THEN** the type SHALL be `untyped` with a comment such as `# oneOf: A | B`, and the generator SHALL NOT raise + +#### Scenario: allOf composition +- **WHEN** a schema uses `allOf` to compose two object members +- **THEN** the generated value object SHALL include the union of both members' properties (last writer wins on collision, with a warning) + +### Requirement: Every generated file carries a frozen-string header and AUTO-GENERATED banner +Every generated `.rb` file SHALL begin with `# frozen_string_literal: true` on the first line, followed by a banner `# AUTO-GENERATED — do not edit`, the source spec path, and a `sha256` hash of the source spec. Every generated `.rbs` file SHALL carry an equivalent comment banner. + +#### Scenario: Ruby header +- **WHEN** any `.rb` file is generated +- **THEN** its first line SHALL be `# frozen_string_literal: true` and the following comment lines SHALL include `# AUTO-GENERATED — do not edit`, `# Source: openapi/.yaml`, and `# Hash: sha256:` + +#### Scenario: RBS header +- **WHEN** any `.rbs` file is generated +- **THEN** it SHALL carry an equivalent `# AUTO-GENERATED — do not edit` comment banner with source and hash + +### Requirement: Namespaces are named after spec families deterministically +The generator SHALL derive the Ruby module name from the spec filename by converting kebab-case to PascalCase and preserving the version suffix (`v1`→`V1`), and the directory/file path by converting to snake_case. Portuguese spec names SHALL NOT be translated. + +#### Scenario: Namespace derivation +- **WHEN** the spec file is `service-invoice-rtc-v1.yaml` +- **THEN** the module SHALL be `Nfe::Generated::ServiceInvoiceRtcV1` and the directory SHALL be `lib/nfe/generated/service_invoice_rtc_v1/` + +#### Scenario: Version suffix is preserved +- **WHEN** both `consulta-cnpj.yaml` and `consulta-cnpj-v3.yaml` are present +- **THEN** they SHALL produce distinct namespaces `ConsultaCnpj` and `ConsultaCnpjV3` so multi-version families coexist without collision + +### Requirement: Generator output is deterministic +Running the generator twice over the same specs SHALL produce byte-identical output. Schemas and properties SHALL be ordered stably (by name), and no variable timestamp SHALL appear inside any file content that the sync guard compares. + +#### Scenario: Idempotent generation +- **WHEN** the generator is run twice in a row against unchanged specs +- **THEN** the second run SHALL produce files byte-identical to the first + +#### Scenario: Marker timestamp isolated from the diff +- **WHEN** `lib/nfe/generated/generated_marker.rb` records a `generated_at` timestamp +- **THEN** that timestamp SHALL be excluded or normalised in the sync-guard comparison so it never causes false drift + +### Requirement: A sync guard fails CI when generated output drifts from specs +The SDK SHALL provide `rake generate:check` (wrapping `ruby scripts/generate.rb --check`) that regenerates output in memory, diffs it against the committed files in both `lib/nfe/generated/` and `sig/nfe/generated/`, and exits non-zero if any file would be added, removed, or changed. A CI job `openapi-sync` SHALL run this check. + +#### Scenario: In sync +- **WHEN** `rake generate:check` runs and the committed generated files match the specs +- **THEN** it SHALL print an in-sync message and exit zero + +#### Scenario: Spec changed without regenerating +- **WHEN** an `openapi/*.yaml` spec is modified but `lib/nfe/generated/` (or `sig/nfe/generated/`) is not regenerated, and `rake generate:check` runs in CI +- **THEN** the check SHALL list the added/removed/changed files and exit non-zero, failing the PR + +#### Scenario: Both output trees are covered +- **WHEN** only an `.rbs` signature drifts from the spec while the `.rb` is in sync +- **THEN** the check SHALL still detect the drift and exit non-zero + +### Requirement: Specs are validated before code is emitted +The spec loader SHALL parse each spec, verify it is a YAML/JSON document declaring an OpenAPI/Swagger version, and treat `components.schemas` as a map. A broken spec SHALL raise loudly during generation rather than silently emitting corrupt code. A spec without `components.schemas` SHALL produce no namespace. + +#### Scenario: Broken spec fails fast +- **WHEN** a spec file is not parseable as a YAML/JSON document +- **THEN** the generator SHALL raise with a message naming the offending file, and SHALL NOT write partial output + +#### Scenario: Spec without schemas produces nothing +- **WHEN** a spec has no `components.schemas` (e.g., `nf-servico-v1.yaml` deriving its type from `operations[...]`, or `cpf-api.yaml`) +- **THEN** the generator SHALL skip it without error, and the missing DTOs SHALL be hand-written by the resource changes (not under `lib/nfe/generated/`) + +### Requirement: Specs are synced from nfeio-docs via a documented manual mechanism +The SDK SHALL provide `rake openapi:sync` that copies the spec set from nfeio-docs (`docs/static/api/*.{yaml,json}`, path configurable) into `openapi/`, normalising JSON to YAML where applicable, without committing or regenerating. `CONTRIBUTING.md` SHALL document the full flow: sync → review diff → `rake generate` → review generated output → commit specs and generated files together. nfeio-docs SHALL be documented as the source of truth. + +#### Scenario: Syncing specs +- **WHEN** `rake openapi:sync` runs with nfeio-docs available +- **THEN** it SHALL update `openapi/*.yaml` from the docs source and report the file diff, without committing or triggering generation + +#### Scenario: Documented sync workflow +- **WHEN** a contributor needs to refresh the API contract +- **THEN** `CONTRIBUTING.md` SHALL instruct them to run `rake openapi:sync`, review the diff, run `rake generate`, review `lib/nfe/generated/` and `sig/nfe/generated/`, and commit all three together + +### Requirement: Generated directories are excluded from strict lint and type checks +The generated trees `lib/nfe/generated/**` and `sig/nfe/generated/**` SHALL be excluded from strict RuboCop and Steep targets (generated code tolerates broad shapes), while the generated RBS signatures SHALL still be loaded so the hand-written surface type-checks against them. Generated paths SHALL be marked `linguist-generated=true` in `.gitattributes`. + +#### Scenario: RuboCop skips generated code +- **WHEN** RuboCop runs across the repository +- **THEN** files under `lib/nfe/generated/` SHALL be excluded from offenses while the hand-written surface remains strictly linted + +#### Scenario: Generated RBS still informs Steep +- **WHEN** Steep type-checks the hand-written resource layer that consumes a generated value object +- **THEN** the signatures under `sig/nfe/generated/` SHALL be loaded so the generated types are known, even though `lib/nfe/generated/` itself is not strictly checked + +#### Scenario: Generated diffs hidden on GitHub +- **WHEN** a PR regenerates `lib/nfe/generated/**` or `sig/nfe/generated/**` +- **THEN** `.gitattributes` SHALL mark those paths `linguist-generated=true` so the diffs are collapsed by default diff --git a/openspec/changes/archive/2026-06-25-add-openapi-pipeline/tasks.md b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/tasks.md new file mode 100644 index 0000000..194b9e5 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-openapi-pipeline/tasks.md @@ -0,0 +1,143 @@ +# Tasks — add-openapi-pipeline + +> Depende de `add-ruby-foundation` (gem `nfe-io` 1.0.0, namespace `Nfe`, piso Ruby 3.2, zero-dep de runtime, RBS/Steep/RuboCop/RSpec, CI matrix 3.2/3.3/3.4). Esta pipeline é consumida por `add-invoice-resources` e demais changes de recursos, que hidratam os `Data.define` gerados. +> +> **Status (2026-06-25): IMPLEMENTADO e verificado verde via Docker na matrix Ruby 3.2/3.3/3.4.** Gerador dev-only (`scripts/generator/*`, stdlib Psych/Digest, zero gem externa) + entry `scripts/generate.rb`; 18 specs sincronizados em `openapi/` (de `nfeio-docs`); `rake generate`/`generate:check`/`openapi:sync`; gerado em `lib/nfe/generated/**` (excluído de RuboCop/Steep-estrito, marcado `linguist-generated`) + sigs em `sig/nfe/generated/**` (validadas por `rbs validate`). Gate: rspec 213/0 (cobertura ~98%), rubocop 0, steep 0, rbs ok, **generate:check in-sync** — nos três Rubies. Geração real: **1100 arquivos, 11 namespaces** (7 specs sem `components.schemas` pulados). Bugs corrigidos na verificação: `class_name` agora capitaliza (constante válida p/ schemas camelCase); `$ref` resolve para o tipo real do alvo (primitivo→`Integer`, objeto→classe, enum/livre→`untyped`/`Hash`); primitivos top-level não viram mais `= Hash`; loader `lib/nfe/generated.rb` excluído do RuboCop. §1.3 (emissor): template-string determinístico, sem `prism` (zero dep). §11.2/§11.3 (CONTRIBUTING/MIGRATION) diferidos para `add-release-tooling`. + +## 1. Dependências dev-only (grupo :codegen) + +- [ ] 1.1 Adicionar grupo `:codegen` no `Gemfile` (ou `group :codegen do ... end`) com as deps de build-time; **garantir que nada disso entra no `nfe-io.gemspec`** (`add_dependency` permanece vazio — zero runtime dep). +- [ ] 1.2 Usar `psych` (stdlib em Ruby 3.2+) como parser YAML primário — `require "psych"`. Documentar que NÃO é dependência de gem externa. +- [ ] 1.3 Decidir o emissor de código: `prism` (parser/emitter oficial Ruby 3.3+, dev-only) OU template-string com normalização determinística (sem dep). Registrar a decisão final em design.md §D3 e aplicar consistentemente. +- [ ] 1.4 Verificar que `bundle install --without codegen` produz um ambiente de runtime sem nenhuma dep de geração (smoke do isolamento dev-only). + +## 2. Inventário de specs (sync do nfeio-docs) + +- [ ] 2.1 Criar diretório `openapi/` no repo. +- [ ] 2.2 Sincronizar o conjunto de specs de `nfeio-docs` (`docs/static/api/*.yaml`) para `openapi/`. Conjunto-base (mesmas famílias de Node/PHP): + - `nf-servico-v1.yaml` (NFS-e clássico, host api.nfe.io) + - `nf-produto-v2.yaml` (NF-e clássico, host api.nfse.io) + - `nf-consumidor-v2.yaml` (NFC-e, host api.nfse.io) + - `consulta-nf.yaml` (consulta NF-e por chave de acesso) + - `consulta-nf-consumidor.yaml` (consulta cupom NFC-e) + - `consulta-cte-v2.yaml` (inbound CT-e) + - `consulta-nfe-distribuicao-v1.yaml` (distribuição inbound NF-e v1) + - `consulta-dfe-distribuicao-v2.yaml` (distribuição inbound NF-e v2, mais nova) + - `consulta-cnpj.yaml` / `consulta-cnpj-v3.yaml` (CNPJ lookup; v3 = CNPJ alfanumérico) + - `cpf-api.yaml` / `cpf-api-v3.yaml` (CPF lookup) + - `consulta-endereco.yaml` / `consulta-endereco-v3.yaml` (CEP lookup) + - `calculo-impostos-v1.yaml` (motor de cálculo de impostos) + - `service-invoice-rtc-v1.yaml` (NFS-e RTC — Reforma Tributária, IBS/CBS/IS) + - `product-invoice-rtc-v1.yaml` (NF-e/NFC-e RTC) + - `contribuintes-v2.yaml` (Company Management unificado v2) + - `product-register-pt-br-v1.yaml` (catálogo de produtos) + - `nfeio.yaml` (Batch Processor / jobs / notificações) +- [ ] 2.3 Documentar quais specs vêm como JSON (ex.: `consumer-invoice.json`, `contribuintes-v2.json` existem no docs) e normalizar para YAML no sync, OU suportar `.json` no loader. Registrar decisão. +- [ ] 2.4 Anotar specs sem `components.schemas` (ex.: `nf-servico-v1` deriva schema de `operations[...]`; `cpf-api` sem schemas) — esses NÃO produzem namespace; os DTOs faltantes ficam hand-written nas changes de recursos. Listar em `openapi/README.md`. +- [ ] 2.5 Criar `openapi/README.md` registrando: fonte (nfeio-docs `docs/static/api/`), data do snapshot, e a regra "specs são copiados manualmente após revisão". + +## 3. Sync-from-docs (mecanismo documentado) + +- [ ] 3.1 Criar task `rake openapi:sync` que copia `nfeio-docs/static/api/*.{yaml,json}` (caminho configurável via env `NFEIO_DOCS_PATH`) para `openapi/`, normalizando JSON→YAML quando aplicável, e reportando o diff de arquivos. +- [ ] 3.2 `rake openapi:sync` NÃO faz commit nem dispara `generate` automaticamente — apenas atualiza os YAMLs para revisão humana. +- [ ] 3.3 Seção em `CONTRIBUTING.md`: "Como atualizar specs OpenAPI" — passos: `rake openapi:sync` → revisar diff → `rake generate` → revisar `lib/nfe/generated/` + `sig/nfe/generated/` → commit dos três (specs + .rb + .rbs) juntos. +- [ ] 3.4 Registrar que o source-of-truth é nfeio-docs e que o Node SDK está atrás dos docs (RTC e v3 ainda não estão no spec dir do Node) — o Ruby sincroniza direto dos docs. + +## 4. Estrutura do gerador + +- [ ] 4.1 Criar `scripts/generate.rb` com shebang `#!/usr/bin/env ruby`, `# frozen_string_literal: true`, parse de args (`--check`, `--spec `, `--verbose`), e require do diretório `scripts/generator/`. +- [ ] 4.2 Criar `scripts/generator/spec_loader.rb` — `Nfe::Build::SpecLoader`: lê YAML via Psych, valida shape mínimo (chave `openapi`/`swagger` presente, `components.schemas` é Hash), expõe `#schemas` (Hash nome→schema), `#path`, `#hash` (SHA-256 do conteúdo bruto via `Digest::SHA256`). Falha alta (`raise`) em spec quebrado. +- [ ] 4.3 Criar `scripts/generator/name_mapper.rb` — `Nfe::Build::NameMapper`: `namespace_from_spec("service-invoice-rtc-v1.yaml") => "ServiceInvoiceRtcV1"` (kebab→PascalCase, preserva `v1`→`V1`); `module_path_from_spec(...) => "service_invoice_rtc_v1"` (snake_case do filename, para diretório/require); `class_name(schema_name)` (defensivo: caracteres inválidos → `_`, prefixa `_` se começar com dígito); `attr_name(prop)` (camelCase/PascalCase do spec → snake_case idiomático Ruby). +- [ ] 4.4 Criar `scripts/generator/type_mapper.rb` — `Nfe::Build::TypeMapper`: schema-fragment → tipo RBS + nota. Mapeia primitivos (`string`→`String`, `integer`→`Integer`, `number`→`Float`, `boolean`→`bool`, `object` free-form→`Hash[String, untyped]`), `$ref` local→nome de classe na mesma família, `array`→`Array[T]`, `nullable`/opcional→`T?`, `oneOf` de primitivos→union RBS (`Integer | String`), `oneOf`/`allOf` complexos→`untyped` com comentário. Conservador: em dúvida, `untyped`. +- [ ] 4.5 Criar `scripts/generator/schema_compiler.rb` — `Nfe::Build::SchemaCompiler`: schema `object` → modelo interno de um `Data.define` (lista ordenada de `{ruby_name, original_name, ruby_type, rbs_type, nullable, required, doc}`). Required sem default; opcional com `= nil` (ou keyword default `nil`). +- [ ] 4.6 Criar `scripts/generator/enum_compiler.rb` — `Nfe::Build::EnumCompiler`: schema com `enum: [...]` → modelo de módulo de constantes congeladas; retorna `nil` se o schema não for enum. Suporta backing String e Integer; nomeia constantes a partir dos valores (PascalCase/UPPER_SNAKE) com colisão resolvida deterministicamente. +- [ ] 4.7 Criar `scripts/generator/ruby_emitter.rb` — `Nfe::Build::RubyEmitter`: modelo → string `.rb` (banner + `module Nfe; module Generated; module ; = Data.define(...) end end end`). Indentação e ordenação determinísticas. +- [ ] 4.8 Criar `scripts/generator/rbs_emitter.rb` — `Nfe::Build::RbsEmitter`: mesmo modelo → string `.rbs` (banner em comentário + `module Nfe; module Generated; module ; class ... end end end end`) com atributos tipados e assinatura do construtor `Data.define`. +- [ ] 4.9 Criar `scripts/generator/generator.rb` — `Nfe::Build::Generator`: orquestra (descobre specs em `openapi/`, carrega, compila, emite). `#generate => Hash[rel_path => contents]` (em memória, para check mode) cobrindo `.rb` E `.rbs`; `#write_to(lib_root, sig_root) => Array[paths]`. +- [ ] 4.10 Criar `scripts/generator/check_mode.rb` — `Nfe::Build::CheckMode.diff(generator, lib_root, sig_root) => {ok:, added:, removed:, changed:}`: compara saída esperada (em memória) com o checked-in nos dois diretórios; ordena listas; `ok` true só se vazio em todos. + +## 5. Compilação de tipos (regras de mapeamento) + +- [ ] 5.1 Primitivos: `string`→`String`, `integer`→`Integer`, `number`→`Float`, `boolean`→`bool` (RBS), `object` (free-form)→`Hash[String, untyped]`. +- [ ] 5.2 `nullable: true` (ou propriedade opcional não-required) → tipo RBS `T?` e keyword arg com default `nil` no `Data.define`. +- [ ] 5.3 `$ref` local (`#/components/schemas/Foo`) → resolve para `Foo` (mesma família/módulo). Cross-file `$ref` não suportado (cada spec é self-contained); logar warning e cair para `untyped`. +- [ ] 5.4 `format: date-time` / `date` → `String` (fiel ao wire ISO 8601; conversão para `Time` fica em helpers da camada de recursos, não no DTO gerado). +- [ ] 5.5 `array` com `items` → `Array[ItemType]`; sem `items` → `Array[untyped]`. +- [ ] 5.6 `oneOf` entre primitivos → union RBS (`Integer | String`); keyword arg Ruby aceita ambos. +- [ ] 5.7 `oneOf`/`anyOf` entre objetos → `untyped` com comentário `# oneOf: A | B` (sem discriminator confiável nos specs). +- [ ] 5.8 `allOf` → merge raso das propriedades dos membros (composição); colisão de propriedade resolve para o último membro com warning. +- [ ] 5.9 Required vs opcional: campos em `required: [...]` viram keyword args obrigatórios (sem default); demais ganham default `nil`. +- [ ] 5.10 Nomes de propriedade: spec frequentemente usa camelCase (`federalTaxNumber`); `Data.define` usa snake_case idiomático (`federal_tax_number`). O `RubyEmitter` registra o nome original em comentário para rastreabilidade; a hidratação (camada de recursos) faz o mapeamento camel→snake. +- [ ] 5.11 `additionalProperties` / objetos sem propriedades nomeadas → não gerar `Data.define` vazio; cair para alias `Hash[String, untyped]` com comentário. + +## 6. Layout de saída e banner + +- [ ] 6.1 `lib/nfe/generated//.rb` — 1 `Data.define` por arquivo, autoload-friendly. +- [ ] 6.2 `sig/nfe/generated//.rbs` — 1 assinatura por arquivo, espelhando 1:1 o `.rb`. +- [ ] 6.3 Banner em todo `.rb`: + ```ruby + # frozen_string_literal: true + # AUTO-GENERATED — do not edit + # Source: openapi/.yaml + # Hash: sha256: + ``` +- [ ] 6.4 Banner equivalente em todo `.rbs` (comentários `#`). +- [ ] 6.5 `lib/nfe/generated/generated_marker.rb` — `module Nfe; module Generated; MARKER = { generated_at: "...", specs: { "" => "sha256:..." } }.freeze; end; end`. O `generated_at` NÃO entra no corpo comparado pelo check mode (ou é normalizado), para manter determinismo. +- [ ] 6.6 Garantir `# frozen_string_literal: true` como primeira linha de TODO `.rb` gerado (regra de `add-ruby-foundation`). +- [ ] 6.7 Saída determinística: ordenar schemas e propriedades por nome; nenhuma fonte de não-determinismo (sem timestamp no corpo comparado, sem ordem de Hash dependente de inserção). + +## 7. Mapeamento para Ruby idiomático + +- [ ] 7.1 `object` schema → `Const = Data.define(:attr_a, :attr_b, ...)` com keyword constructor (Ruby `Data.define` aceita posicional E keyword; documentar uso keyword na hidratação). +- [ ] 7.2 Value objects imutáveis por construção (`Data.define` é frozen) — alinha com a decisão canônica "immutable Data.define value objects". +- [ ] 7.3 `enum` → `module ; ValueA = "a"; ValueB = "b"; ALL = [ValueA, ValueB].freeze; end` (constantes congeladas; sem dependência de runtime). RBS correspondente declara as constantes com seus tipos literais quando possível. +- [ ] 7.4 Namespaces: `module Nfe; module Generated; module ; ... end end end` — 1 família por spec, nome derivado mecanicamente (`NfServicoV1`, `NfProdutoV2`, `NfConsumidorV2`, `ConsultaCteV2`, `ConsultaDfeDistribuicaoV2`, `CalculoImpostosV1`, `ConsultaCnpjV3`, `ServiceInvoiceRtcV1`, `ProductInvoiceRtcV1`, `ContribuintesV2`, etc.). +- [ ] 7.5 Modelos anêmicos: apenas atributos imutáveis, sem lógica de negócio. O único método gerado é `from_api` (§7.7). Polling, downloads e demais helpers vivem nas changes de recursos. +- [ ] 7.6 `require` interno: cada arquivo gerado é self-contained (sem `require` de gem externa). **Decisão (D17): loader por `require_relative` explícito** — o gerador emite `lib/nfe/generated.rb` que faz `require_relative` de cada arquivo gerado em ordem estável; sem autoload mágico. +- [ ] 7.7 `from_api(payload)` em cada `Data.define` (GAP#7): mapeia chaves camelCase→membros snake_case, descarta chaves desconhecidas, recursa em atributos `$ref` (objeto → `from_api` do DTO referenciado; array de `$ref` → `map` elemento a elemento). Primitivos e `Hash` free-form atribuídos como estão. É o único método gerado no value object. Emitir a assinatura `.rbs` correspondente (`def self.from_api: (Hash[String, untyped] payload) -> instance`) no mesmo passo (template fixo de D17). + +## 8. Rake tasks + integração CI + +- [ ] 8.1 Adicionar no `Rakefile`: `task :generate` → `ruby scripts/generate.rb`; `namespace :generate { task :check => ... }` → `ruby scripts/generate.rb --check`. +- [ ] 8.2 Adicionar `task "openapi:sync"` (§3.1). +- [ ] 8.3 Job `openapi-sync` em `.github/workflows/ci.yml` (reutiliza a matrix/checkout de `add-ruby-foundation`): roda `bundle install` (com grupo `:codegen`) e `rake generate:check`; falha o PR se houver drift. +- [ ] 8.4 `.rubocop.yml`: `AllCops.Exclude` inclui `lib/nfe/generated/**/*` (gerado tolera shapes amplos; o lint estrito permanece na superfície hand-written). +- [ ] 8.5 `Steepfile`: `check "lib/nfe/generated"` excluído do alvo estrito OU configurado em nível mais frouxo; as assinaturas geradas em `sig/nfe/generated/` ainda são carregadas para que a camada hand-written tipe contra elas. +- [ ] 8.6 `.gitattributes`: `lib/nfe/generated/** linguist-generated=true` e `sig/nfe/generated/** linguist-generated=true` (esconde diffs gerados no GitHub). +- [ ] 8.7 Confirmar que `rake generate:check` cobre AMBOS os diretórios (`lib/nfe/generated/` e `sig/nfe/generated/`). + +## 9. Testes (RSpec) + +- [ ] 9.1 Fixture mínima `spec/fixtures/openapi/minimal.yaml` — exercita: `object` com required+opcional, `$ref`, `array` de `$ref`, `enum` string, `enum` integer, `nullable`, `oneOf` de primitivos, propriedade camelCase. +- [ ] 9.2 `spec/generator/spec_loader_spec.rb` — parse OK, validação de shape, `#schemas`, `#hash` estável, raise em YAML quebrado e em spec sem `components.schemas`. +- [ ] 9.3 `spec/generator/name_mapper_spec.rb` — `namespace_from_spec`, `module_path_from_spec`, `class_name` defensivo, `attr_name` camel→snake. +- [ ] 9.4 `spec/generator/type_mapper_spec.rb` — primitivos, `$ref`, `array`, `nullable`→`?`, `oneOf` primitivos→union, `oneOf` objetos→`untyped`, `date-time`→`String`. +- [ ] 9.5 `spec/generator/schema_compiler_spec.rb` — required sem default, opcional com `nil`, ordenação estável, `allOf` merge, nome reservado. +- [ ] 9.6 `spec/generator/enum_compiler_spec.rb` — backing string/int, não-enum retorna `nil`, colisão de constante resolvida. +- [ ] 9.7 `spec/generator/ruby_emitter_spec.rb` — banner presente, `# frozen_string_literal: true` na linha 1, `Data.define` correto, `from_api` emitido, eval do output produz constante carregável. +- [ ] 9.7.1 `spec/generator/from_api_spec.rb` (GAP#7) — eval do DTO gerado e exercitar `from_api`: camelCase→snake_case, chave desconhecida descartada sem raise, objeto `$ref` aninhado hidratado no DTO, array de `$ref` mapeado elemento a elemento, `nil` tolerado. +- [ ] 9.8 `spec/generator/rbs_emitter_spec.rb` — banner, sintaxe RBS válida (parse via `rbs` se disponível), atributos espelham o `.rb`. +- [ ] 9.9 `spec/generator/generator_spec.rb` — `generate` retorna `.rb` + `.rbs`, `write_to` escreve nos dois diretórios, idempotência (gerar 2x → bytes idênticos). +- [ ] 9.10 `spec/generator/check_mode_spec.rb` — sem drift→`ok:true`; arquivo alterado→`changed`; arquivo faltante→`added`; arquivo extra→`removed`. +- [ ] 9.11 Cobertura SimpleCov >= 80% no diretório `scripts/generator/` (alinhado ao piso de `add-ruby-foundation`). + +## 10. Execução real (geração inicial) + +- [x] 10.1 `rake generate` rodado contra os specs sincronizados — **1100 arquivos** (550 `.rb` + 549 `.rbs` + loader + marker), **11 namespaces** (docker 3.2/3.3/3.4). +- [x] 10.2 Amostrado `ServiceInvoiceRtcV1`/`ProductInvoiceRtcV1`/`NfProdutoV2`/`NfConsumidorV2` — banner, namespace, `Data.define` + `from_api`, e `.rbs` conferidos. +- [ ] 10.3 Commitar `openapi/*` + `lib/nfe/generated/**` + `sig/nfe/generated/**` no MESMO commit — **a critério do mantenedor (nada commitado ainda)**. +- [x] 10.4 `steep check` 0 erros (gerado ignorado do alvo estrito, sigs geradas carregadas) — docker 3.2/3.3/3.4. +- [x] 10.5 `rubocop` 0 ofensas (gerado + loader excluídos) — docker 3.2/3.3/3.4. +- [x] 10.6 `rake generate:check` → "Generated output is in sync" — docker 3.2/3.3/3.4. +- [x] 10.7 Specs sem `components.schemas` anotados (gerador loga; listados em `openapi/README.md`): `consulta-cnpj`, `consulta-endereco`, `consulta-nf-v3`, `consulta-nf`, `consumer-invoice.json`, `cpf-api`, `nf-servico-v1`. + +## 11. Documentação + +- [x] 11.1 `lib/nfe/generated/README.md` — explica geração, regeneração (`rake generate`) e a regra "não editar à mão". +- [ ] 11.2 `CONTRIBUTING.md` — fluxo de sync + patterns/limites OpenAPI — **DEFERRED para `add-release-tooling`** (dona do `CONTRIBUTING.md`). +- [ ] 11.3 Nota em `MIGRATION.md` (tipos agora em `Nfe::Generated::*`) — **DEFERRED para `add-release-tooling`** (consolidação da migração). + +## 12. Validação OpenSpec + +- [x] 12.1 `openspec validate add-openapi-pipeline --strict` passa. +- [x] 12.2 Referências cruzadas a `add-ruby-foundation` conferidas na prosa (proposal/design). diff --git a/openspec/changes/archive/2026-06-25-add-release-tooling/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-release-tooling/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-release-tooling/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-release-tooling/README.md b/openspec/changes/archive/2026-06-25-add-release-tooling/README.md new file mode 100644 index 0000000..4dfab53 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-release-tooling/README.md @@ -0,0 +1,3 @@ +# add-release-tooling + +Empacotamento, publicação no RubyGems, workflow de release no GitHub Actions, CHANGELOG/MIGRATION/README/CONTRIBUTING, samples runnable e a skill de IA `nfeio-ruby-sdk` que fecham a v1.0.0 do gem `nfe-io`. diff --git a/openspec/changes/archive/2026-06-25-add-release-tooling/design.md b/openspec/changes/archive/2026-06-25-add-release-tooling/design.md new file mode 100644 index 0000000..5a736a4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-release-tooling/design.md @@ -0,0 +1,139 @@ +# Design — add-release-tooling + +## Context + +Esta é a **última change da v1.0.0** do gem `nfe-io`. As changes irmãs já entregaram: + +- `add-ruby-foundation` — estrutura do gem, `# frozen_string_literal: true`, RuboCop, RSpec, SimpleCov, CI matrix Ruby 3.2/3.3/3.4, branch `master` (v1) e `0.x-legacy` (congelada). +- `add-http-transport` — `Net::HTTP` puro, retry/backoff, timeouts, downloads binários. +- `add-openapi-pipeline` — gerador OpenAPI → `Data.define` em `lib/nfe/generated/` + `.rbs` em `sig/`. +- `add-client-core` — `Nfe::Client.new(api_key:)`, accessors lazy, roteamento multi-host, hierarquia de erros, contrato 202 `Pending`/`Issued`, `FlowStatus`. +- `add-entity-resources`, `add-invoice-resources`, `add-rtc-invoice-emission`, `add-lookup-resources` — os 17 recursos. + +O que falta é **release engineering + documentação + skill de IA**. Nenhuma linha de runtime nova; o trabalho é tornar o SDK **instalável, migrável, avaliável, publicável e assistível por IA**. + +A peça de maior valor para o usuário final é o `MIGRATION.md` (separa "SDK pronto" de "SDK adotável"). Para o mantenedor é o par `release.sh` + `release.yml` (transforma o ritual frágil de release num único comando + gate de CI). Para integradores assistidos por IA é a skill `nfeio-ruby-sdk`. + +O `nfe-io.gemspec` legado ainda declara `rest-client`, Ruby 2.4.1 e metadados de 2017 — precisa de reescrita total, batendo com a decisão canônica de zero dependências de runtime. + +## Goals / Non-Goals + +**Goals** +- `nfe-io.gemspec` moderno: Ruby ≥ 3.2, **zero runtime deps**, metadados completos, MFA obrigatória, `sig/` empacotado, versão fonte-única em `Nfe::VERSION`. +- `CHANGELOG.md` (pt-BR, Keep a Changelog) e `MIGRATION.md` exaustivo v0.3.x → v1.0.0 cobrindo 100% dos recursos. +- `README.md` expandido + `CONTRIBUTING.md` (pt-BR). +- `samples/` com um script runnable por caso de uso primário. +- `scripts/release.sh` single-command com `--dry-run`. +- `.github/workflows/release.yml`: tag → CI completo (rspec + rubocop + steep + generate:check) → `gem build` → publicação no RubyGems via **trusted publishing (OIDC)** → GitHub Release com `.gem` + checksum SHA-256. +- Skill de IA `skills/nfeio-ruby-sdk/SKILL.md` + `references/`, modelada na do Node. +- Política RC + beta antes de qualquer GA. +- Atualizar a página viva existente `docs/desenvolvedores/bibliotecas/ruby.md` no `nfeio-docs` (remover snippet de webhook errado e exemplos `Nfe.api_key` v0.3; adicionar quickstart `Nfe::Client.new`; espelhar a estrutura das docs do Node). + +**Non-Goals** +- Benchmarks de performance (SDK é síncrono/blocking; sem base comparável útil). +- Telemetria/usage stats (privacidade; Stripe não tem; pular). +- Site de docs próprio (`nfeio-docs` é mantido pelo time; o SDK apenas linka). +- Tradução EN do MIGRATION na v1.0 (audiência primária é pt-BR, NF-e/NFS-e/NFC-e/CT-e são instrumentos fiscais brasileiros). +- Ferramenta de auto-upgrade (transform/rewriter v0.3.x → v1) — futuro se houver demanda. +- Novos recursos de SDK — fora de escopo desta change. + +## Decisions + +### D1. Zero dependências de runtime — gemspec sem `add_dependency` +**Decisão**: o `nfe-io.gemspec` v1 **não** declara nenhuma dependência de runtime; apenas `add_development_dependency` (rspec, rubocop, steep, rbs, simplecov, rake). `required_ruby_version >= 3.2`. + +**Por quê**: decisão canônica do projeto (apenas stdlib: `net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`). O legado dependia de `rest-client ~> 2.0.2`; removê-lo elimina cadeia transitiva e conflitos de versão no consumidor — vantagem competitiva igual à do SDK Node (zero deps). + +### D2. Versão como fonte única em `Nfe::VERSION` +**Decisão**: `lib/nfe/version.rb` é a única fonte da verdade. O gemspec faz `require_relative "lib/nfe/version"` e usa `Nfe::VERSION`; o `release.sh` reescreve essa constante; o `release.yml` lê a tag. + +**Por quê**: evita drift entre gemspec, tag git e RubyGems. Padrão idiomático Ruby (Bundler `gem` scaffold). Bump `0.3.2 → 1.0.0`. + +**Forma hífen vs ponto**: as tags git usam a forma com hífen (`vX.Y.Z`, `vX.Y.Z-rc.N`), mas `Nfe::VERSION` e o gem publicado usam a forma **pontilhada** (`X.Y.Z`, `X.Y.Z.rc.N`) — o RubyGems exige o ponto no prerelease. O `release.sh` escreve a forma pontilhada em `version.rb` e cria a tag com hífen; o `release.yml` deriva a versão pontilhada da tag e afirma que o gem construído bate (aborta em divergência). O cenário de Bundler/`~> 1.0` usa a forma pontilhada (`= 1.0.0.rc.1`) — mantido. + +### D3. Publicação via RubyGems trusted publishing (OIDC), não API key em secret +**Decisão**: o job `publish` do `release.yml` usa `permissions: id-token: write` + trusted publishing do RubyGems (token OIDC efêmero), sem `GEM_HOST_API_KEY` persistente. Fallback documentado: secret `RUBYGEMS_API_KEY` se OIDC não estiver configurado para o repo. + +**Por quê**: OIDC elimina credencial de longa duração no GitHub (superfície de ataque menor), espelha o estado-da-arte de supply-chain security e o trusted publishing do PyPI/npm. A vinculação repo↔gem é configuração one-time no RubyGems (ação admin), por isso o fallback fica documentado. + +**Alternativa rejeitada**: `gem push` manual no terminal do mantenedor — frágil, depende de MFA interativa, sem gate de CI. + +### D4. Release em duas peças: script local (prep) + workflow (publish) +**Decisão**: `scripts/release.sh` faz só a **preparação** local (bump de versão, rotação de CHANGELOG, commit, tag, push). A **publicação** acontece no `release.yml` disparado pelo push da tag. O script **nunca** faz `gem push`. + +**Por quê**: separa intenção (humano corta a tag) de execução (CI publica com gate verde e credencial OIDC). Se o CI falhar, a tag existe mas o gem não é publicado — rollback é deletar a tag e retag. Publicar do laptop pula o gate de CI e vaza credenciais. + +```yaml +# .github/workflows/release.yml +on: + push: + tags: ['v*'] +permissions: + contents: write # criar GitHub Release + id-token: write # OIDC para RubyGems trusted publishing +``` + +### D5. CI gate completo antes de publicar +**Decisão**: o job `verify` roda a matrix Ruby 3.2/3.3/3.4 com `rake spec` (SimpleCov ≥ 80%), `rubocop`, `steep check` e `rake generate:check`. `publish` tem `needs: verify`. + +**Por quê**: o SDK toca emissão fiscal. Publicar com tipo quebrado, lint sujo ou código gerado fora de sync é inaceitável. `generate:check` garante que `lib/nfe/generated/` e `sig/` refletem o `openapi/` commitado. + +### D6. Gem assinado/checksummed +**Decisão**: o `publish` gera `sha256sum nfe-io-X.Y.Z.gem` e anexa o `.gem` + `.sha256` ao GitHub Release. MFA obrigatória via `spec.metadata["rubygems_mfa_required"] = "true"`. + +**Por quê**: checksum permite verificação independente do artefato; MFA obrigatória protege a conta do gem. Assinatura criptográfica completa (cert chain `gem cert`) é opcional/futura — checksum + OIDC + MFA já cobrem o essencial sem fricção de gestão de chaves. + +### D7. Samples são scripts runnable, não snippets em docs +**Decisão**: cada sample é um arquivo Ruby executável (`ruby samples/x.rb`) que carrega `samples/config.rb` (lê env vars e instancia `$nfe`). Sample é demo de uso real, não template exaustivo. + +**Por quê**: snippets em docs apodrecem; samples rodam e quebram se a compatibilidade quebrar (smoke test embutido). Os downloads usam `File.binwrite` para reforçar o contrato de `String` binária. `.env` no `.gitignore`. + +### D8. MIGRATION.md com mapeamento completo + apêndices end-to-end +**Decisão**: além das tabelas classe/método, três apêndices: **vanilla** (script CLI), **Rails** (initializer + controller de webhook sobre `request.raw_post`), e referência a integradores. Cobre os 17 recursos. + +**Por quê**: a migração v0.3.x → v1 é um salto grande (global estático → instância; rest-client → stdlib; classes achatadas → 17 recursos snake_case). A audiência primária do SDK Ruby são scripts e apps Rails; cobrir esses cenários reduz a fricção da maioria da base. + +### D9. Webhook signature documentado com o esquema CORRETO +**Decisão**: README, MIGRATION e skill documentam `X-Hub-Signature` + **HMAC-SHA1** sobre os **bytes crus** do corpo, hex case-insensitive, prefixo `sha1=`, comparação timing-safe. Alertam explicitamente que o esquema antigo (`X-NFe-Signature` + SHA-256) presente em docs de distribuição está **errado** vs produção. + +**Por quê**: recon confirmou (probe em produção) que o esquema real é HMAC-SHA1 com `X-Hub-Signature`. Em Ruby: ler `request.raw_post` (Rails) / `request.body.read` (Rack) antes de parsear JSON, `OpenSSL::HMAC.hexdigest("SHA1", secret, body)`, comparar com `Rack::Utils.secure_compare` ou implementação timing-safe própria. Re-serializar o JSON quebra a verificação. + +### D10. Skill de IA espelha a do Node, adaptada a Ruby idiomático +**Decisão**: `skills/nfeio-ruby-sdk/SKILL.md` segue a estrutura da `nfeio-node-sdk` (front-matter com gatilhos, quickstart, resource map, padrões core, pitfalls, decision tree) + `references/*.md` segmentados. Adapta idiomas: `Promise`→retorno síncrono, `Buffer`→`String` binária, camelCase→snake_case, union types→classes `Pending`/`Issued`, `instanceof`→`is_a?`/`case/in`. + +**Por quê**: a skill do Node é a referência de padrões de SDK; manter paridade de estrutura facilita manutenção cruzada e dá ao agente um mapa idêntico ao das outras linguagens. + +### D11. Política RC + beta antes do GA +**Decisão**: a primeira `v1.0.0` é precedida de `v1.0.0-rc.1` (publicado como prerelease no RubyGems, fora do `latest`) e um período de beta; issue crítica → `rc.2` reinicia o relógio. Patches (`v1.0.1`) podem sair direto. + +**Por quê**: SDK fiscal — bug em emissão = nota fiscal errada = problema legal. Pré-releases no RubyGems não viram `latest` (consumidores precisam opt-in com `--pre`/`= 1.0.0.rc.1`), então o beta não afeta quem usa `~> 1.0` por engano. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| OIDC trusted publishing exige setup admin one-time no RubyGems | Fallback documentado: secret `RUBYGEMS_API_KEY` + `GEM_HOST_API_KEY` no job `publish` | +| Publicação no RubyGems é irreversível por versão (yank não apaga) | RC + beta antes do GA; `--dry-run` no release.sh; gate de CI obrigatório | +| Cobertura ≥ 80% pode forçar testes triviais em `Data.define` | `lib/nfe/generated/` excluído do denominador SimpleCov; value objects puros dispensam teste mecânico | +| `MIGRATION.md` completo é longo de manter | Aceito; é a referência canônica, versionada por tag (stale pós-release é aceitável) | +| Pré-release no RubyGems poluindo `latest` | Pré-releases (`-rc`/`-beta`) não são resolvidos por `~> 1.0`; só com opt-in explícito | +| `release.sh` em PowerShell/Windows | Linux/macOS apenas; dev Windows usa WSL. CONTRIBUTING explicita | +| Tag empurrada mas CI falha → gem não publicado | Esperado: rollback é deletar a tag e retag após corrigir; GitHub Release não é criado sem `verify` verde | +| Página de docs depende do time de `nfeio-docs` | Não bloqueia a release do gem; é tarefa coordenada e linkável depois | + +## Resolved (durante recon — 2026-06-24) + +### R1. Nome do gem e bump de versão +**Decisão**: nome `nfe-io` mantido (não renomear). Bump `0.3.2 → 1.0.0`. Greenfield: nada reaproveitado do código atual. Confirmado pelo mantenedor. + +### R2. Branch de legado +**Decisão**: `master` atual (v0.3.2, rest-client) vai para a branch `0.x-legacy` (congelada, sem manutenção). v1 é desenvolvida em `master`. CONTRIBUTING e MIGRATION documentam. + +### R3. Tradução EN fica fora da v1.0 +**Decisão**: README e MIGRATION em pt-BR. EN entra como feature futura se houver demanda concreta de integrador internacional. + +## Open Questions (precisam de decisão sua) + +- **Duração exata do período de beta** — 7 ou 14 dias para o `v1.0.0` GA? Tasks §12.3 deixa "mínimo definido na política"; cravar o número antes de cortar o `rc.1`. +- **Setup de OIDC no RubyGems** — quem tem acesso admin da conta `nfe-io` no RubyGems para vincular o repo `nfe/client-ruby` ao trusted publishing? Se indisponível na data, ativar o fallback `RUBYGEMS_API_KEY` (D3). +- **Janela da página de docs** — coordenar com o time de `nfeio-docs` se a página Ruby sai junto com o GA ou logo depois (Tasks §10). diff --git a/openspec/changes/archive/2026-06-25-add-release-tooling/proposal.md b/openspec/changes/archive/2026-06-25-add-release-tooling/proposal.md new file mode 100644 index 0000000..3bf2fd9 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-release-tooling/proposal.md @@ -0,0 +1,99 @@ +# add-release-tooling + +## Why + +As changes anteriores (`add-ruby-foundation`, `add-http-transport`, `add-openapi-pipeline`, `add-client-core`, `add-entity-resources`, `add-invoice-resources`, `add-rtc-invoice-emission`, `add-lookup-resources`) entregam o SDK **funcionalmente completo**: gem `nfe-io` com zero dependências de runtime, `Nfe::Client.new(api_key:)` estilo Stripe, 17 recursos snake_case, modelos `Data.define` gerados de OpenAPI, assinaturas RBS, Steep, RuboCop e RSpec com cobertura ≥ 80%. + +**Esta change fecha a release** — é a última do bump 0.3.2 → 1.0.0. Sem ela o SDK está pronto mas ninguém consegue: + +1. **Instalar** via `gem install nfe-io` / `bundle add nfe-io` — o `nfe-io.gemspec` legado ainda declara `rest-client` e metadados de 2017 (Ruby 2.4.1, autor antigo, homepage `pluga.co`). +2. **Migrar** do v0.3.x (global `Nfe.api_key("...")`, rest-client, classes achatadas) sem ler o código — falta um `MIGRATION.md` exaustivo. +3. **Avaliar** sem mergulhar no código — faltam `samples/` runnable e um `README.md` com quickstart por recurso. +4. **Cortar** uma release semver sem ritual manual frágil — falta o workflow `release.yml` (tag → CI → build → push gem) e o `CHANGELOG.md`. +5. **Confiar** que a publicação é segura — falta RubyGems trusted publishing (OIDC), gem assinado/checksummed e versão com fonte única de verdade. +6. **Pedir ajuda à IA** com código correto — falta a skill `skills/nfeio-ruby-sdk/SKILL.md`, espelhada na skill do Node. + +A política de release é conservadora porque o SDK toca **emissão fiscal** (bug = nota fiscal errada = problema legal): a primeira tag estável `v1.0.0` é precedida de pelo menos um `v1.0.0-rc.1` e um período de pré-lançamento mínimo antes do GA. + +Esta change não adiciona superfície de SDK — é **release engineering + documentação + skill de IA**. Depende de todas as changes irmãs estarem aplicadas e estáveis. + +## What Changes + +### Gemspec moderno + fonte única da versão + +- Reescrever `nfe-io.gemspec`: nome `nfe-io` (mantido), `required_ruby_version >= 3.2`, **sem `add_dependency`** (zero runtime deps), `add_development_dependency` para rspec/rubocop/steep/simplecov, metadados completos (`homepage`, `source_code_uri`, `changelog_uri`, `bug_tracker_uri`, `documentation_uri`, `rubygems_mfa_required => "true"`), `spec.files` via `git ls-files` excluindo `spec/`, `samples/`, `skills/`. +- `Nfe::VERSION` em `lib/nfe/version.rb` é a **fonte única de verdade**; o gemspec e o workflow leem dela. Subir de `0.3.2` para `1.0.0`. +- `spec.metadata["rubygems_mfa_required"] = "true"` e empacotar `*.rbs` em `sig/` no gem. + +### CHANGELOG.md (pt-BR, Keep a Changelog) + +- Formato [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/) + [SemVer](https://semver.org/lang/pt-BR/). +- Seção `[Não lançado]` no topo + entrada `[1.0.0] - AAAA-MM-DD` com a reescrita greenfield categorizada (`Adicionado`, `Alterado`, `Removido`, `Corrigido`). +- O `release.sh` rotaciona `[Não lançado]` → `[X.Y.Z]` na data do release. + +### MIGRATION.md exaustivo (pt-BR) v0.3.x → v1.0.0 + +- Tabela de instalação (`gem "nfe-io", "~> 0.3"` → `~> 1.0`). +- Requisito de Ruby (2.x → 3.2+). +- Configuração: global `Nfe.api_key("...")` (setter por método) e `Nfe.configure { |c| c.url = ... }` → `Nfe::Client.new(api_key:)` (instância, não estático) + roteamento multi-host automático + segunda chave `data_api_key:` + fallback de env vars (`NFE_API_KEY`/`NFE_DATA_API_KEY`, argumento explícito vence). +- Mapeamento de classes v0.3.x → recursos v1 (todos os 17 accessors snake_case). +- Mapeamento método-a-método por recurso (assinatura antiga → nova). +- `rest-client` removido — exceptions de rede agora são `Nfe::ApiConnectionError`/`Nfe::TimeoutError` (`TimeoutError < ApiConnectionError`) em vez de `RestClient::Exception`. +- Nova hierarquia de erros tipados (tabela completa `Nfe::Error` e subclasses por status HTTP). +- Contrato 202 discriminado (`Pending`/`Issued`) + polling manual via `FlowStatus`. +- Verificação de assinatura de webhook (`X-Hub-Signature` + HMAC-SHA1 sobre bytes crus). +- Downloads agora retornam `String` binária (`ASCII-8BIT`). +- Lista de recursos diferidos no v1.0 (`create_and_wait`, `create_batch`, upload de certificado multipart). +- Apêndices end-to-end: **script vanilla**, **Rails initializer**, e referência a integradores. + +### README.md expandido (pt-BR) + +- Badges (RubyGems version, CI, cobertura, licença), instalação, requisitos (Ruby 3.2+, zero deps). +- Quickstart `Nfe::Client.new(api_key:)`. +- Mapa de recursos: tabela dos 17 accessors → host → operações-chave (espelha a skill). +- 1-liner por recurso. +- Tratamento de erros, polling do contrato 202, configuração (timeout, retry, `data_api_key`), downloads binários, verificação de webhook. +- Seção "Versionamento" (semver + cadência RC) e link para `MIGRATION.md`. + +### CONTRIBUTING.md (pt-BR) + +- Política de branches: `master` (v1) ativo, `0.x-legacy` congelado. +- Setup local (Ruby 3.2, `bundle install`), toolchain (`rake spec`, `rubocop`, `steep check`, `rake generate:check`). +- Convenções: `# frozen_string_literal: true` em todo `.rb`, nunca editar `lib/nfe/generated/`, regenerar de OpenAPI. +- Workflow OpenSpec, commits semânticos, cadência de release (RC + período de beta). + +### samples/ runnable + +Um script Ruby executável por caso de uso primário (`ruby samples/.rb`), carregando `samples/config.rb` (lê env vars), com `samples/.env.example`, `samples/README.md` e `.env` no `.gitignore`. + +### .github/workflows/release.yml + scripts/release.sh + +- `release.yml` disparado por push de tag `v*`: roda **todo o CI** (rspec + rubocop + steep + `generate:check`) na matrix Ruby 3.2/3.3/3.4, depois `gem build`, **publica no RubyGems via trusted publishing (OIDC)**, anexa o `.gem` + checksum SHA-256 ao GitHub Release. +- `scripts/release.sh` interativo (`--dry-run`, `--skip-tests`, `--skip-git`): valida branch/working tree/CI, pede versão, atualiza `Nfe::VERSION`, rotaciona CHANGELOG, commit, tag anotada, push. + +### skills/nfeio-ruby-sdk/SKILL.md + references/ + +- Skill de IA modelada na `nfeio-node-sdk`: front-matter com gatilhos, quickstart, mapa de recursos, padrões (contrato 202, erros, paginação, downloads, webhook), pitfalls idiomáticos de Ruby, decision tree, e arquivos `references/*.md` segmentados. + +### Integração com nfeio-docs + +- **Atualizar** a página viva existente `docs/desenvolvedores/bibliotecas/ruby.md` no `nfeio-docs` (repo é a fonte de verdade): remover o snippet errado de webhook (`X-NFEIO-Signature` + Base64) e os exemplos `Nfe.api_key` v0.3, adicionar o quickstart `Nfe::Client.new(api_key:)` e espelhar a estrutura das docs do Node (`migracao`/`changelog`/`exemplos`), com link para README/MIGRATION. Tarefa coordenada com o time de docs. + +## Capabilities + +### New Capabilities +- `release-tooling`: gemspec + versão fonte-única, CHANGELOG, MIGRATION, README, CONTRIBUTING, samples, workflow de release (CI gate + RubyGems OIDC + gem assinado/checksummed), `release.sh`, skill `nfeio-ruby-sdk` e integração de docs. + +### Modified Capabilities +- Nenhuma. Esta change apenas **introduz** `release-tooling`; as capabilities funcionais permanecem como definidas pelas changes irmãs. (O banner de status no README é cosmético e coberto aqui, sem alterar requirements de outra capability.) + +## Impact + +- **Affected code/files**: `nfe-io.gemspec`, `lib/nfe/version.rb`, `CHANGELOG.md`, `MIGRATION.md`, `README.md`, `CONTRIBUTING.md`, `samples/*`, `scripts/release.sh`, `.github/workflows/release.yml`, `skills/nfeio-ruby-sdk/*`, `.gitignore`. +- **Spec impact**: cria a capability `release-tooling`. +- **Dependencies**: depende de `add-ruby-foundation`, `add-http-transport`, `add-openapi-pipeline`, `add-client-core`, `add-entity-resources`, `add-invoice-resources`, `add-rtc-invoice-emission` e `add-lookup-resources` — todas aplicadas e estáveis. Esta é a última change da v1. +- **Riscos**: + - Trusted publishing (OIDC) precisa de configuração one-time no RubyGems vinculando o repo GitHub; fallback documentado é `gem push` com API key em secret. + - Publicação no RubyGems é irreversível por versão (yank ≠ delete); mitigado por RC + beta antes do GA. + - `MIGRATION.md` completo é longo de manter; aceito como referência canônica versionada por tag. +- **Política de release**: a primeira tag estável `v1.0.0` SHALL ser precedida de pelo menos um RC e um período de beta. Capturado como requirement no spec. diff --git a/openspec/changes/archive/2026-06-25-add-release-tooling/specs/release-tooling/spec.md b/openspec/changes/archive/2026-06-25-add-release-tooling/specs/release-tooling/spec.md new file mode 100644 index 0000000..1840226 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-release-tooling/specs/release-tooling/spec.md @@ -0,0 +1,279 @@ +# release-tooling — Delta + +## ADDED Requirements + +### Requirement: Modern gemspec with zero runtime dependencies +The `nfe-io.gemspec` SHALL declare the gem name `nfe-io`, `required_ruby_version >= 3.2`, and SHALL NOT contain any runtime dependency (no `add_dependency`). It SHALL register only development dependencies (rspec, rubocop, steep, rbs, simplecov, rake). It SHALL set complete metadata including `homepage_uri`, `source_code_uri`, `changelog_uri`, `bug_tracker_uri`, `documentation_uri`, and `rubygems_mfa_required => "true"`. The packaged gem SHALL include the RBS signatures under `sig/`. + +This requirement implements the release of the SDK built by `add-ruby-foundation`, `add-http-transport`, `add-openapi-pipeline`, `add-client-core`, `add-entity-resources`, `add-invoice-resources`, `add-rtc-invoice-emission`, and `add-lookup-resources`. + +#### Scenario: Building the gem +- **WHEN** a maintainer runs `gem build nfe-io.gemspec` +- **THEN** the build SHALL produce `nfe-io-.gem` without warnings, and `gem spec nfe-io-.gem` SHALL report zero runtime dependencies + +#### Scenario: Adding a runtime dependency +- **WHEN** a contributor proposes adding any non-stdlib package to the gem's runtime dependencies +- **THEN** the proposal SHALL require an explicit decision in a new OpenSpec change, because the SDK is committed to Ruby standard library only + +#### Scenario: Installing on Ruby below 3.2 +- **WHEN** a user runs `gem install nfe-io` on Ruby 3.1 or earlier +- **THEN** RubyGems SHALL refuse installation with a `required_ruby_version` error + +#### Scenario: RBS shipped with the gem +- **WHEN** the gem is installed +- **THEN** the `sig/` directory containing the RBS signatures SHALL be present in the installed gem so consumers can type-check against it + +### Requirement: Version is a single source of truth +The constant `Nfe::VERSION` in `lib/nfe/version.rb` SHALL be the single source of truth for the gem version. The gemspec SHALL read the version from this constant, and the release tooling SHALL update only this constant when bumping the version. For the v1 release the version SHALL be `1.0.0` (a major bump from the legacy `0.3.2`). + +Git tags SHALL use the hyphenated prerelease form `vX.Y.Z` and `vX.Y.Z-rc.N`, but `Nfe::VERSION` and the published gem SHALL use the dotted prerelease form `X.Y.Z` and `X.Y.Z.rc.N` (RubyGems requires the dot). `scripts/release.sh` SHALL write the dotted form to `lib/nfe/version.rb` and create the hyphenated tag, and the release workflow SHALL assert that the built-gem version equals the dotted version derived from the tag. + +#### Scenario: Gemspec reads the constant +- **WHEN** `gem build nfe-io.gemspec` runs +- **THEN** the produced gem's version SHALL equal the value of `Nfe::VERSION`, with no version literal duplicated elsewhere + +#### Scenario: Frozen string literal header +- **WHEN** `lib/nfe/version.rb` is inspected +- **THEN** its first line SHALL be `# frozen_string_literal: true`, consistent with every `.rb` file in the project + +#### Scenario: Hyphenated tag, dotted gem version +- **WHEN** the release script cuts a release candidate tagged `v1.0.0-rc.1` +- **THEN** it SHALL write `Nfe::VERSION = "1.0.0.rc.1"` (dotted) to `lib/nfe/version.rb` and create the annotated tag `v1.0.0-rc.1` (hyphenated) + +#### Scenario: Workflow asserts version matches tag +- **WHEN** the release workflow runs for a pushed tag `vX.Y.Z-rc.N` +- **THEN** it SHALL derive the dotted version `X.Y.Z.rc.N` from the tag and assert the built-gem version (`Nfe::VERSION`) equals it, aborting the publish on any mismatch + +### Requirement: CHANGELOG following Keep a Changelog +The repository SHALL include `CHANGELOG.md` written in Brazilian Portuguese, following the Keep a Changelog format and Semantic Versioning. It SHALL contain an `[Não lançado]` section at the top and a `[1.0.0]` entry documenting the greenfield rewrite categorized into `Adicionado`, `Alterado`, and `Removido`. + +#### Scenario: Reading the changelog +- **WHEN** a user opens `CHANGELOG.md` +- **THEN** they SHALL find a `[1.0.0]` entry listing the new `Nfe::Client` API, the 17 resources, generated `Data.define` models, RBS signatures, the discriminated 202 contract, and the removal of the `rest-client` dependency and the global `Nfe.api_key` configuration + +#### Scenario: Changelog rotation on release +- **WHEN** the release script cuts version `X.Y.Z` +- **THEN** the `[Não lançado]` section SHALL be rotated into a dated `[X.Y.Z] - YYYY-MM-DD` heading + +### Requirement: Exhaustive migration guide from v0.3.x to v1.0.0 +The repository SHALL include `MIGRATION.md` in Brazilian Portuguese documenting the complete migration from v0.3.x to v1.0.0, including: + +- Gem version constraint change (`~> 0.3` → `~> 1.0`) +- Ruby version change (2.x → 3.2+) +- Configuration change from the global `Nfe.api_key("...")` setter method (and `Nfe.configure { |c| c.url = ... }`) to the instance `Nfe::Client.new(api_key:)`, the per-class `Nfe::ServiceInvoice.company_id("...")` pattern replaced by a per-call `company_id:` argument, plus automatic per-resource multi-host routing, the new `data_api_key:`, and `NFE_API_KEY`/`NFE_DATA_API_KEY` environment-variable fallback (explicit argument wins) +- Class-to-resource mapping for all 17 snake_case accessors +- Per-resource method mapping (old signature → new signature) +- Removal of the `rest-client` dependency and the resulting change from `RestClient::Exception` to the typed `Nfe::ApiConnectionError`/`Nfe::TimeoutError` hierarchy (`TimeoutError < ApiConnectionError`) +- The full typed error hierarchy table (`Nfe::Error` base with `AuthenticationError`, `AuthorizationError`, `InvalidRequestError`, `NotFoundError`, `ConflictError`, `RateLimitError`, `ServerError`, `ApiConnectionError`, `TimeoutError`, `SignatureVerificationError`, `ConfigurationError`, `InvoiceProcessingError`) +- The discriminated 202 `Pending`/`Issued` contract with a manual polling example +- Webhook signature verification migration +- Binary `String` downloads (`ASCII-8BIT`) +- The explicit list of features deferred from v1.0 +- End-to-end examples for vanilla scripts and Rails + +#### Scenario: A v0.3.x user migrating +- **WHEN** a developer using v0.3.x opens `MIGRATION.md` +- **THEN** they SHALL find a full mapping of their existing code to v1, plus at least one end-to-end example matching their integration pattern (vanilla script or Rails) + +#### Scenario: Looking up a deferred feature +- **WHEN** a developer searches the document for `create_and_wait`, `create_batch`, or certificate upload +- **THEN** they SHALL find the deferred-features section explaining the absence and the manual workaround (e.g., polling via `Nfe::FlowStatus.terminal?`) + +#### Scenario: Configuration migration +- **WHEN** a developer reads the configuration section +- **THEN** it SHALL show the v0.3.x global `Nfe.api_key("...")` setter method (and `Nfe.configure { |c| c.url = ... }`) replaced by `Nfe::Client.new(api_key: "...")`, the per-class `Nfe::ServiceInvoice.company_id("...")` replaced by a per-call `company_id:` argument, and SHALL explain that the base URL is no longer set globally but routed per resource + +#### Scenario: Environment-variable fallback +- **WHEN** a developer constructs `Nfe::Client.new` without an explicit `api_key:`/`data_api_key:` +- **THEN** the documentation SHALL show `Configuration` reading `NFE_API_KEY` and `NFE_DATA_API_KEY` from the environment as a fallback, with an explicit constructor argument taking precedence over the environment value + +### Requirement: Expanded README covering quickstart, resources, and patterns +The repository SHALL include an expanded `README.md` in Brazilian Portuguese covering installation, Ruby 3.2+ and zero-dependency requirements, a `Nfe::Client.new(api_key:)` quickstart, a resource map of all 17 accessors with host and key operations, a one-line example per resource, error handling, the 202 polling contract, configuration (timeout, retry, `data_api_key`, and `NFE_API_KEY`/`NFE_DATA_API_KEY` environment-variable fallback), a Sandbox vs Production section, binary downloads, and webhook signature verification. + +#### Scenario: Consumer evaluating the SDK +- **WHEN** a developer opens `README.md` +- **THEN** they SHALL find a copy-pasteable quickstart, a table of all 17 resources mapped to their hosts and operations, and a configuration section documenting `api_key`, `data_api_key`, `environment`, `timeout`, and `retry` + +#### Scenario: Environment-variable configuration +- **WHEN** a developer reads the configuration section +- **THEN** it SHALL document that `Configuration` reads `NFE_API_KEY` and `NFE_DATA_API_KEY` from the environment as a fallback, with an explicit constructor argument winning over the environment value + +#### Scenario: Sandbox vs Production +- **WHEN** a developer reads the Sandbox vs Production section +- **THEN** it SHALL explain that the `Nfe::Client.new` `environment:` symbol selects a credential/key (not a URL, since host routing stays automatic per resource), how to obtain test credentials, and that `product_invoices`/`consumer_invoices` list and emission operations take a SEPARATE string `environment` parameter (`"Production"`/`"Test"`), including a Test-environment emission sample + +#### Scenario: Webhook freshness warning +- **WHEN** a developer reads the README webhook section +- **THEN** it SHALL warn that a valid signature is NOT proof of freshness (NFE.io sends no anti-replay primitive), so handlers MUST be idempotent and deduplicate on the event/invoice id + +#### Scenario: Versioning section +- **WHEN** a developer reads the versioning section +- **THEN** it SHALL state the SemVer policy and the RC/beta cadence, and link to `CHANGELOG.md` and `MIGRATION.md` + +### Requirement: Contributing guide +The repository SHALL include `CONTRIBUTING.md` in Brazilian Portuguese documenting the branch policy (`master` active for v1, `0.x-legacy` frozen), local setup on Ruby 3.2+, the toolchain (`rake spec`, `rubocop`, `steep check`, `rake generate` / `rake generate:check`), the convention that every `.rb` file starts with `# frozen_string_literal: true`, the rule that generated files under `lib/nfe/generated/` are never hand-edited, and the release cadence. + +#### Scenario: Contributor setting up +- **WHEN** a new contributor opens `CONTRIBUTING.md` +- **THEN** they SHALL find the commands to install dependencies, run the tests, lint, type-check, and regenerate code from the OpenAPI specs + +#### Scenario: Editing generated code +- **WHEN** a contributor considers editing a file under `lib/nfe/generated/` +- **THEN** `CONTRIBUTING.md` SHALL instruct them to edit the OpenAPI spec and run `rake generate` instead, and SHALL note that CI fails via `rake generate:check` when the generated tree is out of sync + +### Requirement: Runnable sample programs cover the main use cases +The repository SHALL ship a `samples/` directory containing runnable Ruby scripts covering the primary use cases of the SDK. Each script SHALL be self-contained, loadable via `samples/config.rb`, and documented in `samples/README.md`. A `samples/.env.example` SHALL be provided and `samples/.env` SHALL be git-ignored. + +The minimum set of samples SHALL include: + +- `service_invoice_issue.rb` (NFS-e emission + manual polling) +- `product_invoice_issue.rb` (NF-e emission) +- `consumer_invoice_issue.rb` (NFC-e emission) +- `company_crud.rb` (full CRUD of companies) +- `legal_person_create.rb` and `legal_person_update.rb` +- `webhook_verify.rb` (HMAC-SHA1 validation over raw body bytes) +- `cnpj_lookup.rb` +- `cpf_lookup.rb` +- `cep_lookup.rb` +- `tax_calculation.rb` +- `rtc_service_invoice.rb` (NFS-e RTC emission, depends on `add-rtc-invoice-emission`) + +#### Scenario: Consumer evaluating the SDK +- **WHEN** a developer clones the repository and opens `samples/` +- **THEN** they SHALL find a runnable example for each major API category, plus a `.env.example` and `README.md` explaining setup + +#### Scenario: Running a sample +- **WHEN** a developer configures `samples/.env` with valid sandbox credentials and runs `ruby samples/service_invoice_issue.rb` +- **THEN** the script SHALL execute end-to-end against the NFE.io sandbox and print the outcome (Pending or Issued) + +#### Scenario: Download sample writes binary +- **WHEN** a sample downloads a PDF or XML +- **THEN** it SHALL write the result with `File.binwrite`, reinforcing the binary `String` (`ASCII-8BIT`) download contract + +### Requirement: Single-command release preparation script +The repository SHALL provide `scripts/release.sh` that performs version bump, changelog rotation, commit, annotated tag, and push in a single interactive command, with `--dry-run`, `--skip-tests`, and `--skip-git` flags. The script SHALL NOT publish the gem itself — publication happens in the release workflow after the tag is pushed. + +#### Scenario: Cutting a release on a clean branch +- **WHEN** a maintainer runs `scripts/release.sh` on the `master` branch with a clean working tree and green CI +- **THEN** the script SHALL prompt for a version, update `Nfe::VERSION`, rotate `CHANGELOG.md`, commit, create an annotated tag `vX.Y.Z`, and push the commit and tag to origin + +#### Scenario: Dry-run rehearsal +- **WHEN** the maintainer runs `scripts/release.sh --dry-run` +- **THEN** the script SHALL print every step it would perform without modifying any file or invoking any git command with side effects + +#### Scenario: Dirty working tree refusal +- **WHEN** the working tree has uncommitted changes and the script is invoked without `--skip-git` +- **THEN** the script SHALL refuse to proceed with an explanatory message + +#### Scenario: Existing tag refusal +- **WHEN** the requested version corresponds to an existing git tag +- **THEN** the script SHALL fail early with a clear message before any change is made + +#### Scenario: Invalid version format +- **WHEN** the maintainer types a version that does not match `X.Y.Z` or `X.Y.Z-rc.N` or `X.Y.Z-beta.N` +- **THEN** the script SHALL reject it and prompt again or exit + +#### Scenario: No local gem push +- **WHEN** the release script completes successfully +- **THEN** it SHALL NOT have invoked `gem push`; the gem is published only by the release workflow triggered by the pushed tag + +### Requirement: Release workflow gated on full CI, publishing to RubyGems +The repository SHALL include `.github/workflows/release.yml` triggered by pushes of tags matching `v*`. A `verify` job SHALL run the full CI gate — `rake spec` (with SimpleCov ≥ 80%), `rubocop`, `steep check`, and `rake generate:check` — across the Ruby 3.2/3.3/3.4 matrix. A `publish` job, depending on `verify`, SHALL build the gem and publish it to RubyGems, and SHALL create a GitHub Release. + +#### Scenario: Tag push triggers verification then publish +- **WHEN** a tag `v1.0.0-rc.1` is pushed +- **THEN** GitHub Actions SHALL run the verification matrix, and only upon success SHALL the `publish` job build and push the gem and create the GitHub Release + +#### Scenario: Failed verification aborts publish +- **WHEN** any job in the verification matrix fails for the tag +- **THEN** the gem SHALL NOT be published and no GitHub Release SHALL be created; the tag remains but the publish does not + +#### Scenario: Generated code out of sync blocks release +- **WHEN** `rake generate:check` detects that `lib/nfe/generated/` or `sig/` is out of sync with `openapi/*.yaml` +- **THEN** the `verify` job SHALL fail and the release SHALL be aborted + +### Requirement: RubyGems trusted publishing via OIDC +The `publish` job SHALL publish to RubyGems using trusted publishing via GitHub OIDC, granting the job `id-token: write` permission and obtaining an ephemeral credential, without storing a long-lived API key. When OIDC trusted publishing is not configured, the workflow SHALL fall back to a `GEM_HOST_API_KEY` sourced from the `RUBYGEMS_API_KEY` repository secret. + +#### Scenario: Publishing with OIDC +- **WHEN** the `publish` job runs for a tag and the repository is registered as a trusted publisher on RubyGems +- **THEN** the job SHALL authenticate via OIDC and push the gem without any persistent API key + +#### Scenario: Fallback to API key +- **WHEN** OIDC trusted publishing is not yet configured for the repository +- **THEN** the workflow SHALL use `GEM_HOST_API_KEY` from the `RUBYGEMS_API_KEY` secret to push the gem + +### Requirement: Released gem is checksummed and MFA-protected +The `publish` job SHALL generate a SHA-256 checksum of the built `.gem` and attach both the `.gem` and its `.sha256` file to the GitHub Release. The gem SHALL declare `rubygems_mfa_required => "true"` so that interactive operations on the gem require multi-factor authentication. + +#### Scenario: Checksum attached to release +- **WHEN** a release is published for tag `vX.Y.Z` +- **THEN** the GitHub Release SHALL include `nfe-io-X.Y.Z.gem` and `nfe-io-X.Y.Z.gem.sha256`, enabling independent verification of the artifact + +#### Scenario: MFA required on the gem +- **WHEN** an account attempts a privileged operation on the `nfe-io` gem on RubyGems +- **THEN** RubyGems SHALL require multi-factor authentication because the gem metadata declares `rubygems_mfa_required` + +### Requirement: AI skill for the Ruby SDK +The repository SHALL include `skills/nfeio-ruby-sdk/SKILL.md`, modeled on the Node SDK skill, with YAML front-matter (`name: nfeio-ruby-sdk` and a `description` of trigger conditions) and sections covering: gem/require, quickstart, a resource map of all 17 snake_case accessors, the discriminated 202 contract with manual polling, the typed error hierarchy, page-style vs cursor pagination, binary downloads, webhook signature verification, idiomatic Ruby pitfalls, and a decision tree. It SHALL include segmented `references/*.md` files. + +#### Scenario: Agent invoked on NFE.io Ruby code +- **WHEN** an AI agent encounters code that requires `nfe` or references `Nfe::Client`, or a request about Brazilian fiscal documents in Ruby +- **THEN** the `nfeio-ruby-sdk` skill SHALL provide the resource map, the 202 contract guidance, and the error hierarchy needed to write correct code + +#### Scenario: Reference files present +- **WHEN** the skill directory is inspected +- **THEN** it SHALL contain `references/service-invoices-and-polling.md`, `references/product-invoices-and-taxes.md`, `references/data-services-and-lookups.md`, `references/error-handling-and-patterns.md`, and `references/rtc-emission.md` + +#### Scenario: Idioms adapted to Ruby +- **WHEN** the skill documents an SDK pattern +- **THEN** it SHALL use idiomatic Ruby (synchronous returns instead of Promises, binary `String` instead of Buffer, snake_case accessors, `Data.define` value objects, `is_a?`/`case in` instead of `instanceof`) + +### Requirement: Webhook signature documentation uses the correct scheme +The README, MIGRATION guide, and AI skill SHALL document webhook signature verification as `X-Hub-Signature` with HMAC-SHA1 computed over the raw request body bytes, with a case-insensitive hex comparison, the `sha1=` prefix, and a timing-safe comparison. They SHALL warn that the legacy `X-NFe-Signature` + HMAC-SHA256 scheme found in some distribution docs is incorrect versus production. They SHALL also warn that a valid signature is NOT proof of freshness — NFE.io sends no anti-replay primitive — so handlers MUST be idempotent and deduplicate on the event/invoice id. + +#### Scenario: Documenting signature verification +- **WHEN** a developer reads the webhook section in the README, MIGRATION, or skill +- **THEN** it SHALL instruct reading the raw body (`request.raw_post` in Rails, `request.body.read` in Rack) before JSON parsing, computing `OpenSSL::HMAC.hexdigest("SHA1", secret, raw_body)`, and comparing timing-safely against the `X-Hub-Signature` header value + +#### Scenario: Warning about the wrong scheme +- **WHEN** a developer might otherwise copy the `X-NFe-Signature` + SHA-256 scheme from older distribution docs +- **THEN** the documentation SHALL explicitly flag that scheme as incorrect and direct them to HMAC-SHA1 with `X-Hub-Signature` + +#### Scenario: Signature validity is not freshness +- **WHEN** a developer reads the webhook section in the README, MIGRATION, or skill +- **THEN** it SHALL state that a valid signature does not guarantee freshness (no anti-replay primitive is sent), and SHALL instruct that handlers be idempotent and deduplicate on the event/invoice id + +### Requirement: RC and beta period before any GA release +The first stable `v1.0.0` release SHALL be preceded by at least one release candidate (`v1.0.0-rc.1` or later) published to RubyGems as a prerelease, followed by a beta period. During the beta period the `master` README SHALL display a banner indicating the in-development status; at the GA release the banner SHALL be removed, tied to the prerelease-vs-final flow of `scripts/release.sh` (a prerelease keeps the banner, a final release removes it). The README SHALL carry a one-line forward-compatibility note stating that `Pending`/`Issued` and `FlowStatus` are stable public API. Prerelease versions SHALL NOT be resolved as `latest` by RubyGems for consumers using a `~> 1.0` constraint. + +#### Scenario: First v1.0.0 release +- **WHEN** the maintainer prepares to publish v1.0.0 for the first time +- **THEN** the workflow SHALL be: tag `v1.0.0-rc.1` → beta period → if no critical issues, tag `v1.0.0` + +#### Scenario: Banner removed at GA +- **WHEN** the maintainer cuts the final `v1.0.0` (non-prerelease) via `scripts/release.sh` +- **THEN** the in-development banner SHALL be removed from the README, while a prerelease release SHALL leave it in place + +#### Scenario: Critical issue during beta +- **WHEN** a critical issue is reported during the beta period +- **THEN** the maintainer SHALL fix it and tag `v1.0.0-rc.2`, restarting the beta clock + +#### Scenario: Prerelease not auto-installed +- **WHEN** a consumer depends on `gem "nfe-io", "~> 1.0"` while only `v1.0.0-rc.1` is published +- **THEN** Bundler SHALL NOT resolve the prerelease unless the consumer opts in explicitly (e.g., `= 1.0.0.rc.1`) + +#### Scenario: Patch release +- **WHEN** a patch release (`v1.0.1`) addresses a bug without API change +- **THEN** the maintainer MAY release directly without an RC/beta period, since the public surface is unchanged + +### Requirement: Ruby SDK page in nfeio-docs +The existing live Ruby SDK page `docs/desenvolvedores/bibliotecas/ruby.md` in the `nfeio-docs` repository (the source of truth for API behavior) SHALL be updated: the incorrect `X-NFEIO-Signature` + Base64 webhook snippet and the global v0.3 `Nfe.api_key` examples SHALL be removed; a `Nfe::Client.new(api_key:)` quickstart SHALL be added; and the page SHALL mirror the Node SDK docs structure (migration, changelog, examples sections), with links to the README and MIGRATION guide. The SDK README SHALL link back to this documentation page. + +#### Scenario: Docs page updated and linked +- **WHEN** a user browses the NFE.io documentation under "Bibliotecas → Ruby" +- **THEN** they SHALL find an installation and `Nfe::Client.new(api_key:)` quickstart page for the `nfe-io` gem — with the wrong `X-NFEIO-Signature` + Base64 webhook snippet and the global `Nfe.api_key` v0.3 examples removed — linking to the GitHub README and MIGRATION guide + +#### Scenario: README links to docs +- **WHEN** a user reads the README's documentation section +- **THEN** it SHALL link to the Ruby SDK page in the NFE.io documentation diff --git a/openspec/changes/archive/2026-06-25-add-release-tooling/tasks.md b/openspec/changes/archive/2026-06-25-add-release-tooling/tasks.md new file mode 100644 index 0000000..e3ac265 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-release-tooling/tasks.md @@ -0,0 +1,174 @@ +# Tasks — add-release-tooling + +> Greenfield: todas as caixas começam desmarcadas. Depende de todas as changes +> irmãs (`add-ruby-foundation` … `add-lookup-resources`) aplicadas e estáveis. + +## 1. Gemspec moderno + fonte única da versão + +- [x] 1.1 Reescrever `nfe-io.gemspec`: remover `# coding: utf-8`, remover `$LOAD_PATH` hack legado, `require_relative "lib/nfe/version"`. +- [x] 1.2 `spec.name = "nfe-io"` (mantido); `spec.version = Nfe::VERSION`. +- [x] 1.3 Atualizar metadados: `spec.authors`, `spec.email = ["suporte@nfe.io"]`, `spec.summary`/`spec.description` (SDK oficial NFE.io para documentos fiscais brasileiros), `spec.homepage = "https://nfe.io"`, `spec.license = "MIT"`. +- [x] 1.4 `spec.required_ruby_version = ">= 3.2"`. +- [x] 1.5 **Remover** `spec.add_dependency "rest-client"` e qualquer outra dependência de runtime (zero deps; apenas stdlib). +- [x] 1.6 `add_development_dependency`: `rspec`, `rubocop`, `rubocop-rspec`, `steep`, `rbs`, `simplecov`, `rake`. Remover `bundler`/`byebug` legados (ou manter `debug` da stdlib). +- [x] 1.7 `spec.metadata`: `"homepage_uri"`, `"source_code_uri" => "https://github.com/nfe/client-ruby"`, `"changelog_uri" => ".../blob/master/CHANGELOG.md"`, `"bug_tracker_uri"`, `"documentation_uri"`, `"rubygems_mfa_required" => "true"`. +- [x] 1.8 `spec.files = Dir.chdir(__dir__) { \`git ls-files -z\`.split("\x0") }` rejeitando `spec/`, `samples/`, `skills/`, `.github/`, `openspec/`, dotfiles de dev — mas **incluindo** `sig/**/*.rbs`, `lib/**/*.rb`, `README.md`, `CHANGELOG.md`, `MIGRATION.md`, `LICENSE.txt`. +- [x] 1.9 `spec.require_paths = ["lib"]`; confirmar que `sig/` é empacotado (RBS distribuído junto ao gem). +- [x] 1.10 Atualizar `lib/nfe/version.rb` para `Nfe::VERSION = "1.0.0"` (com `# frozen_string_literal: true` no topo) — fonte única lida por gemspec e workflow. +- [x] 1.11 `bundle exec rake build` gera `nfe-io-1.0.0.gem` sem warnings; `gem spec nfe-io-1.0.0.gem` mostra metadados corretos e zero runtime deps. +- [x] 1.12 Atualizar `Rakefile` para expor `build`, `install`, `release` (Bundler::GemHelper) além de `spec`. + +## 2. CHANGELOG.md (pt-BR, Keep a Changelog) + +- [x] 2.1 Criar `CHANGELOG.md` com cabeçalho Keep a Changelog 1.1.0 + SemVer (links pt-BR). +- [x] 2.2 Seção `## [Não lançado]` vazia no topo (rotacionada pelo `release.sh`). +- [x] 2.3 Entrada `## [1.0.0] - AAAA-MM-DD` documentando a reescrita greenfield, categorizada: + - `### Adicionado`: `Nfe::Client.new(api_key:)`, 17 recursos snake_case, modelos `Data.define` gerados, RBS + Steep, contrato 202 discriminado, emissão RTC (IBS/CBS/IS), verificação de webhook HMAC-SHA1, roteamento multi-host, retry/backoff, downloads binários. + - `### Alterado`: namespace `Nfe`, Ruby floor 3.2, paginação page/cursor. + - `### Removido`: dependência `rest-client`, config global `Nfe.api_key`, classes achatadas v0.3.x. +- [x] 2.4 Rodapé com links de comparação de versões (`[1.0.0]: .../releases/tag/v1.0.0`, `[Não lançado]: .../compare/v1.0.0...HEAD`). + +## 3. MIGRATION.md exaustivo (pt-BR) v0.3.x → v1.0.0 + +- [x] 3.1 Cabeçalho explicando que v1 é reescrita completa sem camada de compatibilidade; `master` = v1, branch `0.x-legacy` congelada. +- [x] 3.2 Seção "Instalação": `gem "nfe-io", "~> 0.3"` → `gem "nfe-io", "~> 1.0"`; aviso de breaking change major. +- [x] 3.3 Seção "Versão do Ruby": Ruby 2.x → 3.2/3.3/3.4. +- [x] 3.4 Seção "Configuração": `Nfe.api_key("...")` (setter global por **chamada de método**, não atribuição) → `Nfe::Client.new(api_key: "...")` (instância). Documentar também `Nfe.configure { |c| c.url = "..." }` → `Nfe::Client.new(base_url:)` e o padrão por-classe `Nfe::ServiceInvoice.company_id("...")` → `client.service_invoices.create(company_id:, ...)` (o company_id deixa de ser estado global por classe e passa a ser argumento por chamada). Documentar que a base URL deixou de ser global e passa a ser roteada por recurso (api.nfe.io, api.nfse.io, address.api.nfe.io/v2, nfe.api.nfe.io, legalentity.api.nfe.io, naturalperson.api.nfe.io). +- [x] 3.5 Seção "Segunda chave de API" (novidade): `data_api_key:` para recursos de dados (CEP/CNPJ/CPF/query), com fallback para `api_key`. +- [x] 3.6 Seção "Mapeamento de classes" — tabela classes v0.3.x → accessor v1 (os 17: `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, `state_taxes`). +- [x] 3.7 Seção "Mapeamento de métodos por recurso" — para cada recurso, tabela método v0.3.x → método v1 (snake_case, com diff de assinatura). +- [x] 3.8 Seção "Remoção do rest-client" — `RestClient::Exception` → hierarquia `Nfe::ApiConnectionError`/`Nfe::TimeoutError` (`TimeoutError < ApiConnectionError`); nenhuma dependência de runtime. +- [x] 3.9 Seção "Tratamento de erros" — tabela completa `Nfe::Error` base + `AuthenticationError`(401), `AuthorizationError`(403), `InvalidRequestError`(400/422), `NotFoundError`(404), `ConflictError`(409), `RateLimitError`(429), `ServerError`(5xx), `ApiConnectionError`, `TimeoutError`(< `ApiConnectionError`), `SignatureVerificationError`, `ConfigurationError`, `InvoiceProcessingError`. +- [x] 3.10 Seção "Respostas assíncronas (202)" — contrato discriminado `Pending`/`Issued`; exemplo de loop de polling manual usando `Nfe::FlowStatus.terminal?`. +- [x] 3.11 Seção "Verificação de assinatura de webhook" — `X-Hub-Signature` + HMAC-SHA1 sobre **bytes crus** do corpo (não JSON re-serializado); ler `request.body.read` antes de parsear; comparar case-insensitive; usar `OpenSSL::HMAC` + comparação timing-safe (`Rack::Utils.secure_compare` ou implementação própria com stdlib). Alertar que docs antigas de distribuição (`X-NFe-Signature` + SHA-256) estão **erradas**. +- [x] 3.12 Seção "Downloads" — agora retornam `String` binária (`ASCII-8BIT`) em vez de objeto rest-client; salvar com `File.binwrite`. +- [x] 3.13 Seção "Features diferidas na v1.0" — `create_and_wait`, `create_batch`, upload/replace/validate de certificado multipart, `getStatus` como endpoint HTTP dedicado (derivado de `retrieve` no v1). Explicar workaround (polling manual via `FlowStatus`). +- [x] 3.14 Apêndice A — exemplo end-to-end **vanilla** (script CLI v0.3.x → v1, diff lado a lado: emissão de NFS-e + polling). +- [x] 3.15 Apêndice B — exemplo end-to-end **Rails** (initializer `config/initializers/nfe.rb` com `Nfe::Client` memoizado; controller de webhook validando assinatura sobre `request.raw_post`). +- [x] 3.16 Seção "Resumo de breaking changes" — bullet list categorizada (gem, Ruby, configuração, superfície de API, erros, downloads, webhook). +- [x] 3.17 Revisão de ponta a ponta: nenhum método/campo inventado; nomes batem com as specs das changes irmãs. + +## 4. README.md expandido (pt-BR) + +- [x] 4.1 Substituir o README legado; H1 + tagline + badges (RubyGems version, CI status, cobertura, licença MIT). +- [x] 4.2 Seção "Requisitos": Ruby 3.2+, zero dependências de runtime (apenas stdlib: net/http, json, openssl, uri, securerandom, stringio, time, base64). +- [x] 4.3 Seção "Instalação": `gem install nfe-io` e `bundle add nfe-io`. +- [x] 4.4 Seção "Quickstart": `require "nfe"`, `Nfe::Client.new(api_key: ENV["NFE_API_KEY"])`, exemplo curto de emissão + leitura. +- [x] 4.5 Seção "Configuração": `api_key:`, `data_api_key:`, `environment:`, `timeout:`, `retry:` (max_retries/base_delay/max_delay/backoff), com defaults. Documentar fallback de variáveis de ambiente: `Configuration` lê `NFE_API_KEY` / `NFE_DATA_API_KEY` do ambiente quando o argumento explícito é omitido (precedência: argumento explícito vence o env). +- [x] 4.5a Seção "Sandbox vs Produção": o parâmetro `environment:` do `Nfe::Client.new` é um **símbolo** que seleciona uma CHAVE (credencial/conta), **não** uma URL — o roteamento de host continua automático por recurso. Explicar como obter credenciais de teste. Alertar que `product_invoices`/`consumer_invoices` recebem um parâmetro `environment` **String** SEPARADO (`"Production"`/`"Test"`) nas operações de `list`/emissão. Incluir um exemplo de emissão em ambiente de teste. +- [x] 4.6 Seção "Mapa de recursos": tabela dos 17 accessors → host → escopo (company/global) → operações-chave (espelha a skill). +- [x] 4.7 Seção "Recursos (1-liner cada)": um exemplo por recurso (service_invoices, product_invoices, consumer_invoices, transportation_invoices, inbound_product_invoices, companies, legal_people, natural_people, webhooks, addresses, legal_entity_lookup, natural_person_lookup, tax_calculation, tax_codes, state_taxes, product_invoice_query, consumer_invoice_query). +- [x] 4.8 Seção "Emissão assíncrona (contrato 202)": discriminar `Pending`/`Issued`; loop de polling manual via `Nfe::FlowStatus.terminal?`. +- [x] 4.9 Seção "Tratamento de erros": `begin/rescue` por classe tipada; tabela de erros. +- [x] 4.10 Seção "Downloads": retornam `String` binária; `File.binwrite`. +- [x] 4.11 Seção "Webhooks": criar webhook + validar assinatura HMAC-SHA1 sobre bytes crus. Alertar que validade de assinatura **não** é prova de frescor (a NFE.io não envia primitiva anti-replay/timestamp): handlers DEVEM ser idempotentes e deduplicar pelo id do evento/nota. +- [x] 4.12 Seção "Versionamento": semver + cadência RC/beta + link para `CHANGELOG.md` e `MIGRATION.md`. +- [x] 4.13 Seção "Type checking": SDK distribui `.rbs` em `sig/`; instruções de Steep para consumidores. +- [x] 4.14 Remover o badge/banner Travis legado (`.travis.yml`) e qualquer referência a `pluga.co`. + +## 5. CONTRIBUTING.md (pt-BR) + +- [x] 5.1 Seção "Branches": `master` (v1, ativo) e `0.x-legacy` (congelada, sem manutenção); PRs contra `0.x-legacy` são fechados. +- [x] 5.2 Seção "Setup local": Ruby 3.2+ (via rbenv/asdf), `bundle install`. +- [x] 5.3 Seção "Toolchain" — tabela: `rake spec` (RSpec), `rubocop` (lint), `steep check` (type check), `rake generate` / `rake generate:check` (codegen OpenAPI), `simplecov` (cobertura ≥ 80%). +- [x] 5.4 Seção "Convenções": `# frozen_string_literal: true` no topo de todo `.rb`; PSR-equivalente snake_case; keyword args; `Data.define` para value objects. +- [x] 5.5 Seção "Arquivos gerados": nunca editar `lib/nfe/generated/` nem `sig/` gerados à mão; regenerar de `openapi/*.yaml` via `rake generate`; commitar spec + gerado no mesmo PR; CI falha via `generate:check` se fora de sync. +- [x] 5.6 Seção "Commits": Conventional Commits (`feat:`, `fix:`, `docs:`, `chore(release):`). +- [x] 5.7 Seção "Workflow OpenSpec": changes ativas em `openspec/changes/`. +- [x] 5.8 Seção "Cadência de release": patch direto após CI verde; minor/major com RC + período de beta (ver `release-tooling`). + +## 6. samples/ runnable + +- [x] 6.1 Criar `samples/.env.example` com `NFE_API_KEY=`, `NFE_DATA_API_KEY=`, `NFE_COMPANY_ID=`, `NFE_WEBHOOK_SECRET=`. +- [x] 6.2 Criar `samples/config.rb` — bootstrap: `require "nfe"`, lê env vars, instancia `$nfe = Nfe::Client.new(api_key:, data_api_key:)` e expõe `$company_id`; aborta com mensagem clara se `NFE_API_KEY` ausente. +- [x] 6.3 Criar `samples/README.md` — instruções: copiar `.env.example`, exportar variáveis, `ruby samples/.rb`. +- [x] 6.4 `samples/service_invoice_issue.rb` — emissão NFS-e + polling manual + `download_pdf` salvando com `File.binwrite`. +- [x] 6.5 `samples/product_invoice_issue.rb` — emissão NF-e (assíncrona, conclusão via webhook). +- [x] 6.6 `samples/consumer_invoice_issue.rb` — emissão NFC-e (contrato discriminado). +- [x] 6.7 `samples/company_crud.rb` — create + list + retrieve + update + remove. +- [x] 6.8 `samples/legal_person_create.rb` e `samples/legal_person_update.rb`. +- [x] 6.9 `samples/webhook_verify.rb` — mini servidor (`WEBrick`/`rackup` da stdlib ou exemplo de handler) que lê bytes crus, valida HMAC-SHA1 e loga. +- [x] 6.10 `samples/cnpj_lookup.rb` — `legal_entity_lookup.basic_info` + `state_tax_for_invoice`. +- [x] 6.11 `samples/cpf_lookup.rb` — `natural_person_lookup.status`. +- [x] 6.12 `samples/cep_lookup.rb` — `addresses.lookup_by_postal_code("01310-100")`. +- [x] 6.13 `samples/tax_calculation.rb` — `tax_calculation.calculate(tenant_id, request)`. +- [x] 6.14 `samples/rtc_service_invoice.rb` — emissão NFS-e RTC com grupo `ibs_cbs` (depende de `add-rtc-invoice-emission`). +- [x] 6.15 Cada sample com comentário-cabeçalho de pré-requisitos (env vars, company sandbox). +- [x] 6.16 Adicionar `samples/.env` ao `.gitignore` (não commitar credenciais). + +## 7. scripts/release.sh + +- [x] 7.1 Criar `scripts/release.sh` (bash, `set -euo pipefail`, cores, `--help`). +- [x] 7.2 Flags: `--dry-run`, `--skip-tests`, `--skip-git`. +- [x] 7.3 Pre-flight: branch é `master`? working tree limpo? CI verde no último commit (`gh run list --branch master --limit 1 --json conclusion`)? `ruby`/`bundle`/`gh` disponíveis? +- [x] 7.4 Prompt interativo de versão; validar regex `^\d+\.\d+\.\d+(-(rc|beta)\.\d+)?$`; rejeitar inválido. +- [x] 7.5 Falhar cedo se a tag `vX.Y.Z` já existir (idempotência). +- [x] 7.6 Atualizar `lib/nfe/version.rb` (`Nfe::VERSION`) com a forma **pontilhada** do prerelease: tag `vX.Y.Z-rc.N` (hífen) mas `Nfe::VERSION = "X.Y.Z.rc.N"` (ponto — exigido pelo RubyGems). Para release final, ambos são `X.Y.Z`. A tag git usa a forma com hífen; `version.rb` e o gem publicado usam a forma pontilhada. +- [x] 7.7 Rotacionar `CHANGELOG.md`: `[Não lançado]` → `[X.Y.Z] - $(date +%F)`. +- [x] 7.8 Rodar `bundle exec rake spec`, `rubocop`, `steep check`, `rake generate:check` (a menos que `--skip-tests`). +- [x] 7.9 Commit `chore(release): vX.Y.Z` (a menos que `--skip-git`/`--dry-run`). +- [x] 7.10 Tag anotada `vX.Y.Z` com mensagem extraída do CHANGELOG. +- [x] 7.11 Push commit + tag para `origin` (a menos que `--skip-git`/`--dry-run`). +- [x] 7.12 `--dry-run` imprime cada passo sem efeitos colaterais. +- [x] 7.13 NÃO faz `gem push` localmente — a publicação no RubyGems acontece no workflow via OIDC após o push da tag. + +## 8. .github/workflows/release.yml (CI gate + RubyGems OIDC) + +- [x] 8.1 Criar `.github/workflows/release.yml`; trigger `push: tags: ['v*']`. +- [x] 8.2 Job `verify`: matrix Ruby `['3.2','3.3','3.4']`; `bundle install`; `bundle exec rake spec` (com SimpleCov, falha < 80%), `bundle exec rubocop`, `bundle exec steep check`, `bundle exec rake generate:check`. Falha aqui = release abortado. +- [x] 8.3 Job `publish`: `needs: verify`; roda em Ruby 3.3; `permissions: { contents: write, id-token: write }`. +- [x] 8.4 `publish`: `gem build nfe-io.gemspec`; gerar checksum `sha256sum nfe-io-*.gem > nfe-io-*.gem.sha256`. +- [x] 8.5 `publish`: **RubyGems trusted publishing via OIDC** (`rubygems/configure-rubygems-credentials` + `gem push`), sem API key em secret quando OIDC estiver configurado. +- [x] 8.5a `publish`: passo de **asserção de versão** — derivar a versão pontilhada da tag (`vX.Y.Z-rc.N` → `X.Y.Z.rc.N`) e afirmar que a versão do gem construído (`Nfe::VERSION`) é exatamente igual; abortar o publish em caso de divergência. +- [x] 8.6 `publish`: criar GitHub Release (`gh release create` ou `softprops/action-gh-release`) com notas extraídas do CHANGELOG e anexar o `.gem` + `.sha256`. +- [x] 8.7 Pré-releases (tags `*-rc.*`/`*-beta.*`) marcadas como prerelease no GitHub Release e empurradas com `--otp`/pre-release no RubyGems (não viram `latest`). +- [x] 8.8 Fallback documentado: se OIDC não estiver disponível, usar `GEM_HOST_API_KEY` de secret (`RUBYGEMS_API_KEY`). +- [x] 8.9 Confirmar que o CI base (`.github/workflows/ci.yml`, de `add-ruby-foundation`) cobre push/PR em `master`; o `release.yml` reusa os mesmos comandos para o gate. + +## 9. skills/nfeio-ruby-sdk/ (skill de IA) + +- [x] 9.1 Criar `skills/nfeio-ruby-sdk/SKILL.md` com front-matter YAML (`name: nfeio-ruby-sdk`, `description:` com gatilhos: import de `nfe`/`Nfe::Client`, NFE.io, NFS-e/NF-e/CT-e/NFC-e, nota fiscal, CNPJ/CPF/CEP, etc., explicitando que cobre os 17 recursos). +- [x] 9.2 Seção "Gem & require": `gem "nfe-io"`, `require "nfe"`, Ruby 3.2+, zero deps. +- [x] 9.3 Seção "Quickstart": `Nfe::Client.new(api_key:, data_api_key:, environment:, timeout:, retry:)`; documentar fallback de env vars `NFE_API_KEY`/`NFE_DATA_API_KEY` (argumento explícito vence) e que `environment:` é um símbolo que seleciona uma CHAVE, não uma URL. +- [x] 9.3a Seção "Sandbox vs Produção": como obter credenciais de teste; `product_invoices`/`consumer_invoices` recebem um parâmetro `environment` String SEPARADO (`"Production"`/`"Test"`) em list/emissão; exemplo de emissão em Test. +- [x] 9.4 Seção "Resource Map": tabela dos 17 accessors snake_case → host → escopo → operações. +- [x] 9.5 Seção "Contrato 202": discriminar `Pending`/`Issued`; polling manual com `Nfe::FlowStatus.terminal?`; estados terminais e não-terminais. +- [x] 9.6 Seção "Error handling": hierarquia `Nfe::Error` + subclasses por status; `rescue` idiomático. +- [x] 9.7 Seção "Pagination": page-style (`page_index`/`page_count`) vs cursor (`starting_after`/`ending_before`/`limit`); `environment` obrigatório em product_invoices. +- [x] 9.8 Seção "Downloads": `String` binária (`ASCII-8BIT`); exceção: `product_invoices.download_pdf` retorna recurso com URI; `File.binwrite`. +- [x] 9.9 Seção "Webhooks": `X-Hub-Signature` + HMAC-SHA1 sobre bytes crus (`request.raw_post`/`request.body.read`), comparação timing-safe. Alertar que validade != frescor (sem primitiva anti-replay): handlers idempotentes e dedupe por id do evento/nota. +- [x] 9.10 Seção "Pitfalls idiomáticos Ruby": `companies.delete` chamado `remove` (evitar conflito), keyword args, value objects imutáveis `Data.define`, access keys de 44 dígitos, carta de correção 15–1000 chars sem acentos. +- [x] 9.11 Seção "Decision tree" ("Quero…" → recurso.método). +- [x] 9.12 Criar `skills/nfeio-ruby-sdk/references/service-invoices-and-polling.md`. +- [x] 9.13 Criar `skills/nfeio-ruby-sdk/references/product-invoices-and-taxes.md`. +- [x] 9.14 Criar `skills/nfeio-ruby-sdk/references/data-services-and-lookups.md`. +- [x] 9.15 Criar `skills/nfeio-ruby-sdk/references/error-handling-and-patterns.md`. +- [x] 9.16 Criar `skills/nfeio-ruby-sdk/references/rtc-emission.md` (IBS/CBS/IS; depende de `add-rtc-invoice-emission`). + +## 10. Integração com nfeio-docs + +- [ ] 10.1 **Atualizar** (não criar) a página viva existente `docs/desenvolvedores/bibliotecas/ruby.md` no `nfeio-docs` (repo é a fonte de verdade), coordenando com o time de docs. +- [ ] 10.2 **Remover** o snippet errado de webhook (`X-NFEIO-Signature` + Base64) e os exemplos de `Nfe.api_key` globais do estilo v0.3. +- [ ] 10.3 **Adicionar** o quickstart `Nfe::Client.new(api_key:)` e espelhar a estrutura das docs do Node (seções `migracao`/`changelog`/`exemplos`): instalação, quickstart, link para README e MIGRATION no GitHub. +- [ ] 10.4 Linkar a página de docs de volta no README (seção "Documentação"). + +## 11. Validação final + +- [x] 11.1 `bundle exec rake spec` com SimpleCov — cobertura ≥ 80% em `lib/nfe/` excluindo `lib/nfe/generated/`. +- [x] 11.2 `bundle exec rubocop` — sem offenses. +- [x] 11.3 `bundle exec steep check` — sem erros de tipo. +- [x] 11.4 `bundle exec rake generate:check` — gerado em sync com `openapi/*.yaml`. +- [x] 11.5 `gem build nfe-io.gemspec` — gera `nfe-io-1.0.0.gem` sem warnings; `gem spec` confirma zero runtime deps e `sig/` empacotado. +- [ ] 11.6 Rodar todos os samples contra sandbox — compilam e rodam sem erro. +- [ ] 11.7 `./scripts/release.sh --dry-run` — imprime os passos sem efeitos colaterais. +- [x] 11.8 `openspec validate add-release-tooling` — passa. +- [x] 11.9 Revisão manual do `MIGRATION.md` e `README.md` de ponta a ponta. + +## 12. Política de RC + beta e GA + +- [ ] 12.1 Cortar `v1.0.0-rc.1` via `scripts/release.sh`; confirmar que o workflow publica como prerelease no RubyGems e no GitHub. +- [ ] 12.2 Anunciar o RC internamente (Teams) + para integradores conhecidos; abrir issue "v1.0 Beta Tracking". +- [ ] 12.3 Período de beta (mínimo definido na política); coletar feedback. +- [ ] 12.4 Sem issues críticas → cortar `v1.0.0` GA; com issue crítica → `v1.0.0-rc.2`, reinicia o relógio. +- [ ] 12.5 Pós-GA: atualizar badges do README para estável; confirmar `gem install nfe-io` resolve para `1.0.0` como `latest`. +- [ ] 12.6 No GA, **remover** o banner "v1 em desenvolvimento" do README — amarrado ao fluxo prerelease-vs-final do `release.sh` (prerelease mantém o banner; release final o remove). Adicionar uma nota de forward-compat de uma linha de que `Pending`/`Issued` + `FlowStatus` são API pública estável. diff --git a/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/README.md b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/README.md new file mode 100644 index 0000000..ddd5373 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/README.md @@ -0,0 +1,3 @@ +# add-rtc-invoice-emission + +Emissão de notas fiscais no layout da Reforma Tributária do Consumo (RTC) — grupo IBS + CBS (e, para produto, também o Imposto Seletivo / IS) — via recursos dedicados `client.service_invoices_rtc` (NFS-e) e `client.product_invoices_rtc` (NF-e/NFC-e — modelos 55 e 65) no SDK Ruby v1. diff --git a/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/design.md b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/design.md new file mode 100644 index 0000000..96cf533 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/design.md @@ -0,0 +1,183 @@ +# Design — add-rtc-invoice-emission + +## Context + +A **Reforma Tributária do Consumo (RTC)** adiciona os tributos IBS (estadual + municipal), CBS e — só para produto — o Imposto Seletivo (IS) aos documentos fiscais. A `nfeio-docs` publica os leiautes como **duas** OpenAPIs dedicadas: +- `service-invoice-rtc-v1.yaml` (NFS-e; host `https://api.nfe.io`, `version: v3`, snapshot `NT_2025.002_v1.30_RTC`, 18 schemas nomeados; grupo `ibsCbs` no nível raiz). +- `product-invoice-rtc-v1.yaml` (NF-e/NFC-e; host `https://api.nfse.io`, `version: v3`, snapshot `NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS`, 140 schemas nomeados, OpenAPI 3.0.1; grupos `IBSCBS` e `IS` no nível do item — `items[].tax`). Única operação na spec: `POST /v2/companies/:companyId/productinvoices` (`createProductInvoice`). + +O fato central, ancorado em `docs/documentacao/reforma-tributaria/index.md`, é que **a RTC NÃO cria uma API nova**: ela adiciona grupos de campos e novas versões de layout, e o fluxo de emissão continua o mesmo. A seleção do leiaute RTC é por **forma do payload** (presença de `ibsCbs` na NFS-e; presença do grupo item-level `IBSCBS` na NF-e/NFC-e), sem header nem query param — exatamente os mesmos endpoints que as superfícies clássicas usam. + +Esta change reusa as abstrações compartilhadas de `add-client-core` (contrato discriminado 202 `Pending`/`Issued`, `FlowStatus`, `IdValidator`, `download`/`hydrate_list`/`handle_async_response` do `Nfe::Resources::AbstractResource`, `ListResponse`/`ListPage`, host map / roteamento multi-base-URL), os padrões das superfícies clássicas de service-invoice e product-invoice de `add-invoice-resources` (subtipos `Nfe::Resources::ServiceInvoicePending`/`Nfe::Resources::ServiceInvoiceIssued`; ciclo de vida do produto) e a geração de `Data.define` + `.rbs` de `add-openapi-pipeline`, para uma capability fiscal **nova** (NFS-e RTC + NF-e/NFC-e RTC) e ainda em evolução regulatória. Espelha o SDK Node de referência, que modela `serviceInvoicesRtc` E `productInvoicesRtc` na MESMA change RTC. + +Diferença de qualidade de tipos vs NFS-e clássica: `nf-servico-v1.yaml` tem **0 component schemas** (o `ServiceInvoice` clássico é derivado de `operations[...]`); ambas as specs RTC definem **schemas nomeados** (`NFSeRequest`/`ibsCbs`; `ProductInvoiceRequest`/`IBSCBSTaxResource`/`ISTaxResource`), então o gerador produz tipos ricos sem ginástica de derivação. Esse é um dos motivos de a RTC ser o "happy path" e poder embarcar de forma independente. + +## Goals / Non-Goals + +**Goals** +- Emitir NFS-e no leiaute RTC via recurso dedicado `client.service_invoices_rtc`, com o grupo `ibsCbs` no payload. +- Emitir NF-e/NFC-e no leiaute RTC via recurso dedicado `client.product_invoices_rtc`, com os grupos item-level `IBSCBS` (`state`/`municipal`/`cbs`) e `IS` (Imposto Seletivo) no payload. +- Reusar o contrato discriminado 202 de `add-client-core` (`Nfe::Pending`/`Nfe::Issued`) nos dois recursos: `create` retorna `*RtcPending` (202+Location) ou `*RtcIssued` (201+corpo). +- Tipar request/response a partir dos schemas nomeados das specs RTC (`NFSeRequest`/`ibsCbs`; `ProductInvoiceRequest`/`IBSCBSTaxResource`/`ISTaxResource`) gerados por `add-openapi-pipeline` como `Data.define` imutáveis. +- Baixar o XML do evento de cancelamento (`e110001`) da NFS-e via `download_cancellation_xml` (retorna `String` binária `ASCII-8BIT`); baixar PDF/XML/rejeição/EPEC/CC-e da NF-e/NFC-e — todos retornam `Nfe::NfeFileResource` (uma URI), igual à superfície clássica `product_invoices` e ao schema `FileResource{uri}` de `nf-produto-v2.yaml`. +- Oferecer ciclo de vida completo de produto (retrieve/list/cancel/items/events/downloads/CC-e/inutilização) por paridade com a superfície clássica, no mesmo host `api.nfse.io`. +- Validar IDs antes do HTTP (fail-fast) e suportar polling manual via `FlowStatus.terminal?`. +- Deixar os recursos clássicos `service_invoices` e `product_invoices` 100% intactos (RTC é opt-in). + +**Non-Goals** +- `create_and_wait` / `create_batch` — diferidos, consistente com `add-invoice-resources`, para ambos os recursos. +- Validação local/runtime dos campos RTC (tabelas de `operationIndicator`/`classCode`/`situationCode`, valores de IS) — a API valida server-side; o SDK só faz fail-fast de ID. +- Cálculo de IBS/CBS/IS — o motor de cálculo (`calculo-impostos-v1`) é outro escopo; aqui o caller informa os valores no payload. +- Novos eventos de pós-autorização do RTC documentados no fluxograma de ciclo de vida — ainda não são endpoints na spec; fora de escopo até virarem paths. + +## Decisions + +### D1. Recurso dedicado `service_invoices_rtc` (não evoluir o clássico) +**Decisão**: introduzir um recurso novo `client.service_invoices_rtc` em vez de adicionar um modo RTC ao `service_invoices` existente. + +**Por quê**: +- Isola o churn regulatório (Notas Técnicas) fora do caminho de emissão clássico — o `service_invoices` não muda de assinatura quando o leiaute RTC evolui. +- Espelha a própria documentação, que entrega RTC como uma spec OpenAPI separada (`service-invoice-rtc-v1.yaml`). +- RTC fica explicitamente opt-in: o caller escolhe `service_invoices_rtc` deliberadamente. +- Espelha a proposta do Node SDK (`serviceInvoicesRtc` / `productInvoicesRtc` dedicados). + +**Alternativa rejeitada**: adicionar `ibs_cbs:` opcional ao `service_invoices.create` clássico e detectar RTC por presença do campo. Funciona (é assim que o servidor seleciona), mas acopla o churn RTC à assinatura do recurso clássico e torna o tipo do request ambíguo (clássico-derivado vs `NFSeRequest` nomeado). + +### D2. Mesmo endpoint, mesmo host, mesmo host-client `main` +**Decisão**: `service_invoices_rtc` usa `POST /v1/companies/{company_id}/serviceinvoices` no host `https://api.nfe.io` (família `main`; `base_url_for(:main)` retorna o host e o `/v1` vem do `api_version` do recurso, URL efetiva `https://api.nfe.io/v1/...`), reusando o **mesmo** host client do `service_invoices` clássico via `Configuration` — **sem nova base URL**. + +**Por quê**: a RTC não introduz endpoint nem host novo (confirmado na spec `servers: https://api.nfe.io` e no recon). O canônico do projeto é "nenhum recurso hard-codeia URL; a fonte única é a `Configuration`". `api_family` do recurso retorna `:main`. + +**Implementação**: `ServiceInvoicesRtc#api_family` → `:main`; o Client passa o host client `main` já existente ao instanciar o recurso (lazy), não cria um novo. + +### D3. DTO de request a partir do schema nomeado `NFSeRequest` +**Decisão**: o corpo de `create` é tipado pelo `Data.define` gerado `Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest`, que carrega o grupo aninhado `ibsCbs`. O método também aceita um `Hash` cru (paridade com os demais recursos), serializado com as chaves JSON originais. + +**Por quê**: +- Os schemas nomeados da spec RTC geram tipos ricos (★★★), superiores ao caminho derivado de `operations[...]` da NFS-e clássica. +- `Data.define` é imutável e idiomático em Ruby moderno; valores são value objects sem efeito colateral. +- Aceitar `Hash` mantém ergonomia para quem monta o payload à mão a partir dos exemplos da spec (`MinimumExample`, `IntermediateExample`, `CompleteExample`). + +**Mapeamento `ibsCbs`** (campos-chave, em `snake_case` no Ruby, chave JSON original preservada): + +| Ruby | JSON | Notas | +|---|---|---| +| `operation_indicator` | `operationIndicator` / `cIndOp` | obrigatório, `^[0-9]{6}$`, define local de incidência IBS/CBS | +| `class_code` | `classCode` / `cClassTrib` | obrigatório, max 6 | +| `situation_code` | `situationCode` / CST | opcional, max 3 — derivável dos 3 primeiros chars de `class_code` | +| `purpose` | `purpose` | enum `regular` (default) | +| `destination_indicator` | `destinationIndicator` | `SameAsBuyer` (default) / `DifferentFromBuyer` | +| `ibs.state` / `ibs.municipal` | `ibs.state`/`ibs.municipal` | cada um com `rate`/`effective_rate`/`deferment`/`amount` | +| `cbs` | `cbs` | `rate`/`effective_rate`/`deferment`/`amount` | +| `regular_taxation`, `presumed_credits`, `government_purchase`, `credit_transfer`, `third_party_reimbursements` | idem | mecanismos RTC especiais | + +`required: [class_code, operation_indicator]` no grupo `ibsCbs` (confirmado na spec). O SDK NÃO valida esses campos localmente além do que o gerador emite — quem valida o conteúdo é a API. + +### D4. Contrato discriminado 202 reusado, com classes RTC concretas +**Decisão**: criar `Nfe::Resources::ServiceInvoiceRtcPending` e `Nfe::Resources::ServiceInvoiceRtcIssued`, implementando os protocolos `Nfe::Pending`/`Nfe::Issued` definidos em `add-client-core` (espelhando os subtipos concretos `Nfe::Resources::ServiceInvoicePending`/`Nfe::Resources::ServiceInvoiceIssued` de `add-invoice-resources`). Cada classe expõe também os predicados `pending?`/`issued?`, de modo que a discriminação funcione tanto por `is_a?` quanto por predicado — igual aos subtipos clássicos. + +```ruby +Nfe::Resources::ServiceInvoiceRtcPending # implementa Pending: invoice_id, location, pending? => true, issued? => false +Nfe::Resources::ServiceInvoiceRtcIssued # implementa Issued: resource -> DTO RTC, issued? => true, pending? => false +``` + +**Por quê**: +- Mantém `is_a?(Nfe::Resources::ServiceInvoiceRtcPending)` (e `result.pending?`) semanticamente preciso e distinto do `Nfe::Resources::ServiceInvoicePending` clássico. +- Reusa a extração de `invoice_id` do header `Location` (regex `%r{serviceinvoices/([a-z0-9-]+)}i`) já definida em `add-invoice-resources` — não duplicar. +- 202 sem `Location` → `Nfe::InvoiceProcessingError` (mesmo contrato do clássico). + +**Alternativa rejeitada**: reusar as classes `Nfe::Resources::ServiceInvoicePending`/`Nfe::Resources::ServiceInvoiceIssued` do clássico. Funcionaria, mas perde a distinção de tipo e acopla o `resource()` ao DTO clássico (derivado), não ao DTO RTC nomeado. + +### D5. `create_and_wait` / `create_batch` diferidos +**Decisão**: NÃO implementar nesta change. Caller usa loop manual com `Nfe::FlowStatus.terminal?` (helper público de `add-client-core`): + +```ruby +result = client.service_invoices_rtc.create(company_id: cid, data: payload) +if result.is_a?(Nfe::Resources::ServiceInvoiceRtcPending) + loop do + sleep 2 + invoice = client.service_invoices_rtc.retrieve(company_id: cid, invoice_id: result.invoice_id) + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + end +end +``` + +**Por quê**: consistência com a decisão já cristalizada em `add-invoice-resources` (Node difere ambos para release futura; PHP v3.0 os defere). Estados terminais: `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`. + +### D6. `download_cancellation_xml` retorna `String` binária +**Decisão**: `download_cancellation_xml(company_id:, invoice_id:)` faz `GET .../cancellation-xml` com `Accept: application/xml` e retorna `String` binária (`force_encoding('ASCII-8BIT')`), via o helper `download` do `Nfe::Resources::AbstractResource`. + +**Por quê**: +- Canônico do projeto: downloads retornam bytes crus binary-safe (não `Buffer`/`StringIO`); o caller decide se grava em disco. +- O endpoint é **novo do RTC** (Release 2026.5, 2026-06-04): baixa o XML do evento de cancelamento (`e110001`) **separado** do XML de emissão. Disponível **apenas** no Ambiente Nacional (ADN) e só após status `Cancelled`. Quando há tanto o request `e110001` quanto o retorno autorizado (`procEventoNFSe`), a API prioriza o autorizado. + +**Tratamento de erro**: provedores municipais/ABRASF não têm evento de cancelamento próprio → a API retorna `404`. O SDK mapeia para `Nfe::NotFoundError` (mesmo mapeamento HTTP→erro definido em `add-client-core`); documentamos que esse 404 é esperado fora do Ambiente Nacional. + +### D7. Validação fail-fast de IDs antes do HTTP +**Decisão**: cada método chama `Nfe::IdValidator.company_id` / `Nfe::IdValidator.invoice_id` (de `add-client-core`) no início, levantando `Nfe::InvalidRequestError` em pt-BR antes de qualquer chamada de rede. + +**Por quê**: paridade com os demais recursos; mensagem clara e cedo. O `service-invoice-rtc-v1.yaml` declara `company_id` e `id` como `string` obrigatórios — apenas garantimos não-vazio (a API valida o resto). + +### D8. Snapshot da spec fixado e re-sync por Nota Técnica +**Decisão**: o leiaute RTC é tratado como **snapshot fixado** (`NT_2025.002_v1.30_RTC`, `version: v3`). O gerador sincroniza a partir de `nfeio-docs`; a cada Nota Técnica relevante, re-sincroniza-se a spec e re-geram-se os DTOs. + +**Por quê**: o próprio cabeçalho da spec avisa "Sujeito a alterações mediante notas técnicas e processos de homologação". Fixar o snapshot evita surpresas e torna explícito quando o SDK precisa de atualização. Registrado também como Risco abaixo. + +### D9. Accessor lazy e contagem de recursos +**Decisão**: `client.service_invoices_rtc` é um accessor lazy memoizado, igual aos demais. Eleva a contagem de accessors de 17 para 18, documentado como **adendo RTC / paridade-plus** (não faz parte dos 17 recursos canônicos do PHP/Node). + +**Por quê**: mantém o estilo Stripe-like (single client + accessors lazy) e deixa explícito, para mantenedores futuros, que `service_invoices_rtc`/`product_invoices_rtc` são acréscimos deliberados do leiaute RTC e não fazem parte dos 17 recursos de paridade. A contagem de accessors passa de 17 para 19. + +### D10. Recurso dedicado `product_invoices_rtc` no host `cte`/`api.nfse.io` +**Decisão**: introduzir `client.product_invoices_rtc` para emitir NF-e (modelo 55) e NFC-e (modelo 65) no leiaute RTC. `api_family` → `:cte` (alias `:product_invoices`), `api_version` → `"v2"`, resolvendo `https://api.nfse.io/v2/...` via `Configuration#base_url_for(:cte)` — **o MESMO host e base do `product_invoices` clássico**, sem nova base URL. + +**Por quê**: +- A spec RTC de produto declara `servers: https://api.nfse.io` (descrição "Nota Fiscal de Produto/Consumidor (RTC)"). Esse é o host da família `cte` (onde já vivem `product_invoices`, `consumer_invoices`, `transportation_invoices`, etc., confirmado no host map de `add-client-core`). O Node roteia o RTC de produto via `getCteHttpClient()` (o cliente `api.nfse.io`). +- **NÃO** rotear o produto RTC para `api.nfe.io` (esse é o host `main`, da NFS-e). Discrepância de fonte sinalizada no recon: a prosa do design Node menciona `getCteHttpClient`, que É o cliente `api.nfse.io` no Node — em Ruby mapeamos para a família `:cte`. +- Isola o churn regulatório fora do `product_invoices` clássico; RTC opt-in; espelha o `productInvoicesRtc` do Node. + +### D11. NF-e (mod 55) vs NFC-e (mod 65): UM recurso, UM endpoint, distinção por forma do payload +**Decisão**: um único `product_invoices_rtc` cobre NF-e E NFC-e. Não há campo discriminador `model`/`mod` na raiz do `ProductInvoiceRequest` nem endpoints separados. A distinção é por **forma do payload**: + +| Aspecto | NF-e (modelo 55) | NFC-e (modelo 65) | +|---|---|---| +| `print_type` (`PrintType`) | `NFeNormalPortrait`/`NFeNormalLandscape`/`NFeSimplified` | `DANFE_NFC_E`/`DANFE_NFC_E_MSG_ELETRONICA` | +| `consumer_type` (indFinal) / `presence_type` (indPres) | conforme operação | tipicamente `FinalConsumer` + `Internet`/`Presential` | +| `buyer` (dest) | **obrigatório** | opcional | +| `expected_delivery_on` | pode ser informado | NÃO informar | + +**Por quê**: a spec é "Leiaute NFe/NFCe RTC — Modelo 55 e 65" com uma só operação `createProductInvoice`. O campo `mod` só aparece em sub-schemas de documento referenciado (`TaxCouponInformationResource.modelDocumentFiscal`, `DocumentInvoiceReferenceResource`), não na raiz do request. Logo o SDK não precisa de um seletor: o caller popula os campos opcionais conforme o modelo. Não enviamos nenhum header/param discriminador. + +### D12. Grupos de tributo RTC no nível do ITEM; IBS dividido estadual+municipal; CBS federal; IS exclusivo de produto +**Decisão**: tipar os grupos RTC de produto onde a spec os coloca — em `InvoiceItemTaxResource` (`items[].tax`), lado a lado com os grupos legados (`icms`/`ipi`/`ii`/`pis`/`cofins`/`icmsDestination`). DOIS grupos novos: +- `IBSCBS` → `IBSCBSTaxResource`, que nesta (vs NFS-e) carrega `state` → `IBSStateTaxResource` e `municipal` → `IBSMunicipalTaxResource` (IBS é de competência compartilhada → split estadual/municipal), e `cbs` → `CBSTaxResource` (federal, SEM split). Cada esfera de IBS carrega `rate`/`deferment`/`returned_amount`/`reduction`/`amount`. Inclui `calculation_mode` (`Manual`|`OfficialService`) e mecanismos especiais (`regular_taxation`, `government_purchase`, `monophase`, `credit_transfer`, `operational_presumed_credit`, `credit_reversal`, `zfm_presumed_credit`). +- `IS` → `ISTaxResource` (Imposto Seletivo), tributo **novo e EXCLUSIVO de produto**: `situation_code`, `classification_code`, `basis`, `rate`, `unit_rate`, `unit`, `quantity`, `amount`. + +**Contraste com NFS-e RTC**: a NFS-e RTC tem só um grupo `ibsCbs` no nível RAIZ (com `operation_indicator` + `class_code`, sem split estadual/municipal e SEM Imposto Seletivo). O split estadual/municipal do IBS, os mecanismos por esfera (deferment/returnedAmount/reduction) e o IS são **exclusivos do produto**. + +**Por quê**: refletir fielmente a spec (140 schemas) — não inventar estrutura. Mantém `Hash` como fallback no caminho de request caso o gerador seja raso em algum subgrupo aninhado. + +### D13. Contrato 202 discriminado para produto, apesar de a spec documentar 201 +**Decisão**: criar `Nfe::Resources::ProductInvoiceRtcPending`/`Nfe::Resources::ProductInvoiceRtcIssued` (implementando `Pending`/`Issued`) e tratar a resposta de `create` de forma discriminada: 202+`Location` → Pending; 201+corpo → Issued. Extração de `invoice_id` via `%r{productinvoices/([a-z0-9-]+)}i`; 202 sem `Location` → `Nfe::InvoiceProcessingError`. + +**Por quê**: a spec RTC documenta o POST como `201` (→ `InvoiceResource`), mas a superfície clássica de produto trata o MESMO POST como `202`-enfileirado. A emissão é **sempre assíncrona** (conclusão por webhook/polling), independentemente do código. Tratar ambos via o mesmo contrato discriminado de `add-client-core` cobre as duas formas sem acoplar o caller ao código HTTP. `cancel`/CC-e/inutilização também são assíncronos (cancel = 204-enfileirado → `RequestCancellationResource`). + +### D14. Ciclo de vida completo carregado da superfície clássica de produto +**Decisão**: além do `create` (única operação que a spec RTC define), `product_invoices_rtc` expõe `create_with_state_tax`, `retrieve`, `list`, `cancel`, `list_items`, `list_events`, downloads (`pdf`/`xml`/`xml-rejection`/`xml-epec`), CC-e (`send_correction_letter` + downloads) e inutilização (`disable`/`disable_range`) — todos carregados da superfície **clássica** `product_invoices`. + +**Por quê**: os métodos clássicos compartilham host (`api.nfse.io`), base (`/v2`) e tipos de resposta (`InvoiceResource` é o mesmo que o `create` RTC retorna), então dão ao recurso RTC um ciclo de vida completo sem nova infra — exatamente como o Node prevê layering por cima do `productInvoicesRtc.create`. **Ambiente Nacional NÃO se aplica ao produto** (NF-e/NFC-e vai direto à SEFAZ), portanto produto não tem `download_cancellation_xml`; em vez disso usa `xml-rejection`/`xml-epec` e o ciclo de CC-e/inutilização. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| Leiaute RTC sujeito a Notas Técnicas / homologação; campos podem mudar | Tratar a spec como snapshot fixado (`NT_2025.002_v1.30_RTC`); re-sync + re-gen a cada NT; comunicar em doc que é "evolving" | +| Dois caminhos de emissão de NFS-e (clássico vs RTC) confundem o usuário | Nomes distintos (`service_invoices` vs `service_invoices_rtc`); RTC explicitamente opt-in; README com exemplo claro de quando usar cada um | +| `download_cancellation_xml` (NFS-e) só existe em Ambiente Nacional → 404 em municipal/ABRASF | Documentar o 404 esperado; mapear para `Nfe::NotFoundError`; deixar claro o pré-requisito de status `Cancelled` | +| Roteamento do produto RTC para o host errado (`api.nfe.io` em vez de `api.nfse.io`) | `api_family` → `:cte` (mesmo host do `product_invoices` clássico); teste de roteamento assertando `https://api.nfse.io`; discrepância de fonte (prosa do Node) explicitada em D10 | +| Spec RTC de produto documenta `create` como `201`, mas o fluxo é assíncrono (clássico = `202`) | Contrato discriminado trata 201 E 202; emissão sempre tratada como assíncrona (Pending/Issued); doc deixa explícito | +| 140 schemas de produto: gerador pode não tipar todos os subgrupos aninhados de `IBSCBS`/`IS` | Validar na §7 das tasks; `Hash` como fallback no caminho de request mantém ergonomia | +| Confundir grupo raiz `ibsCbs` (NFS-e) com grupo item-level `IBSCBS` (produto), ou esperar IS/split estadual-municipal na NFS-e | D12 documenta o contraste; recursos e DTOs separados (`service_invoice_rtc_v1` vs `product_invoice_rtc_v1`) | +| Geração de DTO pode não cobrir todos os subgrupos aninhados de `ibsCbs` se o gerador for raso em `additionalProperties: false` | Validar na §1 das tasks que o subgrupo `ibsCbs` e seus filhos (`ibs.state`/`ibs.municipal`/`cbs`/mecanismos) geram tipos; fallback para `Hash` no caminho de request mantém ergonomia mesmo se algum subgrupo não tipar | +| `operationIndicator` errado leva a apuração de imposto incorreta | Fora do controle do SDK (validação de conteúdo é server-side); documentar link para a Tabela de `operationIndicator` da doc funcional | +| Acoplamento à ordem de entrega das dependências (`add-client-core`, `add-invoice-resources`, `add-openapi-pipeline`) | Cross-reference explícito; esta change não inicia até os protocolos `Pending`/`Issued`, `FlowStatus`, `IdValidator`, `download` (de `add-client-core`) e o pipeline estarem disponíveis | diff --git a/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/proposal.md b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/proposal.md new file mode 100644 index 0000000..1ed418b --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/proposal.md @@ -0,0 +1,89 @@ +# add-rtc-invoice-emission + +## Why + +A **Reforma Tributária do Consumo (RTC)** introduz os novos tributos sobre consumo — **IBS** (Imposto sobre Bens e Serviços, dividido em esfera estadual e municipal), **CBS** (Contribuição sobre Bens e Serviços) e, exclusivamente para produto, o **IS** (Imposto Seletivo) — nos documentos fiscais eletrônicos. Para **NFS-e**, isso se materializa em um **novo grupo `ibsCbs`** (nível raiz) no payload de emissão; para **NF-e/NFC-e** (produto), em **novos grupos no nível do item** (`items[].tax.IBSCBS` e `items[].tax.IS`), com IBS dividido em esfera estadual (`state`) e municipal (`municipal`), CBS federal e Imposto Seletivo. Ambos carregam regras próprias de local de incidência, classificação tributária (`classCode`/`cClassTrib`), código de situação (CST) e mecanismos especiais (diferimento, redução, crédito presumido, compras governamentais, monofásico, transferência de crédito, estorno, ZFM). + +A fonte da verdade (`nfeio-docs`) publica esses layouts como **duas** OpenAPIs dedicadas: +- `service-invoice-rtc-v1.yaml` — título "API de Emissão de NFS-e - RTC", host `https://api.nfe.io`, `version: v3`, snapshot `NT_2025.002_v1.30_RTC`, 18 schemas nomeados, incluindo `NFSeRequest` e `ibsCbs`. +- `product-invoice-rtc-v1.yaml` — título "API de Emissão de Nota Fiscal de Produto (NFe/NFCe) - RTC", host `https://api.nfse.io`, `version: v3`, snapshot `NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS` (Leiaute NFe/NFCe RTC — Modelo 55 e 65), 140 schemas nomeados, incluindo `ProductInvoiceRequest`, `IBSCBSTaxResource`, `IBSStateTaxResource`, `IBSMunicipalTaxResource`, `CBSTaxResource` e `ISTaxResource`. + +Conforme `docs/documentacao/reforma-tributaria/index.md`, **a RTC não cria uma API nova**: ela adiciona novos grupos de campos e novas versões de layout — **o fluxo de emissão continua o mesmo** e a seleção do leiaute RTC é feita pela **forma do payload** (presença do grupo `ibsCbs` na NFS-e; presença do grupo item-level `IBSCBS` na NF-e/NFC-e), sem header nem query param. NF-e (modelo 55) e NFC-e (modelo 65) compartilham **um único endpoint e uma única spec**; são distinguidas pela **forma do payload** (`printType`, `consumerType`/`presenceType`, presença ou não de `buyer`/`expectedDeliveryOn`), não por um campo discriminador nem por endpoints separados. + +Esta change adiciona ao SDK Ruby v1 a emissão de **NFS-e** E de **NF-e/NFC-e** no layout RTC. Ela é **aditiva e opt-in**: surface em recursos dedicados `client.service_invoices_rtc` e `client.product_invoices_rtc`, deixando os recursos clássicos `client.service_invoices` e `client.product_invoices` (definidos em `add-invoice-resources`) **intactos**. Isso isola o churn regulatório do RTC (sujeito a Notas Técnicas) fora do caminho de emissão clássico, espelhando exatamente a separação que a própria documentação (specs RTC dedicadas) e o SDK Node de referência (`serviceInvoicesRtc` + `productInvoicesRtc`) adotam. + +Depende de: +- **`add-client-core`** — possui e define as abstrações compartilhadas reusadas aqui: o contrato discriminado 202 (`Nfe::Pending`/`Nfe::Issued`), o helper `Nfe::FlowStatus.terminal?`, o `Nfe::IdValidator`, o `download` binário e o `hydrate_list`/`handle_async_response` do `Nfe::Resources::AbstractResource`, o `Nfe::ListResponse`/`Nfe::ListPage` e o host map / roteamento multi-base-URL. O `service_invoices_rtc` usa o host `main` → `base_url_for(:main)` retorna `https://api.nfe.io`, `/v1` via `api_version`, URL efetiva `https://api.nfe.io/v1/...`. O `product_invoices_rtc` usa o host `cte` (alias `:product_invoices`) → `base_url_for(:cte)` retorna `https://api.nfse.io`, `/v2` via `api_version`, URL efetiva `https://api.nfse.io/v2/...` — **mesmo host do `product_invoices` clássico**, sem nova base URL. +- **`add-invoice-resources`** — reusa as superfícies clássicas de service-invoice e product-invoice e seus padrões: os recursos `service_invoices` e `product_invoices` (que permanecem intactos) e os subtipos concretos `ServiceInvoicePending`/`ServiceInvoiceIssued` que servem de modelo para os equivalentes RTC, além da superfície de ciclo de vida do produto (retrieve/list/cancel/events/items/downloads/CC-e/inutilização) carregada por paridade. +- **`add-openapi-pipeline`** — o gerador sincroniza `service-invoice-rtc-v1.yaml` E `product-invoice-rtc-v1.yaml` a partir de `nfeio-docs` e emite os value objects imutáveis (`Data.define`) sob `lib/nfe/generated/` mais as assinaturas `.rbs` sob `sig/`. Os schemas nomeados das specs RTC (`NFSeRequest`/`ibsCbs`; `ProductInvoiceRequest`/`IBSCBSTaxResource`/`ISTaxResource`) geram tipos ricos, sem a derivação de `operations[...]` que a NFS-e clássica (`nf-servico-v1.yaml`, 0 component schemas) exige. + +## What Changes + +### Novos recursos (2) + +| Recurso | Padrão | Host (família) | Operações | +|---|---|---|---| +| `client.service_invoices_rtc` | Emissão NFS-e RTC (IBS/CBS, nível raiz) | `https://api.nfe.io` (`main`); `/v1` via `api_version`, URL efetiva `https://api.nfe.io/v1/...` | `create` (202/201 discriminado), `retrieve`, `cancel`, `download_cancellation_xml` | +| `client.product_invoices_rtc` | Emissão NF-e/NFC-e RTC (IBS estadual+municipal, CBS, IS — nível do item) | `https://api.nfse.io` (`cte`, alias `:product_invoices`); `/v2` via `api_version`, URL efetiva `https://api.nfse.io/v2/...` | `create` (202/201 discriminado), `create_with_state_tax`, `retrieve`, `list`, `cancel`, `list_items`, `list_events`, `download_pdf`, `download_xml`, `download_rejection_xml`, `download_epec_xml`, `send_correction_letter`, `download_correction_letter_pdf`, `download_correction_letter_xml`, `disable`, `disable_range` | + +#### `client.service_invoices_rtc` (NFS-e RTC) + +- **`create(company_id:, data:, idempotency_key: nil, request_options: nil)`** — `POST /v1/companies/{company_id}/serviceinvoices` com corpo no formato `NFSeRequest` (grupo `ibsCbs` obrigando `operation_indicator` + `class_code`). Reusa o contrato discriminado 202: retorna `Nfe::Resources::ServiceInvoiceRtcPending` (HTTP 202 + header `Location`) ou `Nfe::Resources::ServiceInvoiceRtcIssued` (HTTP 201 + corpo materializado). Mesmo endpoint da NFS-e clássica — o servidor seleciona o leiaute RTC pela presença do `ibsCbs`. Aceita `idempotency_key:` opcional (enviado como header `Idempotency-Key` para retry seguro; POST NÃO é auto-retried pelo transport) e `request_options:` opcional (`Nfe::RequestOptions` de `add-client-core`, sobrepõe `api_key`/`base_url`/`timeout` por chamada). +- **`retrieve(company_id:, invoice_id:)`** — `GET /v1/companies/{company_id}/serviceinvoices/{invoice_id}` para polling manual via `Nfe::FlowStatus.terminal?`. +- **`cancel(company_id:, invoice_id:)`** — `DELETE` do invoice (síncrono). +- **`download_cancellation_xml(company_id:, invoice_id:)`** ⭐ — `GET /v1/companies/{company_id}/serviceinvoices/{invoice_id}/cancellation-xml`. Recurso **novo do RTC** (Release 2026.5): baixa o XML do **evento de cancelamento** (`e110001`), separado do XML de emissão. Disponível **apenas** no **Ambiente Nacional (ADN)** e só após status `Cancelled`; provedores municipais/ABRASF retornam 404. Retorna `String` binária (bytes crus, ASCII-8BIT). + +#### `client.product_invoices_rtc` (NF-e/NFC-e RTC) ⭐ novo nesta expansão + +- **`create(company_id:, data:, idempotency_key: nil, request_options: nil)`** — `POST /v2/companies/{company_id}/productinvoices` com corpo no formato `ProductInvoiceRequest` (única operação que a spec RTC de produto define; `operationId createProductInvoice`). Corpo carrega, no nível do item (`items[].tax`), os novos grupos `IBSCBS` (`IBSCBSTaxResource`, com `state`/`municipal`/`cbs`) e `IS` (`ISTaxResource`, Imposto Seletivo). NF-e (modelo 55) vs NFC-e (modelo 65) é distinguida pela forma do payload (`printType`, `consumerType`/`presenceType`, `buyer`, `expectedDeliveryOn`), não por discriminador. Emissão assíncrona: a spec documenta 201, mas a superfície clássica de produto trata o mesmo POST como 202-enfileirado — o recurso usa o contrato discriminado 202: retorna `Nfe::Resources::ProductInvoiceRtcPending` (202 + `Location`) ou `Nfe::Resources::ProductInvoiceRtcIssued` (201 + corpo). Aceita `idempotency_key:` opcional (header `Idempotency-Key`; POST não é auto-retried) e `request_options:` opcional (`Nfe::RequestOptions`, sobrepõe `api_key`/`base_url`/`timeout` por chamada). +- **`create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)`** — `POST /v2/companies/{company_id}/statetaxes/{state_tax_id}/productinvoices`; emite contra uma Inscrição Estadual específica. Mesmo corpo RTC e mesmos `idempotency_key:`/`request_options:` do `create`. Carregado da superfície clássica de produto por paridade. +- **`retrieve(company_id:, invoice_id:)`** — `GET /v2/companies/{company_id}/productinvoices/{invoice_id}`; hidrata `InvoiceResource`. +- **`list(company_id:, ...)`** — `GET /v2/companies/{company_id}/productinvoices`; `environment` obrigatório; paginação por cursor (`starting_after`/`ending_before`/`limit`/`q`) via `Nfe::ListResponse`/`Nfe::ListPage`. +- **`cancel(company_id:, invoice_id:, reason:)`** — `DELETE /v2/companies/{company_id}/productinvoices/{invoice_id}?reason=`; assíncrono (204-enfileirado); retorna `RequestCancellationResource` (`{account_id, company_id, product_invoice_id, reason}`). +- **`list_items(company_id:, invoice_id:)`** — `GET .../items` (`InvoiceItemsResource`). +- **`list_events(company_id:, invoice_id:)`** — `GET .../events` (`InvoiceEventsResource` de `ActivityResource`). +- **`download_pdf` / `download_xml` / `download_rejection_xml` / `download_epec_xml`** — `GET .../pdf?force=` (DANFE), `.../xml` (autorizado), `.../xml-rejection`, `.../xml-epec` (contingência EPEC). Cada um retorna `Nfe::NfeFileResource` (uma URI), igual à superfície clássica `product_invoices` e ao schema `FileResource{uri}` de `nf-produto-v2.yaml` — não bytes crus. +- **`send_correction_letter(company_id:, invoice_id:, reason:)`** — `PUT .../correctionletter` (CC-e; `reason` 15–1000 chars, sem acentos/especiais; assíncrono). +- **`download_correction_letter_pdf` / `download_correction_letter_xml`** — `GET .../correctionletter/pdf` e `.../correctionletter/xml`; cada um retorna `Nfe::NfeFileResource` (uma URI), igual à superfície clássica `product_invoices`. +- **`disable(company_id:, invoice_id:, reason:)`** — `POST .../disablement?reason=` (inutilização de uma nota; assíncrono). +- **`disable_range(company_id:, data:)`** — `POST /v2/companies/{company_id}/productinvoices/disablement` (inutilização de faixa de numeração; corpo `DisablementResource`). + +> A spec RTC de produto define formalmente **apenas** o `create` (POST). Os demais métodos de ciclo de vida (retrieve/list/cancel/events/items/downloads/CC-e/inutilização) são carregados da superfície **clássica** `product_invoices` (mesmo host `api.nfse.io` e mesma base `/v2`) por paridade, dando ao recurso RTC um ciclo de vida completo — exatamente como o Node prevê layering por cima do `productInvoicesRtc.create`. + +### DTOs gerados (pipeline) + +- Sincronizar `service-invoice-rtc-v1.yaml` E `product-invoice-rtc-v1.yaml` para o set de specs do gerador. +- Emitir, sob `lib/nfe/generated/service_invoice_rtc_v1/`, os value objects `Data.define` dos 18 schemas nomeados da NFS-e RTC: `NFSeRequest`, `ibsCbs` (com `ibs`/`cbs`/`regularTaxation`/`presumedCredits`/`governmentPurchase`/`creditTransfer`/`thirdPartyReimbursements`), `addressDefinition`, `partyDefinition`, `serviceAmountDefinitions`, `approximateTax`, `deduction`, `benefit`, `suspension`, etc., mais `sig/` correspondente. +- Emitir, sob `lib/nfe/generated/product_invoice_rtc_v1/`, os value objects `Data.define` dos 140 schemas nomeados da NF-e/NFC-e RTC, incluindo: `ProductInvoiceRequest` (raiz; `required: items, payment`), `InvoiceResource`, `InvoiceWithoutEventsResource`, `ProductInvoicesResource`, `InvoiceItemResource`, `InvoiceItemTaxResource` (carrega `IS` + `IBSCBS`), `IBSCBSTaxResource`, `IBSStateTaxResource`, `IBSMunicipalTaxResource`, `CBSTaxResource`, `ISTaxResource`, `DefermentTaxResource`, `ReturnedTaxResource`, `ReductionTaxResource`, `RegularTaxationResource`, `GovernmentPurchaseTaxResource`, `MonophaseIBSCBSTaxResource`, `CreditTransferTaxResource`, `OperationalPresumedCreditResource`, `CreditReversalResource`, `ZfmPresumedCreditResource`, `CompetenceAdjustmentResource`, os totais (`IBSCBSTotalsResource`, `IBSTotalsResource`, `CBSTotalsResource`, `ISTotalsResource`, `Monophase*Totals`, `TotalsWithholdings`), os enums (`PrintType`, `OperationType`, `ConsumerType`, `ConsumerPresenceType`, `PurposeType`, `InvoiceStatus`), e `RequestCancellationResource`/`DisablementResource`/`FileResource`/`ErrorResource`/`ErrorsResource`, mais `sig/` correspondente. + +### Classes de resposta (suporte) + +- `Nfe::Resources::ServiceInvoiceRtcPending` (implementa o protocolo `Nfe::Pending` de `add-client-core`: `invoice_id`, `location`, predicados `pending?`/`issued?`). +- `Nfe::Resources::ServiceInvoiceRtcIssued` (implementa o protocolo `Nfe::Issued` de `add-client-core`: `resource` → DTO de service-invoice RTC; predicados `issued?`/`pending?`). +- `Nfe::Resources::ProductInvoiceRtcPending` (implementa `Nfe::Pending`: `invoice_id`, `location`, predicados `pending?`/`issued?`). +- `Nfe::Resources::ProductInvoiceRtcIssued` (implementa `Nfe::Issued`: `resource` → `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource`; predicados `issued?`/`pending?`). + +> Os predicados `pending?`/`issued?` em cada classe RTC espelham a discriminação clássica (`is_a?` E predicado), consistente com os subtipos `Nfe::Resources::ServiceInvoicePending`/`Nfe::Resources::ServiceInvoiceIssued` de `add-invoice-resources`. + +## Capabilities + +### New Capabilities +- `rtc-invoice-emission`: recursos dedicados `service_invoices_rtc` (NFS-e, grupo raiz `ibsCbs`) e `product_invoices_rtc` (NF-e/NFC-e, grupos item-level `IBSCBS` com `state`/`municipal`/`cbs` e `IS`/Imposto Seletivo), ambos com contrato discriminado 202, validação de IDs, polling manual via `FlowStatus`, downloads binários e — para NFS-e — o download do XML de evento de cancelamento (Ambiente Nacional). + +### Modified Capabilities +- (nenhuma) — esta change é puramente aditiva. NÃO modifica a capability `invoice-resources` (de `add-invoice-resources`): os recursos clássicos `service_invoices` e `product_invoices` permanecem inalterados. + +## Impact + +- **Código afetado**: + - NFS-e RTC: novo `lib/nfe/resources/service_invoices_rtc.rb`; novos `lib/nfe/resources/service_invoice_rtc_pending.rb` e `service_invoice_rtc_issued.rb`; DTOs gerados em `lib/nfe/generated/service_invoice_rtc_v1/`; assinaturas em `sig/nfe/resources/service_invoices_rtc.rbs` e `sig/nfe/generated/service_invoice_rtc_v1/`. + - NF-e/NFC-e RTC: novo `lib/nfe/resources/product_invoices_rtc.rb`; novos `lib/nfe/resources/product_invoice_rtc_pending.rb` e `product_invoice_rtc_issued.rb`; DTOs gerados em `lib/nfe/generated/product_invoice_rtc_v1/`; assinaturas em `sig/nfe/resources/product_invoices_rtc.rbs` e `sig/nfe/generated/product_invoice_rtc_v1/`. + - Novos accessors lazy `service_invoices_rtc` e `product_invoices_rtc` em `lib/nfe/client.rb` (passa a expor 19 accessors); assinatura do `Client` atualizada. +- **Spec impact**: adiciona a capability `rtc-invoice-emission`. Sem deltas MODIFIED. +- **Dependências**: `add-client-core` (contrato 202 `Pending`/`Issued`, `FlowStatus`, `IdValidator`, `download`/`hydrate_list`/`handle_async_response` do `Nfe::Resources::AbstractResource`, `ListResponse`/`ListPage`, host map / roteamento multi-base-URL), `add-invoice-resources` (superfícies clássicas `service_invoices`/`product_invoices` e padrões dos subtipos `ServiceInvoicePending`/`ServiceInvoiceIssued`), `add-openapi-pipeline` (geração de DTOs `Data.define` + `.rbs` para as duas specs RTC). +- **Risks**: + - O leiaute RTC está **sujeito a Notas Técnicas** e homologação — tratamos as duas specs como snapshots fixados (`NT_2025.002_v1.30_RTC` para NFS-e; `NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS` para produto) e re-sincronizamos a cada NT. + - Quatro caminhos de emissão (clássico vs RTC, para serviço e para produto) podem confundir — mitigado por nomes distintos, doc clara e opt-in explícito. + - `download_cancellation_xml` (NFS-e) só existe em Ambiente Nacional — documentamos o 404 esperado para municipal/ABRASF e mapeamos para `Nfe::NotFoundError`. + - A spec RTC de produto documenta o `create` como `201` (a superfície clássica trata como `202`-enfileirado) — o recurso trata ambos via contrato discriminado; emissão é sempre assíncrona (conclusão por webhook/polling). O Ambiente Nacional NÃO se aplica ao produto (NF-e/NFC-e vai direto à SEFAZ). + - O volume de schemas do produto (140) é grande; o gerador pode não tipar todos os subgrupos aninhados de `IBSCBS`/`IS` — mantemos `Hash` como fallback no caminho de request. diff --git a/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/specs/rtc-invoice-emission/spec.md b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/specs/rtc-invoice-emission/spec.md new file mode 100644 index 0000000..8fc6f7b --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/specs/rtc-invoice-emission/spec.md @@ -0,0 +1,335 @@ +# rtc-invoice-emission — Delta + +## ADDED Requirements + +### Requirement: Dedicated RTC service-invoice resource exposed on the Client + +The SDK SHALL expose a dedicated resource `client.service_invoices_rtc` for emitting service invoices (NFS-e) under the Reforma Tributária do Consumo (RTC) layout. The classic `client.service_invoices` resource (from `add-invoice-resources`) SHALL remain unchanged; RTC emission SHALL be opt-in via the new resource. + +The resource SHALL target the `main` API family — host `https://api.nfe.io` (`base_url_for(:main)`), with the `/v1` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfe.io/v1/...` — resolved through `Nfe::Configuration`, reusing the same host client as the classic `service_invoices` resource. No new base URL SHALL be introduced. + +#### Scenario: Accessing the RTC resource from the Client + +- **WHEN** a consumer reads `client.service_invoices_rtc` +- **THEN** the accessor SHALL return a fully functional `Nfe::Resources::ServiceInvoicesRtc` instance (lazily created and memoized), not a stub that raises `NoMethodError` + +#### Scenario: RTC reuses the main host without a new base URL + +- **WHEN** any method of `service_invoices_rtc` issues an HTTP request +- **THEN** the outgoing request SHALL target the host `https://api.nfe.io` (the `main` family, with the `/v1` segment supplied by the resource `api_version`, effective URL `https://api.nfe.io/v1/...`), the same host used by the classic `service_invoices` resource +- **AND** no new base-URL constant SHALL be added to `Nfe::Configuration` + +#### Scenario: Classic service-invoice resource is unaffected + +- **WHEN** the RTC resource is added to the Client +- **THEN** `client.service_invoices` SHALL keep its existing method signatures and behavior unchanged + +### Requirement: RTC service-invoice emission supports the discriminated 202 contract + +`Nfe::Resources::ServiceInvoicesRtc#create` SHALL accept keyword arguments `company_id:` and `data:`, where `data` is an `Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest` value object or a `Hash`. It SHALL issue `POST /companies/{company_id}/serviceinvoices` and SHALL return either a `Nfe::Resources::ServiceInvoiceRtcPending` (when the API responds HTTP 202 with a `Location` header) or a `Nfe::Resources::ServiceInvoiceRtcIssued` (when the API responds HTTP 201 with the materialized invoice body). + +The RTC layout SHALL be selected by the presence of the `ibsCbs` group in the payload — there is no header or query parameter. This is the same endpoint the classic `service_invoices` resource uses. + +`#create` SHALL additionally accept an optional `idempotency_key:` keyword (sent as the `Idempotency-Key` HTTP header for safe retries) and an optional `request_options:` keyword (an `Nfe::RequestOptions` from `add-client-core`, threaded into the request to override `api_key`/`base_url`/`timeout` per call). POST SHALL NOT be auto-retried by the transport. + +#### Scenario: Idempotency key forwarded as a header + +- **WHEN** `create(company_id:, data:, idempotency_key: "service-rtc-42")` is called +- **THEN** the outgoing request SHALL carry the `Idempotency-Key: service-rtc-42` header +- **AND** when `idempotency_key:` is omitted, no `Idempotency-Key` header SHALL be sent + +#### Scenario: Per-call request options override the Client defaults + +- **WHEN** `create(company_id:, data:, request_options: Nfe::RequestOptions.new(api_key: "tenant-key", base_url: nil, timeout: nil))` is called +- **THEN** the request SHALL authenticate with `tenant-key` for that call only, without mutating the shared Client + +#### Scenario: Async emission returns a Pending result + +- **WHEN** `client.service_invoices_rtc.create(company_id:, data:)` is called and the API responds HTTP 202 with `Location: /v1/companies/{company_id}/serviceinvoices/{invoice_id}` +- **THEN** the method SHALL return a `Nfe::Resources::ServiceInvoiceRtcPending` whose `invoice_id` matches the final path segment of the `Location` header (extracted via `%r{serviceinvoices/([a-z0-9-]+)}i`) +- **AND** whose `location` matches the header value + +#### Scenario: Immediate emission returns an Issued result + +- **WHEN** the API responds HTTP 201 with the invoice body +- **THEN** the method SHALL return a `Nfe::Resources::ServiceInvoiceRtcIssued` whose `resource` returns a service-invoice RTC DTO hydrated from the response body + +#### Scenario: 202 without a Location header raises a processing error + +- **WHEN** the API responds HTTP 202 but omits the `Location` header +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` + +#### Scenario: Payload carries the ibsCbs group + +- **WHEN** `create` is called with the spec's minimum payload (`borrower`, `cityServiceCode`, `federalServiceCode`, `description`, `servicesAmount`, `nbsCode`, and an `ibsCbs` group) +- **THEN** the serialized request body SHALL contain the `ibsCbs` group with `operationIndicator` matching `^[0-9]{6}$` and a `classCode` of at most 6 characters +- **AND** both `operationIndicator` and `classCode` SHALL be required within the `ibsCbs` group + +### Requirement: RTC service-invoice retrieve and cancel + +`Nfe::Resources::ServiceInvoicesRtc` SHALL expose `retrieve(company_id:, invoice_id:)` issuing `GET /companies/{company_id}/serviceinvoices/{invoice_id}` and `cancel(company_id:, invoice_id:)` issuing `DELETE /companies/{company_id}/serviceinvoices/{invoice_id}`. + +#### Scenario: Retrieve returns a typed DTO + +- **WHEN** `retrieve(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a service-invoice RTC value object (`Data.define`) hydrated from the response body, exposing at least `flow_status` + +#### Scenario: Retrieve of a missing invoice raises NotFoundError + +- **WHEN** `retrieve(company_id:, invoice_id:)` receives HTTP 404 +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +#### Scenario: Cancel returns the updated invoice synchronously + +- **WHEN** `cancel(company_id:, invoice_id:)` is called +- **THEN** the SDK SHALL issue the `DELETE` request and return the updated service-invoice RTC DTO + +### Requirement: Download the cancellation-event XML (Ambiente Nacional) + +`Nfe::Resources::ServiceInvoicesRtc` SHALL expose `download_cancellation_xml(company_id:, invoice_id:)` issuing `GET /companies/{company_id}/serviceinvoices/{invoice_id}/cancellation-xml` with `Accept: application/xml`. It SHALL return the cancellation-event (`e110001`) XML as a binary-safe `String` (encoding `ASCII-8BIT`). This endpoint is available only for invoices in the Ambiente Nacional (ADN) and only after the invoice reaches the `Cancelled` status. + +#### Scenario: Cancellation XML returns raw bytes + +- **WHEN** `download_cancellation_xml(company_id:, invoice_id:)` succeeds for a cancelled Ambiente Nacional invoice +- **THEN** the return value SHALL be a `String` whose encoding is `ASCII-8BIT` and whose first non-BOM character is `<` + +#### Scenario: Municipal/ABRASF provider has no cancellation event + +- **WHEN** `download_cancellation_xml` is called for an invoice from a municipal/ABRASF provider, or for an invoice not yet cancelled, and the API responds HTTP 404 +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +### Requirement: Fail-fast identifier validation before the HTTP request + +Every `ServiceInvoicesRtc` method that takes a `company_id` or `invoice_id` SHALL validate it through `Nfe::IdValidator` (from `add-client-core`) before issuing any HTTP request, raising `Nfe::InvalidRequestError` synchronously on empty or whitespace-only values. + +#### Scenario: Empty company ID rejected before HTTP + +- **WHEN** any `ServiceInvoicesRtc` method is called with an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` with a Portuguese-language message identifying the invalid argument +- **AND** no HTTP request SHALL be issued + +#### Scenario: Empty invoice ID rejected before HTTP + +- **WHEN** `retrieve`, `cancel`, or `download_cancellation_xml` is called with an empty `invoice_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` without issuing an HTTP request + +### Requirement: Discriminated RTC response classes + +The SDK SHALL provide concrete, immutable response classes for RTC service-invoice creation, implementing the `Pending` and `Issued` protocols defined in `add-client-core`: + +- `Nfe::Resources::ServiceInvoiceRtcPending` implementing `Pending` — exposing `invoice_id`, `location`, and the predicate `pending?` (returning `true`) / `issued?` (returning `false`) +- `Nfe::Resources::ServiceInvoiceRtcIssued` implementing `Issued` — exposing `resource` typed at the service-invoice RTC DTO, and the predicate `issued?` (returning `true`) / `pending?` (returning `false`) + +#### Scenario: Discriminating with is_a? + +- **WHEN** a consumer writes `if result.is_a?(Nfe::Resources::ServiceInvoiceRtcPending) then ... else ... end` +- **THEN** the pending branch SHALL expose `invoice_id`/`location` and the issued branch SHALL expose `resource` +- **AND** the two classes SHALL be distinct from the classic `Nfe::Resources::ServiceInvoicePending`/`Nfe::Resources::ServiceInvoiceIssued` + +#### Scenario: Discriminating with predicate methods + +- **WHEN** a consumer receives the result of `create` and calls `result.pending?` / `result.issued?` +- **THEN** `Nfe::Resources::ServiceInvoiceRtcPending#pending?` SHALL return `true` and `#issued?` SHALL return `false` +- **AND** `Nfe::Resources::ServiceInvoiceRtcIssued#issued?` SHALL return `true` and `#pending?` SHALL return `false` + +### Requirement: RTC DTOs are generated from the named OpenAPI schemas + +The OpenAPI pipeline (from `add-openapi-pipeline`) SHALL sync `service-invoice-rtc-v1.yaml` from `nfeio-docs` and emit immutable `Data.define` value objects under `lib/nfe/generated/service_invoice_rtc_v1/` for the spec's named schemas, including `NFSeRequest` and the nested `ibsCbs` group, plus corresponding `.rbs` signatures under `sig/`. Generated files SHALL NOT be hand-edited. + +#### Scenario: NFSeRequest generated as an immutable value object + +- **WHEN** the pipeline generates types from `service-invoice-rtc-v1.yaml` +- **THEN** `Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest` SHALL exist as a `Data.define` value object exposing snake_case accessors (e.g., `services_amount`, `nbs_code`, `city_service_code`) +- **AND** it SHALL carry the nested `ibsCbs` group with `operation_indicator`, `class_code`, `situation_code`, `ibs`, and `cbs` + +#### Scenario: Generated files carry the frozen-string-literal magic comment + +- **WHEN** any file under `lib/nfe/generated/service_invoice_rtc_v1/` is generated +- **THEN** it SHALL start with `# frozen_string_literal: true` + +### Requirement: Manual polling via FlowStatus terminal-state helper + +The SDK SHALL support manual polling of RTC emission by reusing `Nfe::FlowStatus.terminal?` from `add-client-core`. The SDK v1 SHALL NOT implement `create_and_wait` or `create_batch` on the RTC resource. + +#### Scenario: Polling until a terminal flow status + +- **WHEN** a consumer receives a `Nfe::Resources::ServiceInvoiceRtcPending` and loops calling `retrieve` until `Nfe::FlowStatus.terminal?(invoice.flow_status)` returns `true` +- **THEN** the loop SHALL terminate when `flow_status` is one of `Issued`, `IssueFailed`, `Cancelled`, or `CancelFailed` + +#### Scenario: create_and_wait is not defined + +- **WHEN** consumer code calls `client.service_invoices_rtc.create_and_wait(...)` +- **THEN** Ruby SHALL raise `NoMethodError`, since the method is not defined in v1 + +### Requirement: Dedicated RTC product-invoice resource exposed on the Client + +The SDK SHALL expose a dedicated resource `client.product_invoices_rtc` for emitting product invoices (NF-e modelo 55 and NFC-e modelo 65) under the Reforma Tributária do Consumo (RTC) layout. The classic `client.product_invoices` resource (from `add-invoice-resources`) SHALL remain unchanged; RTC emission SHALL be opt-in via the new resource. + +The resource SHALL target the `cte` API family (alias `:product_invoices`) — host `https://api.nfse.io` (`base_url_for(:cte)`), with the `/v2` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfse.io/v2/...` — resolved through `Nfe::Configuration`, reusing the same host client as the classic `product_invoices` resource. No new base URL SHALL be introduced, and the resource SHALL NOT be routed to the `main` host `https://api.nfe.io`. + +#### Scenario: Accessing the product RTC resource from the Client + +- **WHEN** a consumer reads `client.product_invoices_rtc` +- **THEN** the accessor SHALL return a fully functional `Nfe::Resources::ProductInvoicesRtc` instance (lazily created and memoized), not a stub that raises `NoMethodError` + +#### Scenario: Product RTC reuses the api.nfse.io host without a new base URL + +- **WHEN** any method of `product_invoices_rtc` issues an HTTP request +- **THEN** the outgoing request SHALL target the host `https://api.nfse.io` (the `cte` family, with the `/v2` segment supplied by the resource `api_version`, effective URL `https://api.nfse.io/v2/...`), the same host used by the classic `product_invoices` resource +- **AND** no new base-URL constant SHALL be added to `Nfe::Configuration`, and the request SHALL NOT target `https://api.nfe.io` + +#### Scenario: Classic product-invoice resource is unaffected + +- **WHEN** the product RTC resource is added to the Client +- **THEN** `client.product_invoices` SHALL keep its existing method signatures and behavior unchanged + +### Requirement: RTC product-invoice emission supports the discriminated 202 contract + +`Nfe::Resources::ProductInvoicesRtc#create` SHALL accept keyword arguments `company_id:` and `data:`, where `data` is an `Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest` value object or a `Hash`. It SHALL issue `POST /companies/{company_id}/productinvoices` and SHALL return either a `Nfe::Resources::ProductInvoiceRtcPending` (when the API responds HTTP 202 with a `Location` header) or a `Nfe::Resources::ProductInvoiceRtcIssued` (when the API responds HTTP 201 with the materialized invoice body). + +The RTC layout SHALL be selected by the presence of the item-level `IBSCBS` group in the payload — there SHALL be no header or query parameter. This is the same endpoint the classic `product_invoices` resource uses. Emission SHALL be treated as asynchronous regardless of whether the API returns HTTP 201 or 202. + +Both `#create` and `#create_with_state_tax` SHALL additionally accept an optional `idempotency_key:` keyword (sent as the `Idempotency-Key` HTTP header for safe retries) and an optional `request_options:` keyword (an `Nfe::RequestOptions` from `add-client-core`, threaded into the request to override `api_key`/`base_url`/`timeout` per call). POST SHALL NOT be auto-retried by the transport. + +#### Scenario: Idempotency key forwarded as a header + +- **WHEN** `create(company_id:, data:, idempotency_key: "product-rtc-42")` is called +- **THEN** the outgoing request SHALL carry the `Idempotency-Key: product-rtc-42` header +- **AND** when `idempotency_key:` is omitted, no `Idempotency-Key` header SHALL be sent + +#### Scenario: Per-call request options override the Client defaults + +- **WHEN** `create(company_id:, data:, request_options: Nfe::RequestOptions.new(api_key: "tenant-key", base_url: nil, timeout: nil))` is called +- **THEN** the request SHALL authenticate with `tenant-key` for that call only, without mutating the shared Client + +#### Scenario: Async product emission returns a Pending result + +- **WHEN** `client.product_invoices_rtc.create(company_id:, data:)` is called and the API responds HTTP 202 with `Location: /v2/companies/{company_id}/productinvoices/{invoice_id}` +- **THEN** the method SHALL return a `Nfe::Resources::ProductInvoiceRtcPending` whose `invoice_id` matches the final path segment of the `Location` header (extracted via `%r{productinvoices/([a-z0-9-]+)}i`) +- **AND** whose `location` matches the header value + +#### Scenario: Immediate product emission returns an Issued result + +- **WHEN** the API responds HTTP 201 with the invoice body +- **THEN** the method SHALL return a `Nfe::Resources::ProductInvoiceRtcIssued` whose `resource` returns a `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource` hydrated from the response body + +#### Scenario: 202 without a Location header raises a processing error + +- **WHEN** the API responds HTTP 202 but omits the `Location` header +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` + +#### Scenario: No discriminator header or parameter is sent + +- **WHEN** `create` is called with a payload carrying the item-level `IBSCBS` group +- **THEN** the serialized request SHALL select the RTC layout solely by payload shape +- **AND** no header or query parameter naming a `model`/`mod` or RTC flag SHALL be added to the request + +### Requirement: Product RTC payload carries item-level IBS/CBS and IS tax groups + +The product RTC payload SHALL carry the new RTC tax groups at the item level, on `InvoiceItemTaxResource` (`items[].tax`), alongside the legacy groups. The `IBSCBS` group (`IBSCBSTaxResource`) SHALL split IBS into a state sphere (`state` → `IBSStateTaxResource`) and a municipal sphere (`municipal` → `IBSMunicipalTaxResource`), with CBS (`cbs` → `CBSTaxResource`) being federal and carrying no state/municipal split. The `IS` group (`ISTaxResource`, Imposto Seletivo) SHALL be a product-only tax group with no equivalent on the NFS-e RTC payload. + +#### Scenario: IBSCBS group present with state, municipal, and federal CBS + +- **WHEN** `create` is called with an item carrying `items[].tax.IBSCBS` +- **THEN** the serialized `IBSCBS` group SHALL contain a `state` sub-group and a `municipal` sub-group for IBS, each exposing `rate` and `amount` +- **AND** it SHALL contain a single federal `cbs` sub-group with no state/municipal split + +#### Scenario: Imposto Seletivo (IS) group present on the item + +- **WHEN** `create` is called with an item carrying `items[].tax.IS` +- **THEN** the serialized `IS` group SHALL expose `situation_code`, `classification_code`, `basis`, `rate`, and `amount` +- **AND** the `IS` group SHALL be specific to the product RTC payload and absent from the NFS-e RTC payload + +### Requirement: NF-e and NFC-e share one resource, distinguished by payload shape + +`Nfe::Resources::ProductInvoicesRtc` SHALL emit both NF-e (modelo 55) and NFC-e (modelo 65) through the single `create` method and the single `POST /companies/{company_id}/productinvoices` endpoint. The two SHALL be distinguished by the shape of the payload — `print_type` (`PrintType`), `consumer_type`/`presence_type`, presence of `buyer`, and presence of `expected_delivery_on` — and SHALL NOT require a discriminator field on the request root nor a separate endpoint. + +#### Scenario: NFC-e emitted via the same endpoint as NF-e + +- **WHEN** `create` is called once with an NF-e payload (`print_type` an `NFe*` value, `buyer` present) and once with an NFC-e payload (`print_type` `DANFE_NFC_E`, `consumer_type`/`presence_type` set, no `buyer`) +- **THEN** both requests SHALL be issued to the same `POST /companies/{company_id}/productinvoices` endpoint on `https://api.nfse.io` +- **AND** neither request SHALL include a `model`/`mod` discriminator on the request root + +### Requirement: Product RTC lifecycle methods + +`Nfe::Resources::ProductInvoicesRtc` SHALL expose, carried over from the classic product surface on the same host and base path, the following methods: `create_with_state_tax(company_id:, state_tax_id:, data:)` issuing `POST /companies/{company_id}/statetaxes/{state_tax_id}/productinvoices`; `retrieve(company_id:, invoice_id:)`; `list(company_id:, environment:, ...)` with cursor pagination; `cancel(company_id:, invoice_id:, reason:)`; `list_items`; `list_events`; the file-resource downloads `download_pdf`, `download_xml`, `download_rejection_xml`, `download_epec_xml` (each returning a `Nfe::NfeFileResource` URI, matching the classic `ProductInvoices` contract and `nf-produto-v2.yaml` `FileResource{uri}`); the correction-letter methods `send_correction_letter`, `download_correction_letter_pdf`, `download_correction_letter_xml`; and the disablement methods `disable`, `disable_range`. + +#### Scenario: Retrieve returns a typed InvoiceResource + +- **WHEN** `retrieve(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource` value object hydrated from the response body, exposing at least `flow_status` + +#### Scenario: Retrieve of a missing invoice raises NotFoundError + +- **WHEN** `retrieve(company_id:, invoice_id:)` receives HTTP 404 +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +#### Scenario: List returns a paginated ListResponse + +- **WHEN** `list(company_id:, environment:)` succeeds +- **THEN** the return value SHALL be a `Nfe::ListResponse` exposing the `product_invoices` page and cursor pagination (`starting_after`/`ending_before`/`limit`) + +#### Scenario: Cancel is asynchronous and returns a cancellation resource + +- **WHEN** `cancel(company_id:, invoice_id:, reason:)` is called +- **THEN** the SDK SHALL issue `DELETE /companies/{company_id}/productinvoices/{invoice_id}?reason=` and return a `RequestCancellationResource` + +#### Scenario: Downloads return a file resource URI + +- **WHEN** `download_pdf`, `download_xml`, `download_rejection_xml`, or `download_epec_xml` succeeds +- **THEN** the return value SHALL be a `Nfe::NfeFileResource` exposing a `uri` (matching the `FileResource{uri}` schema in `nf-produto-v2.yaml`), NOT raw `ASCII-8BIT` bytes +- **AND** this SHALL match the classic `ProductInvoices` download contract + +#### Scenario: Disablement of a numbering range + +- **WHEN** `disable_range(company_id:, data:)` is called +- **THEN** the SDK SHALL issue `POST /companies/{company_id}/productinvoices/disablement` with a `DisablementResource`-shaped body and return a `DisablementResource` + +### Requirement: Fail-fast identifier validation on the product RTC resource + +Every `ProductInvoicesRtc` method that takes a `company_id`, `invoice_id`, or `state_tax_id` SHALL validate it through `Nfe::IdValidator` (from `add-client-core`) before issuing any HTTP request, raising `Nfe::InvalidRequestError` synchronously on empty or whitespace-only values. + +#### Scenario: Empty company ID rejected before HTTP + +- **WHEN** any `ProductInvoicesRtc` method is called with an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` with a Portuguese-language message identifying the invalid argument +- **AND** no HTTP request SHALL be issued + +#### Scenario: Empty state tax ID rejected before HTTP + +- **WHEN** `create_with_state_tax` is called with an empty `state_tax_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` without issuing an HTTP request + +### Requirement: Discriminated product RTC response classes + +The SDK SHALL provide concrete, immutable response classes for product RTC invoice creation, implementing the `Pending` and `Issued` protocols defined in `add-client-core`: + +- `Nfe::Resources::ProductInvoiceRtcPending` implementing `Pending` — exposing `invoice_id`, `location`, and the predicate `pending?` (returning `true`) / `issued?` (returning `false`) +- `Nfe::Resources::ProductInvoiceRtcIssued` implementing `Issued` — exposing `resource` typed at `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource`, and the predicate `issued?` (returning `true`) / `pending?` (returning `false`) + +#### Scenario: Discriminating product results with is_a? + +- **WHEN** a consumer writes `if result.is_a?(Nfe::Resources::ProductInvoiceRtcPending) then ... else ... end` +- **THEN** the pending branch SHALL expose `invoice_id`/`location` and the issued branch SHALL expose `resource` +- **AND** the two classes SHALL be distinct from the classic `Nfe::Resources::ProductInvoicePending`/`Nfe::Resources::ProductInvoiceIssued` and from the NFS-e RTC response classes + +#### Scenario: Discriminating product results with predicate methods + +- **WHEN** a consumer receives the result of `create` and calls `result.pending?` / `result.issued?` +- **THEN** `Nfe::Resources::ProductInvoiceRtcPending#pending?` SHALL return `true` and `#issued?` SHALL return `false` +- **AND** `Nfe::Resources::ProductInvoiceRtcIssued#issued?` SHALL return `true` and `#pending?` SHALL return `false` + +### Requirement: Product RTC DTOs are generated from the named OpenAPI schemas + +The OpenAPI pipeline (from `add-openapi-pipeline`) SHALL sync `product-invoice-rtc-v1.yaml` from `nfeio-docs` and emit immutable `Data.define` value objects under `lib/nfe/generated/product_invoice_rtc_v1/` for the spec's named schemas, including `ProductInvoiceRequest`, `InvoiceResource`, `InvoiceItemTaxResource`, `IBSCBSTaxResource`, `IBSStateTaxResource`, `IBSMunicipalTaxResource`, `CBSTaxResource`, and `ISTaxResource`, plus corresponding `.rbs` signatures under `sig/`. Generated files SHALL NOT be hand-edited. + +#### Scenario: ProductInvoiceRequest generated as an immutable value object + +- **WHEN** the pipeline generates types from `product-invoice-rtc-v1.yaml` +- **THEN** `Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest` SHALL exist as a `Data.define` value object exposing snake_case accessors +- **AND** `Nfe::Generated::ProductInvoiceRtcV1::IBSCBSTaxResource` SHALL exist exposing the `state`, `municipal`, and `cbs` sub-groups, and `Nfe::Generated::ProductInvoiceRtcV1::ISTaxResource` SHALL exist + +#### Scenario: Generated product files carry the frozen-string-literal magic comment + +- **WHEN** any file under `lib/nfe/generated/product_invoice_rtc_v1/` is generated +- **THEN** it SHALL start with `# frozen_string_literal: true` diff --git a/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/tasks.md b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/tasks.md new file mode 100644 index 0000000..f738f35 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-rtc-invoice-emission/tasks.md @@ -0,0 +1,133 @@ +# Tasks — add-rtc-invoice-emission + +> Greenfield planning. Todos os itens UNCHECKED. Depende de `add-client-core` (contrato 202 `Pending`/`Issued`, `FlowStatus`, `IdValidator`, `download`/`hydrate_list`/`handle_async_response` do `Nfe::Resources::AbstractResource`, `ListResponse`/`ListPage`, host map / roteamento multi-base-URL), de `add-invoice-resources` (superfícies clássicas `service_invoices`/`product_invoices` e padrões dos subtipos `ServiceInvoicePending`/`ServiceInvoiceIssued`) e de `add-openapi-pipeline` (geração de DTOs `Data.define` + assinaturas `.rbs`). +> +> A change cobre DOIS recursos RTC: **NFS-e** (`service_invoices_rtc`, §§1–6) e **NF-e/NFC-e** (`product_invoices_rtc`, §§7–11). Ordem sugerida: §1 (pipeline NFS-e) → §2 (responses NFS-e) → §3 (resource NFS-e) → §4 (client wiring) → §5 (testes NFS-e) → §7 (pipeline produto) → §8 (responses produto) → §9 (resource produto) → §10 (testes produto) → §6/§11 (docs/validação). + +## 1. Pipeline: sincronizar e gerar DTOs RTC (depende de add-openapi-pipeline) + +- [x] 1.1 Adicionar `service-invoice-rtc-v1.yaml` ao manifesto de specs do gerador, sincronizando a partir de `nfeio-docs` (fonte da verdade; o snapshot fixado é `NT_2025.002_v1.30_RTC`, `version: v3`). Registrar a origem e a data do snapshot em comentário do manifesto. +- [x] 1.2 Rodar o gerador e confirmar que ele emite, sob `lib/nfe/generated/service_invoice_rtc_v1/`, value objects `Data.define` imutáveis para os 18 schemas nomeados: `NFSeRequest`, `ibsCbs`, `addressDefinition`, `partyDefinition`, `serviceAmountDefinitions`, `activityEvent`, `approximateTax`, `ReferenceSubstitution`, `lease`, `construction`, `realEstate`, `foreignTrade`, `deduction`, `deductionDocument`, `benefit`, `suspension`, `approximateTotals`, `thirdPartyReimbursementDocument`. +- [x] 1.3 Confirmar que o subgrupo aninhado `ibsCbs` gera (ou expõe via tipos aninhados) os campos do grupo IBS/CBS: `operation_indicator` (cIndOp, `^[0-9]{6}$`), `class_code` (cClassTrib, max 6), `situation_code` (CST, opcional/derivável), `purpose` (enum `regular`, default), `destination_indicator` (`SameAsBuyer`/`DifferentFromBuyer`), `basis`, `reimbursed_resupplied_amount`, `is_donation`, `personal_use`, e os subgrupos `ibs` (com `state`/`municipal`, cada um com `rate`/`effective_rate`/`deferment`/`amount`), `cbs` (`rate`/`effective_rate`/`deferment`/`amount`), `regular_taxation`, `presumed_credits`, `government_purchase`, `credit_transfer`, `third_party_reimbursements`. +- [x] 1.4 Confirmar nomes de campo em `snake_case` no Ruby gerado (ex.: `operationIndicator` → `operation_indicator`, `nbsCode` → `nbs_code`, `servicesAmount` → `services_amount`), com a chave JSON original preservada na serialização. +- [x] 1.5 Confirmar geração das assinaturas `sig/nfe/generated/service_invoice_rtc_v1/*.rbs` e que `bin/steep check` passa sobre os tipos gerados. +- [x] 1.6 Cada arquivo gerado inicia com `# frozen_string_literal: true` e o banner "DO NOT hand-edit — generated" do pipeline. NÃO editar manualmente nenhum arquivo sob `lib/nfe/generated/`. + +## 2. Classes de resposta (Pending + Issued concretas) + +- [x] 2.1 Criar `lib/nfe/resources/service_invoice_rtc_pending.rb` definindo `Nfe::Resources::ServiceInvoiceRtcPending` — implementa o protocolo `Nfe::Pending` de `add-client-core`; expõe `invoice_id` (extraído do header `Location` via regex `%r{serviceinvoices/([a-z0-9-]+)}i`), `location` e os predicados `pending?` (→ `true`) / `issued?` (→ `false`). Imutável (`Data.define`). `# frozen_string_literal: true`. +- [x] 2.2 Criar `lib/nfe/resources/service_invoice_rtc_issued.rb` definindo `Nfe::Resources::ServiceInvoiceRtcIssued` — implementa o protocolo `Nfe::Issued` de `add-client-core`; expõe `resource` retornando o DTO `Nfe::Generated::ServiceInvoiceRtcV1` de service-invoice hidratado do corpo 201 e os predicados `issued?` (→ `true`) / `pending?` (→ `false`). Imutável. +- [x] 2.3 Reusar o mesmo extrator de `invoice_id` do header `Location` que os subtipos clássicos de `add-invoice-resources` usam (não duplicar a regex); levantar `Nfe::InvoiceProcessingError` quando o 202 não trouxer header `Location`. +- [x] 2.4 Assinaturas `sig/nfe/resources/service_invoice_rtc_pending.rbs` e `sig/nfe/resources/service_invoice_rtc_issued.rbs`. + +## 3. Recurso `ServiceInvoicesRtc` + +- [x] 3.1 Criar `lib/nfe/resources/service_invoices_rtc.rb` com `# frozen_string_literal: true`. Herda do `Nfe::Resources::AbstractResource` (de `add-client-core`). `api_family` retorna `:main` → `base_url_for(:main)` resolve o host `https://api.nfe.io` via `Configuration` e o `/v1` vem do `api_version` do recurso (URL efetiva `https://api.nfe.io/v1/...`; sem hard-code de URL; reusa o mesmo host client do `service_invoices` clássico). +- [x] 3.2 `create(company_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /companies/{company_id}/serviceinvoices`. Aceita `data` como `Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest` OU `Hash`. Trata a resposta discriminada: 202 + `Location` → `Nfe::Resources::ServiceInvoiceRtcPending`; 201 + corpo → `Nfe::Resources::ServiceInvoiceRtcIssued`. `idempotency_key:` → header `Idempotency-Key` (POST NÃO auto-retried); `request_options:` (`Nfe::RequestOptions` de `add-client-core`) repassado ao request/transport (override de `api_key`/`base_url`/`timeout` por chamada). Documentar no comentário que o leiaute RTC é selecionado pela presença do grupo `ibsCbs` no payload (sem header/param) e que é o **mesmo endpoint** do `service_invoices` clássico. +- [x] 3.3 `retrieve(company_id:, invoice_id:)` — `GET /companies/{company_id}/serviceinvoices/{invoice_id}`; hidrata o DTO de service-invoice RTC; levanta `Nfe::NotFoundError` quando não houver dados (404). +- [x] 3.4 `cancel(company_id:, invoice_id:)` — `DELETE /companies/{company_id}/serviceinvoices/{invoice_id}`; retorna o DTO de invoice atualizado (síncrono). +- [x] 3.5 `download_cancellation_xml(company_id:, invoice_id:)` — `GET /companies/{company_id}/serviceinvoices/{invoice_id}/cancellation-xml` com `Accept: application/xml`. Usa o helper `download` do `Nfe::Resources::AbstractResource`; retorna `String` binária (`force_encoding('ASCII-8BIT')`). Documentar: apenas Ambiente Nacional (ADN), só após status `Cancelled`; 404 (municipal/ABRASF ou ainda não cancelada) → `Nfe::NotFoundError`. +- [x] 3.6 Validar IDs no início de cada método via `Nfe::IdValidator.company_id` e `Nfe::IdValidator.invoice_id` (de `add-client-core`), levantando `Nfe::InvalidRequestError` em pt-BR antes de qualquer chamada HTTP (fail-fast). +- [x] 3.7 Expor (documentar) o helper de polling manual: o caller usa `retrieve` em loop até `Nfe::FlowStatus.terminal?(invoice.flow_status)`. NÃO implementar `create_and_wait` nem `create_batch` (vide design D5). +- [x] 3.8 Comentário de cabeçalho do recurso documentando a superfície RTC vs clássica e o status "leiaute sujeito a Notas Técnicas (snapshot NT_2025.002_v1.30_RTC)". + +## 4. Wiring no Client + +- [x] 4.1 Adicionar accessor lazy `service_invoices_rtc` em `lib/nfe/client.rb` — instancia `Nfe::Resources::ServiceInvoicesRtc` sob demanda, passando o host client `main` (reusado, não um novo). Snake_case, consistente com os demais accessors. +- [x] 4.2 Adicionar accessor lazy `product_invoices_rtc` em `lib/nfe/client.rb` — instancia `Nfe::Resources::ProductInvoicesRtc` sob demanda, passando o host client `cte`/`api.nfse.io` (reusado, mesmo do `product_invoices` clássico, não um novo). Snake_case. +- [x] 4.3 Atualizar a contagem de accessors do Client (passa de 17 para 19 com os dois recursos RTC) onde houver asserção/documentação dessa contagem, deixando claro que `service_invoices_rtc` e `product_invoices_rtc` são **paridade-plus / adendo RTC** (não constam dos 17 recursos canônicos do PHP/Node). +- [x] 4.4 Assinaturas `sig/nfe/resources/service_invoices_rtc.rbs` e `sig/nfe/resources/product_invoices_rtc.rbs` e atualização da assinatura do `Client` para incluir os dois novos accessors. + +## 5. Testes (RSpec, cobertura >= 80%) + +- [x] 5.1 `spec/nfe/resources/service_invoices_rtc_spec.rb` — `create` 202 → `Nfe::Resources::ServiceInvoiceRtcPending` com `invoice_id` extraído do `Location` e `location` correto. +- [x] 5.2 `create` 201 → `Nfe::Resources::ServiceInvoiceRtcIssued` com `resource` hidratado a partir do corpo. +- [x] 5.3 `create` 202 sem header `Location` → levanta `Nfe::InvoiceProcessingError`. +- [x] 5.4 `create` com payload mínimo do exemplo `MinimumExample` da spec (`borrower`, `cityServiceCode`, `federalServiceCode`, `description`, `servicesAmount`, `nbsCode`, `ibsCbs{operationIndicator, classCode}`) — assertar que o corpo enviado contém o grupo `ibsCbs` com `operation_indicator` `^[0-9]{6}$` e `class_code`. +- [x] 5.5 `create` com `IntermediateExample` (subgrupos `ibs.state`/`ibs.municipal`/`cbs`) — round-trip do DTO `Data.define`. +- [x] 5.6 `retrieve` happy path → DTO tipado; 404 → `Nfe::NotFoundError`. +- [x] 5.7 `cancel` → DTO atualizado (síncrono). +- [x] 5.8 `download_cancellation_xml` → `String` binária começando com `<` (após BOM opcional); encoding `ASCII-8BIT`. +- [x] 5.9 `download_cancellation_xml` 404 (provedor municipal/ABRASF ou nota não cancelada) → `Nfe::NotFoundError`. +- [x] 5.10 Validação fail-fast: `company_id`/`invoice_id` vazio ou em branco → `Nfe::InvalidRequestError` SEM chamada HTTP (verificar via stub que o transport não foi invocado). +- [x] 5.10b `create(..., idempotency_key: "k")` → request carrega header `Idempotency-Key: k`; sem o kwarg, nenhum header `Idempotency-Key` é enviado. `create(..., request_options: Nfe::RequestOptions.new(api_key: "tenant-key", ...))` → autentica com `tenant-key` só naquela chamada, sem mutar o Client compartilhado. +- [x] 5.11 Roteamento: a requisição de qualquer método sai para o host `https://api.nfe.io` (família `main`; `/v1` via `api_version`, URL efetiva `https://api.nfe.io/v1/...`), idêntico ao `service_invoices` clássico. +- [x] 5.12 `spec/nfe/client_spec.rb` — `client.service_invoices_rtc` retorna uma instância funcional (memoizada na segunda leitura); contagem de accessors atualizada. +- [x] 5.13 Regressão: confirmar que `client.service_invoices` (clássico, de `add-invoice-resources`) permanece inalterado por esta change. + +## 6. Documentação, tipos e validação + +- [x] 6.1 README/exemplo: emissão de NFS-e RTC com grupo `ibsCbs` + loop de polling manual via `FlowStatus.terminal?`; nota de que RTC é opt-in via `service_invoices_rtc` e o clássico continua disponível. +- [x] 6.2 Documentar o snapshot fixado (`NT_2025.002_v1.30_RTC`) e o processo de re-sync a cada Nota Técnica. +- [x] 6.3 `bin/steep check` (Steep) limpo sobre o novo recurso, responses e DTOs. +- [x] 6.4 RuboCop limpo nos novos arquivos (`# frozen_string_literal: true` em todos). +- [x] 6.5 SimpleCov >= 80% no novo recurso. +- [x] 6.6 `openspec validate add-rtc-invoice-emission --strict` passa. + +## 7. Pipeline: sincronizar e gerar DTOs RTC de produto (depende de add-openapi-pipeline) + +- [x] 7.1 Adicionar `product-invoice-rtc-v1.yaml` ao manifesto de specs do gerador, sincronizando a partir de `nfeio-docs` (`docs/static/api/`; snapshot fixado `NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS`, `version: v3`, OpenAPI 3.0.1, host `https://api.nfse.io`). Registrar origem e data do snapshot em comentário do manifesto. +- [x] 7.2 Rodar o gerador e confirmar que ele emite, sob `lib/nfe/generated/product_invoice_rtc_v1/`, value objects `Data.define` imutáveis para os 140 schemas nomeados, incluindo a raiz `ProductInvoiceRequest` (`required: items, payment`), `InvoiceResource`, `InvoiceWithoutEventsResource`, `ProductInvoicesResource`, `InvoiceItemResource`, `InvoiceItemTaxResource`, `RequestCancellationResource`, `DisablementResource`, `FileResource`, `ErrorResource`/`ErrorsResource`, `InvoiceEventsResource`/`ActivityResource`, `InvoiceItemsResource` e `TaxpayerCommentsResource`. +- [x] 7.3 Confirmar que `InvoiceItemTaxResource` (em `items[].tax`) gera (ou expõe via tipos aninhados) os DOIS novos grupos RTC de nível de item, lado a lado com os grupos legados (`icms`/`ipi`/`ii`/`pis`/`cofins`/`icmsDestination`): (1) `IS` → `ISTaxResource` (Imposto Seletivo: `situation_code`, `classification_code`, `basis`, `rate`, `unit_rate`, `unit`, `quantity`, `amount`); (2) `IBSCBS` → `IBSCBSTaxResource`. +- [x] 7.4 Confirmar que `IBSCBSTaxResource` gera os campos `situation_code` (CST, derivável de `class_code`), `class_code` (cClassTrib, max 6), `calculation_mode` (enum `Manual`|`OfficialService`, default `Manual`), `donation_indicator`, `basis`, `ibs_total_amount`, e os subgrupos `state` → `IBSStateTaxResource`, `municipal` → `IBSMunicipalTaxResource`, `cbs` → `CBSTaxResource`, mais os mecanismos `regular_taxation`, `government_purchase`, `monophase`, `credit_transfer`, `operational_presumed_credit`, `credit_reversal`, `zfm_presumed_credit`. +- [x] 7.5 Confirmar que `IBSStateTaxResource` e `IBSMunicipalTaxResource` têm a mesma forma (`rate`, `deferment` → `DefermentTaxResource`, `returned_amount` → `ReturnedTaxResource`, `reduction` → `ReductionTaxResource`, `amount`), e que `CBSTaxResource` é federal (mesmos `rate`/`deferment`/`returned_amount`/`reduction`/`amount`, SEM split estadual/municipal). +- [x] 7.6 Confirmar geração do campo item-level `competence_adjustment` → `CompetenceAdjustmentResource` (gAjusteCompet) e dos totais (`IBSCBSTotalsResource`, `IBSTotalsResource`, `IBSStateTotalsResource`, `IBSMunicipalTotalsResource`, `CBSTotalsResource`, `ISTotalsResource`, `Monophase*Totals`, `TotalsWithholdings`). +- [x] 7.7 Confirmar geração dos enums `PrintType` (`None`|`NFeNormalPortrait`|`NFeNormalLandscape`|`NFeSimplified`|`DANFE_NFC_E`|`DANFE_NFC_E_MSG_ELETRONICA`), `OperationType`, `ConsumerType`, `ConsumerPresenceType`, `PurposeType`, `InvoiceStatus` (`None`|`Created`|`Processing`|`Issued`|`IssuedContingency`|`Cancelled`|`Disabled`|`IssueDenied`|`Error`). +- [x] 7.8 Confirmar nomes de campo em `snake_case` no Ruby gerado (chave JSON original preservada na serialização) e geração das assinaturas `sig/nfe/generated/product_invoice_rtc_v1/*.rbs`; `bin/steep check` limpo. +- [x] 7.9 Cada arquivo gerado inicia com `# frozen_string_literal: true` e o banner "DO NOT hand-edit — generated". NÃO editar manualmente nada sob `lib/nfe/generated/`. + +## 8. Classes de resposta de produto (Pending + Issued concretas) + +- [x] 8.1 Criar `lib/nfe/resources/product_invoice_rtc_pending.rb` definindo `Nfe::Resources::ProductInvoiceRtcPending` — implementa o protocolo `Nfe::Pending`; expõe `invoice_id` (extraído do header `Location` via regex `%r{productinvoices/([a-z0-9-]+)}i`), `location` e os predicados `pending?` (→ `true`) / `issued?` (→ `false`). Imutável (`Data.define`). `# frozen_string_literal: true`. +- [x] 8.2 Criar `lib/nfe/resources/product_invoice_rtc_issued.rb` definindo `Nfe::Resources::ProductInvoiceRtcIssued` — implementa o protocolo `Nfe::Issued`; expõe `resource` retornando o DTO `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource` hidratado do corpo 201 e os predicados `issued?` (→ `true`) / `pending?` (→ `false`). Imutável. +- [x] 8.3 Reusar o mesmo padrão de extração de `invoice_id` do header `Location` dos subtipos clássicos; levantar `Nfe::InvoiceProcessingError` quando o 202 não trouxer header `Location`. +- [x] 8.4 Assinaturas `sig/nfe/resources/product_invoice_rtc_pending.rbs` e `sig/nfe/resources/product_invoice_rtc_issued.rbs`. + +## 9. Recurso `ProductInvoicesRtc` + +- [x] 9.1 Criar `lib/nfe/resources/product_invoices_rtc.rb` com `# frozen_string_literal: true`. Herda do `Nfe::Resources::AbstractResource`. `api_family` retorna `:cte` (alias `:product_invoices`) → `base_url_for(:cte)` resolve `https://api.nfse.io`; `api_version` retorna `"v2"` (URL efetiva `https://api.nfse.io/v2/...`). Sem hard-code de URL; reusa o mesmo host client do `product_invoices` clássico. +- [x] 9.2 `create(company_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /companies/{company_id}/productinvoices`. Aceita `data` como `Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest` OU `Hash`. Trata a resposta discriminada: 202 + `Location` → `Nfe::Resources::ProductInvoiceRtcPending`; 201 + corpo → `Nfe::Resources::ProductInvoiceRtcIssued`. `idempotency_key:` → header `Idempotency-Key` (POST NÃO auto-retried); `request_options:` (`Nfe::RequestOptions`) repassado ao request/transport (override por chamada). Documentar no comentário: leiaute RTC selecionado pela presença do grupo item-level `IBSCBS` (sem header/param); NF-e (mod 55) vs NFC-e (mod 65) por forma do payload; emissão sempre assíncrona (spec documenta 201, clássico trata como 202). +- [x] 9.3 `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` — `POST /companies/{company_id}/statetaxes/{state_tax_id}/productinvoices`; mesmo corpo e mesmo tratamento discriminado de resposta; mesmos `idempotency_key:`/`request_options:` do `create`. Validar `state_tax_id` via `Nfe::IdValidator.state_tax_id`. +- [x] 9.4 `retrieve(company_id:, invoice_id:)` — `GET /companies/{company_id}/productinvoices/{invoice_id}`; hidrata `InvoiceResource`; 404 → `Nfe::NotFoundError`. +- [x] 9.5 `list(company_id:, environment:, starting_after: nil, ending_before: nil, limit: nil, q: nil)` — `GET /companies/{company_id}/productinvoices`; `environment` obrigatório; paginação por cursor via `hydrate_list` → `Nfe::ListResponse`/`Nfe::ListPage` (wrapper `ProductInvoicesResource`, `product_invoices[]` + `has_more`). +- [x] 9.6 `cancel(company_id:, invoice_id:, reason: nil)` — `DELETE /companies/{company_id}/productinvoices/{invoice_id}?reason=`; assíncrono (204-enfileirado); retorna `RequestCancellationResource`. +- [x] 9.7 `list_items(company_id:, invoice_id:)` — `GET .../items` (`InvoiceItemsResource`); `list_events(company_id:, invoice_id:)` — `GET .../events` (`InvoiceEventsResource` de `ActivityResource`). +- [x] 9.8 Downloads (retornam `Nfe::NfeFileResource` com `uri`, igual à superfície clássica `product_invoices` e ao schema `FileResource{uri}` de `nf-produto-v2.yaml` — NÃO bytes `ASCII-8BIT` crus): `download_pdf(company_id:, invoice_id:, force: false)` → `.../pdf?force=`; `download_xml` → `.../xml`; `download_rejection_xml` → `.../xml-rejection`; `download_epec_xml` → `.../xml-epec`. +- [x] 9.9 CC-e: `send_correction_letter(company_id:, invoice_id:, reason:)` — `PUT .../correctionletter` (corpo `{reason}`; `reason` 15–1000 chars, sem acentos/especiais; assíncrono); `download_correction_letter_pdf` → `.../correctionletter/pdf`; `download_correction_letter_xml` → `.../correctionletter/xml` (downloads retornam `Nfe::NfeFileResource` com `uri`, igual à superfície clássica `product_invoices`). +- [x] 9.10 Inutilização: `disable(company_id:, invoice_id:, reason:)` — `POST .../productinvoices/{invoice_id}/disablement?reason=` (assíncrono); `disable_range(company_id:, data:)` — `POST .../productinvoices/disablement` (corpo `DisablementResource`-shaped: `environment`, `serie`, `state`, `begin_number`, `last_number`, `reason?`), retorna `DisablementResource`. +- [x] 9.11 Validar IDs no início de cada método via `Nfe::IdValidator.company_id`/`.invoice_id`/`.state_tax_id`, levantando `Nfe::InvalidRequestError` em pt-BR antes de qualquer HTTP (fail-fast). +- [x] 9.12 Documentar polling manual: caller usa `retrieve` em loop até `Nfe::FlowStatus.terminal?(invoice.flow_status)`. NÃO implementar `create_and_wait`/`create_batch` (vide design D5). Comentário de cabeçalho documentando superfície RTC vs clássica, host `api.nfse.io`, e snapshot `NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS`. + +## 10. Testes de produto (RSpec, cobertura >= 80%) + +- [x] 10.1 `spec/nfe/resources/product_invoices_rtc_spec.rb` — `create` 202 → `Nfe::Resources::ProductInvoiceRtcPending` com `invoice_id` extraído do `Location` (`%r{productinvoices/([a-z0-9-]+)}i`) e `location` correto. +- [x] 10.2 `create` 201 → `Nfe::Resources::ProductInvoiceRtcIssued` com `resource` (`InvoiceResource`) hidratado. +- [x] 10.3 `create` 202 sem header `Location` → `Nfe::InvoiceProcessingError`. +- [x] 10.4 `create` com payload portando o grupo item-level `IBSCBS` — assertar que o corpo enviado contém `items[].tax.IBSCBS` com os subgrupos `state`/`municipal`/`cbs` e que IBS é dividido em estadual+municipal enquanto CBS é federal (sem split). +- [x] 10.5 `create` com grupo item-level `IS` (Imposto Seletivo) presente — round-trip do DTO `Data.define` (`situation_code`/`classification_code`/`rate`/`amount`). +- [x] 10.6 NFC-e vs NF-e: dois payloads — um NF-e (mod 55, `printType` NFe*, `buyer` presente) e um NFC-e (mod 65, `printType` `DANFE_NFC_E`, `consumerType`/`presenceType`, sem `buyer`/`expectedDeliveryOn`) — ambos passam pelo MESMO `create`/endpoint; assertar que nenhum header/param discriminador é enviado. +- [x] 10.7 `create_with_state_tax` → POST contra `.../statetaxes/{state_tax_id}/productinvoices`; `state_tax_id` inválido → `Nfe::InvalidRequestError` sem HTTP. +- [x] 10.8 `retrieve` happy path → `InvoiceResource`; 404 → `Nfe::NotFoundError`. +- [x] 10.9 `list` → `Nfe::ListResponse` com `product_invoices` e paginação por cursor; `environment` ausente → `ArgumentError`. +- [x] 10.10 `cancel` → `RequestCancellationResource`; `reason` repassado como query param. +- [x] 10.11 `list_items` / `list_events` → DTOs tipados. +- [x] 10.12 Downloads (`download_pdf`/`download_xml`/`download_rejection_xml`/`download_epec_xml`/`download_correction_letter_pdf`/`download_correction_letter_xml`) → `Nfe::NfeFileResource` com `uri` (igual à superfície clássica `product_invoices` e ao schema `FileResource{uri}` de `nf-produto-v2.yaml`); NÃO bytes `ASCII-8BIT` crus. +- [x] 10.13 `send_correction_letter` → assíncrono; `disable`/`disable_range` → DTOs corretos. +- [x] 10.14 Validação fail-fast: `company_id`/`invoice_id` vazio → `Nfe::InvalidRequestError` SEM chamada HTTP (verificar via stub que o transport não foi invocado). +- [x] 10.14b `create`/`create_with_state_tax(..., idempotency_key: "k")` → header `Idempotency-Key: k`; sem o kwarg, nenhum header enviado. `request_options:` (`Nfe::RequestOptions`) → override de `api_key` por chamada sem mutar o Client. +- [x] 10.15 Roteamento: a requisição de qualquer método sai para o host `https://api.nfse.io` (família `cte`; `/v2` via `api_version`, URL efetiva `https://api.nfse.io/v2/...`), idêntico ao `product_invoices` clássico. +- [x] 10.16 `spec/nfe/client_spec.rb` — `client.product_invoices_rtc` retorna instância funcional (memoizada); contagem de accessors atualizada (19). +- [x] 10.17 Regressão: confirmar que `client.product_invoices` (clássico) permanece inalterado por esta change. + +## 11. Documentação e validação (produto) + +- [x] 11.1 README/exemplo: emissão de NF-e/NFC-e RTC com grupos item-level `IBSCBS` (`state`/`municipal`/`cbs`) e `IS`; nota distinguindo NF-e (mod 55) de NFC-e (mod 65) por forma do payload; loop de polling manual via `FlowStatus.terminal?`; nota de que RTC é opt-in via `product_invoices_rtc` e o clássico continua disponível. +- [x] 11.2 Documentar o snapshot fixado (`NT_2025.002_v1.30_RTC_NF-e_IBS_CBS_IS`) e o processo de re-sync por Nota Técnica. +- [x] 11.3 `bin/steep check` limpo sobre `ProductInvoicesRtc`, suas responses e DTOs; RuboCop limpo (`# frozen_string_literal: true` em todos); SimpleCov >= 80% no novo recurso. + +## 12. Fora de escopo (registrado explicitamente) + +- [ ] 12.1 `create_and_wait` / `create_batch` — diferidos (vide design D5), consistente com `add-invoice-resources`, para ambos os recursos RTC. +- [ ] 12.2 Validação runtime/local dos campos RTC (ex.: tabelas de `operationIndicator`/`classCode`/`situationCode`, valores de IS) — a API valida server-side; o SDK só faz fail-fast de ID/access-key. +- [ ] 12.3 Novos EVENTOS de pós-autorização do RTC documentados no `fluxograma-ciclo-vida-nfe.md` (Solicitação de Apropriação de Crédito Presumido, Imobilização de Item, Destinação para Consumo Pessoal, Informação de Pagamento Integral, Perecimento/Perda/Roubo no Transporte, Atualização da Data de Previsão de Entrega) — ainda NÃO são endpoints na spec RTC; fora de escopo até virarem paths. +- [ ] 12.4 Motor de cálculo de IBS/CBS/IS (`calculo-impostos-v1`) — outro escopo; aqui o caller informa os valores no payload. diff --git a/openspec/changes/archive/2026-06-25-add-ruby-foundation/.openspec.yaml b/openspec/changes/archive/2026-06-25-add-ruby-foundation/.openspec.yaml new file mode 100644 index 0000000..fab62b4 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-ruby-foundation/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-24 diff --git a/openspec/changes/archive/2026-06-25-add-ruby-foundation/README.md b/openspec/changes/archive/2026-06-25-add-ruby-foundation/README.md new file mode 100644 index 0000000..2eccba2 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-ruby-foundation/README.md @@ -0,0 +1,3 @@ +# add-ruby-foundation + +Fundação do rewrite greenfield v1: gem `nfe-io` 1.0.0, namespace `Nfe`, piso Ruby 3.2, zero dependências de runtime, RBS/Steep/RuboCop/RSpec e CI matrix 3.2/3.3/3.4. diff --git a/openspec/changes/archive/2026-06-25-add-ruby-foundation/design.md b/openspec/changes/archive/2026-06-25-add-ruby-foundation/design.md new file mode 100644 index 0000000..56b9d8a --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-ruby-foundation/design.md @@ -0,0 +1,96 @@ +# Design — add-ruby-foundation + +## Context + +A gem `nfe-io` atual (v0.3.2) é Ruby 2.4-era: depende de `rest-client`, usa estado global (`@@api_key`), objetos dinâmicos (`Nfe::NfeObject` com `method_missing`), e cobre só quatro recursos. Os SDKs de referência já estabeleceram o padrão de paridade que a v1 Ruby deve seguir: + +- **Node.js** (`client-nodejs`, `nfe-io`): `NfeClient` + recursos como properties *lazy*, zero deps de runtime, multi-base-URL, polling de 202, hierarquia de erros tipada, tipos gerados de OpenAPI. +- **PHP** (`nfe/client-php`): mesma superfície, PHPStan L8, value objects, `Config::baseUrlForApi(family)` como fonte única de hosts. + +A filosofia de referência é **Stripe**: cliente único + acessores de recurso, serviços *hand-written* sobre modelos gerados. A v1 Ruby **não é refactor; é rewrite greenfield** — nada de `lib/nfe/*` legado é importado. Esta change estabelece o terreno onde as changes seguintes (HTTP core, codegen de OpenAPI, `Nfe::Client`, recursos) vão crescer. É a change **foundational**, sem dependências a montante. + +`nfeio-docs` (symlink `nfeio-docs/`) é a **fonte da verdade** para o comportamento da API; os SDKs Node e PHP são a **referência** para padrões e superfície de recursos. + +## Goals / Non-Goals + +**Goals:** +- Piso Ruby 3.2+ definido e enforced (gemspec `required_ruby_version` + CI matrix 3.2/3.3/3.4) +- Namespace raiz `Nfe`, entrypoint único `Nfe::Client.new(api_key:)` estilo Stripe, acessores *lazy* `snake_case` para os 17 recursos +- `# frozen_string_literal: true` na primeira linha de **todo** arquivo `.rb` (enforçado por RuboCop) +- **Zero dependências de runtime** — somente stdlib (`net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`); `rest-client` removido +- Value objects imutáveis via `Data.define` (Ruby 3.2+) +- Rigor de tipos paralelo ao Node (`.d.ts`) e PHP (PHPStan L8): RBS shipado em `sig/`, type-check com Steep, lint com RuboCop +- Testes com RSpec, cobertura >= 80% via SimpleCov, gate no CI +- `Configuration` como **fonte única** do mapa multi-base-URL (nenhum recurso hard-coda URL) +- Branch `0.x-legacy` congelado; v1 em `master` + +**Non-Goals:** +- Camada HTTP (`Net::HTTP` wrapper, retry, rate-limit) — change futura +- Codegen de OpenAPI (gerador + `lib/nfe/generated/` + `sig/nfe/generated/`) — change futura +- Qualquer corpo de recurso de API (CRUD, downloads, polling, 202) — changes futuras +- Suporte a Ruby < 3.2 ou shim de compat com a v0.x +- Backport de fixes para o `0.x-legacy` (fica congelado) +- Publicação no RubyGems (change de release) + +## Decisions + +### D1. Piso Ruby 3.2 (não 3.1, não 3.3) +**Decisão**: `spec.required_ruby_version = ">= 3.2"`; CI em 3.2 / 3.3 / 3.4. +**Por quê**: `Data.define` — base dos value objects imutáveis do SDK — só existe a partir do Ruby **3.2**. 3.1 não tem `Data`. 3.2 é o piso natural e ainda amplamente suportado. 3.3 e 3.4 entram como alvos de CI, não como piso. *Alternativa rejeitada*: piso 3.1 + `Struct`/`Comparable` artesanal — perde a imutabilidade e a ergonomia de `Data.define` por nada. + +### D2. Gem name permanece `nfe-io` (sem rename) +**Decisão**: `spec.name = "nfe-io"`, bump 0.3.2 → 1.0.0. +**Por quê**: Diferente do PHP (que renomeou `nfe/nfe` → `nfe/client-php`), no RubyGems o nome `nfe-io` já é o canônico e está publicado. Renomear fragmentaria a descoberta e quebraria `gem "nfe-io"` existente. O bump de **major** (SemVer) comunica a quebra; quem precisa do código antigo fixa `~> 0.3`. *Alternativa rejeitada*: novo nome `nfe-io-client` — confunde sem ganho. + +### D3. Layout `lib/nfe/`, gerados isolados em `lib/nfe/generated/` +**Decisão**: código *hand-written* em `lib/nfe/...`; modelos gerados em `lib/nfe/generated/`; RBS em `sig/` (com `sig/nfe/generated/` para os `.rbs` gerados). `lib/nfe/generated/` **nunca** é editado à mão. +**Por quê**: Espelha a separação Node (`src/generated/`) e PHP (`src/Generated/`). Mantém o gerador idempotente — regenerar não toca em código artesanal. RuboCop e (inicialmente) Steep excluem `generated/` porque são confiáveis por construção. *Alternativa rejeitada*: misturar gerado e *hand-written* — envenena diffs e regen. + +### D4. Entrypoint `Nfe::Client.new(api_key:)` + acessores *lazy* `snake_case` +**Decisão**: cliente único estilo Stripe. Acessores `snake_case` (`client.service_invoices`, `client.legal_entity_lookup`, ...) que instanciam o recurso na primeira leitura (memoizado), passando o HTTP client apropriado por família. +**Por quê**: Paridade com Node (`client.serviceInvoices`) e PHP (`$nfe->serviceInvoices`), adaptado ao idioma Ruby (`snake_case`). *Lazy* evita instanciar 17 recursos + N HTTP clients no `new`; também permite que um client só com `data_api_key` funcione para recursos de dados e só falhe (`Nfe::ConfigurationError`) quando um recurso `main` é tocado sem `api_key`. Substitui o estado global `@@api_key` do legado por estado de instância. *Alternativa rejeitada*: métodos globais `Nfe.service_invoices` — estado global, não thread-safe, contraria Stripe. + +### D5. Value objects via `Data.define`, não `Struct` nem `OpenStruct` +**Decisão**: todo modelo de domínio é `Data.define(:campo1, :campo2) do ... end`, imutável, com keyword args. +**Por quê**: `Data` (3.2+) é imutável por padrão, tem `==`/`hash`/`with` de graça, e é o idioma moderno para value objects. `Struct` é mutável; `OpenStruct` é lento e sem tipos. Substitui o `NfeObject` com `method_missing` do legado (frágil, sem tipos, sem RBS possível). *Alternativa rejeitada*: classes manuais com `attr_reader` + `initialize` — boilerplate que `Data.define` elimina. + +### D6. Zero deps de runtime — só stdlib +**Decisão**: nenhum `add_dependency`. HTTP via `net/http`; JSON via `json`; HMAC/PKCS12 via `openssl`; URLs via `uri`; IDs via `securerandom`; buffers via `stringio`; datas via `time`; encode via `base64`. +**Por quê**: Paridade com Node (zero-dep) e PHP (só extensões). `rest-client` (dep do legado) é desnecessário — `Net::HTTP` cobre tudo, inclusive multipart e download binário. Menos superfície de supply-chain, menos conflito de versão no Bundler do consumidor. *Alternativa rejeitada*: `faraday`/`httparty` — adiciona dep transitiva sem ganho sobre stdlib. + +### D7. Rigor de tipos: RBS shipado + Steep no CI +**Decisão**: assinaturas `.rbs` em `sig/` versionadas e empacotadas na gem; `steep check` e `rbs validate` no CI; lint com RuboCop. +**Por quê**: Paralelo ao Node (`.d.ts`) e PHP (PHPStan L8). RBS é o caminho oficial de tipos no Ruby; shipar `sig/` na gem dá tipos a quem usa Steep/Sorbet downstream. O gerador emite `.rbs` junto dos value objects, mantendo modelos e tipos em sincronia. *Alternativa rejeitada*: Sorbet (`.rbi` + `sig do ... end` inline) — mais intrusivo no código, exige runtime; RBS é externo e idiomático. + +### D8. Downloads → `String` binária; async → retorno síncrono +**Decisão**: métodos de download retornam `String` com `force_encoding(Encoding::ASCII_8BIT)` (binary-safe). Toda chamada é síncrona (sem Promises/async); o contrato 202 vira value objects discriminados (Pending vs. Issued) e o polling é um loop síncrono. +**Por quê**: Ruby não tem `Buffer`; a convenção binária é `String` ASCII-8BIT. Node usa `Promise`/`Buffer`; PHP usa `string` raw bytes — Ruby segue o PHP. FlowStatus terminal (`Issued`/`IssueFailed`/`Cancelled`/`CancelFailed`) gateia o polling. Esta change só **documenta** a convenção; a implementação vem nas changes de HTTP/recurso. + +### D9. `Configuration` como fonte única do mapa multi-base-URL +**Decisão**: `Nfe::Configuration#base_url_for(family)` resolve as 6 famílias; nenhum recurso hard-coda host. Família desconhecida → host `main` como default seguro. +**Por quê**: Paridade com `Config::baseUrlForApi(family)` do PHP. Centraliza a única coisa que difere entre recursos (host). Mapa confirmado: `main` → `https://api.nfe.io` (o `/v1` é fornecido pelo `api_version` do recurso, URL efetiva `https://api.nfe.io/v1/...`); `addresses` → `https://address.api.nfe.io/v2` (exceção documentada: o `/v2` é parte do host); `nfe-query` → `https://nfe.api.nfe.io`; `legal-entity` → `https://legalentity.api.nfe.io`; `natural-person` → `https://naturalperson.api.nfe.io`; `cte` → `https://api.nfse.io`. + +### D10. Branch `0.x-legacy` congelado; v1 em `master` +**Decisão**: snapshot do master atual (v0.3.2) para `0.x-legacy` antes da limpeza; v1 desenvolvida no `master`; CI só no `master`. +**Por quê**: Diferente do PHP (que pôs v3 num branch e deixou `master` no v2), aqui a v1 é o futuro e merece o `master`; o legado vai para um branch nominado e congelado. Quem precisa do antigo fixa `~> 0.3` (resolve do `0.x-legacy`). *Alternativa rejeitada*: deixar o legado no `master` e a v1 num branch — inverte a expectativa de "master = versão atual". + +### D11. Sem shim de compatibilidade v0.x +**Decisão**: zero compat no nível de código. `require "nfe"` continua válido como entrypoint, mas `Nfe.api_key(...)` e os objetos dinâmicos somem; a API passa a ser `Nfe::Client.new(api_key:)`. Migrar é leitura do `MIGRATION.md`. +**Por quê**: Shim envenena o namespace novo (estado global, `method_missing`). Stripe não faz isso entre majors. Quem não pode migrar fixa `~> 0.3`. + +## Risks / Trade-offs + +| Risco | Mitigação | +|---|---| +| Piso Ruby 3.2 exclui apps presos em 2.x/3.0/3.1 | Aceitável — `Data.define` exige 3.2; usuários legados ficam em `~> 0.3` (branch `0.x-legacy`) | +| Consumidores confundem v0.x (entrypoint global) com v1 (`Nfe::Client`) | `MIGRATION.md` explícito + bump de major (SemVer) + banner no `README` | +| `Net::HTTP` exige mais código que `rest-client` (retry, multipart, timeout manuais) | Aceitável — isolado na camada HTTP (change futura); zero-dep vale o custo; paridade com Node/PHP | +| Steep em código gerado pode gerar ruído | `lib/nfe/generated/` excluído do check estrito inicial; refinar conforme o codegen amadurece | +| Gate de cobertura 80% pode travar PRs cedo | Smoke de fundação (version/client/configuration) já cobre; o gate cresce com os recursos | +| `Gemfile.lock` ausente reduz reprodutibilidade local | Convenção de gem lib (não commitar lock); CI usa `bundler-cache` para estabilidade | +| Família de host desconhecida roteada para `main` pode mascarar bug de roteamento | Default seguro documentado; recon contínuo contra o Node SDK valida cada família | + +## Open Questions + +- **Política pública do legado**: optei por "frozen indefinido" no branch `0.x-legacy`. Se quisermos um EOL com data formal (ex.: "2027-01-01"), este é o lugar de capturar. +- **`.ruby-version` de desenvolvimento**: aponto `3.4` (mais recente da matrix) para o dev local; o piso suportado permanece `3.2` via gemspec. Confirmar se o time prefere fixar `3.2` no `.ruby-version`. diff --git a/openspec/changes/archive/2026-06-25-add-ruby-foundation/proposal.md b/openspec/changes/archive/2026-06-25-add-ruby-foundation/proposal.md new file mode 100644 index 0000000..dc78fb9 --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-ruby-foundation/proposal.md @@ -0,0 +1,54 @@ +# add-ruby-foundation + +## Why + +A gem `nfe-io` atual (v0.3.2) está **anos sem manutenção** e foi escrita para um Ruby muito antigo (`.ruby-version` aponta `ruby-2.4.1`). Sintomas concretos do código legado: + +- Dependência de runtime de **`rest-client ~> 2.0.2`** (HTTP de terceiros) +- Estado global mutável via variável de classe `@@api_key` +- Sem tipos, sem RBS, sem `frozen_string_literal` +- Objetos de domínio dinâmicos (`Nfe::NfeObject` com `method_missing`), sem value objects imutáveis +- Cobertura mínima de recursos (apenas `service_invoice`, `company`, `legal_people`, `natural_people`) +- `bundler ~> 1.10`, `rake ~> 10.0` — toolchain pré-2016 +- CI via `.travis.yml` (desligado) + +Para alcançar paridade com os SDKs de referência — Node.js (`nfe-io`, zero-dep, TypeScript) e PHP (`nfe/client-php`, PHPStan L8) — e seguir a filosofia Stripe (cliente único + acessores de recurso *lazy*, ergonomia *hand-crafted* sobre modelos gerados), o caminho não é refatorar incremental. É um **rewrite greenfield v1 com piso Ruby 3.2+**, nada reaproveitado do código atual. + +Esta change estabelece a fundação. Ela **não entrega valor de runtime** sozinha — só viabiliza as changes seguintes (HTTP core, codegen de OpenAPI, `Nfe::Client`, recursos). É a primeira change do grafo; não depende de nenhuma outra. + +## What Changes + +- **Gem name**: permanece `nfe-io` (sem rename — diferente do PHP). Bump de major **0.3.2 → 1.0.0** +- **Ruby requirement**: `required_ruby_version >= 3.2` (drop 2.x/3.0/3.1) +- **Zero deps de runtime**: remover `rest-client`; usar **somente stdlib** (`net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`) +- **Namespace raiz**: `Nfe`; entrypoint único `Nfe::Client.new(api_key: "...")` (estilo Stripe), com acessores de recurso `snake_case` *lazy* (ex.: `client.service_invoices`) +- **Layout**: código *hand-written* em `lib/nfe/...`; modelos gerados em `lib/nfe/generated/`; assinaturas RBS em `sig/` +- **`frozen_string_literal: true`** como primeira linha de **todo** arquivo `.rb` +- **Value objects** imutáveis via `Data.define` (Ruby 3.2+) — substitui o `NfeObject` dinâmico do legado +- **Dev tooling**: `rspec`, `rubocop`, `rbs`, `steep`, `simplecov` (dev-only; zero impacto no pacote publicado) +- **Type rigor**: shipar assinaturas RBS, type-check com Steep no CI, lint com RuboCop, cobertura SimpleCov **>= 80%** +- **Branch strategy**: snapshot do master atual (v0.3.2, baseado em rest-client) para branch **`0.x-legacy`** congelado; v1 desenvolvido em **`master`** +- **CI**: GitHub Actions com matrix **Ruby 3.2 / 3.3 / 3.4** rodando `rspec` + `rubocop` + `steep check` + `rbs validate` + gate de cobertura SimpleCov >= 80% +- **Arquivos de fundação**: `nfe-io.gemspec` reescrito, `Gemfile`, `Rakefile`, `.ruby-version`, `.rubocop.yml`, `Steepfile`, `sig/` layout, `.rspec`, `.github/workflows/ci.yml` +- **`MIGRATION.md`** stub (v0.x → v1, breaking total, sem backports) +- **`README.md`** com marcador "v1 em desenvolvimento" e status do legado +- **`LICENSE`** mantida (MIT) +- **`openspec/project.md`**: contexto do projeto Ruby (propósito, stack, convenções, arquitetura, testes, git, release, domínio, constraints) +- **Não** importar nenhum arquivo de `lib/nfe/*` legado para a v1 — `lib/nfe/` nasce limpo + +## Capabilities + +### New Capabilities +- `sdk-foundation`: versionamento, namespace, layout, requirements de runtime/dev, toolchain de tipos, CI matrix e política de branch/manutenção do SDK Ruby v1 + +### Modified Capabilities +- (nenhuma — o repositório ainda não tem specs versionadas em `openspec/specs/`) + +## Impact + +- **Affected code**: nasce `lib/nfe/` (limpo), `nfe-io.gemspec` reescrito, `Gemfile`, `Rakefile`, `.ruby-version`, `.rubocop.yml`, `Steepfile`, `sig/`, `.rspec`, `.github/workflows/ci.yml`, `MIGRATION.md`, `README.md`; remoção de `.travis.yml`, `.ruby-gemset`, `lib/data/ssl-bundle.crt` e de toda a árvore `lib/nfe/*` legada +- **Backwards compatibility**: **quebra total**. A v1 não reusa nada da v0.3.2. Quem precisa do código antigo fixa `gem "nfe-io", "~> 0.3"` (instala do branch `0.x-legacy`, congelado) +- **Dependencies**: **zero deps de runtime** (remoção definitiva do `rest-client`). Novas deps **dev-only** (`rspec`, `rubocop`, `rbs`, `steep`, `simplecov`) não entram no pacote publicado +- **Downstream**: integrações que hoje fazem `require "nfe"` + `Nfe.api_key(...)` quebram na v1 (`require "nfe"` continua válido como entrypoint, mas a API passa a ser `Nfe::Client.new(api_key:)`). Migração é trabalho de leitura do `MIGRATION.md` +- **Dependencies entre changes**: esta é a change **foundational** — não depende de nenhuma outra; todas as changes subsequentes (HTTP core, codegen, client, recursos) dependem dela +- **Risco aberto**: confirmar política pública do legado — "frozen indefinido" (escolhido) vs. EOL com data formal diff --git a/openspec/changes/archive/2026-06-25-add-ruby-foundation/specs/sdk-foundation/spec.md b/openspec/changes/archive/2026-06-25-add-ruby-foundation/specs/sdk-foundation/spec.md new file mode 100644 index 0000000..f7164eb --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-ruby-foundation/specs/sdk-foundation/spec.md @@ -0,0 +1,223 @@ +# sdk-foundation — Delta + +## ADDED Requirements + +### Requirement: Minimum Ruby version +The SDK SHALL declare a minimum Ruby runtime of 3.2 via `required_ruby_version` and SHALL NOT support Ruby versions below 3.2. + +#### Scenario: Installing on Ruby 3.1 +- **WHEN** a user runs `gem install nfe-io` (or `bundle install`) on Ruby 3.1 +- **THEN** RubyGems SHALL refuse installation with a `required_ruby_version` constraint error + +#### Scenario: Installing on Ruby 3.2 or above +- **WHEN** a user installs the gem on Ruby 3.2, 3.3, or 3.4 +- **THEN** RubyGems SHALL install the package successfully + +### Requirement: Gem name and version +The SDK SHALL be published on RubyGems under the unchanged name `nfe-io`, and the version constant `Nfe::VERSION` SHALL be `"1.0.0"` (a major bump from the legacy `0.3.2`). + +#### Scenario: Installing the SDK +- **WHEN** a user runs `gem install nfe-io` +- **THEN** the package SHALL resolve to this repository's tagged v1 releases under the same gem name as the legacy line + +#### Scenario: Reading the version constant +- **WHEN** a consumer reads `Nfe::VERSION` +- **THEN** it SHALL return the string `"1.0.0"` + +### Requirement: Root module namespace +The SDK SHALL expose all public classes under the `Nfe` Ruby module and SHALL be requirable via `require "nfe"`. + +#### Scenario: Requiring the entrypoint +- **WHEN** a consumer writes `require "nfe"` +- **THEN** the constant `Nfe::Client` SHALL be defined without any additional `require` + +#### Scenario: File location and namespace alignment +- **WHEN** a class `Nfe::Configuration` is defined +- **THEN** the file SHALL be located at `lib/nfe/configuration.rb` + +### Requirement: frozen_string_literal magic comment in every source file +Every Ruby source file under `lib/` and `sig/`-adjacent tooling SHALL declare `# frozen_string_literal: true` as its first line. + +#### Scenario: A source file missing the magic comment +- **WHEN** a contributor adds a file `lib/nfe/foo.rb` without `# frozen_string_literal: true` as the first line +- **THEN** CI (RuboCop cop `Style/FrozenStringLiteralComment` with `EnforcedStyle: always`) SHALL fail the build + +### Requirement: Zero runtime dependencies +The gemspec SHALL declare no runtime dependencies (no `add_dependency` calls) and the SDK SHALL rely exclusively on the Ruby standard library: `net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, and `base64`. + +#### Scenario: Inspecting the built gem +- **WHEN** the gem is built and its dependencies inspected (`gem specification nfe-io dependencies`) +- **THEN** the runtime dependency list SHALL be empty (development dependencies excluded) + +#### Scenario: Proposing a runtime dependency +- **WHEN** a contributor proposes adding a gem to the runtime dependencies (not development dependencies) +- **THEN** the proposal SHALL require an explicit design decision in a new OpenSpec change + +#### Scenario: rest-client removed +- **WHEN** the v1 gemspec is inspected +- **THEN** it SHALL NOT depend on `rest-client` (the legacy v0.3.2 runtime dependency) + +### Requirement: Single client entrypoint with lazy resource accessors +The SDK SHALL expose a single client constructed via `Nfe::Client.new(api_key:, data_api_key: nil, environment: :production, base_url: nil, timeout: 30, retry_config: nil)` using keyword arguments, and SHALL provide lazy, memoized, `snake_case` accessors for all 17 resources. + +#### Scenario: Constructing the client +- **WHEN** a consumer calls `Nfe::Client.new(api_key: "sk_test_...")` +- **THEN** the method SHALL return a client instance without raising, and without eagerly instantiating any resource or HTTP client + +#### Scenario: All 17 resource accessors are present +- **WHEN** a consumer reads each of `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, and `state_taxes` on the client +- **THEN** each accessor SHALL be defined and SHALL return a resource object (not raise `NoMethodError`) + +#### Scenario: Accessor naming is snake_case +- **WHEN** the public accessor for the Node SDK's `serviceInvoices` / PHP's `serviceInvoices` is referenced +- **THEN** it SHALL be named `service_invoices` (idiomatic Ruby snake_case), and likewise `legal_entity_lookup`, `natural_person_lookup`, `inbound_product_invoices`, etc. + +#### Scenario: Lazy memoized instantiation +- **WHEN** a consumer reads `client.companies` twice +- **THEN** the same resource instance SHALL be returned on both reads (memoized on first access) + +#### Scenario: Instance state replaces global API key +- **WHEN** two clients are constructed with different API keys +- **THEN** each client SHALL hold its own credentials as instance state, with no shared global `@@api_key` + +### Requirement: Configuration is the single source of the multi-base-URL host map +The SDK SHALL resolve API host base URLs exclusively through `Nfe::Configuration`, exposing a lookup (e.g. `#base_url_for(family)`) for the six host families, and no resource SHALL hard-code a host URL. + +#### Scenario: Resolving each host family +- **WHEN** `base_url_for` is queried for each family +- **THEN** it SHALL return: `main` → `https://api.nfe.io` (the `/v1` segment is supplied by the resource `api_version`, not baked into the host); `addresses` → `https://address.api.nfe.io/v2` (documented exception: the `/v2` is part of the base URL); `nfe-query` → `https://nfe.api.nfe.io`; `legal-entity` → `https://legalentity.api.nfe.io`; `natural-person` → `https://naturalperson.api.nfe.io`; `cte` → `https://api.nfse.io` + +#### Scenario: Unknown family falls back to main +- **WHEN** `base_url_for` is queried for a family not in the map +- **THEN** it SHALL return the `main` host `https://api.nfe.io` as a safe default (the `/v1` segment is supplied by the resource `api_version`) + +#### Scenario: No resource hard-codes a URL +- **WHEN** the `lib/nfe/` source tree is searched for literal host strings outside `lib/nfe/configuration.rb` +- **THEN** no resource file SHALL contain a hard-coded `https://*.nfe.io` or `https://api.nfse.io` host + +### Requirement: Generated models are immutable value objects isolated from hand-written code +The SDK SHALL emit OpenAPI-derived models as immutable `Data.define` value objects under `lib/nfe/generated/`, with corresponding RBS signatures under `sig/nfe/generated/`, and these generated files SHALL NEVER be hand-edited. + +#### Scenario: Generated tree is isolated +- **WHEN** the code generator runs +- **THEN** it SHALL write value objects only under `lib/nfe/generated/` and signatures only under `sig/nfe/generated/`, leaving hand-written code untouched + +#### Scenario: Value objects are immutable +- **WHEN** a generated model is instantiated and a consumer attempts to mutate one of its attributes +- **THEN** the object SHALL be immutable (a `Data.define` instance has no attribute writers) + +#### Scenario: Generated code is excluded from lint +- **WHEN** RuboCop runs +- **THEN** `lib/nfe/generated/**/*` SHALL be excluded from linting because the files are generated, not hand-written + +### Requirement: Immutable domain models use Data.define +Hand-written domain models and value objects SHALL be defined with `Data.define` (Ruby 3.2+) using keyword construction, replacing any dynamic `method_missing`-based object from the legacy code. + +#### Scenario: A value object is immutable and comparable +- **WHEN** two `Data.define`-based value objects are built with equal attributes +- **THEN** they SHALL be `==` to each other and SHALL expose no attribute setters + +### Requirement: FlowStatus terminal states gate polling +The SDK SHALL define a `FlowStatus` concept whose terminal states are exactly `Issued`, `IssueFailed`, `Cancelled`, and `CancelFailed`, with a predicate (e.g. `terminal?`) used to gate polling loops; non-terminal states include `PullFromCityHall`, `WaitingCalculateTaxes`, `WaitingDefineRpsNumber`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, and `WaitingDownload`. + +#### Scenario: Terminal status detection +- **WHEN** `terminal?` is evaluated for `Issued`, `IssueFailed`, `Cancelled`, or `CancelFailed` +- **THEN** it SHALL return `true` + +#### Scenario: Non-terminal status detection +- **WHEN** `terminal?` is evaluated for `WaitingSend` (or any other non-terminal state) +- **THEN** it SHALL return `false` + +### Requirement: Downloads return binary-safe Strings +The SDK SHALL document and require that all raw-bytes download methods return a `String` whose encoding is forced to `Encoding::ASCII_8BIT` (binary-safe), since Ruby has no `Buffer` type. + +#### Scenario: PDF download encoding +- **WHEN** a download method returns raw PDF or XML bytes +- **THEN** the returned `String` SHALL have encoding `ASCII-8BIT` so the bytes are preserved without transcoding + +### Requirement: Synchronous discriminated 202 result contract +The SDK SHALL model the create contract synchronously (no async/Promises): a creation call SHALL return a `Pending` result (HTTP 202 with a `Location` header) or an `Issued` result (HTTP 201 with the materialized body) as distinct value objects. + +#### Scenario: Async creation yields Pending +- **WHEN** a create endpoint responds HTTP 202 with a `Location` header +- **THEN** the SDK SHALL return a `Pending` result object carrying the location and the extracted invoice id (no Promise) + +#### Scenario: Immediate creation yields Issued +- **WHEN** a create endpoint responds HTTP 201 with the resource body +- **THEN** the SDK SHALL return an `Issued` result object carrying the hydrated value object (no Promise) + +### Requirement: Type rigor via RBS, Steep, and RuboCop +The SDK SHALL ship RBS signatures under `sig/`, type-check with Steep, and lint with RuboCop, all enforced in CI. + +#### Scenario: RBS signatures are shipped in the gem +- **WHEN** the gem is built +- **THEN** `sig/**/*.rbs` SHALL be included in the packaged files + +#### Scenario: Running the type checker +- **WHEN** a contributor runs `bundle exec steep check` +- **THEN** Steep SHALL type-check `lib/` against the signatures in `sig/` and report zero errors for the foundation artifacts + +#### Scenario: Validating the signatures +- **WHEN** a contributor runs `bundle exec rbs validate` +- **THEN** the RBS signatures under `sig/` SHALL validate successfully + +### Requirement: Test suite with coverage gate +The SDK SHALL test with RSpec and SHALL enforce a SimpleCov line-coverage minimum of 80%, failing the build below that threshold. + +#### Scenario: Running the test suite +- **WHEN** a contributor runs `bundle exec rspec` +- **THEN** RSpec SHALL execute the specs under `spec/` with SimpleCov measuring coverage + +#### Scenario: Coverage below the gate fails the build +- **WHEN** measured line coverage is below 80% +- **THEN** SimpleCov SHALL cause the process to exit non-zero, failing CI + +### Requirement: Development tooling +The gemspec SHALL declare development dependencies on `rake`, `rspec`, `rubocop`, `rubocop-rspec`, `rbs`, `steep`, and `simplecov`, and the `Rakefile` SHALL expose tasks for `spec`, `rubocop`, `steep`, and `rbs`. + +#### Scenario: Default rake task runs the full quality gate +- **WHEN** a contributor runs `bundle exec rake` +- **THEN** the default task SHALL run RSpec, RuboCop, Steep, and RBS validation + +### Requirement: CI matrix across supported Ruby versions +The repository SHALL run continuous integration via GitHub Actions against Ruby 3.2, 3.3, and 3.4 on every push and pull request to the `master` branch, running RSpec, RuboCop, Steep, and `rbs validate`, with the SimpleCov >= 80% gate. + +#### Scenario: Pushing to master +- **WHEN** a commit is pushed to `master` +- **THEN** GitHub Actions SHALL run `rspec`, `rubocop`, `steep check`, and `rbs validate` for each Ruby version in the matrix (3.2, 3.3, 3.4) + +#### Scenario: CI ignores the legacy branch +- **WHEN** a commit is pushed to `0.x-legacy` +- **THEN** the v1 CI workflow SHALL NOT run against it + +### Requirement: Branch and version policy +The `master` branch SHALL host all v1 development. The legacy v0.3.2 (rest-client based) codebase SHALL be snapshotted to a frozen `0.x-legacy` branch that receives no maintenance. + +#### Scenario: Consumer choosing the legacy line +- **WHEN** a consumer pins `gem "nfe-io", "~> 0.3"` +- **THEN** the resolved release line SHALL be the frozen v0.x code (snapshotted on `0.x-legacy`), which receives no further updates + +#### Scenario: Consumer choosing v1 +- **WHEN** a consumer pins `gem "nfe-io", "~> 1.0"` +- **THEN** the resolved release line SHALL be the v1 code developed on `master` + +### Requirement: Greenfield rewrite reuses no legacy code +The v1 SDK SHALL NOT import, copy, or adapt any file from the legacy `lib/nfe/*` tree (e.g. `nfe_object.rb`, `api_resource.rb`, `api_operations/*`, the global `@@api_key` configuration); `lib/nfe/` SHALL be authored clean. + +#### Scenario: No legacy artifacts in v1 +- **WHEN** the v1 `lib/nfe/` tree is inspected +- **THEN** it SHALL contain no `method_missing`-based dynamic object, no `rest-client` usage, and no module-level global API key state + +### Requirement: License retained as MIT +The SDK SHALL retain the MIT license, declared as `spec.license = "MIT"` and shipped as a license file in the gem. + +#### Scenario: License declaration +- **WHEN** the gemspec is inspected +- **THEN** `spec.license` SHALL be `"MIT"` and the license file SHALL be present in the repository + +### Requirement: Migration documentation stub +The repository SHALL include a `MIGRATION.md` documenting the v0.x → v1 breaking changes, including the entrypoint change from `Nfe.api_key(...)` to `Nfe::Client.new(api_key:)`, removal of `rest-client`, the move to immutable value objects, and a statement that the legacy line receives no backports. + +#### Scenario: Migration guide present +- **WHEN** a consumer upgrading from v0.x opens `MIGRATION.md` +- **THEN** it SHALL describe the new client entrypoint, the zero-runtime-dependency change, and the no-backport policy for the `0.x-legacy` branch diff --git a/openspec/changes/archive/2026-06-25-add-ruby-foundation/tasks.md b/openspec/changes/archive/2026-06-25-add-ruby-foundation/tasks.md new file mode 100644 index 0000000..78675ec --- /dev/null +++ b/openspec/changes/archive/2026-06-25-add-ruby-foundation/tasks.md @@ -0,0 +1,110 @@ +# Tasks — add-ruby-foundation + +> Plano greenfield. Estabelece a fundação; nenhum recurso de API é implementado aqui (isso vive nas changes seguintes). Paths absolutos relativos à raiz do repo `client-ruby/`. +> +> **Status de implementação (2026-06-24):** fundação implementada e **validada via Docker** (`docker compose`, matrix Ruby 3.2/3.3/3.4) — tudo verde: rspec 14/0 (cobertura de linha 100%), rubocop 0 offenses, steep 0 erros, rbs válido, `gem build` ok, zero deps de runtime. `[x]` = feito/verificado; `[ ] (admin)` = tarefa humana de operação (push/branch protection/RubyGems). Legado preservado em `0.x-legacy` (`4a8ad8f`). Implementação feita no branch de trabalho atual (`next`); consolidação para `master` conforme política (1.3) fica a critério do mantenedor. + +## 1. Branch & política de manutenção + +- [x] 1.1 Snapshot do `master` atual (v0.3.2, baseado em rest-client) para o branch `0.x-legacy` (`git branch 0.x-legacy master` antes de qualquer remoção) +- [ ] 1.2 Push do branch `0.x-legacy` e marcá-lo como congelado (sem manutenção, sem backports) — **DEFERRED (admin; humano roda `git push -u origin 0.x-legacy`)** +- [x] 1.3 Desenvolver a v1 substituindo o conteúdo legado — **feito no branch `next`; mover/abrir PR para `master` é decisão do mantenedor** +- [ ] 1.4 Configurar branch protection no GitHub: `master` aceita PRs com CI verde — **DEFERRED (admin, GitHub UI)** +- [ ] 1.5 Configurar publicação no RubyGems do nome `nfe-io` 1.0.0 — **DEFERRED (admin, change de release)** + +## 2. Limpeza do legado + +- [x] 2.1 Remover a árvore legada: `lib/nfe/service_invoice.rb`, `lib/nfe/api_resource.rb`, `lib/nfe/nfe_object.rb`, `lib/nfe/util.rb`, `lib/nfe/company.rb`, `lib/nfe/configuration.rb`, `lib/nfe/version.rb`, `lib/nfe/natural_people.rb`, `lib/nfe/legal_people.rb`, `lib/nfe/api_operations/*`, `lib/nfe/errors/nfe_error.rb` (configuration/version reescritos; demais removidos — preservados em `0.x-legacy`) +- [x] 2.2 Remover `lib/data/ssl-bundle.crt` (usaremos o bundle de CA do OpenSSL/stdlib, sem bundle versionado) +- [x] 2.3 Remover `.travis.yml` e `.ruby-gemset` +- [x] 2.4 Esvaziar `spec/` legado (reescrito com RSpec moderno) +- [x] 2.5 Manter `LICENSE.txt` (MIT) intacta + +## 3. Gemspec & metadados + +- [x] 3.1 Reescrever `nfe-io.gemspec` (renomeado de `nfe.gemspec`): name `nfe-io`, version `Nfe::VERSION` (1.0.0), `required_ruby_version >= 3.2`, summary/description, homepage, license MIT, metadata (homepage/source/changelog/bug_tracker + `rubygems_mfa_required`), authors NFE.io Team / suporte@nfe.io +- [x] 3.2 **Zero `add_dependency`** (nenhuma dep de runtime) — `rest-client` removido +- [x] 3.3 `add_development_dependency` apenas: `rake`, `rspec`, `rubocop`, `rubocop-rspec`, `rbs`, `steep`, `simplecov` +- [x] 3.4 `spec.files`: `lib/**/*.rb`, `sig/**/*.rbs`, `README.md`, `MIGRATION.md`, `CHANGELOG.md`, `LICENSE.txt` +- [x] 3.5 `spec.require_paths = ["lib"]`; sem `bindir`/`exe` +- [x] 3.6 Criar `lib/nfe/version.rb` com `module Nfe; VERSION = "1.0.0"; end` + `# frozen_string_literal: true` + +## 4. Layout `lib/` & namespace + +- [x] 4.1 `lib/nfe.rb` entrypoint: `# frozen_string_literal: true`, requires (`version`/`configuration`/`flow_status`/`client`), `module Nfe` +- [x] 4.2 Árvore *hand-written*: `lib/nfe/`, `lib/nfe/resources/`, `lib/nfe/errors/`, `lib/nfe/http/` (placeholders com `.gitkeep` documentado) +- [x] 4.3 `lib/nfe/generated/` reservado para value objects gerados (NUNCA editar à mão); `.gitkeep` explicando a origem +- [x] 4.4 `lib/nfe/configuration.rb` como fonte única do mapa multi-base-URL (`base_url_for`): main→api.nfe.io, addresses→address.api.nfe.io/v2, nfe-query→nfe.api.nfe.io, legal-entity→legalentity.api.nfe.io, natural-person→naturalperson.api.nfe.io, cte→api.nfse.io, desconhecida→main +- [x] 4.5 `lib/nfe/client.rb` com `Nfe::Client.new(api_key:, data_api_key:, environment:, base_url:, timeout:, retry_config:)` e os 17 acessores lazy `snake_case` (stubs nesta change; corpos nas seguintes) +- [x] 4.6 `# frozen_string_literal: true` como **primeira linha** de todo `.rb` (verificado) + +## 5. Value objects com `Data.define` + +- [x] 5.1 Convenção: modelos imutáveis usam `Data.define(...)` (Ruby 3.2+), keyword args, `snake_case` +- [x] 5.2 Exemplo de referência: `lib/nfe/flow_status.rb` — estados terminais (`Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`) e não-terminais + `terminal?` +- [x] 5.3 Documentar no `project.md`: downloads retornam `String` binária (`ASCII_8BIT`) e o contrato 202 discriminado (Pending/Issued) será modelado nos recursos + +## 6. RBS & assinaturas de tipo + +- [x] 6.1 Layout `sig/` espelhando `lib/`: `sig/nfe.rbs`, `sig/nfe/version.rbs`, `sig/nfe/client.rbs`, `sig/nfe/configuration.rbs`, `sig/nfe/flow_status.rbs` +- [x] 6.2 `sig/nfe/generated/` reservado (par com `lib/nfe/generated/`); `.gitkeep` +- [x] 6.3 Assinaturas RBS dos artefatos de fundação (`VERSION`, `Client.new`, 17 acessores, `Configuration#base_url_for`, `FlowStatus`) +- [x] 6.4 `rbs validate` passa (verificado via docker 3.2/3.3/3.4) + +## 7. Steep (type-check) + +- [x] 7.1 `Steepfile` com `target :lib`, `check "lib"`, `signature "sig"` +- [x] 7.2 `ignore "lib/nfe/generated"` no check estrito inicial +- [x] 7.3 `bundle exec steep check` verde (verificado via docker 3.2/3.3/3.4) + +## 8. RuboCop (lint/estilo) + +- [x] 8.1 `.rubocop.yml`: `plugins: rubocop-rspec` (API 3.x); `TargetRubyVersion: 3.2`; `NewCops: enable` +- [x] 8.2 `Style/FrozenStringLiteralComment: EnforcedStyle: always` +- [x] 8.3 Excluir `lib/nfe/generated/**/*`, `bin/**/*` e symlinks de referência +- [x] 8.4 Calibrar cops de métrica (Method/Abc/Class/Block) com limites razoáveis +- [x] 8.5 `bundle exec rubocop` verde — 0 offenses (verificado via docker 3.2/3.3/3.4) + +## 9. RSpec & SimpleCov + +- [x] 9.1 `.rspec` com `--require spec_helper`, `--format documentation`, `--color` +- [x] 9.2 `spec/spec_helper.rb` carrega SimpleCov **antes** do código (`add_filter` spec/generated, `minimum_coverage 80`) +- [x] 9.3 Specs smoke: `version_spec.rb`, `client_spec.rb` (17 acessores + stub), `configuration_spec.rb` (host map + fallback), `flow_status_spec.rb` +- [x] 9.4 Cobertura >= 80% verificada — 100% de linha (verificado via docker 3.2/3.3/3.4) + +## 10. Gemfile & Rakefile + +- [x] 10.1 `Gemfile`: `source`, `gemspec`, `# frozen_string_literal: true` +- [x] 10.2 `Rakefile`: tarefas `spec`/`rubocop`/`steep`/`rbs`; `task default: %i[spec rubocop steep rbs]` +- [x] 10.3 `.ruby-version` apontando `3.4` (piso suportado 3.2) + +## 11. CI (GitHub Actions) + +- [x] 11.1 `.github/workflows/ci.yml` em `push`/`pull_request` no `master` +- [x] 11.2 Matrix `ruby-version: ['3.2','3.3','3.4']` com `ruby/setup-ruby` + `bundler-cache: true` +- [x] 11.3 Steps: `rspec` (cobertura), `rubocop`, `steep check`, `rbs validate` +- [x] 11.4 Gate de cobertura via `minimum_coverage` (exit code != 0) +- [x] 11.5 CI só no `master`; ignora `0.x-legacy` +- [x] 11.6 Badge de status no `README.md` + +## 12. Documentação base + +- [x] 12.1 `README.md`: banner "v1 em desenvolvimento", status legado, exemplo `Nfe::Client.new`, tabela dos 17 recursos por grupo, nota zero-dep +- [x] 12.2 `MIGRATION.md`: tabela v0.x→v1 (entrypoint, remoção rest-client, value objects), aviso de breaking total / sem backports +- [x] 12.3 `CHANGELOG.md` formato Keep-a-Changelog com `[Unreleased]` / `[0.3.2]` +- [x] 12.4 `.gitignore`: `pkg/`, `coverage/`, `.bundle/`, `Gemfile.lock`, `.steep/`, `*.gem`, `.rbs_collection.*` + +## 13. `openspec/project.md` + +- [x] 13.1 `openspec/project.md` (contexto Ruby): Purpose, Tech Stack, Conventions, Domain, Constraints, Dependencies, Useful Files & Commands +- [x] 13.2 Documenta mapa multi-base-URL como fonte única, contrato 202, FlowStatus terminal, downloads `String` binária, `lib/nfe/generated/` nunca editado à mão + +## 14. Validação + +- [x] 14.1 `bundle install` em Ruby 3.2 limpo — sem deps de runtime (docker: 53 gems, todos dev) +- [x] 14.2 `bundle exec rspec` — 14 exemplos / 0 falhas, cobertura de linha 100% (docker 3.2/3.3/3.4) +- [x] 14.3 `bundle exec rubocop` — 0 ofensas (docker 3.2/3.3/3.4) +- [x] 14.4 `bundle exec steep check` — 0 erros (docker 3.2/3.3/3.4) +- [x] 14.5 `bundle exec rbs validate` — assinaturas válidas (docker 3.2/3.3/3.4) +- [x] 14.6 `gem build nfe-io.gemspec` — empacota `nfe-io-1.0.0.gem`; `runtime_dependencies == []` confirmado +- [x] 14.7 `openspec validate add-ruby-foundation` — passa (`--strict`) diff --git a/openspec/config.yaml b/openspec/config.yaml new file mode 100644 index 0000000..8544fed --- /dev/null +++ b/openspec/config.yaml @@ -0,0 +1,48 @@ +schema: spec-driven + +# Project context (shown to AI when creating artifacts). +context: | + Project: NFE.io Ruby SDK (gem `nfe-io`), greenfield rewrite v1 (0.3.2 -> 1.0.0). + Legacy (rest-client, Ruby 2.4) is frozen on branch `0.x-legacy`; v1 lives on `master`, nothing reused. + + Tech stack: + - Ruby >= 3.2 (Data.define requires it); CI matrix Ruby 3.2 / 3.3 / 3.4. + - Zero runtime dependencies: stdlib only (net/http, json, openssl, uri, securerandom, stringio, time, base64). No rest-client / faraday / httparty. + - Dev-only: RSpec + SimpleCov (gate >= 80%), RuboCop (+ rubocop-rspec), RBS signatures under sig/, Steep type-checker. Codegen deps confined to a :codegen Gemfile group, never in the published gem. + + Conventions: + - Every .rb file starts with `# frozen_string_literal: true`. + - snake_case methods/accessors/files; CamelCase classes/modules; public API uses keyword arguments. + - Domain models are immutable `Data.define` value objects (never Struct/OpenStruct/method_missing). + - All calls synchronous (no Promises). The HTTP 202 async contract is modeled as discriminated `Pending`/`Issued` value objects; polling is a manual loop gated by `FlowStatus#terminal?`. + - Downloads return a binary-safe String (ASCII-8BIT) — Ruby has no Buffer. + + Architecture: + - Single client, Stripe-style: `Nfe::Client.new(api_key:)` with lazy, memoized snake_case resource accessors (17-resource surface, parity-plus with Node/PHP SDKs). + - Multi-base-URL host map is the single source of truth in `Nfe::Configuration#base_url_for(family)`: main -> https://api.nfe.io, addresses -> https://address.api.nfe.io/v2, nfe-query -> https://nfe.api.nfe.io, legal-entity -> https://legalentity.api.nfe.io, natural-person -> https://naturalperson.api.nfe.io, cte -> https://api.nfse.io. No resource hard-codes a host; unknown family falls back to main. + - Generated models from OpenAPI: `lib/nfe/generated/` holds machine-generated Data.define DTOs (DO NOT EDIT) with .rbs under `sig/nfe/generated/`, synced from `nfeio-docs` (source of truth) via `rake openapi:sync`; hand-written DX layer lives outside generated/. + - Typed error hierarchy: `Nfe::Error` base + subclasses per HTTP status, raised via an ErrorFactory. + + Domain: Brazilian electronic fiscal documents — NFS-e (service), NF-e (product), NFC-e (consumer), CT-e (transportation), inbound distribution, plus lookups (CNPJ/CPF/CEP/address, tax calc/codes, state taxes) and RTC (Reforma Tributaria — IBS/CBS groups, selected by payload shape). Webhooks use HMAC-SHA1 over raw body bytes, header `X-Hub-Signature`, format `sha1=`. + + Spec & docs style: pt-BR narrative (proposal/README/design) with English spec deltas under specs/. + +# Per-artifact rules (optional) +# Add custom rules for specific artifacts. +# Example: +# rules: +# proposal: +# - Keep proposals under 500 words +# - Always include a "Non-goals" section +# tasks: +# - Break tasks into chunks of max 2 hours + +# Per-artifact rules (optional) +# Add custom rules for specific artifacts. +# Example: +# rules: +# proposal: +# - Keep proposals under 500 words +# - Always include a "Non-goals" section +# tasks: +# - Break tasks into chunks of max 2 hours diff --git a/openspec/project.md b/openspec/project.md new file mode 100644 index 0000000..4b375df --- /dev/null +++ b/openspec/project.md @@ -0,0 +1,96 @@ +# Project Context + +## Purpose +This repository implements the official NFE.io Ruby SDK (gem `nfe-io`). It is undergoing a major modernization (v0.3.2 → v1.0.0): a **greenfield rewrite** that drops the old `rest-client`-based, Ruby 2.4-era codebase in favor of a stdlib-only, type-rigorous, OpenAPI-generated runtime with a small hand-written DX layer. Goals: +- Provide a modern, typed, **zero-runtime-dependency** SDK for Ruby 3.2+. +- Reach feature parity with the Node.js and PHP SDKs (the same 17-resource surface, parity-plus). +- Improve developer experience with a single client, typed errors, retry handling, immutable value objects, and comprehensive tests and docs. + +The legacy v0.3.2 code is snapshotted to the frozen `0.x-legacy` branch; v1 is developed on `master`. Nothing from the legacy code is reused. + +## Tech Stack +- Primary language: `Ruby` (>= 3.2) +- Runtime target: Ruby 3.2 / 3.3 / 3.4 (CI matrix) +- HTTP / crypto / IO: Ruby **standard library only** — `net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, `base64`. **No `rest-client`, `faraday`, or `httparty`.** +- Test runner: `RSpec` +- Coverage: `SimpleCov` (gate >= 80%) +- Type signatures: `RBS` (shipped under `sig/`) +- Type checker: `Steep` +- Lint/format: `RuboCop` (+ `rubocop-rspec`) +- OpenAPI tooling: a code generator (synced from `nfeio-docs`) that emits `Data.define` value objects under `lib/nfe/generated/` and `.rbs` signatures under `sig/nfe/generated/`. + +## Project Conventions + +### Code Style +- Every `.rb` file starts with `# frozen_string_literal: true` (enforced by RuboCop `Style/FrozenStringLiteralComment: always`). +- `snake_case` for methods, accessors, and file names; `CamelCase` for classes/modules. +- Public API uses **keyword arguments** (e.g. `Nfe::Client.new(api_key:)`). +- Domain models are immutable **`Data.define`** value objects — never `Struct`, `OpenStruct`, or `method_missing` dynamic objects. +- Downloads return a binary-safe `String` (`force_encoding(Encoding::ASCII_8BIT)`) — Ruby has no `Buffer`. +- All calls are **synchronous** (no Promises/async); the 202 contract is modeled as discriminated `Pending`/`Issued` value objects, and polling is a synchronous loop gated by `FlowStatus#terminal?`. +- Run `bundle exec rubocop` and satisfy all cops before committing. + +### Architecture Patterns +- `lib/nfe/generated/` is the machine-generated OpenAPI output — **DO NOT EDIT**; corresponding signatures live in `sig/nfe/generated/`. All hand-written code lives outside `generated/`. +- Hand-written layers: + - `lib/nfe/client.rb`: the single `Nfe::Client` (Stripe-style) with lazy, memoized `snake_case` resource accessors. + - `lib/nfe/configuration.rb`: the **single source** of the multi-base-URL host map (`#base_url_for(family)`); no resource hard-codes a host. + - `lib/nfe/http/`: a `Net::HTTP`-based HTTP client with retry, timeout, multipart, and binary download support (later change). + - `lib/nfe/resources/`: the 17 resource classes, each constructed with the HTTP client for its host family. + - `lib/nfe/errors/`: a typed error hierarchy (`Nfe::Error` base + `AuthenticationError`, `AuthorizationError`, `InvalidRequestError`, `NotFoundError`, `ConflictError`, `RateLimitError`, `ServerError`, `ApiConnectionError`, `TimeoutError`, `SignatureVerificationError`, `ConfigurationError`, `InvoiceProcessingError`). +- Multi-base-URL routing: each resource belongs to a host family (`main`, `addresses`, `nfe-query`, `legal-entity`, `natural-person`, `cte`). `Configuration#base_url_for(family)` resolves the host; unknown families fall back to `main` (`https://api.nfe.io/v1`). +- Most invoice/people endpoints are company-scoped (`company_id`). +- The 17 resources by group: **entity** (4) — `companies`, `legal_people`, `natural_people`, `webhooks`; **invoice** (5) — `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`; **lookup** (8) — `product_invoice_query`, `consumer_invoice_query`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, `state_taxes`. + +### Testing Strategy +- Unit specs under `spec/nfe/` exercise small modules and helpers. +- Integration specs simulate API behavior (including 202 async flows) with local stubs (no network). +- Coverage target: SimpleCov **>= 80%** line coverage; the gate fails the build below threshold (`SimpleCov.minimum_coverage 80`). +- Before merging: `bundle exec rspec && bundle exec rubocop && bundle exec steep check && bundle exec rbs validate` must pass. + +### Git Workflow +- Branching: feature branches off `master`. Name branches `feat/`, `fix/`, `chore/`. +- Commits: conventional commit style (e.g. `feat(service-invoices): add create_and_wait`). +- Pull requests: include specs; update `CHANGELOG.md` for notable/breaking changes. +- CI runs only on `master` (v1); the `0.x-legacy` branch is frozen and unmonitored. + +### Release & Versioning +- SemVer. v1 starts at `1.0.0`; the legacy line stays on `~> 0.3` (frozen, snapshotted on `0.x-legacy`). +- `Nfe::VERSION` lives in `lib/nfe/version.rb`. +- Releasing publishes `nfe-io` to RubyGems (separate release change); `rubygems_mfa_required` is set in the gemspec metadata. +- Packaged files include `lib/`, `sig/`, `README.md`, `MIGRATION.md`, `CHANGELOG.md`, and `LICENSE.txt`. + +## Domain Context +- The SDK targets the NFE.io API for issuing and managing Brazilian electronic fiscal documents: NFS-e (service invoices), NF-e (product invoices), NFC-e (consumer invoices), CT-e (transportation), and inbound NF-e/CT-e distribution, plus lookups (CNPJ, CPF, address/CEP, tax calculation, tax codes, state taxes). +- Key domain concepts: + - Most service/product invoice and people endpoints are scoped to a `company_id`. + - Creating an invoice may return **HTTP 202** (async, with a `Location` header to poll) or **HTTP 201** (immediate, materialized body). The SDK returns discriminated `Pending`/`Issued` value objects; the invoice id is parsed from the `Location` header. + - `FlowStatus` terminal states (`Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`) gate polling; non-terminal states keep polling. + - Webhook signatures use **HMAC-SHA1** over the **raw request body bytes**, header `X-Hub-Signature`, format `sha1=` (uppercase on the wire, compared case-insensitively), timing-safe. (The legacy `X-NFe-Signature` + SHA-256 scheme in some distribuicao docs is incorrect — do not implement it.) + - Company digital-certificate upload is a `multipart/form-data` POST of a PKCS#12 (A1, `.pfx`/`.p12`) file + password; validate with `OpenSSL::PKCS12` (real parse + password check), not a magic-byte heuristic. + - RTC (Reforma Tributária do Consumo) adds IBS/CBS/IS tax groups; emission is selected by payload shape (presence of `ibs_cbs`), not a header — handled by dedicated RTC resources/specs in a later change. +- `nfeio-docs` (symlinked) is the **source of truth** for API behavior; the Node and PHP SDKs are the **reference** for SDK patterns and the resource surface. + +## Important Constraints +- `lib/nfe/generated/` is auto-generated and must never be hand-edited. +- Minimum Ruby is **3.2** (`Data.define` requires it). +- **Zero runtime dependencies** in the published gem; development dependencies (rspec, rubocop, rbs, steep, simplecov) are allowed. +- No resource may hard-code a host URL — all routing goes through `Nfe::Configuration#base_url_for`. +- The v1 line breaks compatibility with v0.x; breaking changes are documented in `MIGRATION.md` and `CHANGELOG.md`. + +## External Dependencies +- Upstream API hosts (resolved in `Configuration`): `https://api.nfe.io/v1` (main), `https://api.nfse.io` (cte/nfse families), `https://address.api.nfe.io/v2`, `https://nfe.api.nfe.io`, `https://legalentity.api.nfe.io`, `https://naturalperson.api.nfe.io`. +- OpenAPI spec files synced from `nfeio-docs` — used by the generation scripts (later change). + +## Useful Files & Commands +- SDK sources: `lib/nfe/` (hand-written) and `lib/nfe/generated/` (auto-generated); signatures in `sig/` and `sig/nfe/generated/`. +- Core commands: + - `bundle exec rspec` — run specs (with SimpleCov coverage gate) + - `bundle exec rubocop` — lint/format + - `bundle exec steep check` — type-check `lib/` against `sig/` + - `bundle exec rbs validate` — validate RBS signatures + - `bundle exec rake` — full quality gate (spec + rubocop + steep + rbs) + - `gem build nfe-io.gemspec` — package the gem + +## Contacts / Maintainers +- Maintained by the NFE.io team (suporte@nfe.io). See `README.md` and the gemspec `authors`/`metadata` for current ownership. diff --git a/openspec/specs/client-core/spec.md b/openspec/specs/client-core/spec.md new file mode 100644 index 0000000..f52f703 --- /dev/null +++ b/openspec/specs/client-core/spec.md @@ -0,0 +1,301 @@ +# client-core Specification + +## Purpose +TBD - created by archiving change add-client-core. Update Purpose after archive. +## Requirements +### Requirement: Public Client class as the single entry point +The SDK SHALL expose `Nfe::Client` as the single primary entry point. Consumers SHALL instantiate it with at minimum an API key and obtain access to all SDK functionality through this object. The class SHALL be the public surface and SHALL NOT be designed for subclassing; customization SHALL be achieved by composing `Nfe::Configuration` and an injected transport. + +#### Scenario: Minimal instantiation +- **WHEN** a consumer writes `Nfe::Client.new(api_key: "my-key")` +- **THEN** the object SHALL be ready to use with sensible defaults (production environment, default retry policy, default `Net::HTTP`-based transport) + +#### Scenario: Instantiation with explicit configuration +- **WHEN** a consumer writes `Nfe::Client.new(configuration: Nfe::Configuration.new(api_key: "k", timeout: 120))` +- **THEN** the supplied `Nfe::Configuration` SHALL govern all subsequent requests and the convenience keyword arguments SHALL be ignored + +#### Scenario: Missing all keys +- **WHEN** a consumer writes `Nfe::Client.new` with neither `api_key` nor `data_api_key` nor `configuration`, **and** neither `NFE_API_KEY` nor `NFE_DATA_API_KEY` is present in the environment +- **THEN** the SDK SHALL raise `Nfe::ConfigurationError` indicating that an API key is required + +### Requirement: Typed Configuration with constructor validation +The SDK SHALL provide `Nfe::Configuration` carrying all configuration options: `api_key`, `data_api_key`, `environment`, `timeout`, `open_timeout`, `max_retries`, `logger`, `user_agent_suffix`, `base_url_overrides`, `ca_file`, `ca_path`, and `proxy`. Construction SHALL validate the inputs and SHALL raise `Nfe::ConfigurationError` on invalid values. + +#### Scenario: Defaults applied +- **WHEN** a consumer writes `Nfe::Configuration.new(api_key: "k")` +- **THEN** `environment` SHALL default to `:production`, `max_retries` SHALL default to a non-negative integer, and `timeout`/`open_timeout` SHALL default to positive values + +#### Scenario: Empty API key rejected +- **WHEN** a consumer writes `Nfe::Configuration.new(api_key: "")` with no `data_api_key` and no `NFE_API_KEY`/`NFE_DATA_API_KEY` in the environment +- **THEN** the constructor SHALL raise `Nfe::ConfigurationError` + +#### Scenario: Data-only configuration is valid +- **WHEN** a consumer writes `Nfe::Configuration.new(data_api_key: "d")` with no `api_key` +- **THEN** the object SHALL construct successfully, deferring the main-key requirement until a main-family resource is accessed + +#### Scenario: Invalid environment rejected +- **WHEN** a consumer writes `Nfe::Configuration.new(api_key: "k", environment: :sandbox)` +- **THEN** the constructor SHALL raise `Nfe::ConfigurationError`, since only `:production` and `:development` are accepted + +### Requirement: Environment selects key, not URL +The SDK SHALL accept `environment` as one of `:production` (default) or `:development`. Both environments SHALL target the same API endpoints; the active environment SHALL be differentiated by the API key in use, not by a distinct base URL. + +#### Scenario: Production and development share endpoints +- **WHEN** a consumer constructs a client with `environment: :development` +- **THEN** the resolved base URLs SHALL be identical to those used under `:production`, and only the API key SHALL differ in effect + +### Requirement: Multi-base-URL host map is the single source of truth +`Nfe::Configuration` SHALL expose `base_url_for(family)` returning the correct host per NFE.io product family. This method SHALL be the only place that knows hosts; no resource SHALL hard-code a URL. The mapping SHALL be: `main` → `https://api.nfe.io`; `addresses` → `https://address.api.nfe.io/v2`; `nfe-query` → `https://nfe.api.nfe.io`; `legal-entity` → `https://legalentity.api.nfe.io`; `natural-person` → `https://naturalperson.api.nfe.io`; `cte` → `https://api.nfse.io`. An unknown family SHALL fall back to the `main` host. + +#### Scenario: Main family resolution +- **WHEN** `base_url_for(:main)` (or an alias such as `:companies`, `:service_invoices`, `:legal_people`, `:natural_people`, `:webhooks`) is called +- **THEN** it SHALL return `https://api.nfe.io` + +#### Scenario: Addresses host embeds the version +- **WHEN** `base_url_for(:addresses)` is called +- **THEN** it SHALL return `https://address.api.nfe.io/v2`, where the `/v2` is part of the base URL and not the resource path + +#### Scenario: CT-e family resolution +- **WHEN** `base_url_for(:cte)` (or an alias such as `:transportation`, `:inbound_product`, `:product_invoices`, `:consumer_invoices`, `:tax_calculation`, `:tax_codes`, `:state_taxes`) is called +- **THEN** it SHALL return `https://api.nfse.io` + +#### Scenario: Query and lookup hosts +- **WHEN** `base_url_for(:nfe_query)`, `base_url_for(:legal_entity)`, and `base_url_for(:natural_person)` are called +- **THEN** they SHALL return `https://nfe.api.nfe.io`, `https://legalentity.api.nfe.io`, and `https://naturalperson.api.nfe.io` respectively + +#### Scenario: Unknown family falls back to main +- **WHEN** `base_url_for(:something_unknown)` is called +- **THEN** it SHALL return `https://api.nfe.io` + +#### Scenario: Per-family override +- **WHEN** a `Configuration` is built with `base_url_overrides: { cte: "https://staging.example" }` and `base_url_for(:cte)` is called +- **THEN** it SHALL return `https://staging.example`, taking precedence over the default map + +### Requirement: API key resolution per family (two-key model) +`Nfe::Configuration` SHALL expose `api_key_for(family)`. Data-services families (`addresses`, `legal-entity`, `natural-person`, `nfe-query`) SHALL use `data_api_key` when present and SHALL fall back to `api_key` otherwise. All other families SHALL use `api_key`. When the resolved key is `nil` at the time a resource is accessed, the SDK SHALL raise `Nfe::ConfigurationError`. + +#### Scenario: Data family uses data key +- **WHEN** a configuration has both `api_key` and `data_api_key` set and `api_key_for(:addresses)` is called +- **THEN** it SHALL return the `data_api_key` + +#### Scenario: Data family falls back to main key +- **WHEN** a configuration has only `api_key` set and `api_key_for(:nfe_query)` is called +- **THEN** it SHALL return the `api_key` + +#### Scenario: Main family always uses main key +- **WHEN** `api_key_for(:main)` is called on a configuration that also has a `data_api_key` +- **THEN** it SHALL return the `api_key`, never the `data_api_key` + +### Requirement: Configuration keys fall back to environment variables +`Nfe::Configuration` SHALL resolve `api_key` from the `NFE_API_KEY` environment variable and `data_api_key` from the `NFE_DATA_API_KEY` environment variable as a FALLBACK. An explicit constructor argument SHALL always win over the environment value (resolution order: explicit argument, then environment). The "at least one key provided" validation SHALL run after this fallback is applied. + +#### Scenario: API key read from environment +- **WHEN** `NFE_API_KEY` is set in the environment and a consumer writes `Nfe::Configuration.new` with no explicit `api_key` +- **THEN** the configuration SHALL adopt the `NFE_API_KEY` value as its `api_key` + +#### Scenario: Data API key read from environment +- **WHEN** `NFE_DATA_API_KEY` is set in the environment and a consumer writes `Nfe::Configuration.new` with no explicit `data_api_key` +- **THEN** the configuration SHALL adopt the `NFE_DATA_API_KEY` value as its `data_api_key` + +#### Scenario: Explicit argument wins over environment +- **WHEN** `NFE_API_KEY` is set in the environment and a consumer writes `Nfe::Configuration.new(api_key: "explicit")` +- **THEN** the configuration SHALL use `"explicit"` and SHALL ignore the environment value + +### Requirement: TLS trust can only be added, never disabled +`Nfe::Configuration#ca_file` (and optionally `#ca_path`) SHALL be the ONLY override of the TLS trust store, and it SHALL only be able to ADD or replace a CA bundle used to verify the peer. The SDK SHALL NOT expose any public API to set `OpenSSL::SSL::VERIFY_NONE` or otherwise disable peer verification (no `insecure_ssl` flag). The upstream `insecureSsl` attribute is a server-side property of a webhook delivery target and SHALL NOT be confused with the SDK's outbound TLS configuration. `Nfe::Configuration#proxy`, when set, SHALL be passed through to the underlying `Net::HTTP` proxy configuration. + +#### Scenario: Custom CA bundle is honored +- **WHEN** a `Configuration` is built with `ca_file: "/path/to/corporate-ca.pem"` +- **THEN** the transport SHALL use that bundle to verify the server certificate while STILL performing full peer verification + +#### Scenario: Peer verification cannot be disabled +- **WHEN** a consumer searches the public `Nfe::Configuration` and `Nfe::Client` surface for a way to disable certificate verification +- **THEN** no public option SHALL set `VERIFY_NONE` or an `insecure_ssl` mode, and peer verification SHALL remain enabled on every request + +### Requirement: Seventeen lazy snake_case resource accessors +`Nfe::Client` SHALL expose at least the following seventeen core resource accessors, each a snake_case method that lazily constructs and memoizes its resource on first read. Opt-in additive changes (e.g. `add-rtc-invoice-emission`) MAY register further accessors on top of these seventeen. The accessors SHALL be: `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, and `state_taxes`. This surface matches the PHP SDK 1:1 — parity-plus over the 16-resource Node SDK: the Ruby/PHP surface adds the 17th resource, `consumer_invoices` (NFC-e emission), which the Node SDK does not expose. + +#### Scenario: Accessing a resource accessor +- **WHEN** consumer code reads `client.service_invoices` +- **THEN** it SHALL return an instance of the corresponding resource class (a subclass of `Nfe::Resources::AbstractResource`) + +#### Scenario: Memoization +- **WHEN** consumer code reads `client.companies` twice +- **THEN** both reads SHALL return the same object identity (the resource SHALL be constructed once and cached) + +#### Scenario: All seventeen core accessors present +- **WHEN** the seventeen accessor names are enumerated against `Nfe::Client` +- **THEN** each SHALL be a defined public method; these seventeen form the core resource surface, and no additional **core** accessor SHALL exist beyond them (opt-in extension changes MAY register further accessors, such as `service_invoices_rtc` and `product_invoices_rtc` from `add-rtc-invoice-emission`) + +#### Scenario: Data-only client serves data resources +- **WHEN** a client constructed with only `data_api_key` reads `client.addresses` +- **THEN** the resource SHALL be usable without raising, because the addresses family resolves the data key + +#### Scenario: Main resource without main key raises on access +- **WHEN** a client constructed with only `data_api_key` reads `client.companies` and issues a request +- **THEN** the SDK SHALL raise `Nfe::ConfigurationError`, because the main family has no resolvable key + +### Requirement: Lazy resource accessors are thread-safe +A single `Nfe::Client` instance SHALL be safe to share across threads. The lazy, memoized resource accessors SHALL guard their memoization with a `Mutex` so that concurrent first reads of the same accessor construct the resource exactly once and never race. This makes a shared `Client` safe under Rails, Sidekiq, and Puma. (The per-origin keep-alive connection pool is guarded by its own `Mutex` in `add-http-transport`.) + +#### Scenario: Concurrent first read returns one instance +- **WHEN** many threads read `client.companies` for the first time concurrently on a shared `Nfe::Client` +- **THEN** every thread SHALL observe the same single resource instance and no duplicate resource SHALL be constructed by a race + +### Requirement: AbstractResource provides HTTP and hydration helpers +The SDK SHALL define `Nfe::Resources::AbstractResource`, constructed with the owning `Nfe::Client`. It SHALL provide protected helpers `get`, `post`, `put`, and `delete` that build requests through the client's transport for the resource's declared family, plus `full_path`, `hydrate`, `download`, `hydrate_list`, and `handle_async_response`. Each subclass SHALL declare its `api_family` and (optionally) `api_version`. + +#### Scenario: Subclass issues a request +- **WHEN** a resource whose `api_family` is `:cte` calls `get("/v2/companies/x/productinvoices")` +- **THEN** the outgoing request SHALL target `https://api.nfse.io` (resolved via `base_url_for(:cte)`) with the family's resolved API key applied + +#### Scenario: full_path with a version +- **WHEN** a resource with `api_version` `"v1"` calls `full_path("/companies/x")` +- **THEN** the result SHALL be `/v1/companies/x` + +#### Scenario: full_path with an empty version +- **WHEN** a resource with an empty `api_version` (e.g., the addresses resource, whose host embeds `/v2`) calls `full_path("/addresses/01310100")` +- **THEN** the result SHALL be `/addresses/01310100` with no doubled leading slash + +#### Scenario: hydrate produces an immutable value object +- **WHEN** `hydrate(SomeDto, payload)` is called with a payload hash +- **THEN** it SHALL return an immutable `Data.define` value object produced by the generated DTO's factory (e.g., `SomeDto.from_api(payload)`) + +### Requirement: Downloads return raw bytes as a binary-safe String +`AbstractResource#download(path)` SHALL return the response body as a Ruby `String` whose encoding is `Encoding::ASCII_8BIT` (binary-safe), so binary documents (PDF/XML/ZIP) are not corrupted by transcoding. The caller decides whether to persist (e.g., `File.binwrite`) or stream the bytes. + +#### Scenario: PDF download is binary-safe +- **WHEN** `download("/.../pdf")` succeeds against the API +- **THEN** the return value SHALL be a `String` with encoding `ASCII-8BIT` whose first four bytes are `%PDF` + +#### Scenario: XML download is binary-safe +- **WHEN** `download("/.../xml")` succeeds +- **THEN** the return value SHALL be a `String` with encoding `ASCII-8BIT` containing the raw XML bytes + +### Requirement: Discriminated 202 contract with Pending and Issued results +The SDK SHALL define `Nfe::Pending` (a `Data.define` exposing `invoice_id` and `location`) and `Nfe::Issued` (a `Data.define` exposing `resource`). `AbstractResource#handle_async_response` SHALL return `Nfe::Pending` for an HTTP 202 response carrying a `Location` header, and `Nfe::Issued` (wrapping a hydrated DTO) for an HTTP 201/200 response with a body. Consumers SHALL discriminate the result with `is_a?`/`case`. + +#### Scenario: Async 202 yields Pending +- **WHEN** `handle_async_response` receives an HTTP 202 with `Location: /v1/companies/x/serviceinvoices/abc-123` +- **THEN** it SHALL return an `Nfe::Pending` whose `invoice_id` is `abc-123` (parsed from the final path segment) and whose `location` is the header value + +#### Scenario: Immediate 201 yields Issued +- **WHEN** `handle_async_response` receives an HTTP 201 with the materialized invoice body +- **THEN** it SHALL return an `Nfe::Issued` whose `resource` is the DTO hydrated from the response body + +#### Scenario: 202 without Location is a protocol violation +- **WHEN** `handle_async_response` receives an HTTP 202 with no `Location` header +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` describing the missing header + +#### Scenario: Discriminating the result +- **WHEN** consumer code branches on `result.is_a?(Nfe::Pending)` +- **THEN** the pending branch SHALL expose `invoice_id`/`location` and the other branch SHALL expose `resource` + +### Requirement: FlowStatus terminal-state helper +The SDK SHALL provide `Nfe::FlowStatus.terminal?(status)` returning `true` for `"Issued"`, `"IssueFailed"`, `"Cancelled"`, and `"CancelFailed"`, and `false` for all other values. The method SHALL accept either a `String` or a `Symbol`. This helper enables manual polling loops in the absence of an automatic polling helper. + +#### Scenario: Terminal status +- **WHEN** `Nfe::FlowStatus.terminal?("Issued")`, `"IssueFailed"`, `"Cancelled"`, or `"CancelFailed"` is called +- **THEN** the method SHALL return `true` + +#### Scenario: Non-terminal status +- **WHEN** `Nfe::FlowStatus.terminal?("WaitingDefineRpsNumber")` (or any of `PullFromCityHall`, `WaitingCalculateTaxes`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, `WaitingDownload`) is called +- **THEN** the method SHALL return `false` + +#### Scenario: Unknown status +- **WHEN** `Nfe::FlowStatus.terminal?("Whatever")` is called +- **THEN** the method SHALL return `false` + +### Requirement: ListResponse accommodates page-style and cursor-style pagination +The SDK SHALL provide `Nfe::ListResponse` carrying `data` (a list of hydrated DTOs) and `page` (`Nfe::ListPage`). `Nfe::ListPage` SHALL expose `page_index`, `page_count`, `starting_after`, `ending_before`, and `total`, all optional, so each resource populates the half relevant to its endpoint. `AbstractResource#hydrate_list(klass, payload, wrapper_key:)` SHALL unwrap `payload[wrapper_key]`, hydrate each item, and build the appropriate `ListPage`. + +#### Scenario: Page-style listing +- **WHEN** a resource paginates with `page_index`/`page_count` (e.g., service invoices, companies, tax codes) +- **THEN** the returned `ListResponse.page` SHALL have `page_index` and `page_count` set and the cursor fields `nil` + +#### Scenario: Cursor-style listing +- **WHEN** a resource paginates with `starting_after`/`ending_before` (e.g., product invoices, consumer invoices, state taxes) +- **THEN** the returned `ListResponse.page` SHALL have the cursor fields set and `page_index` `nil` + +#### Scenario: Data is uniform across shapes +- **WHEN** a consumer reads `result.data` regardless of pagination shape +- **THEN** it SHALL be a list of hydrated DTOs accessible identically in both cases + +### Requirement: ID and access-key validators run before HTTP +The SDK SHALL provide `Nfe::IdValidator` with methods `company_id`, `invoice_id`, `access_key`, `state_tax_id`, `event_key`, `cnpj`, `cpf`, `cep`, and `state`. Each validator SHALL run client-side and SHALL raise `Nfe::InvalidRequestError`, with a Portuguese-language message identifying the invalid argument, before any HTTP request is issued. `access_key` SHALL accept formatted input, strip non-digit characters, validate the result against `/\A\d{44}\z/`, and return the normalized string. `cnpj` SHALL normalize and validate format without coercing to Integer, so that future alphanumeric CNPJ (v3) input is not corrupted. + +#### Scenario: Empty company ID rejected synchronously +- **WHEN** `Nfe::IdValidator.company_id("")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously, without making an HTTP request, with a pt-BR message + +#### Scenario: Access key with formatting is normalized +- **WHEN** `Nfe::IdValidator.access_key("3526 1234 ... (44 digits with separators)")` is called +- **THEN** it SHALL return a 44-character digits-only string and SHALL NOT raise + +#### Scenario: Access key of wrong length rejected +- **WHEN** `Nfe::IdValidator.access_key("123")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` + +#### Scenario: CNPJ is not coerced to Integer +- **WHEN** `Nfe::IdValidator.cnpj("12.345.678/0001-90")` is called +- **THEN** it SHALL return a normalized `String` of digits and SHALL NOT return or rely on an Integer + +#### Scenario: Invalid state rejected +- **WHEN** `Nfe::IdValidator.state("ZZ")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` + +### Requirement: Resource registry maps each accessor to the correct host +Each of the seventeen resource stubs SHALL declare an `api_family` such that, through `Configuration#base_url_for`, it resolves to the canonical host for that product. The five families involved SHALL be: `main` (service_invoices, companies, legal_people, natural_people, webhooks), `cte` (product_invoices, consumer_invoices, transportation_invoices, inbound_product_invoices, tax_calculation, tax_codes, state_taxes), `nfe-query` (product_invoice_query, consumer_invoice_query), `addresses` (addresses), `legal-entity` (legal_entity_lookup), and `natural-person` (natural_person_lookup). + +#### Scenario: Each accessor resolves its expected host +- **WHEN** a resource's declared `api_family` is resolved via `base_url_for` +- **THEN** the host SHALL match the canonical map (e.g., `transportation_invoices` → `https://api.nfse.io`, `addresses` → `https://address.api.nfe.io/v2`, `legal_entity_lookup` → `https://legalentity.api.nfe.io`) + +#### Scenario: Stub method raises until filled by a resource change +- **WHEN** consumer code calls a business method on an unfilled resource stub +- **THEN** the SDK SHALL raise `NotImplementedError` naming the change that implements the resource (e.g., `add-invoice-resources`) + +### Requirement: Low-level request escape hatch +`Nfe::Client` SHALL expose an internal method to issue an arbitrary request against any family, allowing consumers and resources to call endpoints not yet wrapped by a resource. It SHALL resolve the family's host and key and apply the standard authorization and User-Agent headers. + +#### Scenario: Calling an unwrapped endpoint +- **WHEN** a consumer calls `client.request(:get, family: :main, path: "/v1/some/new/endpoint")` +- **THEN** the SDK SHALL issue the request to `https://api.nfe.io/v1/some/new/endpoint` with the main key and standard headers, returning the raw response + +### Requirement: Per-call request options for multi-tenant overrides +The SDK SHALL define `Nfe::RequestOptions` as an immutable `Data.define` carrying optional `api_key`, `base_url`, and `timeout`. `Nfe::Client#request` SHALL accept an optional `request_options:` keyword, and when present its non-nil fields SHALL override the family-resolved `api_key`, `base_url`, and `timeout` for that single call; nil fields SHALL fall back to the normal family resolution. `Nfe::Resources::AbstractResource` SHALL accept and thread an optional `request_options:` through its helpers to `Nfe::Client#request`, and resource methods (at least the emission methods) SHALL accept it. This enables a multi-tenant per-call `api_key` without constructing a second `Client`. + +#### Scenario: Per-call api_key overrides the family key +- **WHEN** a caller passes `request_options: Nfe::RequestOptions.new(api_key: "tenant-key")` to a request on a `Client` configured with a different `api_key` +- **THEN** that single request SHALL authenticate with `"tenant-key"` while other requests continue to use the client's configured key + +#### Scenario: Nil fields fall back to family resolution +- **WHEN** a caller passes `Nfe::RequestOptions.new(timeout: 90)` with `api_key` and `base_url` left nil +- **THEN** only the timeout SHALL be overridden for that call and the `api_key`/`base_url` SHALL resolve normally from the family + +#### Scenario: Two tenants share one client +- **WHEN** two requests on the same `Client` each pass a distinct `request_options.api_key` +- **THEN** each request SHALL use its own tenant key, with no second `Client` instance required + +### Requirement: User-Agent carries the SDK version +The transport SHALL build a `User-Agent` header from `Nfe::VERSION`, optionally appending `user_agent_suffix` when configured. + +#### Scenario: Version in User-Agent +- **WHEN** any request is issued +- **THEN** the `User-Agent` header SHALL include the `Nfe::VERSION` string + +#### Scenario: Integrator suffix appended +- **WHEN** the client is configured with `user_agent_suffix: "my-app/2.1"` +- **THEN** the `User-Agent` header SHALL include both the SDK version and `my-app/2.1` + +### Requirement: createAndWait and polling helper are deferred past 1.0 +The SDK v1.0 SHALL NOT implement `create_and_wait`, `create_batch`, or a `poll_until_complete` helper on the client or any resource. The discriminated `Nfe::Pending`/`Nfe::Issued` contract plus `Nfe::FlowStatus.terminal?` SHALL be sufficient for writing manual polling loops, and these helpers are explicitly deferred to a future release without breaking the public contract. + +#### Scenario: Looking for an automatic polling helper +- **WHEN** consumer code references `client.poll_until_complete(...)` or a resource's `create_and_wait(...)` against v1.0 +- **THEN** Ruby SHALL raise `NoMethodError`, since the method is not defined + +#### Scenario: Manual polling is documented +- **WHEN** v1.0 documentation describes polling +- **THEN** it SHALL show a manual loop using `result.is_a?(Nfe::Pending)`, `retrieve`, and `Nfe::FlowStatus.terminal?` until a terminal state is reached + diff --git a/openspec/specs/entity-resources/spec.md b/openspec/specs/entity-resources/spec.md new file mode 100644 index 0000000..ffdeddd --- /dev/null +++ b/openspec/specs/entity-resources/spec.md @@ -0,0 +1,188 @@ +# entity-resources Specification + +## Purpose +TBD - created by archiving change add-entity-resources. Update Purpose after archive. +## Requirements +### Requirement: Four entity resources are fully implemented +The SDK SHALL implement four entity resource classes under `Nfe::Resources` — `Companies`, `LegalPeople`, `NaturalPeople`, and `Webhooks` — reachable through the lazy snake_case accessors `client.companies`, `client.legal_people`, `client.natural_people`, and `client.webhooks` on the `Nfe::Client` defined in `add-client-core`. All four resolve to the `main` host family (`base_url_for(:main)` → `https://api.nfe.io`, with the `/v1` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfe.io/v1/...`) via `Nfe::Configuration#base_url_for(:main)`. Method names and behaviour SHALL match the NFE.io Node.js SDK 1:1, adapted to Ruby idioms (snake_case methods, keyword arguments, `Data.define` value objects, synchronous returns, raised typed errors). + +#### Scenario: Resource availability on Client +- **WHEN** consumer code reads any of `client.companies`, `client.legal_people`, `client.natural_people`, `client.webhooks` +- **THEN** the accessor SHALL return a fully functional resource instance (not a stub raising `NoMethodError`) + +#### Scenario: Entity resources route to the main host +- **WHEN** any method of any of the four entity resources issues an HTTP request +- **THEN** the request SHALL target the host `https://api.nfe.io` resolved through `Configuration#base_url_for(:main)`, with the `/v1` segment supplied by the resource `api_version` (effective URL `https://api.nfe.io/v1/...`) and no hard-coded host in the resource + +#### Scenario: Parity with the Node SDK +- **WHEN** comparing method names, parameter order, and return-shape categories between this Ruby SDK and the Node SDK for any of the four entity resources +- **THEN** they SHALL be 1:1 equivalent modulo language idioms (snake_case, keyword args, `Data.define`, synchronous returns) and the additions and deferrals documented in this change's design.md + +### Requirement: Companies CRUD with response unwrapping +`Nfe::Resources::Companies` SHALL expose `create`, `list`, `list_all`, `list_each`, `retrieve`, `update`, and `remove` against `/companies`. The NFE.io API wraps responses in `{"companies" => }`; the resource SHALL transparently unwrap that envelope before hydrating a `Nfe::Company` value object. + +#### Scenario: Create returns hydrated value object +- **WHEN** `create(data)` succeeds with the API responding `{"companies" => {"id" => "abc", "name" => "Acme"}}` +- **THEN** the method SHALL return a `Nfe::Company` whose `id` and other fields are populated + +#### Scenario: List pagination converts 1-based to 0-based +- **WHEN** `list(page_count: 20, page_index: 0)` is called and the API responds `{"companies" => [...], "page" => 1}` +- **THEN** the method SHALL return a `Nfe::ListResponse` whose `page.page_index` is `0` (the API uses 1-based indexing and the resource converts to 0-based) + +#### Scenario: list_all auto-paginates +- **WHEN** `list_all` is called against an account with 250 companies +- **THEN** the method SHALL issue multiple GET requests with `page_count: 100` until a page returns fewer than 100 items and SHALL return a single `Array` aggregating all pages + +#### Scenario: list_each streams via an Enumerator +- **WHEN** `list_each` is called without a block +- **THEN** the method SHALL return an `Enumerator` that fetches pages on demand and yields one `Nfe::Company` at a time + +#### Scenario: Remove returns deletion confirmation +- **WHEN** `remove(company_id)` succeeds +- **THEN** the method SHALL return `{ deleted: true, id: company_id }` + +#### Scenario: Not found surfaces typed error +- **WHEN** `retrieve(company_id)` receives HTTP 404 from the API +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +### Requirement: Companies tax-number handling avoids numeric coercion +`Nfe::Resources::Companies#create` and `#update` SHALL validate the `federalTaxNumber` for format and length only (11 digits CPF or 14 digits CNPJ), normalised as a digit string. They SHALL NOT run check-digit validation client-side and SHALL NOT coerce the value to an `Integer`, so that alphanumeric CNPJ (IN RFB 2.229/2024, effective July 2026) is not corrupted. + +#### Scenario: Tax number kept as string +- **WHEN** `create` is called with a 14-character alphanumeric CNPJ +- **THEN** the SDK SHALL accept it without converting to `Integer` and without rejecting it on a numeric-only check-digit rule + +#### Scenario: Wrong-length tax number rejected +- **WHEN** `create` is called with a `federalTaxNumber` whose normalised digit length is neither 11 nor 14 +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` before issuing an HTTP request + +### Requirement: Companies search and finder helpers +`Nfe::Resources::Companies` SHALL expose `find_by_tax_number(tax_number)` returning a `Nfe::Company` or `nil`, and `find_by_name(name)` returning an `Array` of matching companies. Both are convenience helpers built on `list_all` plus client-side filtering and SHALL be documented as intended for small accounts. + +#### Scenario: Find by tax number +- **WHEN** `find_by_tax_number("12345678901234")` is called and a company with that `federalTaxNumber` exists +- **THEN** the method SHALL return that `Nfe::Company` + +#### Scenario: Find by name with no match +- **WHEN** `find_by_name("NonExistent Corp")` is called and no company matches +- **THEN** the method SHALL return an empty `Array` + +#### Scenario: Empty search name rejected +- **WHEN** `find_by_name("")` or a whitespace-only name is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` + +### Requirement: Company certificate upload with real PKCS#12 validation +`Nfe::Resources::Companies` SHALL expose `upload_certificate(company_id, file:, password:, filename: nil)` and `replace_certificate(...)` (an alias) that POST a `multipart/form-data` body to `/companies/{id}/certificate` with the fields `file` (the .pfx/.p12 binary) and `password`. Before uploading, the SDK SHALL pre-validate the certificate locally via `validate_certificate`. The multipart body SHALL be built using Ruby stdlib (`Net::HTTP` form posting), introducing no new runtime dependency. + +#### Scenario: Successful upload +- **WHEN** `upload_certificate(company_id, file: pfx_bytes, password: "secret", filename: "cert.pfx")` is called with a valid certificate and matching password +- **THEN** the SDK SHALL POST a multipart body carrying `file` and `password` to `/companies/{id}/certificate` and return `{ uploaded: true, message: }` + +#### Scenario: Unsupported file extension rejected before upload +- **WHEN** `upload_certificate` is called with `filename: "cert.pem"` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` without issuing an HTTP request + +#### Scenario: Replace is an alias of upload +- **WHEN** `replace_certificate(company_id, file:, password:)` is called +- **THEN** it SHALL behave identically to `upload_certificate` (the API handles replacement) + +### Requirement: Local certificate validation via OpenSSL::PKCS12 +`Nfe::Resources::Companies#validate_certificate(file:, password:)` SHALL perform a local-only validation (no HTTP) by parsing the PKCS#12 bytes with `OpenSSL::PKCS12.new(der_bytes, password)`. A wrong password or malformed DER SHALL raise `Nfe::InvalidRequestError`. On success it SHALL return a `Nfe::CertificateInfo` value object carrying `subject`, `issuer`, `not_before`, `not_after`, and `serial_number` extracted from the parsed certificate. + +#### Scenario: Valid certificate and password +- **WHEN** `validate_certificate(file: pfx_bytes, password: "correct")` is called with a real PKCS#12 and the correct password +- **THEN** the method SHALL return a `Nfe::CertificateInfo` whose `not_after` is the certificate's actual expiry date (not a fabricated placeholder) + +#### Scenario: Wrong password rejected +- **WHEN** `validate_certificate` is called with an incorrect password +- **THEN** `OpenSSL::PKCS12.new` SHALL raise, and the SDK SHALL surface a `Nfe::InvalidRequestError` + +#### Scenario: No HTTP request is made +- **WHEN** `validate_certificate` runs +- **THEN** the SDK SHALL NOT issue any HTTP request + +### Requirement: Certificate password and PKCS#12 bytes are handled in-memory only +The certificate password and PKCS#12 (.pfx/.p12) bytes SHALL be handled in-memory only. The SDK SHALL NOT persist either the password or the PKCS#12 bytes to disk (no temp files, no caches). Neither the password nor the PKCS#12 bytes SHALL appear in any log line, in any raised exception message, or in any `Nfe::Error` attribute (including `Error#to_h` / `Error#message`). The password `String` SHALL NOT be retained beyond the upload call where feasible (it SHALL NOT be stored on the resource instance or memoized). + +#### Scenario: Password absent from logs +- **WHEN** `upload_certificate` or `validate_certificate` runs with debug/body logging enabled +- **THEN** no log line SHALL contain the password value or the PKCS#12 bytes (the multipart body SHALL NOT be logged) + +#### Scenario: Password absent from any raised exception / Error#to_h +- **WHEN** `OpenSSL::PKCS12.new` raises (wrong password or malformed DER) and the SDK surfaces a `Nfe::InvalidRequestError` +- **THEN** the raised error's `message` and `to_h` SHALL NOT contain the password value or the raw PKCS#12 bytes + +### Requirement: Company certificate status and expiry helpers +`Nfe::Resources::Companies` SHALL expose `get_certificate_status(company_id)` returning a `Nfe::CertificateStatus`, `check_certificate_expiration(company_id, threshold_days: 30)`, `get_companies_with_certificates`, and `get_companies_with_expiring_certificates(threshold_days: 30)`. Each SHALL query `GET /companies/{id}/certificate`. The `days_until_expiration` and `expiring_soon` fields SHALL be computed client-side from `expires_on`. + +#### Scenario: Certificate status snapshot +- **WHEN** `get_certificate_status(company_id)` succeeds against `GET /companies/{id}/certificate` +- **THEN** the method SHALL return a `Nfe::CertificateStatus` carrying `has_certificate` (boolean), `expires_on` (string ISO date-time or nil), `valid` (boolean or nil), `days_until_expiration` (integer or nil, computed client-side from `expires_on`), `expiring_soon` (boolean or nil, computed client-side via threshold), and `details` (raw payload) + +#### Scenario: Expiration check within threshold +- **WHEN** `check_certificate_expiration(company_id, threshold_days: 30)` is called and the certificate expires in 10 days +- **THEN** the method SHALL return `{ expiring: true, days_remaining: 10, expires_on: }` + +#### Scenario: Expiration check outside threshold +- **WHEN** the certificate expires in 200 days with `threshold_days: 30` +- **THEN** the method SHALL return `nil` + +#### Scenario: Listing companies with expiring certificates +- **WHEN** `get_companies_with_expiring_certificates(30)` is called +- **THEN** the method SHALL list all companies, query certificate status for each (skipping companies whose status lookup fails), and return only those expiring within the threshold + +### Requirement: LegalPeople and NaturalPeople resources are parallel +`Nfe::Resources::LegalPeople` and `Nfe::Resources::NaturalPeople` SHALL expose the same operations — `list`, `create`, `retrieve`, `update`, `delete`, `create_batch`, and `find_by_tax_number` — differing only in endpoint base path (`/companies/{id}/legalpeople` vs `/companies/{id}/naturalpeople`), response envelope key (`legalPeople` vs `naturalPeople`), and tax-number semantics (CNPJ 14 digits vs CPF 11 digits). `list` takes only a `company_id` (no pagination parameters, matching the Node SDK) and unwraps `{"" => [...]}`. + +#### Scenario: Legal person create unwraps envelope +- **WHEN** `client.legal_people.create(company_id, data)` is called +- **THEN** the SDK SHALL POST `/companies/{company_id}/legalpeople`, unwrap the `legalPeople` envelope, and return a `Nfe::LegalPerson` + +#### Scenario: Natural person tax number normalised +- **WHEN** `find_by_tax_number(company_id, "123.456.789-01")` is called on `NaturalPeople` +- **THEN** the SDK SHALL normalise the input to 11 digits and search by `federalTaxNumber` + +#### Scenario: Batch creation is sequential +- **WHEN** `create_batch(company_id, [a, b, c])` is called +- **THEN** the SDK SHALL invoke `create` sequentially (no concurrency primitive) and return the three created entities in order + +#### Scenario: Delete returns nil +- **WHEN** `delete(company_id, legal_person_id)` succeeds +- **THEN** the method SHALL return `nil` + +### Requirement: Webhooks resource with CRUD, test, and available events +`Nfe::Resources::Webhooks` SHALL expose `list`, `create`, `retrieve`, `update`, `delete`, `test`, and `get_available_events`, all company-scoped under `/companies/{id}/webhooks`. The `test` method triggers a synthetic delivery. `get_available_events` returns a static list matching the Node SDK's hard-coded events. + +#### Scenario: Webhook subscription CRUD +- **WHEN** `client.webhooks.create(company_id, { url: "https://example.com/hook", events: ["invoice.issued"] })` is called +- **THEN** the API SHALL persist the subscription and the method SHALL return a `Nfe::Webhook` with `id`, `url`, `events`, and `secret` populated + +#### Scenario: Test webhook delivery +- **WHEN** `client.webhooks.test(company_id, webhook_id)` is called +- **THEN** the SDK SHALL POST `/companies/{id}/webhooks/{webhook_id}/test` and return `{ success: , message: }` + +#### Scenario: Available events list +- **WHEN** `client.webhooks.get_available_events` is called +- **THEN** the method SHALL return a static `Array` of exactly: `invoice.issued`, `invoice.cancelled`, `invoice.failed`, `invoice.processing`, `company.created`, `company.updated`, `company.deleted` + +### Requirement: ID validators run before HTTP +Every entity resource method that takes an identifier (`company_id`, `legal_person_id`, `natural_person_id`, `webhook_id`) SHALL validate it through the shared ID validators from `add-client-core` before issuing the HTTP request, failing fast with a Portuguese-language message. + +#### Scenario: Empty company ID rejected synchronously +- **WHEN** any entity resource method receives an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without making an HTTP request + +### Requirement: Certificate value objects are immutable +The SDK SHALL provide `Nfe::CertificateInfo = Data.define(:subject, :issuer, :not_before, :not_after, :serial_number)` and `Nfe::CertificateStatus = Data.define(:has_certificate, :expires_on, :valid, :days_until_expiration, :expiring_soon, :details)`. Both SHALL be immutable `Data` value objects. + +#### Scenario: CertificateInfo is frozen +- **WHEN** a `Nfe::CertificateInfo` instance is created +- **THEN** it SHALL be immutable (a `Data` instance), and attempting to mutate a field SHALL raise + +### Requirement: Frozen string literals on every source file +Every Ruby source file added by this change SHALL begin with the magic comment `# frozen_string_literal: true`. + +#### Scenario: Source file without the magic comment +- **WHEN** a contributor adds a file under `lib/nfe/resources/` without the `# frozen_string_literal: true` comment +- **THEN** RuboCop SHALL fail the build + diff --git a/openspec/specs/http-transport/spec.md b/openspec/specs/http-transport/spec.md new file mode 100644 index 0000000..d2a156a --- /dev/null +++ b/openspec/specs/http-transport/spec.md @@ -0,0 +1,261 @@ +# http-transport Specification + +## Purpose +TBD - created by archiving change add-http-transport. Update Purpose after archive. +## Requirements +### Requirement: Transport abstraction +The SDK SHALL define a transport contract `Nfe::Http::Transport` exposing a single method `call(request) -> response`, allowing the HTTP transport implementation to be substituted (default `Net::HTTP`, PSR-3-style logging decorator, or an in-memory fake) without touching resource code. Any object responding to `call(Nfe::Http::Request)` and returning an `Nfe::Http::Response` SHALL be a valid transport (duck typing). + +#### Scenario: Substituting the transport for tests +- **WHEN** a test constructs the SDK with a fake object whose `call` returns queued `Nfe::Http::Response` instances +- **THEN** all HTTP requests SHALL be routed through that fake without reaching the network + +#### Scenario: Transport returns HTTP errors as responses, not exceptions +- **WHEN** a transport receives an HTTP 404 or HTTP 500 from the wire +- **THEN** it SHALL return an `Nfe::Http::Response` carrying that status code, and SHALL NOT raise — so the retry decorator and `Nfe::ErrorFactory` can act on the status + +### Requirement: Default zero-dependency Net::HTTP transport +The SDK SHALL ship `Nfe::Http::NetHttp` as the default transport, implemented using only the Ruby standard library (`net/http`, `uri`, `openssl`, `zlib`, `stringio`). It SHALL NOT require any external gem. + +#### Scenario: Using the SDK without any HTTP gem installed +- **WHEN** a consumer installs `nfe-io` and uses the client without configuring a transport +- **THEN** the SDK SHALL use `Nfe::Http::NetHttp` and perform HTTP requests successfully against the network + +#### Scenario: TLS verification is enforced by default +- **WHEN** `Nfe::Http::NetHttp` sends a request to an `https` base URL +- **THEN** it SHALL enable TLS with `OpenSSL::SSL::VERIFY_PEER` and SHALL NOT disable certificate verification + +#### Scenario: Persistent connection reuse per origin +- **WHEN** two consecutive requests target the same `host:port` +- **THEN** the transport SHALL reuse a single persistent `Net::HTTP` connection (keep-alive) for that origin rather than opening a new TCP/TLS connection each time + +### Requirement: Request value object +The SDK SHALL define `Nfe::Http::Request` as an immutable value object (`Data.define`) carrying `method`, `base_url`, `path`, `headers`, `query`, `body`, `open_timeout`, `read_timeout`, and `idempotency_key`. It SHALL expose `#url` composing the final URL from `base_url`, `path`, and the URL-encoded `query`, and `#idempotent?` returning true for `GET`/`HEAD`/`PUT`/`DELETE` (case-insensitive) or any request carrying an `idempotency_key`. + +#### Scenario: URL composition with query +- **WHEN** a `Request` has `base_url: "https://api.nfse.io"`, `path: "/v2/companies/abc/productinvoices"`, and `query: { environment: "Production", limit: 50 }` +- **THEN** `#url` SHALL return `https://api.nfse.io/v2/companies/abc/productinvoices?environment=Production&limit=50` + +#### Scenario: Idempotency classification +- **WHEN** `#idempotent?` is called on a `GET`, `HEAD`, `PUT`, or `DELETE` request, or on a `POST` request carrying a non-nil `idempotency_key` +- **THEN** it SHALL return `true`; for a `POST` request with no `idempotency_key` it SHALL return `false` + +### Requirement: Response value object +The SDK SHALL define `Nfe::Http::Response` as an immutable value object (`Data.define`) carrying `status` (Integer), `headers` (Hash with lowercase string keys), and `body` (a binary-safe `ASCII-8BIT` String). It SHALL expose `#header(name)` (case-insensitive lookup), `#success?` (true for 2xx), and `#location` (the `Location` header or nil). + +#### Scenario: Case-insensitive header lookup +- **WHEN** a server returns a `Location:` header in any letter casing +- **THEN** `#header("Location")`, `#header("location")`, and `#location` SHALL all return the same value + +#### Scenario: Body is binary-safe +- **WHEN** the response body contains raw PDF or ZIP bytes +- **THEN** `body` SHALL be a String with `ASCII-8BIT` encoding, preserving every byte without transcoding + +### Requirement: Multi-base-URL routing +The SDK SHALL allow each `Nfe::Http::Request` to specify its `base_url` independently, so resources targeting different NFE.io hosts (`api.nfe.io`, `api.nfse.io`, `address.api.nfe.io/v2`, `nfe.api.nfe.io`, `legalentity.api.nfe.io`, `naturalperson.api.nfe.io`) work uniformly through the same transport. The transport SHALL NOT hard-code any host. The host map itself is owned by `Nfe::Configuration` (defined in change `add-client-core`); this capability only requires that the transport honors the `base_url` it receives. + +#### Scenario: A resource targets a non-default host +- **WHEN** a resource constructs `Nfe::Http::Request.new(method: "GET", base_url: "https://api.nfse.io", path: "/v2/...")` +- **THEN** the transport SHALL send the request to `api.nfse.io` regardless of any global default base URL + +### Requirement: gzip transport encoding +The transport SHALL request `Accept-Encoding: gzip` (unless the caller already set an `Accept-Encoding` header) and SHALL transparently decompress a `Content-Encoding: gzip` response body before returning it, removing the `content-encoding` header from the resulting `Response`. + +#### Scenario: Compressed JSON response +- **WHEN** the server returns a body with `Content-Encoding: gzip` +- **THEN** the `Response#body` SHALL contain the decompressed bytes and `Response#header("content-encoding")` SHALL be nil + +#### Scenario: Content-Length reflects the decompressed body +- **WHEN** a `Content-Encoding: gzip` body is inflated +- **THEN** the transport SHALL drop or recompute the `content-length` header so it does not advertise the now-stale compressed byte count + +#### Scenario: Malformed gzip falls back to raw bytes +- **WHEN** the server claims `Content-Encoding: gzip` but the body cannot be inflated +- **THEN** the transport SHALL return the raw body unchanged and SHALL log a warning if a logger is configured, without raising + +### Requirement: Retry policy with exponential backoff and jitter +The SDK SHALL provide `Nfe::Http::RetryPolicy` (`Data.define`) with configurable `max_retries` (default 3), `base_delay` (default 1.0s), `max_delay` (default 30.0s), and `jitter` (default 0.3 = ±30%), plus factories `.default` and `.none`. `#delay_for(attempt)` SHALL compute `min(max_delay, base_delay * 2^(attempt-1))` and apply symmetric jitter, capped at `max_delay`. + +#### Scenario: Backoff is capped +- **WHEN** `#delay_for` is called for an attempt large enough that the exponential term exceeds `max_delay` +- **THEN** the returned delay SHALL NOT exceed `max_delay` + +#### Scenario: Jitter bounds +- **WHEN** `#delay_for(attempt)` is called repeatedly with `jitter: 0.3` +- **THEN** every returned value SHALL fall within `[base * 0.7, base * 1.3]` (clamped to `max_delay`), where `base = min(max_delay, base_delay * 2^(attempt-1))` + +#### Scenario: No-retry policy +- **WHEN** the policy is `RetryPolicy.none` +- **THEN** `max_retries` SHALL be 0 and the retrying transport SHALL make exactly one HTTP attempt + +### Requirement: Retrying transport for transient failures on idempotent requests +The SDK SHALL provide `Nfe::Http::RetryingTransport`, a decorator wrapping any transport with a `RetryPolicy` and an injectable sleep function. It SHALL retry on HTTP 429, HTTP 500–599, and network errors (`Nfe::ApiConnectionError`, including `Nfe::TimeoutError`), but ONLY for idempotent requests (per `Request#idempotent?`). It SHALL NOT retry HTTP 4xx other than 429, and SHALL NOT retry a non-idempotent `POST`. + +#### Scenario: Server returns 503 then succeeds +- **WHEN** the inner transport returns HTTP 503 on a `GET` then HTTP 200 on retry +- **THEN** the retrying transport SHALL transparently return the successful 200 response to the caller + +#### Scenario: Client error other than 429 is not retried +- **WHEN** the inner transport returns HTTP 400 +- **THEN** the retrying transport SHALL return that 400 response immediately without retrying + +#### Scenario: Non-idempotent POST is not retried +- **WHEN** the inner transport returns HTTP 503 for a `POST` request that carries no `idempotency_key` +- **THEN** the retrying transport SHALL return the 503 response without retrying, so the SDK never re-issues an invoice + +#### Scenario: Retries exhausted +- **WHEN** the inner transport returns HTTP 503 on every attempt for an idempotent request up to the configured maximum +- **THEN** the retrying transport SHALL return the last 503 response (which the resource layer maps to `Nfe::ServerError`) + +#### Scenario: Retry-After honored +- **WHEN** the inner transport returns HTTP 429 with `Retry-After: 5` for an idempotent request +- **THEN** the retrying transport SHALL wait at least 5 seconds (clamped to `max_delay`) before the next attempt + +#### Scenario: Network error is retried then propagated +- **WHEN** the inner transport raises `Nfe::ApiConnectionError` on every attempt for an idempotent request +- **THEN** the retrying transport SHALL retry up to `max_retries` and then re-raise the last `Nfe::ApiConnectionError` + +### Requirement: Error hierarchy +The SDK SHALL define an error hierarchy rooted at `Nfe::Error` (subclass of `StandardError`), with concrete subclasses: `AuthenticationError` (401), `AuthorizationError` (403), `InvalidRequestError` (400/422), `NotFoundError` (404), `ConflictError` (409), `RateLimitError` (429), `ServerError` (5xx), `ApiConnectionError` (network), `TimeoutError` (a subclass of `ApiConnectionError`), and `SignatureVerificationError` (webhook verification). `Nfe::Error` SHALL expose `status_code`, `request_id`, `error_code`, `response_body`, and `response_headers`, plus a `#to_h` for logging. + +#### Scenario: Catching a specific error +- **WHEN** consumer code wraps a call with `rescue Nfe::NotFoundError` +- **THEN** the SDK SHALL raise that error specifically on HTTP 404 responses, not the base class + +#### Scenario: Catching all SDK errors +- **WHEN** consumer code wraps a call with `rescue Nfe::Error` +- **THEN** every SDK-raised error SHALL be caught through this base class + +#### Scenario: Timeout is a connection error +- **WHEN** consumer code wraps a call with `rescue Nfe::ApiConnectionError` +- **THEN** it SHALL also catch `Nfe::TimeoutError`, since `TimeoutError` is a subclass of `ApiConnectionError` + +#### Scenario: Error carries response context +- **WHEN** any `Nfe::Error` derived from an HTTP response is raised +- **THEN** it SHALL expose `status_code`, `request_id`, `error_code`, `response_body`, and `response_headers` + +### Requirement: ErrorFactory maps status and body to typed errors +The SDK SHALL provide `Nfe::ErrorFactory` with `from_response(response)` and `from_network_error(exception)`. `from_response` SHALL select the error class by status code (400/422 → `InvalidRequestError`, 401 → `AuthenticationError`, 403 → `AuthorizationError`, 404 → `NotFoundError`, 409 → `ConflictError`, 429 → `RateLimitError`, 500–599 → `ServerError`, other 4xx → `InvalidRequestError`, other ≥500 → `ServerError`). It SHALL extract `message` (from body keys `message`/`error`/`detail`/`details`/`errors`), `error_code` (from `code`/`errorCode`/`error_code`), and `request_id` (from header `x-request-id`, falling back to `x-correlation-id`). Because the extracted `message` echoes server input, the factory SHALL cap the message at a bounded length and scrub control characters before placing it on the error. + +#### Scenario: Oversized server message is capped and scrubbed +- **WHEN** `from_response` receives a body whose `message` is very long or contains control characters +- **THEN** the resulting error message SHALL be truncated to a bounded length with control characters removed, so an attacker-controlled body cannot flood logs or inject terminal sequences + +#### Scenario: 404 maps to NotFoundError +- **WHEN** `from_response` receives a `Response` with status 404 +- **THEN** it SHALL return an `Nfe::NotFoundError` whose `status_code` is 404 + +#### Scenario: 422 maps to InvalidRequestError +- **WHEN** `from_response` receives a `Response` with status 422 +- **THEN** it SHALL return an `Nfe::InvalidRequestError` + +#### Scenario: Rate limit carries retry-after +- **WHEN** `from_response` receives status 429 with a `Retry-After: 30` header +- **THEN** it SHALL return an `Nfe::RateLimitError` whose `retry_after` is 30 + +#### Scenario: Message and request id extracted +- **WHEN** `from_response` receives a JSON body `{ "message": "CNPJ inválido", "code": "INVALID_CNPJ" }` with header `x-request-id: req_123` +- **THEN** the raised error SHALL have message `"CNPJ inválido"`, `error_code` `"INVALID_CNPJ"`, and `request_id` `"req_123"` + +#### Scenario: Non-JSON body does not break the factory +- **WHEN** `from_response` receives a non-JSON body (e.g. HTML or plain text) +- **THEN** it SHALL still return the correct error class with a default message and SHALL NOT raise a parse error + +#### Scenario: Network exception mapping +- **WHEN** `from_network_error` receives a `Net::ReadTimeout` or `Net::OpenTimeout` +- **THEN** it SHALL return an `Nfe::TimeoutError`; for `SocketError`, `Errno::ECONNREFUSED`, or `OpenSSL::SSL::SSLError` it SHALL return an `Nfe::ApiConnectionError`, preserving the original exception as cause + +### Requirement: 202 responses are not auto-followed +The transport SHALL NOT follow HTTP 202 responses or any redirect automatically. The `Response` object SHALL expose the raw status code and headers (including `Location`) so the calling resource can implement the discriminated Pending/Issued contract (defined in `add-client-core`). + +#### Scenario: API returns 202 with Location +- **WHEN** the transport receives HTTP 202 with `Location: /v1/companies/{id}/serviceinvoices/{invoiceId}` +- **THEN** it SHALL return a `Response` with `status == 202` and the `Location` header preserved, without fetching the resource at `Location` + +### Requirement: User-Agent identification +Every outgoing request SHALL carry a `User-Agent` header in the format `NFE.io Ruby Client v ruby/ ()`, built via `Nfe::Http::UserAgent.build`, unless the caller overrides it explicitly. The SDK version SHALL be read from `Nfe::VERSION`. + +#### Scenario: Default User-Agent format +- **WHEN** `Nfe::Http::UserAgent.build` is called with `Nfe::VERSION == "1.0.0"` on Ruby 3.3 +- **THEN** it SHALL return a string matching `NFE.io Ruby Client v1.0.0 ruby/3.3.0 ()` + +### Requirement: API key authentication header +The SDK SHALL authenticate requests using the `X-NFE-APIKEY` header carrying the API key. The header value SHALL be the API key provided on the `Request` (resolved per host family by `Nfe::Configuration` in `add-client-core`). The transport itself SHALL remain authentication-agnostic and send whatever auth header the `Request` carries. + +#### Scenario: API key header sent +- **WHEN** a `Request` is built with header `X-NFE-APIKEY` set to the configured key +- **THEN** the transport SHALL transmit that header verbatim to the wire + +### Requirement: Idempotency-Key slot +The `Nfe::Http::Request` SHALL carry an optional `idempotency_key`. When present, the transport SHALL send it as the `Idempotency-Key` request header. When nil, no `Idempotency-Key` header SHALL be sent. A present key SHALL also make the request eligible for retry per `Request#idempotent?`. + +#### Scenario: Idempotency key sent when present +- **WHEN** a `Request` carries `idempotency_key: "9f1c..."` +- **THEN** the transport SHALL send `Idempotency-Key: 9f1c...` and the request SHALL be retry-eligible even for `POST` + +#### Scenario: No idempotency key by default +- **WHEN** a `Request` has `idempotency_key: nil` +- **THEN** the transport SHALL NOT send any `Idempotency-Key` header + +### Requirement: Pluggable duck-typed logger with secret redaction +The SDK SHALL support an optional logger (a duck-typed object responding to `info`/`warn`/`error`, such as Ruby's stdlib `::Logger`), configured via `Nfe::Configuration` (in `add-client-core`). When provided, the transport layer SHALL log request start at `info`, retries at `warn`, and final failures at `error`. Before logging, it SHALL redact the values of sensitive headers — `X-NFE-APIKEY`, `Authorization`, `Idempotency-Key`, and any header whose name matches `/secret|apikey|token/i` — replacing them with `[REDACTED]`. The SDK SHALL NOT declare any logging gem as a runtime dependency. + +#### Scenario: Logger provided and request fails +- **WHEN** a logger is configured and a request finally fails with HTTP 500 +- **THEN** the logger SHALL receive at least one `error` entry including the method, URL, and status code, with the API key value redacted to `[REDACTED]` + +#### Scenario: No logger provided +- **WHEN** no logger is configured +- **THEN** no logging SHALL occur and no logging gem SHALL be required at runtime + +#### Scenario: Logging never breaks the request +- **WHEN** the configured logger itself raises while logging +- **THEN** the SDK SHALL rescue the logging error and complete the HTTP request normally + +### Requirement: Request and response bodies are never logged by default +The SDK SHALL NOT log request or response BODIES by default. Default log entries SHALL be limited to the HTTP method, URL, status code, and `request_id`. Body logging SHALL be available only behind an explicit opt-in flag (`Nfe::Configuration#log_request_body`, defined in `add-client-core`); when enabled, any logged body SHALL be truncated to a bounded length and SHALL pass through redaction so that secrets and PII never appear verbatim. `Nfe::Error#response_body` SHALL remain available on raised errors for programmatic inspection, but SHALL NOT be auto-logged by the transport's default log entries. + +#### Scenario: Bodies are omitted from default logs +- **WHEN** a logger is configured with no body-logging opt-in and a request carrying a CNPJ/CPF in its body fails with HTTP 422 whose response body echoes the CNPJ/CPF +- **THEN** no log line SHALL contain the request body, the response body, the CNPJ, the CPF, the API key, or the certificate password — only method, URL, status, and `request_id` + +#### Scenario: Opt-in body logging is truncated and redacted +- **WHEN** `log_request_body` is explicitly enabled and a body is logged +- **THEN** the logged body SHALL be truncated to a bounded length and SHALL have sensitive values (API key, `Idempotency-Key`, secrets/tokens) redacted to `[REDACTED]` + +### Requirement: Connection pool is thread-safe +The per-origin keep-alive connection pool inside `Nfe::Http::NetHttp` SHALL be guarded by a `Mutex`, so a single transport (and the `Client` that shares it) MAY be used concurrently from multiple threads without corrupting the pool or sharing a `Net::HTTP` socket across two in-flight requests. This makes a shared `Client` safe under Rails/Sidekiq/Puma multi-threaded execution. + +#### Scenario: Concurrent requests share the transport safely +- **WHEN** multiple threads issue requests through the same `Nfe::Http::NetHttp` instance at the same time +- **THEN** access to the per-origin connection cache SHALL be serialized by a `Mutex` and no two threads SHALL use the same underlying socket simultaneously + +### Requirement: Per-call request option overrides +The transport SHALL honor per-call overrides supplied by the resource layer via `Nfe::RequestOptions` (`Data.define` with `api_key`, `base_url`, `timeout`; defined in `add-client-core`). When a `Request` is built with such overrides, the transport SHALL use the overridden `base_url` and timeout for that single call and SHALL transmit the overridden API key in the `X-NFE-APIKEY` header, without mutating any global configuration or affecting other concurrent calls. This enables multi-tenant per-call API keys without constructing a second `Client`. + +#### Scenario: Per-call base URL and timeout override +- **WHEN** a single `Request` carries an overridden `base_url` and `read_timeout` derived from `Nfe::RequestOptions` +- **THEN** the transport SHALL route that one call to the overridden `base_url` with the overridden timeout, leaving the default configuration unchanged for subsequent calls + +#### Scenario: Per-call API key override +- **WHEN** a single `Request` carries an API key derived from a per-call `Nfe::RequestOptions` +- **THEN** the transport SHALL send that key in `X-NFE-APIKEY` for that call only, enabling multi-tenant usage from one shared `Client` + +### Requirement: POST is not auto-retried even with an idempotency key available +The transport SHALL NOT automatically retry a `POST` request as a safety default, diverging deliberately from the Node.js and PHP SDKs (which retry POST). A `POST` becomes retry-eligible ONLY when the caller supplies an `idempotency_key` (set by the resource `create`/`create_with_state_tax` kwarg, NEVER auto-generated by the transport). This divergence SHALL be documented for integrators in the README (owned by the release-tooling change). + +#### Scenario: POST without idempotency key is never auto-retried +- **WHEN** a `POST` request without an `idempotency_key` receives HTTP 503 +- **THEN** the transport SHALL return the 503 response immediately without retrying, so an invoice is never re-issued automatically + +#### Scenario: POST with caller-supplied idempotency key is retry-eligible +- **WHEN** a `POST` request carries a caller-supplied `idempotency_key` and receives HTTP 503 +- **THEN** the request SHALL be eligible for retry (per `Request#idempotent?`), the `Idempotency-Key` header SHALL be replayed on each attempt, and the key SHALL NOT be auto-generated by the transport + +### Requirement: Polling and batch helpers are not part of v1.0 +The HTTP transport SHALL deliver the raw 202 + `Location` contract but SHALL NOT implement polling (`pollUntilComplete` / `create_and_wait`) nor concurrent batch helpers (`create_batch`). These are explicitly deferred; the discriminated Pending/Issued contract (in `add-client-core`) plus `Nfe::FlowStatus` terminal-state checks are sufficient for manual polling loops. + +#### Scenario: No automatic polling at the transport layer +- **WHEN** the transport returns a 202 with `Location` +- **THEN** it SHALL NOT issue any follow-up GET to that `Location`; resolving the async result is the caller's responsibility + diff --git a/openspec/specs/invoice-resources/spec.md b/openspec/specs/invoice-resources/spec.md new file mode 100644 index 0000000..f2a9047 --- /dev/null +++ b/openspec/specs/invoice-resources/spec.md @@ -0,0 +1,354 @@ +# invoice-resources Specification + +## Purpose +TBD - created by archiving change add-invoice-resources. Update Purpose after archive. +## Requirements +### Requirement: Five invoice resource classes are fully implemented +The SDK SHALL implement exactly five invoice resource classes under `Nfe::Resources` — `ServiceInvoices`, `ProductInvoices`, `ConsumerInvoices`, `TransportationInvoices`, and `InboundProductInvoices` — covering NFS-e, NF-e, NFC-e, inbound CT-e, and inbound supplier NF-e respectively. They SHALL be reachable through the lazy snake_case accessors `client.service_invoices`, `client.product_invoices`, `client.consumer_invoices`, `client.transportation_invoices`, and `client.inbound_product_invoices` defined by `add-client-core`. + +Four of the five (service, product, transportation, inbound-product) match the Node.js SDK 1:1 in method names, parameter set, and return-shape category, modulo Ruby idioms: `Buffer` becomes a binary `String`, `Promise`/async becomes a synchronous return, and `camelCase` becomes `snake_case`. The fifth (`ConsumerInvoices`) is a **parity-plus** addition: the Node SDK does not expose NFC-e emission, but the NFE.io API supports it natively via `nf-consumidor-v2.yaml`. + +The classic service-invoice emission lives in this capability. The new RTC (Reforma Tributária, IBS/CBS/IS) service-invoice and product-invoice emission models are out of scope here and are specified by the `add-rtc-invoice-emission` change. + +#### Scenario: Accessing invoice resources from the client +- **WHEN** a consumer reads any of `client.service_invoices`, `client.product_invoices`, `client.consumer_invoices`, `client.transportation_invoices`, or `client.inbound_product_invoices` +- **THEN** the accessor SHALL return a fully functional resource instance (not a stub that raises `NotImplementedError`) +- **AND** repeated reads of the same accessor SHALL return the same memoized instance + +#### Scenario: Parity with the Node SDK for the four shared resources +- **WHEN** comparing method names, parameter set, and return-shape category between this SDK and the Node SDK for `ServiceInvoices`, `ProductInvoices`, `TransportationInvoices`, or `InboundProductInvoices` +- **THEN** they SHALL be 1:1 equivalent, modulo Ruby idioms (binary `String` for downloads, synchronous returns, snake_case names) + +#### Scenario: NFC-e emission beyond Node parity +- **WHEN** a consumer calls any method on `client.consumer_invoices` +- **THEN** the resource SHALL execute against `https://api.nfse.io/v2/companies/{company_id}/consumerinvoices/*` paths defined in `nf-consumidor-v2.yaml`, even though the equivalent method does not exist in the Node SDK + +### Requirement: Invoice resources route to the host of their API family +Each invoice resource SHALL resolve its base URL through `Nfe::Configuration#base_url_for(family)` (provided by `add-client-core`) and SHALL NOT hard-code any host. `ServiceInvoices` SHALL use the `:main` family (`base_url_for(:main)` → host `https://api.nfe.io`, with the `/v1` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfe.io/v1/...`). `ProductInvoices`, `ConsumerInvoices`, `TransportationInvoices`, and `InboundProductInvoices` SHALL use the `:cte` family (`https://api.nfse.io`). + +#### Scenario: Service invoice routes to api.nfe.io +- **WHEN** any method of `ServiceInvoices` issues an HTTP request +- **THEN** the request host SHALL be `https://api.nfe.io` with the `/v1` base path segment + +#### Scenario: Product, consumer, transportation, and inbound route to api.nfse.io +- **WHEN** any method of `ProductInvoices`, `ConsumerInvoices`, `TransportationInvoices`, or `InboundProductInvoices` issues an HTTP request +- **THEN** the request host SHALL be `https://api.nfse.io`, distinct from the `https://api.nfe.io` host used by `ServiceInvoices` + +### Requirement: Service invoice creation supports the discriminated 202 contract +`ServiceInvoices#create(company_id:, data:)` SHALL accept a company ID and a request payload and SHALL return either a `Nfe::Resources::ServiceInvoicePending` (when the API responds HTTP 202 with a `Location` header) or a `Nfe::Resources::ServiceInvoiceIssued` (when the API responds HTTP 201 with the materialized invoice body). + +#### Scenario: Async invoice creation +- **WHEN** the consumer calls `client.service_invoices.create(company_id:, data:)` and the API responds HTTP 202 with `Location: /v1/companies/{id}/serviceinvoices/{invoice_id}` +- **THEN** the method SHALL return a `ServiceInvoicePending` whose `invoice_id` matches the final path segment (extracted via `%r{serviceinvoices/([a-z0-9-]+)}i`) and whose `location` matches the header value +- **AND** `pending?` SHALL be `true` and `issued?` SHALL be `false` + +#### Scenario: Immediate invoice creation +- **WHEN** the API responds HTTP 201 with the invoice body +- **THEN** the method SHALL return a `ServiceInvoiceIssued` whose `resource` is the typed invoice model hydrated from the response body +- **AND** `issued?` SHALL be `true` and `pending?` SHALL be `false` + +#### Scenario: Async response missing the Location header +- **WHEN** the API responds HTTP 202 but no `Location` header is present, or the invoice ID cannot be extracted from it +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` + +### Requirement: Emission methods accept an idempotency key and per-call request options +The emission methods — `create` and `create_with_state_tax` on `ServiceInvoices`, `ProductInvoices`, and `ConsumerInvoices` — SHALL accept two optional keyword arguments: `idempotency_key:` (default `nil`) and `request_options:` (default `nil`). + +When `idempotency_key:` is supplied, the SDK SHALL send it as the HTTP `Idempotency-Key` request header. The caller supplies a stable key tied to a business identifier. The SDK SHALL NOT auto-retry the POST; the documented safe-retry pattern is for the caller to re-invoke the same emission method with the SAME `idempotency_key:` after a timeout, so the server deduplicates and no duplicate fiscal document is issued. + +When `request_options:` is supplied, it SHALL be a `Nfe::RequestOptions` value object (provided by `add-client-core`) and `Nfe::Resources::AbstractResource` SHALL thread its `api_key`/`base_url`/`timeout` overrides into the request for that single call, without requiring a second `Client`. This capability SHALL NOT redefine `Nfe::RequestOptions`; it consumes it. + +#### Scenario: Idempotency key sent as a header +- **WHEN** `create(company_id:, data:, idempotency_key: 'order-42')` is called +- **THEN** the issued HTTP POST SHALL carry the header `Idempotency-Key: order-42` + +#### Scenario: Safe retry reuses the same key +- **WHEN** an emission call times out and the caller re-invokes the same method with the SAME `idempotency_key:` +- **THEN** the SDK SHALL send the identical `Idempotency-Key` header and SHALL NOT auto-retry the POST on its own, so the server can deduplicate and avoid issuing a duplicate fiscal document + +#### Scenario: Per-call request options override the client defaults +- **WHEN** `create(company_id:, data:, request_options: Nfe::RequestOptions.new(api_key: 'tenant-key', base_url: nil, timeout: nil))` is called +- **THEN** that single request SHALL authenticate with `tenant-key` instead of the `Client`'s default api_key, leaving the shared `Client` unchanged + +#### Scenario: Emission without the optional kwargs is unchanged +- **WHEN** `create(company_id:, data:)` is called without `idempotency_key:` or `request_options:` +- **THEN** the SDK SHALL issue the request with no `Idempotency-Key` header and using the `Client`'s default configuration + +### Requirement: Service invoice CRUD, email, downloads, and status +`ServiceInvoices` SHALL expose `create`, `list`, `retrieve`, `cancel`, `send_email`, `download_pdf`, `download_xml`, and `get_status`. Every method that takes a company ID or invoice ID SHALL validate it through `Nfe::IdValidator` (provided by `add-client-core`) before issuing the HTTP request. + +| Method | HTTP | Path | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | POST | `/companies/{company_id}/serviceinvoices` | +| `list(company_id:, **options)` | GET | `/companies/{company_id}/serviceinvoices` | +| `retrieve(company_id:, invoice_id:)` | GET | `/companies/{company_id}/serviceinvoices/{invoice_id}` | +| `cancel(company_id:, invoice_id:)` | DELETE | `/companies/{company_id}/serviceinvoices/{invoice_id}` | +| `send_email(company_id:, invoice_id:)` | PUT | `/companies/{company_id}/serviceinvoices/{invoice_id}/sendemail` | +| `download_pdf(company_id:, invoice_id: nil)` | GET | `.../{invoice_id}/pdf` or `.../serviceinvoices/pdf` (bulk) | +| `download_xml(company_id:, invoice_id: nil)` | GET | `.../{invoice_id}/xml` or `.../serviceinvoices/xml` (bulk) | +| `get_status(company_id:, invoice_id:)` | (derived) | derived from `retrieve` — no extra HTTP call | + +#### Scenario: Page-style listing +- **WHEN** `list(company_id:, page_index: 0, page_count: 20, issued_begin: '2026-01-01', issued_end: '2026-01-31')` is called +- **THEN** the SDK SHALL return a `Nfe::ListResponse` whose `page` carries `page_index`/`page_count` (cursor fields `nil`) and whose `data` is the unwrapped `serviceInvoices` array + +#### Scenario: Retrieve returns a typed model +- **WHEN** `retrieve(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a typed invoice model (a generated model, or a hand-written `Nfe::ServiceInvoice` value object where the generated tree does not cover the shape) hydrated from the response body + +#### Scenario: Retrieve not found +- **WHEN** `retrieve(company_id:, invoice_id:)` receives HTTP 404, or the response body is empty +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +#### Scenario: Cancel is synchronous +- **WHEN** `cancel(company_id:, invoice_id:)` succeeds +- **THEN** the SDK SHALL return the updated invoice model from the response body + +#### Scenario: Send email +- **WHEN** `send_email(company_id:, invoice_id:)` succeeds +- **THEN** the SDK SHALL issue a `PUT` to `.../sendemail` and return the send result carrying a `sent` flag + +#### Scenario: Bulk download with no invoice ID +- **WHEN** `download_pdf(company_id:)` is called with `invoice_id` omitted +- **THEN** the SDK SHALL request `.../serviceinvoices/pdf` and return the ZIP bytes as a binary `String` + +#### Scenario: Status derived without an HTTP call +- **WHEN** `get_status(company_id:, invoice_id:)` is called +- **THEN** the SDK SHALL call `retrieve` exactly once and SHALL return a value carrying `status`, `invoice`, `complete?` (via `FlowStatus.terminal?`), and `failed?` (true for `IssueFailed`/`CancelFailed`), making no separate status HTTP request + +### Requirement: Product invoice resource mirrors Node SDK breadth +`ProductInvoices` SHALL expose `create`, `create_with_state_tax`, `list`, `retrieve`, `cancel`, `list_items`, `list_events`, `download_pdf`, `download_xml`, `download_rejection_xml`, `download_epec_xml`, `send_correction_letter`, `download_correction_letter_pdf`, `download_correction_letter_xml`, `disable`, and `disable_range`, all under `/v2/companies/{company_id}/productinvoices*` on `https://api.nfse.io`. + +Pagination on `list`, `list_items`, and `list_events` uses cursor semantics (`starting_after`, `ending_before`, `limit`). The `environment` query parameter on `list` is required. + +Both `create` and `create_with_state_tax` SHALL accept the optional `idempotency_key:` and `request_options:` keyword arguments described in the dedicated emission-options requirement. + +#### Scenario: Discriminated creation +- **WHEN** `create(company_id:, data:)` is called and the API enqueues the invoice (HTTP 202) +- **THEN** the method SHALL return a `Nfe::Resources::ProductInvoicePending`; on HTTP 201 it SHALL return a `Nfe::Resources::ProductInvoiceIssued` + +#### Scenario: Creation scoped to a state tax registration +- **WHEN** `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` is called +- **THEN** the SDK SHALL route to `/v2/companies/{company_id}/statetaxes/{state_tax_id}/productinvoices` and SHALL validate `state_tax_id` via `IdValidator` before the request, forwarding `idempotency_key:` as the `Idempotency-Key` header when present + +#### Scenario: Cursor-style listing requires environment +- **WHEN** `list(company_id:, environment: 'Production', limit: 50)` is called +- **THEN** the SDK SHALL return a `ListResponse` whose `page` carries `starting_after`/`ending_before` cursors (not `page_index`) + +#### Scenario: Listing without environment is rejected +- **WHEN** `list(company_id:)` is called without an `environment` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without an HTTP request + +#### Scenario: Cancel forwards a reason +- **WHEN** `cancel(company_id:, invoice_id:, reason: 'Erro de digitação')` is called +- **THEN** the SDK SHALL issue `DELETE .../{invoice_id}?reason=...` and return the cancellation resource (the cancellation is asynchronous) + +#### Scenario: Product invoice downloads return a file URI, not bytes +- **WHEN** `download_pdf`, `download_xml`, `download_rejection_xml`, or `download_epec_xml` succeeds +- **THEN** the return value SHALL be a `Nfe::NfeFileResource` carrying a URI to the file — NOT raw bytes — distinguishing this resource from the byte-returning downloads on the other invoice resources + +#### Scenario: Correction letter length validation +- **WHEN** `send_correction_letter(company_id:, invoice_id:, reason:)` is called with a `reason` whose length is outside `15..1000` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without an HTTP request; with a valid length it SHALL `PUT .../correctionletter` with body `{ reason: }` + +#### Scenario: Per-invoice and range disablement +- **WHEN** `disable(company_id:, invoice_id:, reason:)` is called +- **THEN** the SDK SHALL `POST .../{invoice_id}/disablement?reason=...` +- **WHEN** `disable_range(company_id:, data:)` is called with `{ environment, serie, state, begin_number, last_number, reason? }` +- **THEN** the SDK SHALL `POST /v2/companies/{company_id}/productinvoices/disablement` + +### Requirement: Consumer invoice resource exposes the NFC-e emission lifecycle +`ConsumerInvoices` SHALL target `https://api.nfse.io` under v2 (`base_url_for(:cte)`) and SHALL expose the following methods backed by `nf-consumidor-v2.yaml`: + +| Method | HTTP | Path | +|---|---|---| +| `create(company_id:, data:, idempotency_key: nil, request_options: nil)` | POST | `/v2/companies/{company_id}/consumerinvoices` | +| `create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil)` | POST | `.../statetaxes/{state_tax_id}/consumerinvoices` | +| `list(company_id:, **options)` | GET | `/v2/companies/{company_id}/consumerinvoices` | +| `retrieve(company_id:, invoice_id:)` | GET | `.../consumerinvoices/{invoice_id}` | +| `cancel(company_id:, invoice_id:)` | DELETE | `.../consumerinvoices/{invoice_id}` | +| `list_items(company_id:, invoice_id:)` | GET | `.../{invoice_id}/items` | +| `list_events(company_id:, invoice_id:)` | GET | `.../{invoice_id}/events` | +| `download_pdf(company_id:, invoice_id:)` | GET | `.../{invoice_id}/pdf` | +| `download_xml(company_id:, invoice_id:)` | GET | `.../{invoice_id}/xml` | +| `download_rejection_xml(company_id:, invoice_id:)` | GET | `.../{invoice_id}/xml/rejection` | +| `disable_range(company_id:, data:)` | POST | `.../consumerinvoices/disablement` | + +The resource SHALL NOT define `send_correction_letter` (CC-e applies only to NF-e by Brazilian fiscal law), `download_epec_xml` (no EPEC contingency exists for NFC-e), nor a per-invoice `disable` (NFC-e supports only collective inutilization via `disable_range`). + +#### Scenario: NFC-e discriminated creation +- **WHEN** `create(company_id:, data:)` is called and the API responds HTTP 202 with `Location` +- **THEN** the method SHALL return a `Nfe::Resources::ConsumerInvoicePending` whose `invoice_id` is extracted from the final path segment; on HTTP 201 it SHALL return a `Nfe::Resources::ConsumerInvoiceIssued` whose `resource` is a `Nfe::ConsumerInvoice` + +#### Scenario: NFC-e cancellation is synchronous +- **WHEN** `cancel(company_id:, invoice_id:)` is called +- **THEN** the SDK SHALL `DELETE .../consumerinvoices/{invoice_id}` and return the updated consumer-invoice model + +#### Scenario: NFC-e download returns bytes +- **WHEN** `download_pdf(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a binary `String` (the DANFE NFC-e PDF), unlike `ProductInvoices` which returns a URI + +#### Scenario: NFC-e collective inutilization only +- **WHEN** `disable_range(company_id:, data:)` is called +- **THEN** the SDK SHALL `POST .../consumerinvoices/disablement` + +#### Scenario: Methods absent by fiscal law +- **WHEN** consumer code calls `client.consumer_invoices.send_correction_letter(...)`, `download_epec_xml(...)`, or `disable(...)` +- **THEN** Ruby SHALL raise `NoMethodError`, because those instruments do not exist for NFC-e + +### Requirement: Transportation invoice resource (CT-e inbound) +`TransportationInvoices` SHALL manage inbound CT-e via the `:cte` family (`https://api.nfse.io`) and SHALL expose `enable`, `disable`, `get_settings`, `retrieve` (by access key), `download_xml`, `get_event`, and `download_event_xml`. + +| Method | HTTP | Path | +|---|---|---| +| `enable(company_id:, start_from_nsu: nil, start_from_date: nil)` | POST | `/v2/companies/{company_id}/inbound/transportationinvoices` | +| `disable(company_id:)` | DELETE | `.../inbound/transportationinvoices` | +| `get_settings(company_id:)` | GET | `.../inbound/transportationinvoices` | +| `retrieve(company_id:, access_key:)` | GET | `.../inbound/{access_key}` | +| `download_xml(company_id:, access_key:)` | GET | `.../inbound/{access_key}/xml` | +| `get_event(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}` | +| `download_event_xml(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}/xml` | + +#### Scenario: Enabling auto-fetch returns settings +- **WHEN** `enable(company_id:)` is called +- **THEN** the SDK SHALL `POST .../inbound/transportationinvoices` and return the inbound settings model + +#### Scenario: Access key normalisation +- **WHEN** `retrieve(company_id:, access_key:)` is called with a 44-digit key containing spaces or dots +- **THEN** `Nfe::IdValidator.access_key` SHALL strip non-digits and the request SHALL use the 44-digit value +- **AND** if the normalised value does not match `/\A\d{44}\z/` the SDK SHALL raise `Nfe::InvalidRequestError` before any HTTP request + +#### Scenario: XML downloads return strings +- **WHEN** `download_xml(company_id:, access_key:)` or `download_event_xml(company_id:, access_key:, event_key:)` succeeds +- **THEN** the return value SHALL be a `String` containing the raw XML + +### Requirement: Inbound product invoice resource manages supplier NF-e ingestion +`InboundProductInvoices` SHALL manage supplier-issued NF-e via the `:cte` family (`https://api.nfse.io`) and SHALL expose `enable_auto_fetch`, `disable_auto_fetch`, `get_settings`, `get_details`, `get_product_invoice_details`, `get_event_details`, `get_product_invoice_event_details`, `get_xml`, `get_event_xml`, `get_pdf`, `get_json`, `manifest`, and `reprocess_webhook`. + +The `manifest` method SHALL accept a numeric `tp_event` (default `210210`) and forward it as a query parameter. The module SHALL expose symbolic constants for the manifest event types: `210210` awareness (default), `210220` confirmation, `210240` operation not performed. + +| Method | HTTP | Path | +|---|---|---| +| `enable_auto_fetch(company_id:, **opts)` | POST | `/v2/companies/{company_id}/inbound/productinvoices` | +| `disable_auto_fetch(company_id:)` | DELETE | `.../inbound/productinvoices` | +| `get_settings(company_id:)` | GET | `.../inbound/productinvoices` | +| `get_details(company_id:, access_key:)` | GET | `.../inbound/{access_key}` | +| `get_product_invoice_details(company_id:, access_key:)` | GET | `.../inbound/productinvoice/{access_key}` | +| `get_event_details(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}` | +| `get_product_invoice_event_details(company_id:, access_key:, event_key:)` | GET | `.../inbound/productinvoice/{access_key}/events/{event_key}` | +| `get_xml(company_id:, access_key:)` | GET | `.../inbound/{access_key}/xml` | +| `get_event_xml(company_id:, access_key:, event_key:)` | GET | `.../inbound/{access_key}/events/{event_key}/xml` | +| `get_pdf(company_id:, access_key:)` | GET | `.../inbound/{access_key}/pdf` | +| `get_json(company_id:, access_key:)` | GET | `.../inbound/productinvoice/{access_key}/json` | +| `manifest(company_id:, access_key:, tp_event: 210210)` | POST | `.../inbound/{access_key}/manifest?tpEvent={tp_event}` | +| `reprocess_webhook(company_id:, access_key_or_nsu:)` | POST | `.../inbound/productinvoice/{access_key_or_nsu}/processwebhook` | + +#### Scenario: v1 versus v2 detail endpoints +- **WHEN** `get_details(company_id:, access_key:)` is called +- **THEN** the SDK SHALL request `.../inbound/{access_key}` (webhook v1 format) +- **WHEN** `get_product_invoice_details(company_id:, access_key:)` is called +- **THEN** the SDK SHALL request `.../inbound/productinvoice/{access_key}` (webhook v2 format) + +#### Scenario: Manifesting receipt with default event type +- **WHEN** `manifest(company_id:, access_key:)` is called without `tp_event` +- **THEN** the SDK SHALL `POST .../manifest?tpEvent=210210` (awareness) and return the result as a `String` + +#### Scenario: Manifesting receipt with explicit event type +- **WHEN** `manifest(company_id:, access_key:, tp_event: 210220)` is called +- **THEN** the SDK SHALL `POST .../manifest?tpEvent=210220` (confirmation) + +#### Scenario: PDF download returns bytes +- **WHEN** `get_pdf(company_id:, access_key:)` succeeds +- **THEN** the return value SHALL be a binary `String` (the PDF bytes) + +#### Scenario: Reprocess accepts key or NSU +- **WHEN** `reprocess_webhook(company_id:, access_key_or_nsu:)` is called with either a 44-digit access key or a numeric NSU +- **THEN** the SDK SHALL `POST .../inbound/productinvoice/{access_key_or_nsu}/processwebhook` and SHALL NOT reject a numeric NSU as an invalid access key + +### Requirement: Discriminated response value objects for invoice creation +The SDK SHALL provide the following immutable `Data.define` value objects under `Nfe::Resources`, each exposing `pending?` and `issued?` predicate methods: + +- `ServiceInvoicePending(:invoice_id, :location)` and `ServiceInvoiceIssued(:resource)` +- `ProductInvoicePending(:invoice_id, :location)` and `ProductInvoiceIssued(:resource)` +- `ConsumerInvoicePending(:invoice_id, :location)` and `ConsumerInvoiceIssued(:resource)` + +These implement the `Pending`/`Issued` contract introduced by `add-client-core`. + +#### Scenario: Discriminating with a predicate +- **WHEN** a consumer writes `result.pending? ? handle_pending(result) : handle_issued(result)` +- **THEN** a `*Pending` value SHALL answer `pending?` with `true` and expose `invoice_id`/`location`, and a `*Issued` value SHALL answer `issued?` with `true` and expose `resource` + +#### Scenario: Discriminating with pattern matching +- **WHEN** a consumer writes `case result; in Nfe::Resources::ServiceInvoicePending; ...; in Nfe::Resources::ServiceInvoiceIssued; ...; end` +- **THEN** Ruby `Data` pattern matching SHALL select the correct branch for the returned value object + +### Requirement: Invoice resources validate IDs and access keys before HTTP +Every invoice resource method that takes an identifier SHALL validate it through the `Nfe::IdValidator` module provided by `add-client-core` — calling `company_id`, `invoice_id`, `state_tax_id`, `event_key`, or `access_key` — before issuing the HTTP request. This capability SHALL NOT redefine the validator; it consumes the one defined by `add-client-core`. + +`Nfe::IdValidator.access_key` accepts formatted input (with spaces, dots, dashes), strips non-digit characters, validates that the result has exactly 44 digits (`/\A\d{44}\z/`), and returns the normalised string. + +#### Scenario: Empty company ID rejected before HTTP +- **WHEN** any resource method receives an empty or whitespace-only company ID +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously, with a Portuguese-language message naming the invalid argument, and SHALL make no HTTP request + +#### Scenario: Access key with formatting is normalised +- **WHEN** a resource method receives a 44-digit access key with separators and calls `Nfe::IdValidator.access_key` +- **THEN** the validator SHALL return a 44-character digit-only `String` and SHALL NOT raise + +#### Scenario: Access key of wrong length rejected +- **WHEN** a resource method receives an access key that normalises to fewer than 44 digits +- **THEN** `Nfe::IdValidator.access_key` SHALL raise `Nfe::InvalidRequestError` before any HTTP request + +### Requirement: Invoice listings use the shared ListResponse pagination type +Every invoice resource `list`/`list_items`/`list_events` method SHALL return the `Nfe::ListResponse` value object provided by `add-client-core` (carrying `data` and a `Nfe::ListPage`), populating only the half of `ListPage` (`page_index`/`page_count` for page-style, or `starting_after`/`ending_before` for cursor-style) relevant to its endpoint. This capability SHALL NOT redefine `ListResponse`/`ListPage`; it consumes them. + +#### Scenario: Page-style listing +- **WHEN** a resource paginates with `page_index`/`page_count` (e.g., service invoices) +- **THEN** the returned `ListResponse.page` SHALL have `page_index` and `page_count` set and cursor fields `nil` + +#### Scenario: Cursor-style listing +- **WHEN** a resource paginates with `starting_after`/`ending_before` (e.g., product or consumer invoices) +- **THEN** the returned `ListResponse.page` SHALL have the cursor fields set and `page_index` `nil` + +#### Scenario: Iterating a list response +- **WHEN** a consumer calls `result.each { |item| ... }` or `result.map { ... }` on a `ListResponse` +- **THEN** the iteration SHALL traverse the underlying `data` array via the `Enumerable` included by `add-client-core` + +### Requirement: Invoice status checks use the shared FlowStatus helper +Manual polling and `ServiceInvoices#get_status` SHALL determine terminal state through `Nfe::FlowStatus.terminal?(status)` provided by `add-client-core`, which returns `true` for `Issued`, `Cancelled`, `IssueFailed`, and `CancelFailed`, and `false` otherwise. This capability SHALL NOT redefine `FlowStatus`; it consumes it. + +#### Scenario: Terminal status +- **WHEN** `Nfe::FlowStatus.terminal?('Issued')`, `'Cancelled'`, `'IssueFailed'`, or `'CancelFailed'` is called +- **THEN** the method SHALL return `true` + +#### Scenario: Non-terminal status +- **WHEN** `Nfe::FlowStatus.terminal?('WaitingDefineRpsNumber')` or any other non-terminal value is called +- **THEN** the method SHALL return `false` + +### Requirement: Byte downloads return binary-safe strings +The byte-returning download methods — `ServiceInvoices#download_pdf`/`download_xml`, `ConsumerInvoices#download_pdf`/`download_xml`/`download_rejection_xml`, `TransportationInvoices#download_xml`/`download_event_xml`, and `InboundProductInvoices#get_xml`/`get_event_xml`/`get_pdf` — SHALL return a Ruby `String` containing the raw response bytes with encoding forced to `Encoding::ASCII_8BIT`. They SHALL set the appropriate `Accept` header (`application/pdf` or `application/xml`) and SHALL NOT attempt to parse the body as JSON. + +This requirement does NOT apply to `ProductInvoices` download methods, which return a `Nfe::NfeFileResource` (URI) instead of bytes. + +#### Scenario: PDF download bytes +- **WHEN** any covered `download_pdf`/`get_pdf` method succeeds +- **THEN** the return value SHALL be an `ASCII-8BIT` `String` whose first four bytes are `%PDF` + +#### Scenario: XML download bytes +- **WHEN** any covered `download_xml`/`get_xml` method succeeds +- **THEN** the return value SHALL be an `ASCII-8BIT` `String` whose first non-BOM character is `<` + +### Requirement: create_and_wait and create_batch are deferred +The SDK v1.0 SHALL NOT implement `create_and_wait` or `create_batch` on any invoice resource. The discriminated `Pending`/`Issued` contract plus `FlowStatus.terminal?` are sufficient for manual polling loops in CLI/worker contexts. Both helpers are explicitly deferred to a future minor release. + +#### Scenario: Looking for create_and_wait +- **WHEN** consumer code calls `client.service_invoices.create_and_wait(...)` against v1.0 +- **THEN** Ruby SHALL raise `NoMethodError`, since the method is not defined + +### Requirement: RTC emission is delegated to a separate change +This capability SHALL implement only the classic service-invoice and product-invoice emission. The RTC (Reforma Tributária do Consumo) emission models — adding the IBS, CBS, and IS tax groups — SHALL NOT be implemented here; they are specified by the `add-rtc-invoice-emission` change, which reuses the 202 contract, host routing, and validators defined in this capability. + +#### Scenario: Classic emission only +- **WHEN** a consumer issues a service or product invoice through this capability's `create` methods +- **THEN** the SDK SHALL send the classic (non-RTC) payload shape, and any IBS/CBS/IS handling SHALL be provided by the dedicated RTC resources from `add-rtc-invoice-emission` + diff --git a/openspec/specs/lookup-resources/spec.md b/openspec/specs/lookup-resources/spec.md new file mode 100644 index 0000000..dca0792 --- /dev/null +++ b/openspec/specs/lookup-resources/spec.md @@ -0,0 +1,263 @@ +# lookup-resources Specification + +## Purpose +TBD - created by archiving change add-lookup-resources. Update Purpose after archive. +## Requirements +### Requirement: Eight lookup, query, and state-tax resources are fully implemented +The SDK SHALL implement eight resource classes under `Nfe::Resources` — `Addresses`, `LegalEntityLookup`, `NaturalPersonLookup`, `ProductInvoiceQuery`, `ConsumerInvoiceQuery`, `TaxCalculation`, `TaxCodes`, and `StateTaxes` — each extending `Nfe::Resources::AbstractResource` (from `add-client-core`) and exposed as a lazy snake_case accessor on `Nfe::Client`. Method names, parameter order, and behavior SHALL match the NFE.io Node.js SDK 1:1, adapted to Ruby idioms (snake_case methods, keyword arguments, `Buffer`→binary `String`, `Promise`→synchronous return, `Date`/`Time`/`DateTime` accepted alongside `String` for date inputs). + +This change depends on `add-client-core`, which owns the `Nfe::Configuration` host map, `Nfe::Resources::AbstractResource`, the base `Nfe::IdValidator` (`company_id`, `state_tax_id`, `access_key`), `Nfe::ListResponse`/`Nfe::ListPage`, the typed error classes, and the lazy resource accessors on `Nfe::Client`. + +#### Scenario: Parity with the Node SDK +- **WHEN** comparing method signatures between this Ruby SDK and the Node SDK for any of the eight resources +- **THEN** they SHALL be 1:1 equivalent modulo Ruby idioms (e.g., `lookupByPostalCode` ⇄ `lookup_by_postal_code`, `Date`/`Time` accepted alongside ISO `String`) + +#### Scenario: Accessing lookup resources from Client +- **WHEN** consumer code reads any of `client.addresses`, `client.legal_entity_lookup`, `client.natural_person_lookup`, `client.product_invoice_query`, `client.consumer_invoice_query`, `client.tax_calculation`, `client.tax_codes`, `client.state_taxes` +- **THEN** each accessor SHALL return a fully functional resource instance (not a stub that raises `NoMethodError`) + +### Requirement: Multi-host routing for lookup endpoints +The SDK SHALL route each resource to its correct host as resolved by `Nfe::Configuration` from the resource's `api_family`. No resource SHALL hard-code a host. Six families exercised by this change resolve to dedicated hosts distinct from the default `https://api.nfe.io`: + +| Resource | api_family | Host | +|---|---|---| +| `Addresses` | `addresses` | `https://address.api.nfe.io/v2` (the `/v2` is part of the base URL) | +| `LegalEntityLookup` | `legal-entity` | `https://legalentity.api.nfe.io` | +| `NaturalPersonLookup` | `natural-person` | `https://naturalperson.api.nfe.io` | +| `ProductInvoiceQuery` | `nfe-query` | `https://nfe.api.nfe.io` (paths use `v2`) | +| `ConsumerInvoiceQuery` | `nfe-query` | `https://nfe.api.nfe.io` (paths use `v1` + `/coupon/`) | +| `TaxCalculation`, `TaxCodes`, `StateTaxes` | `cte` | `https://api.nfse.io` | + +#### Scenario: Address lookup routes to the address host with embedded version +- **WHEN** any method of `Nfe::Resources::Addresses` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://address.api.nfe.io/v2/addresses` and SHALL NOT contain a duplicated version segment (no `/v2/v2`) + +#### Scenario: Legal entity lookup routes to its dedicated host +- **WHEN** any method of `Nfe::Resources::LegalEntityLookup` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://legalentity.api.nfe.io` + +#### Scenario: Natural person lookup routes to its dedicated host +- **WHEN** any method of `Nfe::Resources::NaturalPersonLookup` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://naturalperson.api.nfe.io` + +#### Scenario: Both invoice queries share the nfe-query host +- **WHEN** a method of `Nfe::Resources::ProductInvoiceQuery` or `Nfe::Resources::ConsumerInvoiceQuery` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://nfe.api.nfe.io` + +#### Scenario: Tax and state-tax resources route to nfse.io +- **WHEN** a method of `Nfe::Resources::TaxCalculation`, `Nfe::Resources::TaxCodes`, or `Nfe::Resources::StateTaxes` issues a request +- **THEN** the outgoing request URL SHALL begin with `https://api.nfse.io` + +### Requirement: Address lookup by postal code, search, and term +`Nfe::Resources::Addresses` SHALL expose: + +- `lookup_by_postal_code(postal_code)` — accepts a CEP with or without hyphen; normalises to 8 digits via `Nfe::IdValidator.cep`; issues `GET /addresses/{cep}` +- `search(filter: nil)` — accepts an opaque OData `$filter` string forwarded verbatim as the `$filter` query parameter +- `lookup_by_term(term)` — accepts a non-empty search term; URL-encodes it; issues `GET /addresses/{encoded_term}` + +Each method SHALL return an `AddressLookupResponse` value object. + +#### Scenario: CEP with hyphen normalised +- **WHEN** `lookup_by_postal_code("01310-100")` is called +- **THEN** the request SHALL be issued to `/addresses/01310100` (digits only) + +#### Scenario: CEP with invalid length rejected before HTTP +- **WHEN** `lookup_by_postal_code("123")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Search with OData filter forwarded opaquely +- **WHEN** `search(filter: "city eq 'São Paulo'")` is called +- **THEN** the SDK SHALL issue `GET /addresses` with the `$filter` query parameter set to the given expression (URL-encoded by the transport), without parsing or validating the expression + +#### Scenario: Empty search term rejected +- **WHEN** `lookup_by_term("")` or `lookup_by_term(" ")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +### Requirement: Legal entity (CNPJ) lookup with four query methods +`Nfe::Resources::LegalEntityLookup` SHALL expose `get_basic_info(federal_tax_number, update_address: nil, update_city_code: nil)`, `get_state_tax_info(state, federal_tax_number)`, `get_state_tax_for_invoice(state, federal_tax_number)`, and `get_suggested_state_tax_for_invoice(state, federal_tax_number)`. + +Each method SHALL normalise its inputs before issuing the request: CNPJ via `Nfe::IdValidator.cnpj` (14 digits, non-digits stripped) and state via `Nfe::IdValidator.state` (uppercase, validated against the 29-value set of 27 Brazilian UFs plus `EX` and `NA`). + +#### Scenario: CNPJ with punctuation normalised +- **WHEN** `get_basic_info("12.345.678/0001-90")` is called +- **THEN** the SDK SHALL normalise to `12345678000190` and issue `GET /v2/legalentities/basicInfo/12345678000190` + +#### Scenario: State in lowercase normalised to uppercase +- **WHEN** `get_state_tax_info("sp", "12345678000190")` is called +- **THEN** the SDK SHALL normalise the state to `SP` and issue `GET /v2/legalentities/stateTaxInfo/SP/12345678000190` + +#### Scenario: Invalid state code rejected before HTTP +- **WHEN** `get_state_tax_info("XX", "12345678000190")` is called with a code outside the 29-value set +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Optional query parameters forwarded +- **WHEN** `get_basic_info("12345678000190", update_address: false, update_city_code: true)` is called +- **THEN** the SDK SHALL send `updateAddress=false` and `updateCityCode=true` as query parameters, and SHALL omit any option left at its default `nil` + +#### Scenario: Suggested state tax uses the dedicated path +- **WHEN** `get_suggested_state_tax_for_invoice("SP", "12345678000190")` is called +- **THEN** the SDK SHALL issue `GET /v2/legalentities/stateTaxSuggestedForInvoice/SP/12345678000190` + +### Requirement: Natural person (CPF) lookup with date normalisation +`Nfe::Resources::NaturalPersonLookup` SHALL expose `get_status(federal_tax_number, birth_date)` returning a `NaturalPersonStatusResponse`. The CPF SHALL be normalised via `Nfe::IdValidator.cpf` (11 digits). The `birth_date` SHALL accept either an ISO `String` (`YYYY-MM-DD`) or a `Date`/`Time`/`DateTime` object, normalised to `YYYY-MM-DD` via `Nfe::DateNormalizer.to_iso_date`. The request SHALL be `GET /v1/naturalperson/status/{cpf}/{birth_date}`. + +#### Scenario: String birth date +- **WHEN** `get_status("12345678901", "1990-01-15")` is called +- **THEN** the SDK SHALL issue `GET /v1/naturalperson/status/12345678901/1990-01-15` + +#### Scenario: Date object birth date and formatted CPF +- **WHEN** `get_status("123.456.789-01", Date.new(1990, 1, 15))` is called +- **THEN** the SDK SHALL normalise the CPF to `12345678901`, format the date as `1990-01-15`, and issue the same request as the string-date case + +#### Scenario: Invalid birth date format rejected +- **WHEN** `get_status("12345678901", "15/01/1990")` is called (non-ISO format) +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Out-of-range birth date rejected +- **WHEN** `get_status("12345678901", "2026-13-45")` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` (month 13 / day 45 fail the roundtrip) + +### Requirement: Product invoice query by access key with downloads +`Nfe::Resources::ProductInvoiceQuery` SHALL expose `retrieve(access_key)`, `download_pdf(access_key)`, `download_xml(access_key)`, and `list_events(access_key)`, all keyed by a 44-digit access key normalised via `Nfe::IdValidator.access_key` and routed to `https://nfe.api.nfe.io` under API version `v2`. No company scope is required (read-only SEFAZ query). Download methods SHALL return raw bytes as a binary `String`. + +#### Scenario: Retrieve by access key +- **WHEN** `retrieve("35261234...44 digits...")` is called with a valid access key +- **THEN** the SDK SHALL issue `GET https://nfe.api.nfe.io/v2/productinvoices/{access_key}` and return a `ProductInvoiceDetails` value object hydrated from the response + +#### Scenario: Download PDF returns binary bytes +- **WHEN** `download_pdf(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v2/productinvoices/{access_key}.pdf` with `Accept: application/pdf` and return a binary `String` whose first four bytes are `%PDF` + +#### Scenario: Download XML returns binary bytes +- **WHEN** `download_xml(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v2/productinvoices/{access_key}.xml` with `Accept: application/xml` and return a binary `String` whose first non-BOM character is `<` + +#### Scenario: List events uses the events path +- **WHEN** `list_events(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v2/productinvoices/events/{access_key}` and return a `ProductInvoiceEventsResponse` + +#### Scenario: Access key with formatting normalised +- **WHEN** an access key is passed with spaces or dots +- **THEN** the SDK SHALL strip non-digit characters and validate the result has exactly 44 digits, raising `Nfe::InvalidRequestError` otherwise + +### Requirement: Consumer invoice query by access key +`Nfe::Resources::ConsumerInvoiceQuery` SHALL expose `retrieve(access_key)` returning a `TaxCoupon` and `download_xml(access_key)` returning a binary `String`, routed to `https://nfe.api.nfe.io` under API version `v1` with the `/coupon/` path segment. This resource is the **read-only NFC-e/CFe-SAT lookup by access key** and is distinct from the `consumer_invoices` emission resource defined in `add-invoice-resources` (which is company-scoped and routes to `https://api.nfse.io`). + +#### Scenario: Tax coupon retrieval +- **WHEN** `retrieve(access_key)` is called with a valid 44-digit access key +- **THEN** the SDK SHALL issue `GET https://nfe.api.nfe.io/v1/consumerinvoices/coupon/{access_key}` and return a `TaxCoupon` value object whose shape matches the Node SDK's canonical `TaxCoupon` (optional fields including `current_status`, `number`, `access_key`, `issued_on`, `issuer`, `buyer`, `totals`, `items`, `payment`) + +#### Scenario: Tax coupon XML download +- **WHEN** `download_xml(access_key)` is called +- **THEN** the SDK SHALL issue `GET /v1/consumerinvoices/coupon/{access_key}.xml` with `Accept: application/xml` and return the raw XML bytes as a binary `String` + +#### Scenario: Distinct from consumer invoice emission +- **WHEN** a consumer needs to emit an NFC-e rather than query one +- **THEN** they SHALL use `client.consumer_invoices` (from `add-invoice-resources`, host `https://api.nfse.io`), NOT `client.consumer_invoice_query` (host `https://nfe.api.nfe.io`) + +### Requirement: Tax calculation with opaque request payload +`Nfe::Resources::TaxCalculation` SHALL expose `calculate(tenant_id, request)` returning a `CalculateResponse`. It SHALL `POST` to `/tax-rules/{tenant_id}/engine/calculate` (with `tenant_id` URL-encoded) on host `https://api.nfse.io`, forwarding `request` (a `Hash`) as the JSON body. The SDK SHALL validate only that `tenant_id` is non-empty, that `request` carries an `operation_type` (or `operationType`) field, and that `request[:items]` is a non-empty array; it SHALL NOT otherwise validate the request shape. + +#### Scenario: Minimal calculation request +- **WHEN** `calculate("tenant-123", { operation_type: "Outgoing", issuer: {...}, recipient: {...}, items: [{ id: "1", ... }] })` is called +- **THEN** the SDK SHALL POST the body as JSON to `/tax-rules/tenant-123/engine/calculate` and hydrate the response into a `CalculateResponse` + +#### Scenario: Empty items array rejected +- **WHEN** `calculate("tenant", { operation_type: "Outgoing", items: [] })` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +#### Scenario: Empty tenant id rejected +- **WHEN** `calculate("", request)` is called +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +### Requirement: Tax codes listing with page-style pagination +`Nfe::Resources::TaxCodes` SHALL expose four parallel listing methods — `list_operation_codes`, `list_acquisition_purposes`, `list_issuer_tax_profiles`, and `list_recipient_tax_profiles` — each accepting `page_index:` (1-based) and `page_count:` keyword arguments, distinct from the cursor-style pagination used by `StateTaxes`. Each SHALL return a `TaxCodePaginatedResponse` carrying `current_page`, `total_pages`, `total_count`, and `items`. The paths SHALL be `/tax-codes/operation-code`, `/tax-codes/acquisition-purpose`, `/tax-codes/issuer-tax-profile`, and `/tax-codes/recipient-tax-profile` respectively, on host `https://api.nfse.io`. + +#### Scenario: Default pagination defers to the API +- **WHEN** `list_operation_codes` is called with no arguments +- **THEN** the request SHALL omit `pageIndex` and `pageCount`, deferring to the API defaults + +#### Scenario: Explicit 1-based pagination preserved +- **WHEN** `list_operation_codes(page_index: 2, page_count: 20)` is called +- **THEN** the request SHALL include `pageIndex=2` and `pageCount=20` (1-based preserved as the API expects) + +#### Scenario: Each method targets its own path +- **WHEN** `list_acquisition_purposes`, `list_issuer_tax_profiles`, or `list_recipient_tax_profiles` is called +- **THEN** the SDK SHALL issue the request to `/tax-codes/acquisition-purpose`, `/tax-codes/issuer-tax-profile`, or `/tax-codes/recipient-tax-profile` respectively + +### Requirement: State taxes full CRUD with body envelope +`Nfe::Resources::StateTaxes` SHALL expose `list`, `create`, `retrieve`, `update`, and `delete` for company state tax registrations (Inscrições Estaduais), routed to `https://api.nfse.io` under API version `v2`. `list` SHALL use cursor-style pagination (`starting_after:`, `ending_before:`, `limit:`). Both `create` and `update` SHALL wrap the request body as `{ stateTax: }` to match the canonical Node SDK envelope. `company_id` and `state_tax_id` SHALL be validated via `Nfe::IdValidator`. + +#### Scenario: Creating a state tax registration wraps the body +- **WHEN** `create(company_id, { tax_number: "123456789", serie: 1, number: 1, code: "SP" })` is called +- **THEN** the SDK SHALL `POST` to `https://api.nfse.io/v2/companies/{company_id}/statetaxes` with the body `{"stateTax": {"tax_number": "123456789", "serie": 1, ...}}` and return the created `NfeStateTax` + +#### Scenario: Updating wraps the body the same way +- **WHEN** `update(company_id, state_tax_id, { serie: 2 })` is called +- **THEN** the SDK SHALL `PUT` to `/v2/companies/{company_id}/statetaxes/{state_tax_id}` with body `{"stateTax": {"serie": 2}}` + +#### Scenario: Listing with cursor pagination +- **WHEN** `list(company_id, limit: 20)` is called +- **THEN** the SDK SHALL issue the `GET` and return an `Nfe::ListResponse` whose `page` carries the cursor metadata (`starting_after`/`ending_before`) and not `page_index` + +#### Scenario: Deletion returns nil +- **WHEN** `delete(company_id, state_tax_id)` succeeds against HTTP 200 or 204 +- **THEN** the method SHALL return `nil` without raising + +#### Scenario: Empty company id rejected before HTTP +- **WHEN** any `StateTaxes` method receives an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` synchronously without issuing an HTTP request + +### Requirement: DateNormalizer helper +The SDK SHALL provide `Nfe::DateNormalizer` with a `to_iso_date(input)` method returning a `YYYY-MM-DD` `String`. It SHALL accept ISO date strings and `Date`/`Time`/`DateTime` objects, dropping any time component, and SHALL raise `Nfe::InvalidRequestError` for malformed or out-of-range inputs and for unsupported types. It SHALL depend only on the Ruby standard library (`date`, `time`). + +#### Scenario: ISO string passthrough +- **WHEN** `Nfe::DateNormalizer.to_iso_date("1990-01-15")` is called +- **THEN** the method SHALL return `"1990-01-15"` + +#### Scenario: Date/Time object conversion drops the time +- **WHEN** `Nfe::DateNormalizer.to_iso_date(Time.new(1990, 1, 15, 12, 34, 56))` is called +- **THEN** the method SHALL return `"1990-01-15"` + +#### Scenario: Invalid format rejected +- **WHEN** `Nfe::DateNormalizer.to_iso_date("15/01/1990")` is called +- **THEN** the method SHALL raise `Nfe::InvalidRequestError` + +#### Scenario: Out-of-range string rejected +- **WHEN** `Nfe::DateNormalizer.to_iso_date("2026-13-45")` is called +- **THEN** the method SHALL raise `Nfe::InvalidRequestError` + +### Requirement: ID validators cover the lookup surface +`Nfe::IdValidator` SHALL expose `cep(value)`, `state(value)`, `cnpj(value)`, and `cpf(value)` validators in addition to the `company_id`, `state_tax_id`, and `access_key` validators provided by `add-client-core`. Each SHALL strip non-digit characters where appropriate, validate length (or membership for `state`), and return the normalised value, raising `Nfe::InvalidRequestError` (with a Portuguese-language message) on failure. + +#### Scenario: CEP normalisation +- **WHEN** `Nfe::IdValidator.cep("01310-100")` is called +- **THEN** the method SHALL return `"01310100"` (8 digits) + +#### Scenario: State validation rejects unknown codes +- **WHEN** `Nfe::IdValidator.state("ZZ")` is called with a code outside the 29-value set (27 UFs plus `EX` and `NA`) +- **THEN** the method SHALL raise `Nfe::InvalidRequestError` + +#### Scenario: Special state codes EX and NA accepted +- **WHEN** `Nfe::IdValidator.state("ex")` or `Nfe::IdValidator.state("na")` is called +- **THEN** the method SHALL return the uppercase code (`"EX"` / `"NA"`) without raising + +#### Scenario: CNPJ normalisation +- **WHEN** `Nfe::IdValidator.cnpj("12.345.678/0001-90")` is called +- **THEN** the method SHALL return `"12345678000190"` (14 digits) + +#### Scenario: CPF normalisation +- **WHEN** `Nfe::IdValidator.cpf("123.456.789-01")` is called +- **THEN** the method SHALL return `"12345678901"` (11 digits) + +### Requirement: Lookup responses are immutable value objects +Every response returned by a lookup resource (`AddressLookupResponse`, `LegalEntityBasicInfoResponse`, `LegalEntityStateTaxResponse`, `LegalEntityStateTaxForInvoiceResponse`, `NaturalPersonStatusResponse`, `ProductInvoiceDetails`, `ProductInvoiceEventsResponse`, `TaxCoupon`, `CalculateResponse`, `TaxCodePaginatedResponse`, `NfeStateTax`) SHALL be an immutable `Data.define` value object, hydrated from the response body. Where the OpenAPI generator covers the schema, the resource SHALL hydrate against the generated value object under `lib/nfe/generated/`; otherwise the SDK SHALL provide a hand-written value object under `lib/nfe/resources/dto//`. Generated files SHALL NOT be hand-edited. + +#### Scenario: Hydrating a retrieve response +- **WHEN** `Nfe::Resources::ProductInvoiceQuery#retrieve` succeeds against the API +- **THEN** the return value SHALL be an immutable `Data.define` value object (generated or hand-written) whose attributes are populated from the response body + +#### Scenario: Immutability of returned value objects +- **WHEN** consumer code attempts to mutate a returned value object's attribute +- **THEN** the attempt SHALL fail, because the value object is a frozen `Data.define` instance + diff --git a/openspec/specs/openapi-pipeline/spec.md b/openspec/specs/openapi-pipeline/spec.md new file mode 100644 index 0000000..b9b5f6b --- /dev/null +++ b/openspec/specs/openapi-pipeline/spec.md @@ -0,0 +1,217 @@ +# openapi-pipeline Specification + +## Purpose +TBD - created by archiving change add-openapi-pipeline. Update Purpose after archive. +## Requirements +### Requirement: A Ruby code generator reads OpenAPI specs and emits typed value objects +The SDK SHALL provide `scripts/generate.rb`, a Ruby script runnable as `ruby scripts/generate.rb` (no Node, Java, or external generator), that discovers every `*.yaml`/`*.json` spec under `openapi/`, loads each, compiles its `components.schemas`, and emits Ruby code under `lib/nfe/generated/` and matching RBS signatures under `sig/nfe/generated/`. + +The generator SHALL emit **types only** — value objects and enums — and SHALL NOT emit clients, resources, factories, HTTP code, polling, or pagination. Those are hand-written by the resource changes (depende de `add-ruby-foundation`; consumed by `add-invoice-resources`). + +#### Scenario: Running the generator +- **WHEN** a developer runs `ruby scripts/generate.rb` (or `rake generate`) against the `openapi/` directory +- **THEN** the generator SHALL write one `.rb` file per `object`/`enum` schema under `lib/nfe/generated//` and one matching `.rbs` file under `sig/nfe/generated//`, and SHALL print the count of files written + +#### Scenario: Types only, no service surface +- **WHEN** the generator finishes +- **THEN** no client, resource, factory, HTTP, polling, or pagination code SHALL appear under `lib/nfe/generated/` — only `Data.define` value objects, enum constant modules, and the generated marker + +### Requirement: Generation has zero runtime dependencies +The generated code under `lib/nfe/generated/` SHALL be pure Ruby standard library (`Data.define`, frozen constants) with no `require` of any external gem. All generation-time dependencies SHALL be confined to a dev-only `:codegen` Gemfile group and SHALL NOT appear as `add_dependency` in `nfe-io.gemspec`. + +#### Scenario: Published gem carries no codegen dependency +- **WHEN** the gem is installed for runtime use (e.g., `bundle install --without codegen`) +- **THEN** the generated value objects SHALL load and function with only the Ruby standard library, and no codegen dependency SHALL be present + +#### Scenario: YAML parsing uses the standard library +- **WHEN** the generator parses a spec file +- **THEN** it SHALL use `psych` from the Ruby standard library (Ruby 3.2+) as the primary YAML parser, avoiding an external YAML gem + +### Requirement: Generated value objects are immutable Data.define classes +Each OpenAPI `object` schema SHALL be emitted as an immutable `Data.define` value object in the namespace `Nfe::Generated::`, with one attribute per schema property and snake_case attribute names. Generated models SHALL be anemic — attributes only, no business logic. + +#### Scenario: Object schema becomes a Data.define +- **WHEN** the generator processes an `object` schema named `Borrower` with properties `name` and `federalTaxNumber` +- **THEN** it SHALL emit `Nfe::Generated::::Borrower = Data.define(:name, :federal_tax_number, ...)` whose instances are frozen, with the original property name preserved in a comment + +#### Scenario: camelCase property maps to snake_case attribute +- **WHEN** a property is named `federalTaxNumber` in the spec +- **THEN** the generated `Data.define` attribute SHALL be `:federal_tax_number` and the original `federalTaxNumber` SHALL be recorded in a comment for hydration traceability + +### Requirement: Enum schemas become frozen constant modules +Each schema declaring `enum: [...]` SHALL be emitted as a Ruby `module` of frozen constants plus an `ALL` array, rather than loose symbols or an external enum gem. The generator SHALL support both String-backed and Integer-backed enums. + +#### Scenario: String enum +- **WHEN** the generator processes a schema with `enum: ["Issued", "Cancelled"]` +- **THEN** it SHALL emit a module exposing `Issued = "Issued"`, `Cancelled = "Cancelled"`, and `ALL = [Issued, Cancelled].freeze` + +#### Scenario: Non-enum schema returns no enum +- **WHEN** the enum compiler is given an `object` schema with no `enum` key +- **THEN** it SHALL return `nil` (the schema is compiled as a `Data.define` instead) + +### Requirement: Generator emits matching RBS signatures alongside Ruby code +For every generated `.rb` value object or enum module, the generator SHALL emit a matching `.rbs` signature under `sig/nfe/generated//` in the same pass, derived from the same internal model, so the hand-written surface can type-check against generated types with Steep (per `add-ruby-foundation`). + +#### Scenario: RBS mirrors the value object +- **WHEN** the generator emits `Nfe::Generated::NfServicoV1::Borrower = Data.define(...)` +- **THEN** it SHALL also emit `sig/nfe/generated/nf_servico_v1/borrower.rbs` declaring the class, its typed attributes, and the constructor signature + +#### Scenario: No drift between code and signature +- **WHEN** a property's type or nullability changes in the spec and the generator is re-run +- **THEN** both the `.rb` attribute and the `.rbs` type SHALL update together (single internal model), with no manual `.rbs` edit required + +### Requirement: Each generated DTO carries a from_api hydration class method +The generator SHALL emit a `from_api(payload)` class method on every generated `Data.define` value object. `from_api` SHALL map camelCase JSON keys from the API payload to the value object's snake_case members, SHALL drop unknown keys (keys with no matching member), and SHALL recurse into nested object and array attributes — hydrating each referenced (`$ref`) object into its own DTO via that DTO's `from_api`, and each element of a `$ref` array into the item DTO. Primitive and free-form (`Hash`) attributes SHALL be assigned as-is. `from_api` SHALL be the only generated method on the otherwise anemic value object (no business logic). The generator SHALL emit a matching `.rbs` signature for `from_api`. + +The `from_api` call site lives in the hand-written resource/client layer (`klass.from_api(payload)`), but the producer of the method and its `.rbs` is this pipeline. + +#### Scenario: camelCase payload keys map to snake_case members +- **WHEN** `from_api({"federalTaxNumber" => 123, "name" => "Acme"})` is called on a DTO with members `:federal_tax_number` and `:name` +- **THEN** it SHALL return an instance with `federal_tax_number == 123` and `name == "Acme"` + +#### Scenario: Unknown payload fields are dropped +- **WHEN** the payload contains a key with no matching value-object member (e.g., a field the spec did not declare) +- **THEN** `from_api` SHALL ignore that key and construct the instance without raising, so payloads with extra/forward-compatible fields hydrate cleanly + +#### Scenario: Nested object attribute is hydrated into its DTO +- **WHEN** a DTO has an attribute typed as a `$ref` to another generated DTO and the payload supplies a nested object for it +- **THEN** `from_api` SHALL recurse, calling the referenced DTO's `from_api` on the nested object, so the attribute holds a hydrated DTO instance rather than a raw `Hash` + +#### Scenario: Nested array of refs is hydrated element-by-element +- **WHEN** a DTO has an attribute typed as an array of a `$ref` item type and the payload supplies an array of objects +- **THEN** `from_api` SHALL map each element through the item DTO's `from_api`, yielding an `Array` of hydrated DTO instances + +#### Scenario: from_api signature is emitted in RBS +- **WHEN** the generator emits a value object with `from_api` +- **THEN** the matching `.rbs` SHALL declare a `def self.from_api: (Hash[String, untyped] payload) -> instance` signature so the hand-written layer type-checks the hydration call + +### Requirement: Type mapping translates OpenAPI types to idiomatic Ruby and RBS +The generator SHALL map OpenAPI schema fragments to Ruby attributes and RBS types as follows: `string`→`String`, `integer`→`Integer`, `number`→`Float`, `boolean`→`bool`, free-form `object`→`Hash[String, untyped]`, `array` with `items`→`Array[ItemType]`, local `$ref`→the referenced class name in the same family, `format: date-time`/`date`→`String`. When a schema is ambiguous, the generator SHALL fall back to `untyped` rather than fail. + +#### Scenario: Primitive and array mapping +- **WHEN** a property has `type: array` with `items: {type: string}` +- **THEN** the RBS type SHALL be `Array[String]` + +#### Scenario: Local ref resolution +- **WHEN** a property is `{$ref: "#/components/schemas/Address"}` +- **THEN** the type SHALL resolve to `Address` within the same family namespace + +#### Scenario: date-time stays a string +- **WHEN** a property has `format: date-time` +- **THEN** the generated type SHALL be `String` (conversion to `Time` is left to the resource layer) + +#### Scenario: Cross-file ref is unsupported +- **WHEN** a `$ref` points outside the current spec document +- **THEN** the generator SHALL emit `untyped` with a comment and a warning, never raising + +### Requirement: Nullable and optional properties produce nullable RBS types and nil defaults +A property marked `nullable: true`, or any property absent from the schema's `required` list, SHALL be emitted with an RBS type suffixed `?` and SHALL accept `nil`. Properties listed in `required: [...]` SHALL be typed as non-nullable in RBS. + +#### Scenario: Optional property +- **WHEN** a property `email` is not in `required` (or is `nullable: true`) +- **THEN** its RBS type SHALL be `String?` and the value object SHALL accept `nil` for it + +#### Scenario: Required property +- **WHEN** a property `name` is listed in `required` +- **THEN** its RBS type SHALL be non-nullable (`String`) + +### Requirement: oneOf and allOf are mapped conservatively +`oneOf` between primitive types SHALL be emitted as an RBS union (e.g., `Integer | String`). `oneOf`/`anyOf` between object types, lacking a reliable discriminator, SHALL be emitted as `untyped` with an explanatory comment. `allOf` SHALL be a shallow merge of the member schemas' properties. + +#### Scenario: oneOf of primitives +- **WHEN** a property has `oneOf: [{type: integer}, {type: string}]` +- **THEN** the RBS type SHALL be `Integer | String` + +#### Scenario: oneOf of objects +- **WHEN** a property has `oneOf` between two object schemas +- **THEN** the type SHALL be `untyped` with a comment such as `# oneOf: A | B`, and the generator SHALL NOT raise + +#### Scenario: allOf composition +- **WHEN** a schema uses `allOf` to compose two object members +- **THEN** the generated value object SHALL include the union of both members' properties (last writer wins on collision, with a warning) + +### Requirement: Every generated file carries a frozen-string header and AUTO-GENERATED banner +Every generated `.rb` file SHALL begin with `# frozen_string_literal: true` on the first line, followed by a banner `# AUTO-GENERATED — do not edit`, the source spec path, and a `sha256` hash of the source spec. Every generated `.rbs` file SHALL carry an equivalent comment banner. + +#### Scenario: Ruby header +- **WHEN** any `.rb` file is generated +- **THEN** its first line SHALL be `# frozen_string_literal: true` and the following comment lines SHALL include `# AUTO-GENERATED — do not edit`, `# Source: openapi/.yaml`, and `# Hash: sha256:` + +#### Scenario: RBS header +- **WHEN** any `.rbs` file is generated +- **THEN** it SHALL carry an equivalent `# AUTO-GENERATED — do not edit` comment banner with source and hash + +### Requirement: Namespaces are named after spec families deterministically +The generator SHALL derive the Ruby module name from the spec filename by converting kebab-case to PascalCase and preserving the version suffix (`v1`→`V1`), and the directory/file path by converting to snake_case. Portuguese spec names SHALL NOT be translated. + +#### Scenario: Namespace derivation +- **WHEN** the spec file is `service-invoice-rtc-v1.yaml` +- **THEN** the module SHALL be `Nfe::Generated::ServiceInvoiceRtcV1` and the directory SHALL be `lib/nfe/generated/service_invoice_rtc_v1/` + +#### Scenario: Version suffix is preserved +- **WHEN** both `consulta-cnpj.yaml` and `consulta-cnpj-v3.yaml` are present +- **THEN** they SHALL produce distinct namespaces `ConsultaCnpj` and `ConsultaCnpjV3` so multi-version families coexist without collision + +### Requirement: Generator output is deterministic +Running the generator twice over the same specs SHALL produce byte-identical output. Schemas and properties SHALL be ordered stably (by name), and no variable timestamp SHALL appear inside any file content that the sync guard compares. + +#### Scenario: Idempotent generation +- **WHEN** the generator is run twice in a row against unchanged specs +- **THEN** the second run SHALL produce files byte-identical to the first + +#### Scenario: Marker timestamp isolated from the diff +- **WHEN** `lib/nfe/generated/generated_marker.rb` records a `generated_at` timestamp +- **THEN** that timestamp SHALL be excluded or normalised in the sync-guard comparison so it never causes false drift + +### Requirement: A sync guard fails CI when generated output drifts from specs +The SDK SHALL provide `rake generate:check` (wrapping `ruby scripts/generate.rb --check`) that regenerates output in memory, diffs it against the committed files in both `lib/nfe/generated/` and `sig/nfe/generated/`, and exits non-zero if any file would be added, removed, or changed. A CI job `openapi-sync` SHALL run this check. + +#### Scenario: In sync +- **WHEN** `rake generate:check` runs and the committed generated files match the specs +- **THEN** it SHALL print an in-sync message and exit zero + +#### Scenario: Spec changed without regenerating +- **WHEN** an `openapi/*.yaml` spec is modified but `lib/nfe/generated/` (or `sig/nfe/generated/`) is not regenerated, and `rake generate:check` runs in CI +- **THEN** the check SHALL list the added/removed/changed files and exit non-zero, failing the PR + +#### Scenario: Both output trees are covered +- **WHEN** only an `.rbs` signature drifts from the spec while the `.rb` is in sync +- **THEN** the check SHALL still detect the drift and exit non-zero + +### Requirement: Specs are validated before code is emitted +The spec loader SHALL parse each spec, verify it is a YAML/JSON document declaring an OpenAPI/Swagger version, and treat `components.schemas` as a map. A broken spec SHALL raise loudly during generation rather than silently emitting corrupt code. A spec without `components.schemas` SHALL produce no namespace. + +#### Scenario: Broken spec fails fast +- **WHEN** a spec file is not parseable as a YAML/JSON document +- **THEN** the generator SHALL raise with a message naming the offending file, and SHALL NOT write partial output + +#### Scenario: Spec without schemas produces nothing +- **WHEN** a spec has no `components.schemas` (e.g., `nf-servico-v1.yaml` deriving its type from `operations[...]`, or `cpf-api.yaml`) +- **THEN** the generator SHALL skip it without error, and the missing DTOs SHALL be hand-written by the resource changes (not under `lib/nfe/generated/`) + +### Requirement: Specs are synced from nfeio-docs via a documented manual mechanism +The SDK SHALL provide `rake openapi:sync` that copies the spec set from nfeio-docs (`docs/static/api/*.{yaml,json}`, path configurable) into `openapi/`, normalising JSON to YAML where applicable, without committing or regenerating. `CONTRIBUTING.md` SHALL document the full flow: sync → review diff → `rake generate` → review generated output → commit specs and generated files together. nfeio-docs SHALL be documented as the source of truth. + +#### Scenario: Syncing specs +- **WHEN** `rake openapi:sync` runs with nfeio-docs available +- **THEN** it SHALL update `openapi/*.yaml` from the docs source and report the file diff, without committing or triggering generation + +#### Scenario: Documented sync workflow +- **WHEN** a contributor needs to refresh the API contract +- **THEN** `CONTRIBUTING.md` SHALL instruct them to run `rake openapi:sync`, review the diff, run `rake generate`, review `lib/nfe/generated/` and `sig/nfe/generated/`, and commit all three together + +### Requirement: Generated directories are excluded from strict lint and type checks +The generated trees `lib/nfe/generated/**` and `sig/nfe/generated/**` SHALL be excluded from strict RuboCop and Steep targets (generated code tolerates broad shapes), while the generated RBS signatures SHALL still be loaded so the hand-written surface type-checks against them. Generated paths SHALL be marked `linguist-generated=true` in `.gitattributes`. + +#### Scenario: RuboCop skips generated code +- **WHEN** RuboCop runs across the repository +- **THEN** files under `lib/nfe/generated/` SHALL be excluded from offenses while the hand-written surface remains strictly linted + +#### Scenario: Generated RBS still informs Steep +- **WHEN** Steep type-checks the hand-written resource layer that consumes a generated value object +- **THEN** the signatures under `sig/nfe/generated/` SHALL be loaded so the generated types are known, even though `lib/nfe/generated/` itself is not strictly checked + +#### Scenario: Generated diffs hidden on GitHub +- **WHEN** a PR regenerates `lib/nfe/generated/**` or `sig/nfe/generated/**` +- **THEN** `.gitattributes` SHALL mark those paths `linguist-generated=true` so the diffs are collapsed by default + diff --git a/openspec/specs/release-tooling/spec.md b/openspec/specs/release-tooling/spec.md new file mode 100644 index 0000000..49f5baf --- /dev/null +++ b/openspec/specs/release-tooling/spec.md @@ -0,0 +1,281 @@ +# release-tooling Specification + +## Purpose +TBD - created by archiving change add-release-tooling. Update Purpose after archive. +## Requirements +### Requirement: Modern gemspec with zero runtime dependencies +The `nfe-io.gemspec` SHALL declare the gem name `nfe-io`, `required_ruby_version >= 3.2`, and SHALL NOT contain any runtime dependency (no `add_dependency`). It SHALL register only development dependencies (rspec, rubocop, steep, rbs, simplecov, rake). It SHALL set complete metadata including `homepage_uri`, `source_code_uri`, `changelog_uri`, `bug_tracker_uri`, `documentation_uri`, and `rubygems_mfa_required => "true"`. The packaged gem SHALL include the RBS signatures under `sig/`. + +This requirement implements the release of the SDK built by `add-ruby-foundation`, `add-http-transport`, `add-openapi-pipeline`, `add-client-core`, `add-entity-resources`, `add-invoice-resources`, `add-rtc-invoice-emission`, and `add-lookup-resources`. + +#### Scenario: Building the gem +- **WHEN** a maintainer runs `gem build nfe-io.gemspec` +- **THEN** the build SHALL produce `nfe-io-.gem` without warnings, and `gem spec nfe-io-.gem` SHALL report zero runtime dependencies + +#### Scenario: Adding a runtime dependency +- **WHEN** a contributor proposes adding any non-stdlib package to the gem's runtime dependencies +- **THEN** the proposal SHALL require an explicit decision in a new OpenSpec change, because the SDK is committed to Ruby standard library only + +#### Scenario: Installing on Ruby below 3.2 +- **WHEN** a user runs `gem install nfe-io` on Ruby 3.1 or earlier +- **THEN** RubyGems SHALL refuse installation with a `required_ruby_version` error + +#### Scenario: RBS shipped with the gem +- **WHEN** the gem is installed +- **THEN** the `sig/` directory containing the RBS signatures SHALL be present in the installed gem so consumers can type-check against it + +### Requirement: Version is a single source of truth +The constant `Nfe::VERSION` in `lib/nfe/version.rb` SHALL be the single source of truth for the gem version. The gemspec SHALL read the version from this constant, and the release tooling SHALL update only this constant when bumping the version. For the v1 release the version SHALL be `1.0.0` (a major bump from the legacy `0.3.2`). + +Git tags SHALL use the hyphenated prerelease form `vX.Y.Z` and `vX.Y.Z-rc.N`, but `Nfe::VERSION` and the published gem SHALL use the dotted prerelease form `X.Y.Z` and `X.Y.Z.rc.N` (RubyGems requires the dot). `scripts/release.sh` SHALL write the dotted form to `lib/nfe/version.rb` and create the hyphenated tag, and the release workflow SHALL assert that the built-gem version equals the dotted version derived from the tag. + +#### Scenario: Gemspec reads the constant +- **WHEN** `gem build nfe-io.gemspec` runs +- **THEN** the produced gem's version SHALL equal the value of `Nfe::VERSION`, with no version literal duplicated elsewhere + +#### Scenario: Frozen string literal header +- **WHEN** `lib/nfe/version.rb` is inspected +- **THEN** its first line SHALL be `# frozen_string_literal: true`, consistent with every `.rb` file in the project + +#### Scenario: Hyphenated tag, dotted gem version +- **WHEN** the release script cuts a release candidate tagged `v1.0.0-rc.1` +- **THEN** it SHALL write `Nfe::VERSION = "1.0.0.rc.1"` (dotted) to `lib/nfe/version.rb` and create the annotated tag `v1.0.0-rc.1` (hyphenated) + +#### Scenario: Workflow asserts version matches tag +- **WHEN** the release workflow runs for a pushed tag `vX.Y.Z-rc.N` +- **THEN** it SHALL derive the dotted version `X.Y.Z.rc.N` from the tag and assert the built-gem version (`Nfe::VERSION`) equals it, aborting the publish on any mismatch + +### Requirement: CHANGELOG following Keep a Changelog +The repository SHALL include `CHANGELOG.md` written in Brazilian Portuguese, following the Keep a Changelog format and Semantic Versioning. It SHALL contain an `[Não lançado]` section at the top and a `[1.0.0]` entry documenting the greenfield rewrite categorized into `Adicionado`, `Alterado`, and `Removido`. + +#### Scenario: Reading the changelog +- **WHEN** a user opens `CHANGELOG.md` +- **THEN** they SHALL find a `[1.0.0]` entry listing the new `Nfe::Client` API, the 17 resources, generated `Data.define` models, RBS signatures, the discriminated 202 contract, and the removal of the `rest-client` dependency and the global `Nfe.api_key` configuration + +#### Scenario: Changelog rotation on release +- **WHEN** the release script cuts version `X.Y.Z` +- **THEN** the `[Não lançado]` section SHALL be rotated into a dated `[X.Y.Z] - YYYY-MM-DD` heading + +### Requirement: Exhaustive migration guide from v0.3.x to v1.0.0 +The repository SHALL include `MIGRATION.md` in Brazilian Portuguese documenting the complete migration from v0.3.x to v1.0.0, including: + +- Gem version constraint change (`~> 0.3` → `~> 1.0`) +- Ruby version change (2.x → 3.2+) +- Configuration change from the global `Nfe.api_key("...")` setter method (and `Nfe.configure { |c| c.url = ... }`) to the instance `Nfe::Client.new(api_key:)`, the per-class `Nfe::ServiceInvoice.company_id("...")` pattern replaced by a per-call `company_id:` argument, plus automatic per-resource multi-host routing, the new `data_api_key:`, and `NFE_API_KEY`/`NFE_DATA_API_KEY` environment-variable fallback (explicit argument wins) +- Class-to-resource mapping for all 17 snake_case accessors +- Per-resource method mapping (old signature → new signature) +- Removal of the `rest-client` dependency and the resulting change from `RestClient::Exception` to the typed `Nfe::ApiConnectionError`/`Nfe::TimeoutError` hierarchy (`TimeoutError < ApiConnectionError`) +- The full typed error hierarchy table (`Nfe::Error` base with `AuthenticationError`, `AuthorizationError`, `InvalidRequestError`, `NotFoundError`, `ConflictError`, `RateLimitError`, `ServerError`, `ApiConnectionError`, `TimeoutError`, `SignatureVerificationError`, `ConfigurationError`, `InvoiceProcessingError`) +- The discriminated 202 `Pending`/`Issued` contract with a manual polling example +- Webhook signature verification migration +- Binary `String` downloads (`ASCII-8BIT`) +- The explicit list of features deferred from v1.0 +- End-to-end examples for vanilla scripts and Rails + +#### Scenario: A v0.3.x user migrating +- **WHEN** a developer using v0.3.x opens `MIGRATION.md` +- **THEN** they SHALL find a full mapping of their existing code to v1, plus at least one end-to-end example matching their integration pattern (vanilla script or Rails) + +#### Scenario: Looking up a deferred feature +- **WHEN** a developer searches the document for `create_and_wait`, `create_batch`, or certificate upload +- **THEN** they SHALL find the deferred-features section explaining the absence and the manual workaround (e.g., polling via `Nfe::FlowStatus.terminal?`) + +#### Scenario: Configuration migration +- **WHEN** a developer reads the configuration section +- **THEN** it SHALL show the v0.3.x global `Nfe.api_key("...")` setter method (and `Nfe.configure { |c| c.url = ... }`) replaced by `Nfe::Client.new(api_key: "...")`, the per-class `Nfe::ServiceInvoice.company_id("...")` replaced by a per-call `company_id:` argument, and SHALL explain that the base URL is no longer set globally but routed per resource + +#### Scenario: Environment-variable fallback +- **WHEN** a developer constructs `Nfe::Client.new` without an explicit `api_key:`/`data_api_key:` +- **THEN** the documentation SHALL show `Configuration` reading `NFE_API_KEY` and `NFE_DATA_API_KEY` from the environment as a fallback, with an explicit constructor argument taking precedence over the environment value + +### Requirement: Expanded README covering quickstart, resources, and patterns +The repository SHALL include an expanded `README.md` in Brazilian Portuguese covering installation, Ruby 3.2+ and zero-dependency requirements, a `Nfe::Client.new(api_key:)` quickstart, a resource map of all 17 accessors with host and key operations, a one-line example per resource, error handling, the 202 polling contract, configuration (timeout, retry, `data_api_key`, and `NFE_API_KEY`/`NFE_DATA_API_KEY` environment-variable fallback), a Sandbox vs Production section, binary downloads, and webhook signature verification. + +#### Scenario: Consumer evaluating the SDK +- **WHEN** a developer opens `README.md` +- **THEN** they SHALL find a copy-pasteable quickstart, a table of all 17 resources mapped to their hosts and operations, and a configuration section documenting `api_key`, `data_api_key`, `environment`, `timeout`, and `retry` + +#### Scenario: Environment-variable configuration +- **WHEN** a developer reads the configuration section +- **THEN** it SHALL document that `Configuration` reads `NFE_API_KEY` and `NFE_DATA_API_KEY` from the environment as a fallback, with an explicit constructor argument winning over the environment value + +#### Scenario: Sandbox vs Production +- **WHEN** a developer reads the Sandbox vs Production section +- **THEN** it SHALL explain that the `Nfe::Client.new` `environment:` symbol selects a credential/key (not a URL, since host routing stays automatic per resource), how to obtain test credentials, and that `product_invoices`/`consumer_invoices` list and emission operations take a SEPARATE string `environment` parameter (`"Production"`/`"Test"`), including a Test-environment emission sample + +#### Scenario: Webhook freshness warning +- **WHEN** a developer reads the README webhook section +- **THEN** it SHALL warn that a valid signature is NOT proof of freshness (NFE.io sends no anti-replay primitive), so handlers MUST be idempotent and deduplicate on the event/invoice id + +#### Scenario: Versioning section +- **WHEN** a developer reads the versioning section +- **THEN** it SHALL state the SemVer policy and the RC/beta cadence, and link to `CHANGELOG.md` and `MIGRATION.md` + +### Requirement: Contributing guide +The repository SHALL include `CONTRIBUTING.md` in Brazilian Portuguese documenting the branch policy (`master` active for v1, `0.x-legacy` frozen), local setup on Ruby 3.2+, the toolchain (`rake spec`, `rubocop`, `steep check`, `rake generate` / `rake generate:check`), the convention that every `.rb` file starts with `# frozen_string_literal: true`, the rule that generated files under `lib/nfe/generated/` are never hand-edited, and the release cadence. + +#### Scenario: Contributor setting up +- **WHEN** a new contributor opens `CONTRIBUTING.md` +- **THEN** they SHALL find the commands to install dependencies, run the tests, lint, type-check, and regenerate code from the OpenAPI specs + +#### Scenario: Editing generated code +- **WHEN** a contributor considers editing a file under `lib/nfe/generated/` +- **THEN** `CONTRIBUTING.md` SHALL instruct them to edit the OpenAPI spec and run `rake generate` instead, and SHALL note that CI fails via `rake generate:check` when the generated tree is out of sync + +### Requirement: Runnable sample programs cover the main use cases +The repository SHALL ship a `samples/` directory containing runnable Ruby scripts covering the primary use cases of the SDK. Each script SHALL be self-contained, loadable via `samples/config.rb`, and documented in `samples/README.md`. A `samples/.env.example` SHALL be provided and `samples/.env` SHALL be git-ignored. + +The minimum set of samples SHALL include: + +- `service_invoice_issue.rb` (NFS-e emission + manual polling) +- `product_invoice_issue.rb` (NF-e emission) +- `consumer_invoice_issue.rb` (NFC-e emission) +- `company_crud.rb` (full CRUD of companies) +- `legal_person_create.rb` and `legal_person_update.rb` +- `webhook_verify.rb` (HMAC-SHA1 validation over raw body bytes) +- `cnpj_lookup.rb` +- `cpf_lookup.rb` +- `cep_lookup.rb` +- `tax_calculation.rb` +- `rtc_service_invoice.rb` (NFS-e RTC emission, depends on `add-rtc-invoice-emission`) + +#### Scenario: Consumer evaluating the SDK +- **WHEN** a developer clones the repository and opens `samples/` +- **THEN** they SHALL find a runnable example for each major API category, plus a `.env.example` and `README.md` explaining setup + +#### Scenario: Running a sample +- **WHEN** a developer configures `samples/.env` with valid sandbox credentials and runs `ruby samples/service_invoice_issue.rb` +- **THEN** the script SHALL execute end-to-end against the NFE.io sandbox and print the outcome (Pending or Issued) + +#### Scenario: Download sample writes binary +- **WHEN** a sample downloads a PDF or XML +- **THEN** it SHALL write the result with `File.binwrite`, reinforcing the binary `String` (`ASCII-8BIT`) download contract + +### Requirement: Single-command release preparation script +The repository SHALL provide `scripts/release.sh` that performs version bump, changelog rotation, commit, annotated tag, and push in a single interactive command, with `--dry-run`, `--skip-tests`, and `--skip-git` flags. The script SHALL NOT publish the gem itself — publication happens in the release workflow after the tag is pushed. + +#### Scenario: Cutting a release on a clean branch +- **WHEN** a maintainer runs `scripts/release.sh` on the `master` branch with a clean working tree and green CI +- **THEN** the script SHALL prompt for a version, update `Nfe::VERSION`, rotate `CHANGELOG.md`, commit, create an annotated tag `vX.Y.Z`, and push the commit and tag to origin + +#### Scenario: Dry-run rehearsal +- **WHEN** the maintainer runs `scripts/release.sh --dry-run` +- **THEN** the script SHALL print every step it would perform without modifying any file or invoking any git command with side effects + +#### Scenario: Dirty working tree refusal +- **WHEN** the working tree has uncommitted changes and the script is invoked without `--skip-git` +- **THEN** the script SHALL refuse to proceed with an explanatory message + +#### Scenario: Existing tag refusal +- **WHEN** the requested version corresponds to an existing git tag +- **THEN** the script SHALL fail early with a clear message before any change is made + +#### Scenario: Invalid version format +- **WHEN** the maintainer types a version that does not match `X.Y.Z` or `X.Y.Z-rc.N` or `X.Y.Z-beta.N` +- **THEN** the script SHALL reject it and prompt again or exit + +#### Scenario: No local gem push +- **WHEN** the release script completes successfully +- **THEN** it SHALL NOT have invoked `gem push`; the gem is published only by the release workflow triggered by the pushed tag + +### Requirement: Release workflow gated on full CI, publishing to RubyGems +The repository SHALL include `.github/workflows/release.yml` triggered by pushes of tags matching `v*`. A `verify` job SHALL run the full CI gate — `rake spec` (with SimpleCov ≥ 80%), `rubocop`, `steep check`, and `rake generate:check` — across the Ruby 3.2/3.3/3.4 matrix. A `publish` job, depending on `verify`, SHALL build the gem and publish it to RubyGems, and SHALL create a GitHub Release. + +#### Scenario: Tag push triggers verification then publish +- **WHEN** a tag `v1.0.0-rc.1` is pushed +- **THEN** GitHub Actions SHALL run the verification matrix, and only upon success SHALL the `publish` job build and push the gem and create the GitHub Release + +#### Scenario: Failed verification aborts publish +- **WHEN** any job in the verification matrix fails for the tag +- **THEN** the gem SHALL NOT be published and no GitHub Release SHALL be created; the tag remains but the publish does not + +#### Scenario: Generated code out of sync blocks release +- **WHEN** `rake generate:check` detects that `lib/nfe/generated/` or `sig/` is out of sync with `openapi/*.yaml` +- **THEN** the `verify` job SHALL fail and the release SHALL be aborted + +### Requirement: RubyGems trusted publishing via OIDC +The `publish` job SHALL publish to RubyGems using trusted publishing via GitHub OIDC, granting the job `id-token: write` permission and obtaining an ephemeral credential, without storing a long-lived API key. When OIDC trusted publishing is not configured, the workflow SHALL fall back to a `GEM_HOST_API_KEY` sourced from the `RUBYGEMS_API_KEY` repository secret. + +#### Scenario: Publishing with OIDC +- **WHEN** the `publish` job runs for a tag and the repository is registered as a trusted publisher on RubyGems +- **THEN** the job SHALL authenticate via OIDC and push the gem without any persistent API key + +#### Scenario: Fallback to API key +- **WHEN** OIDC trusted publishing is not yet configured for the repository +- **THEN** the workflow SHALL use `GEM_HOST_API_KEY` from the `RUBYGEMS_API_KEY` secret to push the gem + +### Requirement: Released gem is checksummed and MFA-protected +The `publish` job SHALL generate a SHA-256 checksum of the built `.gem` and attach both the `.gem` and its `.sha256` file to the GitHub Release. The gem SHALL declare `rubygems_mfa_required => "true"` so that interactive operations on the gem require multi-factor authentication. + +#### Scenario: Checksum attached to release +- **WHEN** a release is published for tag `vX.Y.Z` +- **THEN** the GitHub Release SHALL include `nfe-io-X.Y.Z.gem` and `nfe-io-X.Y.Z.gem.sha256`, enabling independent verification of the artifact + +#### Scenario: MFA required on the gem +- **WHEN** an account attempts a privileged operation on the `nfe-io` gem on RubyGems +- **THEN** RubyGems SHALL require multi-factor authentication because the gem metadata declares `rubygems_mfa_required` + +### Requirement: AI skill for the Ruby SDK +The repository SHALL include `skills/nfeio-ruby-sdk/SKILL.md`, modeled on the Node SDK skill, with YAML front-matter (`name: nfeio-ruby-sdk` and a `description` of trigger conditions) and sections covering: gem/require, quickstart, a resource map of all 17 snake_case accessors, the discriminated 202 contract with manual polling, the typed error hierarchy, page-style vs cursor pagination, binary downloads, webhook signature verification, idiomatic Ruby pitfalls, and a decision tree. It SHALL include segmented `references/*.md` files. + +#### Scenario: Agent invoked on NFE.io Ruby code +- **WHEN** an AI agent encounters code that requires `nfe` or references `Nfe::Client`, or a request about Brazilian fiscal documents in Ruby +- **THEN** the `nfeio-ruby-sdk` skill SHALL provide the resource map, the 202 contract guidance, and the error hierarchy needed to write correct code + +#### Scenario: Reference files present +- **WHEN** the skill directory is inspected +- **THEN** it SHALL contain `references/service-invoices-and-polling.md`, `references/product-invoices-and-taxes.md`, `references/data-services-and-lookups.md`, `references/error-handling-and-patterns.md`, and `references/rtc-emission.md` + +#### Scenario: Idioms adapted to Ruby +- **WHEN** the skill documents an SDK pattern +- **THEN** it SHALL use idiomatic Ruby (synchronous returns instead of Promises, binary `String` instead of Buffer, snake_case accessors, `Data.define` value objects, `is_a?`/`case in` instead of `instanceof`) + +### Requirement: Webhook signature documentation uses the correct scheme +The README, MIGRATION guide, and AI skill SHALL document webhook signature verification as `X-Hub-Signature` with HMAC-SHA1 computed over the raw request body bytes, with a case-insensitive hex comparison, the `sha1=` prefix, and a timing-safe comparison. They SHALL warn that the legacy `X-NFe-Signature` + HMAC-SHA256 scheme found in some distribution docs is incorrect versus production. They SHALL also warn that a valid signature is NOT proof of freshness — NFE.io sends no anti-replay primitive — so handlers MUST be idempotent and deduplicate on the event/invoice id. + +#### Scenario: Documenting signature verification +- **WHEN** a developer reads the webhook section in the README, MIGRATION, or skill +- **THEN** it SHALL instruct reading the raw body (`request.raw_post` in Rails, `request.body.read` in Rack) before JSON parsing, computing `OpenSSL::HMAC.hexdigest("SHA1", secret, raw_body)`, and comparing timing-safely against the `X-Hub-Signature` header value + +#### Scenario: Warning about the wrong scheme +- **WHEN** a developer might otherwise copy the `X-NFe-Signature` + SHA-256 scheme from older distribution docs +- **THEN** the documentation SHALL explicitly flag that scheme as incorrect and direct them to HMAC-SHA1 with `X-Hub-Signature` + +#### Scenario: Signature validity is not freshness +- **WHEN** a developer reads the webhook section in the README, MIGRATION, or skill +- **THEN** it SHALL state that a valid signature does not guarantee freshness (no anti-replay primitive is sent), and SHALL instruct that handlers be idempotent and deduplicate on the event/invoice id + +### Requirement: RC and beta period before any GA release +The first stable `v1.0.0` release SHALL be preceded by at least one release candidate (`v1.0.0-rc.1` or later) published to RubyGems as a prerelease, followed by a beta period. During the beta period the `master` README SHALL display a banner indicating the in-development status; at the GA release the banner SHALL be removed, tied to the prerelease-vs-final flow of `scripts/release.sh` (a prerelease keeps the banner, a final release removes it). The README SHALL carry a one-line forward-compatibility note stating that `Pending`/`Issued` and `FlowStatus` are stable public API. Prerelease versions SHALL NOT be resolved as `latest` by RubyGems for consumers using a `~> 1.0` constraint. + +#### Scenario: First v1.0.0 release +- **WHEN** the maintainer prepares to publish v1.0.0 for the first time +- **THEN** the workflow SHALL be: tag `v1.0.0-rc.1` → beta period → if no critical issues, tag `v1.0.0` + +#### Scenario: Banner removed at GA +- **WHEN** the maintainer cuts the final `v1.0.0` (non-prerelease) via `scripts/release.sh` +- **THEN** the in-development banner SHALL be removed from the README, while a prerelease release SHALL leave it in place + +#### Scenario: Critical issue during beta +- **WHEN** a critical issue is reported during the beta period +- **THEN** the maintainer SHALL fix it and tag `v1.0.0-rc.2`, restarting the beta clock + +#### Scenario: Prerelease not auto-installed +- **WHEN** a consumer depends on `gem "nfe-io", "~> 1.0"` while only `v1.0.0-rc.1` is published +- **THEN** Bundler SHALL NOT resolve the prerelease unless the consumer opts in explicitly (e.g., `= 1.0.0.rc.1`) + +#### Scenario: Patch release +- **WHEN** a patch release (`v1.0.1`) addresses a bug without API change +- **THEN** the maintainer MAY release directly without an RC/beta period, since the public surface is unchanged + +### Requirement: Ruby SDK page in nfeio-docs +The existing live Ruby SDK page `docs/desenvolvedores/bibliotecas/ruby.md` in the `nfeio-docs` repository (the source of truth for API behavior) SHALL be updated: the incorrect `X-NFEIO-Signature` + Base64 webhook snippet and the global v0.3 `Nfe.api_key` examples SHALL be removed; a `Nfe::Client.new(api_key:)` quickstart SHALL be added; and the page SHALL mirror the Node SDK docs structure (migration, changelog, examples sections), with links to the README and MIGRATION guide. The SDK README SHALL link back to this documentation page. + +#### Scenario: Docs page updated and linked +- **WHEN** a user browses the NFE.io documentation under "Bibliotecas → Ruby" +- **THEN** they SHALL find an installation and `Nfe::Client.new(api_key:)` quickstart page for the `nfe-io` gem — with the wrong `X-NFEIO-Signature` + Base64 webhook snippet and the global `Nfe.api_key` v0.3 examples removed — linking to the GitHub README and MIGRATION guide + +#### Scenario: README links to docs +- **WHEN** a user reads the README's documentation section +- **THEN** it SHALL link to the Ruby SDK page in the NFE.io documentation + diff --git a/openspec/specs/rtc-invoice-emission/spec.md b/openspec/specs/rtc-invoice-emission/spec.md new file mode 100644 index 0000000..c1f90b5 --- /dev/null +++ b/openspec/specs/rtc-invoice-emission/spec.md @@ -0,0 +1,337 @@ +# rtc-invoice-emission Specification + +## Purpose +TBD - created by archiving change add-rtc-invoice-emission. Update Purpose after archive. +## Requirements +### Requirement: Dedicated RTC service-invoice resource exposed on the Client + +The SDK SHALL expose a dedicated resource `client.service_invoices_rtc` for emitting service invoices (NFS-e) under the Reforma Tributária do Consumo (RTC) layout. The classic `client.service_invoices` resource (from `add-invoice-resources`) SHALL remain unchanged; RTC emission SHALL be opt-in via the new resource. + +The resource SHALL target the `main` API family — host `https://api.nfe.io` (`base_url_for(:main)`), with the `/v1` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfe.io/v1/...` — resolved through `Nfe::Configuration`, reusing the same host client as the classic `service_invoices` resource. No new base URL SHALL be introduced. + +#### Scenario: Accessing the RTC resource from the Client + +- **WHEN** a consumer reads `client.service_invoices_rtc` +- **THEN** the accessor SHALL return a fully functional `Nfe::Resources::ServiceInvoicesRtc` instance (lazily created and memoized), not a stub that raises `NoMethodError` + +#### Scenario: RTC reuses the main host without a new base URL + +- **WHEN** any method of `service_invoices_rtc` issues an HTTP request +- **THEN** the outgoing request SHALL target the host `https://api.nfe.io` (the `main` family, with the `/v1` segment supplied by the resource `api_version`, effective URL `https://api.nfe.io/v1/...`), the same host used by the classic `service_invoices` resource +- **AND** no new base-URL constant SHALL be added to `Nfe::Configuration` + +#### Scenario: Classic service-invoice resource is unaffected + +- **WHEN** the RTC resource is added to the Client +- **THEN** `client.service_invoices` SHALL keep its existing method signatures and behavior unchanged + +### Requirement: RTC service-invoice emission supports the discriminated 202 contract + +`Nfe::Resources::ServiceInvoicesRtc#create` SHALL accept keyword arguments `company_id:` and `data:`, where `data` is an `Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest` value object or a `Hash`. It SHALL issue `POST /companies/{company_id}/serviceinvoices` and SHALL return either a `Nfe::Resources::ServiceInvoiceRtcPending` (when the API responds HTTP 202 with a `Location` header) or a `Nfe::Resources::ServiceInvoiceRtcIssued` (when the API responds HTTP 201 with the materialized invoice body). + +The RTC layout SHALL be selected by the presence of the `ibsCbs` group in the payload — there is no header or query parameter. This is the same endpoint the classic `service_invoices` resource uses. + +`#create` SHALL additionally accept an optional `idempotency_key:` keyword (sent as the `Idempotency-Key` HTTP header for safe retries) and an optional `request_options:` keyword (an `Nfe::RequestOptions` from `add-client-core`, threaded into the request to override `api_key`/`base_url`/`timeout` per call). POST SHALL NOT be auto-retried by the transport. + +#### Scenario: Idempotency key forwarded as a header + +- **WHEN** `create(company_id:, data:, idempotency_key: "service-rtc-42")` is called +- **THEN** the outgoing request SHALL carry the `Idempotency-Key: service-rtc-42` header +- **AND** when `idempotency_key:` is omitted, no `Idempotency-Key` header SHALL be sent + +#### Scenario: Per-call request options override the Client defaults + +- **WHEN** `create(company_id:, data:, request_options: Nfe::RequestOptions.new(api_key: "tenant-key", base_url: nil, timeout: nil))` is called +- **THEN** the request SHALL authenticate with `tenant-key` for that call only, without mutating the shared Client + +#### Scenario: Async emission returns a Pending result + +- **WHEN** `client.service_invoices_rtc.create(company_id:, data:)` is called and the API responds HTTP 202 with `Location: /v1/companies/{company_id}/serviceinvoices/{invoice_id}` +- **THEN** the method SHALL return a `Nfe::Resources::ServiceInvoiceRtcPending` whose `invoice_id` matches the final path segment of the `Location` header (extracted via `%r{serviceinvoices/([a-z0-9-]+)}i`) +- **AND** whose `location` matches the header value + +#### Scenario: Immediate emission returns an Issued result + +- **WHEN** the API responds HTTP 201 with the invoice body +- **THEN** the method SHALL return a `Nfe::Resources::ServiceInvoiceRtcIssued` whose `resource` returns a service-invoice RTC DTO hydrated from the response body + +#### Scenario: 202 without a Location header raises a processing error + +- **WHEN** the API responds HTTP 202 but omits the `Location` header +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` + +#### Scenario: Payload carries the ibsCbs group + +- **WHEN** `create` is called with the spec's minimum payload (`borrower`, `cityServiceCode`, `federalServiceCode`, `description`, `servicesAmount`, `nbsCode`, and an `ibsCbs` group) +- **THEN** the serialized request body SHALL contain the `ibsCbs` group with `operationIndicator` matching `^[0-9]{6}$` and a `classCode` of at most 6 characters +- **AND** both `operationIndicator` and `classCode` SHALL be required within the `ibsCbs` group + +### Requirement: RTC service-invoice retrieve and cancel + +`Nfe::Resources::ServiceInvoicesRtc` SHALL expose `retrieve(company_id:, invoice_id:)` issuing `GET /companies/{company_id}/serviceinvoices/{invoice_id}` and `cancel(company_id:, invoice_id:)` issuing `DELETE /companies/{company_id}/serviceinvoices/{invoice_id}`. + +#### Scenario: Retrieve returns a typed DTO + +- **WHEN** `retrieve(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a service-invoice RTC value object (`Data.define`) hydrated from the response body, exposing at least `flow_status` + +#### Scenario: Retrieve of a missing invoice raises NotFoundError + +- **WHEN** `retrieve(company_id:, invoice_id:)` receives HTTP 404 +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +#### Scenario: Cancel returns the updated invoice synchronously + +- **WHEN** `cancel(company_id:, invoice_id:)` is called +- **THEN** the SDK SHALL issue the `DELETE` request and return the updated service-invoice RTC DTO + +### Requirement: Download the cancellation-event XML (Ambiente Nacional) + +`Nfe::Resources::ServiceInvoicesRtc` SHALL expose `download_cancellation_xml(company_id:, invoice_id:)` issuing `GET /companies/{company_id}/serviceinvoices/{invoice_id}/cancellation-xml` with `Accept: application/xml`. It SHALL return the cancellation-event (`e110001`) XML as a binary-safe `String` (encoding `ASCII-8BIT`). This endpoint is available only for invoices in the Ambiente Nacional (ADN) and only after the invoice reaches the `Cancelled` status. + +#### Scenario: Cancellation XML returns raw bytes + +- **WHEN** `download_cancellation_xml(company_id:, invoice_id:)` succeeds for a cancelled Ambiente Nacional invoice +- **THEN** the return value SHALL be a `String` whose encoding is `ASCII-8BIT` and whose first non-BOM character is `<` + +#### Scenario: Municipal/ABRASF provider has no cancellation event + +- **WHEN** `download_cancellation_xml` is called for an invoice from a municipal/ABRASF provider, or for an invoice not yet cancelled, and the API responds HTTP 404 +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +### Requirement: Fail-fast identifier validation before the HTTP request + +Every `ServiceInvoicesRtc` method that takes a `company_id` or `invoice_id` SHALL validate it through `Nfe::IdValidator` (from `add-client-core`) before issuing any HTTP request, raising `Nfe::InvalidRequestError` synchronously on empty or whitespace-only values. + +#### Scenario: Empty company ID rejected before HTTP + +- **WHEN** any `ServiceInvoicesRtc` method is called with an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` with a Portuguese-language message identifying the invalid argument +- **AND** no HTTP request SHALL be issued + +#### Scenario: Empty invoice ID rejected before HTTP + +- **WHEN** `retrieve`, `cancel`, or `download_cancellation_xml` is called with an empty `invoice_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` without issuing an HTTP request + +### Requirement: Discriminated RTC response classes + +The SDK SHALL provide concrete, immutable response classes for RTC service-invoice creation, implementing the `Pending` and `Issued` protocols defined in `add-client-core`: + +- `Nfe::Resources::ServiceInvoiceRtcPending` implementing `Pending` — exposing `invoice_id`, `location`, and the predicate `pending?` (returning `true`) / `issued?` (returning `false`) +- `Nfe::Resources::ServiceInvoiceRtcIssued` implementing `Issued` — exposing `resource` typed at the service-invoice RTC DTO, and the predicate `issued?` (returning `true`) / `pending?` (returning `false`) + +#### Scenario: Discriminating with is_a? + +- **WHEN** a consumer writes `if result.is_a?(Nfe::Resources::ServiceInvoiceRtcPending) then ... else ... end` +- **THEN** the pending branch SHALL expose `invoice_id`/`location` and the issued branch SHALL expose `resource` +- **AND** the two classes SHALL be distinct from the classic `Nfe::Resources::ServiceInvoicePending`/`Nfe::Resources::ServiceInvoiceIssued` + +#### Scenario: Discriminating with predicate methods + +- **WHEN** a consumer receives the result of `create` and calls `result.pending?` / `result.issued?` +- **THEN** `Nfe::Resources::ServiceInvoiceRtcPending#pending?` SHALL return `true` and `#issued?` SHALL return `false` +- **AND** `Nfe::Resources::ServiceInvoiceRtcIssued#issued?` SHALL return `true` and `#pending?` SHALL return `false` + +### Requirement: RTC DTOs are generated from the named OpenAPI schemas + +The OpenAPI pipeline (from `add-openapi-pipeline`) SHALL sync `service-invoice-rtc-v1.yaml` from `nfeio-docs` and emit immutable `Data.define` value objects under `lib/nfe/generated/service_invoice_rtc_v1/` for the spec's named schemas, including `NFSeRequest` and the nested `ibsCbs` group, plus corresponding `.rbs` signatures under `sig/`. Generated files SHALL NOT be hand-edited. + +#### Scenario: NFSeRequest generated as an immutable value object + +- **WHEN** the pipeline generates types from `service-invoice-rtc-v1.yaml` +- **THEN** `Nfe::Generated::ServiceInvoiceRtcV1::NFSeRequest` SHALL exist as a `Data.define` value object exposing snake_case accessors (e.g., `services_amount`, `nbs_code`, `city_service_code`) +- **AND** it SHALL carry the nested `ibsCbs` group with `operation_indicator`, `class_code`, `situation_code`, `ibs`, and `cbs` + +#### Scenario: Generated files carry the frozen-string-literal magic comment + +- **WHEN** any file under `lib/nfe/generated/service_invoice_rtc_v1/` is generated +- **THEN** it SHALL start with `# frozen_string_literal: true` + +### Requirement: Manual polling via FlowStatus terminal-state helper + +The SDK SHALL support manual polling of RTC emission by reusing `Nfe::FlowStatus.terminal?` from `add-client-core`. The SDK v1 SHALL NOT implement `create_and_wait` or `create_batch` on the RTC resource. + +#### Scenario: Polling until a terminal flow status + +- **WHEN** a consumer receives a `Nfe::Resources::ServiceInvoiceRtcPending` and loops calling `retrieve` until `Nfe::FlowStatus.terminal?(invoice.flow_status)` returns `true` +- **THEN** the loop SHALL terminate when `flow_status` is one of `Issued`, `IssueFailed`, `Cancelled`, or `CancelFailed` + +#### Scenario: create_and_wait is not defined + +- **WHEN** consumer code calls `client.service_invoices_rtc.create_and_wait(...)` +- **THEN** Ruby SHALL raise `NoMethodError`, since the method is not defined in v1 + +### Requirement: Dedicated RTC product-invoice resource exposed on the Client + +The SDK SHALL expose a dedicated resource `client.product_invoices_rtc` for emitting product invoices (NF-e modelo 55 and NFC-e modelo 65) under the Reforma Tributária do Consumo (RTC) layout. The classic `client.product_invoices` resource (from `add-invoice-resources`) SHALL remain unchanged; RTC emission SHALL be opt-in via the new resource. + +The resource SHALL target the `cte` API family (alias `:product_invoices`) — host `https://api.nfse.io` (`base_url_for(:cte)`), with the `/v2` segment supplied by the resource `api_version`, yielding effective URLs under `https://api.nfse.io/v2/...` — resolved through `Nfe::Configuration`, reusing the same host client as the classic `product_invoices` resource. No new base URL SHALL be introduced, and the resource SHALL NOT be routed to the `main` host `https://api.nfe.io`. + +#### Scenario: Accessing the product RTC resource from the Client + +- **WHEN** a consumer reads `client.product_invoices_rtc` +- **THEN** the accessor SHALL return a fully functional `Nfe::Resources::ProductInvoicesRtc` instance (lazily created and memoized), not a stub that raises `NoMethodError` + +#### Scenario: Product RTC reuses the api.nfse.io host without a new base URL + +- **WHEN** any method of `product_invoices_rtc` issues an HTTP request +- **THEN** the outgoing request SHALL target the host `https://api.nfse.io` (the `cte` family, with the `/v2` segment supplied by the resource `api_version`, effective URL `https://api.nfse.io/v2/...`), the same host used by the classic `product_invoices` resource +- **AND** no new base-URL constant SHALL be added to `Nfe::Configuration`, and the request SHALL NOT target `https://api.nfe.io` + +#### Scenario: Classic product-invoice resource is unaffected + +- **WHEN** the product RTC resource is added to the Client +- **THEN** `client.product_invoices` SHALL keep its existing method signatures and behavior unchanged + +### Requirement: RTC product-invoice emission supports the discriminated 202 contract + +`Nfe::Resources::ProductInvoicesRtc#create` SHALL accept keyword arguments `company_id:` and `data:`, where `data` is an `Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest` value object or a `Hash`. It SHALL issue `POST /companies/{company_id}/productinvoices` and SHALL return either a `Nfe::Resources::ProductInvoiceRtcPending` (when the API responds HTTP 202 with a `Location` header) or a `Nfe::Resources::ProductInvoiceRtcIssued` (when the API responds HTTP 201 with the materialized invoice body). + +The RTC layout SHALL be selected by the presence of the item-level `IBSCBS` group in the payload — there SHALL be no header or query parameter. This is the same endpoint the classic `product_invoices` resource uses. Emission SHALL be treated as asynchronous regardless of whether the API returns HTTP 201 or 202. + +Both `#create` and `#create_with_state_tax` SHALL additionally accept an optional `idempotency_key:` keyword (sent as the `Idempotency-Key` HTTP header for safe retries) and an optional `request_options:` keyword (an `Nfe::RequestOptions` from `add-client-core`, threaded into the request to override `api_key`/`base_url`/`timeout` per call). POST SHALL NOT be auto-retried by the transport. + +#### Scenario: Idempotency key forwarded as a header + +- **WHEN** `create(company_id:, data:, idempotency_key: "product-rtc-42")` is called +- **THEN** the outgoing request SHALL carry the `Idempotency-Key: product-rtc-42` header +- **AND** when `idempotency_key:` is omitted, no `Idempotency-Key` header SHALL be sent + +#### Scenario: Per-call request options override the Client defaults + +- **WHEN** `create(company_id:, data:, request_options: Nfe::RequestOptions.new(api_key: "tenant-key", base_url: nil, timeout: nil))` is called +- **THEN** the request SHALL authenticate with `tenant-key` for that call only, without mutating the shared Client + +#### Scenario: Async product emission returns a Pending result + +- **WHEN** `client.product_invoices_rtc.create(company_id:, data:)` is called and the API responds HTTP 202 with `Location: /v2/companies/{company_id}/productinvoices/{invoice_id}` +- **THEN** the method SHALL return a `Nfe::Resources::ProductInvoiceRtcPending` whose `invoice_id` matches the final path segment of the `Location` header (extracted via `%r{productinvoices/([a-z0-9-]+)}i`) +- **AND** whose `location` matches the header value + +#### Scenario: Immediate product emission returns an Issued result + +- **WHEN** the API responds HTTP 201 with the invoice body +- **THEN** the method SHALL return a `Nfe::Resources::ProductInvoiceRtcIssued` whose `resource` returns a `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource` hydrated from the response body + +#### Scenario: 202 without a Location header raises a processing error + +- **WHEN** the API responds HTTP 202 but omits the `Location` header +- **THEN** the SDK SHALL raise `Nfe::InvoiceProcessingError` + +#### Scenario: No discriminator header or parameter is sent + +- **WHEN** `create` is called with a payload carrying the item-level `IBSCBS` group +- **THEN** the serialized request SHALL select the RTC layout solely by payload shape +- **AND** no header or query parameter naming a `model`/`mod` or RTC flag SHALL be added to the request + +### Requirement: Product RTC payload carries item-level IBS/CBS and IS tax groups + +The product RTC payload SHALL carry the new RTC tax groups at the item level, on `InvoiceItemTaxResource` (`items[].tax`), alongside the legacy groups. The `IBSCBS` group (`IBSCBSTaxResource`) SHALL split IBS into a state sphere (`state` → `IBSStateTaxResource`) and a municipal sphere (`municipal` → `IBSMunicipalTaxResource`), with CBS (`cbs` → `CBSTaxResource`) being federal and carrying no state/municipal split. The `IS` group (`ISTaxResource`, Imposto Seletivo) SHALL be a product-only tax group with no equivalent on the NFS-e RTC payload. + +#### Scenario: IBSCBS group present with state, municipal, and federal CBS + +- **WHEN** `create` is called with an item carrying `items[].tax.IBSCBS` +- **THEN** the serialized `IBSCBS` group SHALL contain a `state` sub-group and a `municipal` sub-group for IBS, each exposing `rate` and `amount` +- **AND** it SHALL contain a single federal `cbs` sub-group with no state/municipal split + +#### Scenario: Imposto Seletivo (IS) group present on the item + +- **WHEN** `create` is called with an item carrying `items[].tax.IS` +- **THEN** the serialized `IS` group SHALL expose `situation_code`, `classification_code`, `basis`, `rate`, and `amount` +- **AND** the `IS` group SHALL be specific to the product RTC payload and absent from the NFS-e RTC payload + +### Requirement: NF-e and NFC-e share one resource, distinguished by payload shape + +`Nfe::Resources::ProductInvoicesRtc` SHALL emit both NF-e (modelo 55) and NFC-e (modelo 65) through the single `create` method and the single `POST /companies/{company_id}/productinvoices` endpoint. The two SHALL be distinguished by the shape of the payload — `print_type` (`PrintType`), `consumer_type`/`presence_type`, presence of `buyer`, and presence of `expected_delivery_on` — and SHALL NOT require a discriminator field on the request root nor a separate endpoint. + +#### Scenario: NFC-e emitted via the same endpoint as NF-e + +- **WHEN** `create` is called once with an NF-e payload (`print_type` an `NFe*` value, `buyer` present) and once with an NFC-e payload (`print_type` `DANFE_NFC_E`, `consumer_type`/`presence_type` set, no `buyer`) +- **THEN** both requests SHALL be issued to the same `POST /companies/{company_id}/productinvoices` endpoint on `https://api.nfse.io` +- **AND** neither request SHALL include a `model`/`mod` discriminator on the request root + +### Requirement: Product RTC lifecycle methods + +`Nfe::Resources::ProductInvoicesRtc` SHALL expose, carried over from the classic product surface on the same host and base path, the following methods: `create_with_state_tax(company_id:, state_tax_id:, data:)` issuing `POST /companies/{company_id}/statetaxes/{state_tax_id}/productinvoices`; `retrieve(company_id:, invoice_id:)`; `list(company_id:, environment:, ...)` with cursor pagination; `cancel(company_id:, invoice_id:, reason:)`; `list_items`; `list_events`; the file-resource downloads `download_pdf`, `download_xml`, `download_rejection_xml`, `download_epec_xml` (each returning a `Nfe::NfeFileResource` URI, matching the classic `ProductInvoices` contract and `nf-produto-v2.yaml` `FileResource{uri}`); the correction-letter methods `send_correction_letter`, `download_correction_letter_pdf`, `download_correction_letter_xml`; and the disablement methods `disable`, `disable_range`. + +#### Scenario: Retrieve returns a typed InvoiceResource + +- **WHEN** `retrieve(company_id:, invoice_id:)` succeeds +- **THEN** the return value SHALL be a `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource` value object hydrated from the response body, exposing at least `flow_status` + +#### Scenario: Retrieve of a missing invoice raises NotFoundError + +- **WHEN** `retrieve(company_id:, invoice_id:)` receives HTTP 404 +- **THEN** the SDK SHALL raise `Nfe::NotFoundError` + +#### Scenario: List returns a paginated ListResponse + +- **WHEN** `list(company_id:, environment:)` succeeds +- **THEN** the return value SHALL be a `Nfe::ListResponse` exposing the `product_invoices` page and cursor pagination (`starting_after`/`ending_before`/`limit`) + +#### Scenario: Cancel is asynchronous and returns a cancellation resource + +- **WHEN** `cancel(company_id:, invoice_id:, reason:)` is called +- **THEN** the SDK SHALL issue `DELETE /companies/{company_id}/productinvoices/{invoice_id}?reason=` and return a `RequestCancellationResource` + +#### Scenario: Downloads return a file resource URI + +- **WHEN** `download_pdf`, `download_xml`, `download_rejection_xml`, or `download_epec_xml` succeeds +- **THEN** the return value SHALL be a `Nfe::NfeFileResource` exposing a `uri` (matching the `FileResource{uri}` schema in `nf-produto-v2.yaml`), NOT raw `ASCII-8BIT` bytes +- **AND** this SHALL match the classic `ProductInvoices` download contract + +#### Scenario: Disablement of a numbering range + +- **WHEN** `disable_range(company_id:, data:)` is called +- **THEN** the SDK SHALL issue `POST /companies/{company_id}/productinvoices/disablement` with a `DisablementResource`-shaped body and return a `DisablementResource` + +### Requirement: Fail-fast identifier validation on the product RTC resource + +Every `ProductInvoicesRtc` method that takes a `company_id`, `invoice_id`, or `state_tax_id` SHALL validate it through `Nfe::IdValidator` (from `add-client-core`) before issuing any HTTP request, raising `Nfe::InvalidRequestError` synchronously on empty or whitespace-only values. + +#### Scenario: Empty company ID rejected before HTTP + +- **WHEN** any `ProductInvoicesRtc` method is called with an empty or whitespace-only `company_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` with a Portuguese-language message identifying the invalid argument +- **AND** no HTTP request SHALL be issued + +#### Scenario: Empty state tax ID rejected before HTTP + +- **WHEN** `create_with_state_tax` is called with an empty `state_tax_id` +- **THEN** the SDK SHALL raise `Nfe::InvalidRequestError` without issuing an HTTP request + +### Requirement: Discriminated product RTC response classes + +The SDK SHALL provide concrete, immutable response classes for product RTC invoice creation, implementing the `Pending` and `Issued` protocols defined in `add-client-core`: + +- `Nfe::Resources::ProductInvoiceRtcPending` implementing `Pending` — exposing `invoice_id`, `location`, and the predicate `pending?` (returning `true`) / `issued?` (returning `false`) +- `Nfe::Resources::ProductInvoiceRtcIssued` implementing `Issued` — exposing `resource` typed at `Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource`, and the predicate `issued?` (returning `true`) / `pending?` (returning `false`) + +#### Scenario: Discriminating product results with is_a? + +- **WHEN** a consumer writes `if result.is_a?(Nfe::Resources::ProductInvoiceRtcPending) then ... else ... end` +- **THEN** the pending branch SHALL expose `invoice_id`/`location` and the issued branch SHALL expose `resource` +- **AND** the two classes SHALL be distinct from the classic `Nfe::Resources::ProductInvoicePending`/`Nfe::Resources::ProductInvoiceIssued` and from the NFS-e RTC response classes + +#### Scenario: Discriminating product results with predicate methods + +- **WHEN** a consumer receives the result of `create` and calls `result.pending?` / `result.issued?` +- **THEN** `Nfe::Resources::ProductInvoiceRtcPending#pending?` SHALL return `true` and `#issued?` SHALL return `false` +- **AND** `Nfe::Resources::ProductInvoiceRtcIssued#issued?` SHALL return `true` and `#pending?` SHALL return `false` + +### Requirement: Product RTC DTOs are generated from the named OpenAPI schemas + +The OpenAPI pipeline (from `add-openapi-pipeline`) SHALL sync `product-invoice-rtc-v1.yaml` from `nfeio-docs` and emit immutable `Data.define` value objects under `lib/nfe/generated/product_invoice_rtc_v1/` for the spec's named schemas, including `ProductInvoiceRequest`, `InvoiceResource`, `InvoiceItemTaxResource`, `IBSCBSTaxResource`, `IBSStateTaxResource`, `IBSMunicipalTaxResource`, `CBSTaxResource`, and `ISTaxResource`, plus corresponding `.rbs` signatures under `sig/`. Generated files SHALL NOT be hand-edited. + +#### Scenario: ProductInvoiceRequest generated as an immutable value object + +- **WHEN** the pipeline generates types from `product-invoice-rtc-v1.yaml` +- **THEN** `Nfe::Generated::ProductInvoiceRtcV1::ProductInvoiceRequest` SHALL exist as a `Data.define` value object exposing snake_case accessors +- **AND** `Nfe::Generated::ProductInvoiceRtcV1::IBSCBSTaxResource` SHALL exist exposing the `state`, `municipal`, and `cbs` sub-groups, and `Nfe::Generated::ProductInvoiceRtcV1::ISTaxResource` SHALL exist + +#### Scenario: Generated product files carry the frozen-string-literal magic comment + +- **WHEN** any file under `lib/nfe/generated/product_invoice_rtc_v1/` is generated +- **THEN** it SHALL start with `# frozen_string_literal: true` + diff --git a/openspec/specs/sdk-foundation/spec.md b/openspec/specs/sdk-foundation/spec.md new file mode 100644 index 0000000..f6f4d13 --- /dev/null +++ b/openspec/specs/sdk-foundation/spec.md @@ -0,0 +1,225 @@ +# sdk-foundation Specification + +## Purpose +TBD - created by archiving change add-ruby-foundation. Update Purpose after archive. +## Requirements +### Requirement: Minimum Ruby version +The SDK SHALL declare a minimum Ruby runtime of 3.2 via `required_ruby_version` and SHALL NOT support Ruby versions below 3.2. + +#### Scenario: Installing on Ruby 3.1 +- **WHEN** a user runs `gem install nfe-io` (or `bundle install`) on Ruby 3.1 +- **THEN** RubyGems SHALL refuse installation with a `required_ruby_version` constraint error + +#### Scenario: Installing on Ruby 3.2 or above +- **WHEN** a user installs the gem on Ruby 3.2, 3.3, or 3.4 +- **THEN** RubyGems SHALL install the package successfully + +### Requirement: Gem name and version +The SDK SHALL be published on RubyGems under the unchanged name `nfe-io`, and the version constant `Nfe::VERSION` SHALL be `"1.0.0"` (a major bump from the legacy `0.3.2`). + +#### Scenario: Installing the SDK +- **WHEN** a user runs `gem install nfe-io` +- **THEN** the package SHALL resolve to this repository's tagged v1 releases under the same gem name as the legacy line + +#### Scenario: Reading the version constant +- **WHEN** a consumer reads `Nfe::VERSION` +- **THEN** it SHALL return the string `"1.0.0"` + +### Requirement: Root module namespace +The SDK SHALL expose all public classes under the `Nfe` Ruby module and SHALL be requirable via `require "nfe"`. + +#### Scenario: Requiring the entrypoint +- **WHEN** a consumer writes `require "nfe"` +- **THEN** the constant `Nfe::Client` SHALL be defined without any additional `require` + +#### Scenario: File location and namespace alignment +- **WHEN** a class `Nfe::Configuration` is defined +- **THEN** the file SHALL be located at `lib/nfe/configuration.rb` + +### Requirement: frozen_string_literal magic comment in every source file +Every Ruby source file under `lib/` and `sig/`-adjacent tooling SHALL declare `# frozen_string_literal: true` as its first line. + +#### Scenario: A source file missing the magic comment +- **WHEN** a contributor adds a file `lib/nfe/foo.rb` without `# frozen_string_literal: true` as the first line +- **THEN** CI (RuboCop cop `Style/FrozenStringLiteralComment` with `EnforcedStyle: always`) SHALL fail the build + +### Requirement: Zero runtime dependencies +The gemspec SHALL declare no runtime dependencies (no `add_dependency` calls) and the SDK SHALL rely exclusively on the Ruby standard library: `net/http`, `json`, `openssl`, `uri`, `securerandom`, `stringio`, `time`, and `base64`. + +#### Scenario: Inspecting the built gem +- **WHEN** the gem is built and its dependencies inspected (`gem specification nfe-io dependencies`) +- **THEN** the runtime dependency list SHALL be empty (development dependencies excluded) + +#### Scenario: Proposing a runtime dependency +- **WHEN** a contributor proposes adding a gem to the runtime dependencies (not development dependencies) +- **THEN** the proposal SHALL require an explicit design decision in a new OpenSpec change + +#### Scenario: rest-client removed +- **WHEN** the v1 gemspec is inspected +- **THEN** it SHALL NOT depend on `rest-client` (the legacy v0.3.2 runtime dependency) + +### Requirement: Single client entrypoint with lazy resource accessors +The SDK SHALL expose a single client constructed via `Nfe::Client.new(api_key:, data_api_key: nil, environment: :production, base_url: nil, timeout: 30, retry_config: nil)` using keyword arguments, and SHALL provide lazy, memoized, `snake_case` accessors for all 17 resources. + +#### Scenario: Constructing the client +- **WHEN** a consumer calls `Nfe::Client.new(api_key: "sk_test_...")` +- **THEN** the method SHALL return a client instance without raising, and without eagerly instantiating any resource or HTTP client + +#### Scenario: All 17 resource accessors are present +- **WHEN** a consumer reads each of `service_invoices`, `product_invoices`, `consumer_invoices`, `transportation_invoices`, `inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`, `companies`, `legal_people`, `natural_people`, `webhooks`, `addresses`, `legal_entity_lookup`, `natural_person_lookup`, `tax_calculation`, `tax_codes`, and `state_taxes` on the client +- **THEN** each accessor SHALL be defined and SHALL return a resource object (not raise `NoMethodError`) + +#### Scenario: Accessor naming is snake_case +- **WHEN** the public accessor for the Node SDK's `serviceInvoices` / PHP's `serviceInvoices` is referenced +- **THEN** it SHALL be named `service_invoices` (idiomatic Ruby snake_case), and likewise `legal_entity_lookup`, `natural_person_lookup`, `inbound_product_invoices`, etc. + +#### Scenario: Lazy memoized instantiation +- **WHEN** a consumer reads `client.companies` twice +- **THEN** the same resource instance SHALL be returned on both reads (memoized on first access) + +#### Scenario: Instance state replaces global API key +- **WHEN** two clients are constructed with different API keys +- **THEN** each client SHALL hold its own credentials as instance state, with no shared global `@@api_key` + +### Requirement: Configuration is the single source of the multi-base-URL host map +The SDK SHALL resolve API host base URLs exclusively through `Nfe::Configuration`, exposing a lookup (e.g. `#base_url_for(family)`) for the six host families, and no resource SHALL hard-code a host URL. + +#### Scenario: Resolving each host family +- **WHEN** `base_url_for` is queried for each family +- **THEN** it SHALL return: `main` → `https://api.nfe.io` (the `/v1` segment is supplied by the resource `api_version`, not baked into the host); `addresses` → `https://address.api.nfe.io/v2` (documented exception: the `/v2` is part of the base URL); `nfe-query` → `https://nfe.api.nfe.io`; `legal-entity` → `https://legalentity.api.nfe.io`; `natural-person` → `https://naturalperson.api.nfe.io`; `cte` → `https://api.nfse.io` + +#### Scenario: Unknown family falls back to main +- **WHEN** `base_url_for` is queried for a family not in the map +- **THEN** it SHALL return the `main` host `https://api.nfe.io` as a safe default (the `/v1` segment is supplied by the resource `api_version`) + +#### Scenario: No resource hard-codes a URL +- **WHEN** the `lib/nfe/` source tree is searched for literal host strings outside `lib/nfe/configuration.rb` +- **THEN** no resource file SHALL contain a hard-coded `https://*.nfe.io` or `https://api.nfse.io` host + +### Requirement: Generated models are immutable value objects isolated from hand-written code +The SDK SHALL emit OpenAPI-derived models as immutable `Data.define` value objects under `lib/nfe/generated/`, with corresponding RBS signatures under `sig/nfe/generated/`, and these generated files SHALL NEVER be hand-edited. + +#### Scenario: Generated tree is isolated +- **WHEN** the code generator runs +- **THEN** it SHALL write value objects only under `lib/nfe/generated/` and signatures only under `sig/nfe/generated/`, leaving hand-written code untouched + +#### Scenario: Value objects are immutable +- **WHEN** a generated model is instantiated and a consumer attempts to mutate one of its attributes +- **THEN** the object SHALL be immutable (a `Data.define` instance has no attribute writers) + +#### Scenario: Generated code is excluded from lint +- **WHEN** RuboCop runs +- **THEN** `lib/nfe/generated/**/*` SHALL be excluded from linting because the files are generated, not hand-written + +### Requirement: Immutable domain models use Data.define +Hand-written domain models and value objects SHALL be defined with `Data.define` (Ruby 3.2+) using keyword construction, replacing any dynamic `method_missing`-based object from the legacy code. + +#### Scenario: A value object is immutable and comparable +- **WHEN** two `Data.define`-based value objects are built with equal attributes +- **THEN** they SHALL be `==` to each other and SHALL expose no attribute setters + +### Requirement: FlowStatus terminal states gate polling +The SDK SHALL define a `FlowStatus` concept whose terminal states are exactly `Issued`, `IssueFailed`, `Cancelled`, and `CancelFailed`, with a predicate (e.g. `terminal?`) used to gate polling loops; non-terminal states include `PullFromCityHall`, `WaitingCalculateTaxes`, `WaitingDefineRpsNumber`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, and `WaitingDownload`. + +#### Scenario: Terminal status detection +- **WHEN** `terminal?` is evaluated for `Issued`, `IssueFailed`, `Cancelled`, or `CancelFailed` +- **THEN** it SHALL return `true` + +#### Scenario: Non-terminal status detection +- **WHEN** `terminal?` is evaluated for `WaitingSend` (or any other non-terminal state) +- **THEN** it SHALL return `false` + +### Requirement: Downloads return binary-safe Strings +The SDK SHALL document and require that all raw-bytes download methods return a `String` whose encoding is forced to `Encoding::ASCII_8BIT` (binary-safe), since Ruby has no `Buffer` type. + +#### Scenario: PDF download encoding +- **WHEN** a download method returns raw PDF or XML bytes +- **THEN** the returned `String` SHALL have encoding `ASCII-8BIT` so the bytes are preserved without transcoding + +### Requirement: Synchronous discriminated 202 result contract +The SDK SHALL model the create contract synchronously (no async/Promises): a creation call SHALL return a `Pending` result (HTTP 202 with a `Location` header) or an `Issued` result (HTTP 201 with the materialized body) as distinct value objects. + +#### Scenario: Async creation yields Pending +- **WHEN** a create endpoint responds HTTP 202 with a `Location` header +- **THEN** the SDK SHALL return a `Pending` result object carrying the location and the extracted invoice id (no Promise) + +#### Scenario: Immediate creation yields Issued +- **WHEN** a create endpoint responds HTTP 201 with the resource body +- **THEN** the SDK SHALL return an `Issued` result object carrying the hydrated value object (no Promise) + +### Requirement: Type rigor via RBS, Steep, and RuboCop +The SDK SHALL ship RBS signatures under `sig/`, type-check with Steep, and lint with RuboCop, all enforced in CI. + +#### Scenario: RBS signatures are shipped in the gem +- **WHEN** the gem is built +- **THEN** `sig/**/*.rbs` SHALL be included in the packaged files + +#### Scenario: Running the type checker +- **WHEN** a contributor runs `bundle exec steep check` +- **THEN** Steep SHALL type-check `lib/` against the signatures in `sig/` and report zero errors for the foundation artifacts + +#### Scenario: Validating the signatures +- **WHEN** a contributor runs `bundle exec rbs validate` +- **THEN** the RBS signatures under `sig/` SHALL validate successfully + +### Requirement: Test suite with coverage gate +The SDK SHALL test with RSpec and SHALL enforce a SimpleCov line-coverage minimum of 80%, failing the build below that threshold. + +#### Scenario: Running the test suite +- **WHEN** a contributor runs `bundle exec rspec` +- **THEN** RSpec SHALL execute the specs under `spec/` with SimpleCov measuring coverage + +#### Scenario: Coverage below the gate fails the build +- **WHEN** measured line coverage is below 80% +- **THEN** SimpleCov SHALL cause the process to exit non-zero, failing CI + +### Requirement: Development tooling +The gemspec SHALL declare development dependencies on `rake`, `rspec`, `rubocop`, `rubocop-rspec`, `rbs`, `steep`, and `simplecov`, and the `Rakefile` SHALL expose tasks for `spec`, `rubocop`, `steep`, and `rbs`. + +#### Scenario: Default rake task runs the full quality gate +- **WHEN** a contributor runs `bundle exec rake` +- **THEN** the default task SHALL run RSpec, RuboCop, Steep, and RBS validation + +### Requirement: CI matrix across supported Ruby versions +The repository SHALL run continuous integration via GitHub Actions against Ruby 3.2, 3.3, and 3.4 on every push and pull request to the `master` branch, running RSpec, RuboCop, Steep, and `rbs validate`, with the SimpleCov >= 80% gate. + +#### Scenario: Pushing to master +- **WHEN** a commit is pushed to `master` +- **THEN** GitHub Actions SHALL run `rspec`, `rubocop`, `steep check`, and `rbs validate` for each Ruby version in the matrix (3.2, 3.3, 3.4) + +#### Scenario: CI ignores the legacy branch +- **WHEN** a commit is pushed to `0.x-legacy` +- **THEN** the v1 CI workflow SHALL NOT run against it + +### Requirement: Branch and version policy +The `master` branch SHALL host all v1 development. The legacy v0.3.2 (rest-client based) codebase SHALL be snapshotted to a frozen `0.x-legacy` branch that receives no maintenance. + +#### Scenario: Consumer choosing the legacy line +- **WHEN** a consumer pins `gem "nfe-io", "~> 0.3"` +- **THEN** the resolved release line SHALL be the frozen v0.x code (snapshotted on `0.x-legacy`), which receives no further updates + +#### Scenario: Consumer choosing v1 +- **WHEN** a consumer pins `gem "nfe-io", "~> 1.0"` +- **THEN** the resolved release line SHALL be the v1 code developed on `master` + +### Requirement: Greenfield rewrite reuses no legacy code +The v1 SDK SHALL NOT import, copy, or adapt any file from the legacy `lib/nfe/*` tree (e.g. `nfe_object.rb`, `api_resource.rb`, `api_operations/*`, the global `@@api_key` configuration); `lib/nfe/` SHALL be authored clean. + +#### Scenario: No legacy artifacts in v1 +- **WHEN** the v1 `lib/nfe/` tree is inspected +- **THEN** it SHALL contain no `method_missing`-based dynamic object, no `rest-client` usage, and no module-level global API key state + +### Requirement: License retained as MIT +The SDK SHALL retain the MIT license, declared as `spec.license = "MIT"` and shipped as a license file in the gem. + +#### Scenario: License declaration +- **WHEN** the gemspec is inspected +- **THEN** `spec.license` SHALL be `"MIT"` and the license file SHALL be present in the repository + +### Requirement: Migration documentation stub +The repository SHALL include a `MIGRATION.md` documenting the v0.x → v1 breaking changes, including the entrypoint change from `Nfe.api_key(...)` to `Nfe::Client.new(api_key:)`, removal of `rest-client`, the move to immutable value objects, and a statement that the legacy line receives no backports. + +#### Scenario: Migration guide present +- **WHEN** a consumer upgrading from v0.x opens `MIGRATION.md` +- **THEN** it SHALL describe the new client entrypoint, the zero-runtime-dependency change, and the no-backport policy for the `0.x-legacy` branch + diff --git a/openspec/specs/webhook-signature-verification/spec.md b/openspec/specs/webhook-signature-verification/spec.md new file mode 100644 index 0000000..66c1226 --- /dev/null +++ b/openspec/specs/webhook-signature-verification/spec.md @@ -0,0 +1,129 @@ +# webhook-signature-verification Specification + +## Purpose +TBD - created by archiving change add-entity-resources. Update Purpose after archive. +## Requirements +### Requirement: Webhook signature verification helper exists without a Client +The SDK SHALL provide `Nfe::Webhook` as a stateless module of functions (using `module_function`) that verifies NFE.io webhook signatures using only the caller-supplied payload, signature, and secret. It SHALL NOT require an instantiated `Nfe::Client`, SHALL NOT read `Nfe::Configuration`, and SHALL NOT perform any network access. This is the canonical API for signature verification; `Nfe::Resources::Webhooks#verify_signature` MAY delegate to it for Node parity. + +#### Scenario: Verifying without a configured Client +- **WHEN** a webhook endpoint runs in a process that has not instantiated `Nfe::Client` +- **THEN** `Nfe::Webhook.verify_signature(payload:, signature:, secret:)` SHALL function correctly using only the provided arguments + +#### Scenario: No network access +- **WHEN** any `Nfe::Webhook` method runs +- **THEN** it SHALL NOT issue any HTTP request + +### Requirement: verify_signature matches the production HMAC-SHA1 scheme +`Nfe::Webhook.verify_signature(payload:, signature:, secret:) -> Boolean` SHALL return `true` only when the provided signature matches `OpenSSL::HMAC.hexdigest("SHA1", secret, payload)` computed over the raw payload bytes, after requiring and stripping the `sha1=` prefix (compared case-insensitively) and normalising the remaining hex to lower case. The comparison SHALL use `OpenSSL.secure_compare` (constant-time). The method SHALL NOT re-serialize the payload; it SHALL operate on the bytes as given. + +#### Scenario: Validate a real signature from NFE.io (live fixture) +- **WHEN** the caller invokes `verify_signature` with a captured webhook body, the configured secret, and the header value `sha1=BCD17C02B9E3B40A18E745E7E04247E4AD2DD935` whose HMAC-SHA1 over the body bytes with that secret produces that digest +- **THEN** the method SHALL return `true` + +#### Scenario: Uppercase hex on the wire is accepted +- **WHEN** the header value carries the digest in uppercase hex (as NFE.io sends it) +- **THEN** the method SHALL return `true` (comparison is case-insensitive) + +#### Scenario: Lowercase hex is accepted +- **WHEN** the same digest is provided in lowercase hex +- **THEN** the method SHALL return `true` + +#### Scenario: Round-trip of a self-computed signature +- **WHEN** the caller computes `sha1=` + `OpenSSL::HMAC.hexdigest("SHA1", secret, body)` for a random body and secret and passes it back +- **THEN** the method SHALL return `true` + +#### Scenario: Constant-time comparison +- **WHEN** the method compares the received and expected digests +- **THEN** it SHALL use `OpenSSL.secure_compare` and SHALL NOT use `==`, `eql?`, or `String#==` on the hex strings + +### Requirement: verify_signature rejects malformed, missing, and forged input without raising +`Nfe::Webhook.verify_signature` SHALL return `false` — and SHALL NEVER raise an exception — for any tampered body, missing input, malformed signature, wrong algorithm prefix, missing prefix, wrong length, or non-hex content. + +#### Scenario: Tampered body +- **WHEN** a valid signature for body A is checked against body A mutated by one byte +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Wrong secret +- **WHEN** the body and signature are valid for one secret but verified with a different secret +- **THEN** the method SHALL return `false` + +#### Scenario: Wrong algorithm prefix (downgrade attempt) +- **WHEN** the header value is `sha256=<64 hex chars>` +- **THEN** the method SHALL return `false` and SHALL NOT raise (no implicit algorithm upgrade or downgrade) + +#### Scenario: Missing prefix +- **WHEN** the header value is a bare 40-character hex string with no `sha1=` prefix +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Wrong length +- **WHEN** the header value is `sha1=abc` +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Non-hex content +- **WHEN** the header value is `sha1=` followed by 40 non-hex characters +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Missing or empty secret +- **WHEN** `secret` is `nil` or an empty string +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Missing or empty signature +- **WHEN** `signature` is `nil`, an empty string, or an empty array +- **THEN** the method SHALL return `false` and SHALL NOT raise + +#### Scenario: Header delivered as an array +- **WHEN** the signature argument is a single-element array (the shape some Rack/HTTP stacks expose for repeated headers) +- **THEN** the method SHALL use the first element and verify normally + +### Requirement: construct_event verifies, parses, and returns a typed event +`Nfe::Webhook.construct_event(payload:, signature:, secret:) -> Nfe::WebhookEvent` SHALL first call `verify_signature`. If verification fails it SHALL raise `Nfe::SignatureVerificationError`. Otherwise it SHALL parse the payload as JSON, unwrap the NFE.io delivery envelope, and return a `Nfe::WebhookEvent`. A payload that is not valid JSON SHALL raise `Nfe::SignatureVerificationError`. + +#### Scenario: Valid signature yields a WebhookEvent +- **WHEN** `construct_event` is called with a valid signature over the body `{"action":"invoice.issued","payload":{"id":"abc","status":"Issued"}}` +- **THEN** it SHALL return a `Nfe::WebhookEvent` with `type == "invoice.issued"` and `data == {"id" => "abc", "status" => "Issued"}` + +#### Scenario: Invalid signature raises +- **WHEN** `construct_event` is called with a signature that does not match the body and secret +- **THEN** it SHALL raise `Nfe::SignatureVerificationError` and SHALL NOT return an event + +#### Scenario: Malformed JSON raises +- **WHEN** `construct_event` is called with a valid signature but a body that is not valid JSON +- **THEN** it SHALL raise `Nfe::SignatureVerificationError` + +### Requirement: WebhookEvent is an immutable value object +The SDK SHALL provide `Nfe::WebhookEvent = Data.define(:type, :data, :id, :created_at)`. `type` is a required string; `data` is a `Hash` of payload data; `id` and `created_at` are optional (default `nil`). `construct_event` SHALL unwrap both the `{"action" => type, "payload" => data}` and `{"event" => type, "data" => data}` envelope shapes into this form. + +#### Scenario: Envelope unwrapping (action/payload) +- **WHEN** the delivered body is `{"action":"invoice.issued","payload":{"id":"abc"}}` +- **THEN** `construct_event` SHALL produce a `WebhookEvent` with `type == "invoice.issued"` and `data == {"id" => "abc"}` + +#### Scenario: Event is immutable +- **WHEN** a `Nfe::WebhookEvent` is created +- **THEN** it SHALL be a frozen `Data` instance whose fields cannot be mutated + +### Requirement: Documentation steers callers to raw body bytes +The SDK documentation (README and RDoc/YARD on `Nfe::Webhook`) SHALL instruct callers to read the raw request body (e.g. `request.body.read` in Rack/Rails) BEFORE parsing JSON and pass those exact bytes to `verify_signature`/`construct_event`. It SHALL warn explicitly that re-serializing a parsed object (e.g. `payload.to_json`) will not match the signed bytes and will fail unpredictably. + +#### Scenario: Documented example uses raw bytes +- **WHEN** a reader copies the documented webhook-verification example +- **THEN** the snippet SHALL pass the raw request body to the verifier and SHALL parse JSON only after verification succeeds, and SHALL NOT pass a re-serialized object + +### Requirement: No anti-replay primitive — handlers must be idempotent and dedupe on event/invoice id +NFE.io provides no webhook anti-replay primitive: deliveries carry only the `X-Hub-Signature` HMAC-SHA1 over the body, with no timestamp and no nonce. A valid signature therefore proves authenticity but NOT freshness — a replayed delivery carries a perfectly valid signature. The SDK documentation (README and RDoc/YARD on `Nfe::Webhook`) SHALL state this explicitly and instruct consumers that webhook handlers MUST be idempotent and MUST dedupe on the event/invoice id. To support deduplication, `construct_event` SHALL surface a stable event id on `Nfe::WebhookEvent#id` when the delivery envelope carries one (e.g. the event id or the invoice id), and `nil` when absent. + +#### Scenario: Documentation warns that a valid signature is not freshness +- **WHEN** a reader consults the webhook-verification documentation +- **THEN** it SHALL state that NFE.io sends no timestamp/nonce, that signature validity does not imply freshness, and that handlers MUST be idempotent and dedupe on the event/invoice id + +#### Scenario: Stable event id surfaced for deduplication +- **WHEN** `construct_event` parses a delivery whose envelope carries an event id (or invoice id) +- **THEN** the returned `Nfe::WebhookEvent#id` SHALL expose that id so the consumer can dedupe replays, and SHALL be `nil` when no such id is present + +### Requirement: The legacy X-NFe-Signature / SHA-256 scheme is not implemented +The SDK SHALL implement only the `X-Hub-Signature` + HMAC-SHA1 scheme. It SHALL NOT implement the legacy `X-NFe-Signature` header or HMAC-SHA256 algorithm described in the (incorrect) distribuição documentation. + +#### Scenario: SHA-256 header is rejected +- **WHEN** a caller passes a signature header using the legacy `sha256=` form +- **THEN** `verify_signature` SHALL return `false` (the SHA-1 scheme is the only supported scheme) + diff --git a/samples/.env.example b/samples/.env.example new file mode 100644 index 0000000..62547b0 --- /dev/null +++ b/samples/.env.example @@ -0,0 +1,15 @@ +# NFE.io Ruby SDK — variáveis de ambiente para os exemplos. +# Copie para samples/.env e preencha (samples/.env é ignorado pelo .gitignore). + +# Chave de API principal (emissão, empresas, entidades). Obrigatória. +NFE_API_KEY= + +# Chave de API de dados (consultas: CEP, CNPJ, CPF). Opcional — +# quando ausente, as famílias de dados usam NFE_API_KEY como fallback. +NFE_DATA_API_KEY= + +# Id da empresa (company) usada nos exemplos de emissão e CRUD. +NFE_COMPANY_ID= + +# Segredo do webhook, usado em webhook_verify.rb para validar a assinatura. +NFE_WEBHOOK_SECRET= diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 0000000..3475a16 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,76 @@ +# Exemplos do SDK Ruby da NFE.io + +Scripts executáveis que demonstram a gem `nfe-io` (v1) ponta a ponta. Cada +arquivo é independente: carrega `config.rb`, lê variáveis de ambiente e usa o +cliente global `$nfe`. + +## Configuração + +1. Copie o template de variáveis e preencha: + + ```sh + cp samples/.env.example samples/.env + $EDITOR samples/.env + ``` + + `samples/.env` é ignorado pelo Git. Alternativamente, exporte as variáveis + direto no shell: + + ```sh + export NFE_API_KEY="sua-chave" + export NFE_DATA_API_KEY="sua-chave-de-dados" # opcional + export NFE_COMPANY_ID="id-da-empresa" + export NFE_WEBHOOK_SECRET="segredo-do-webhook" # apenas webhook_verify.rb + ``` + +2. Rode qualquer exemplo a partir da raiz do repositório: + + ```sh + ruby samples/.rb + ``` + +`config.rb` prefere a gem instalada (`gem install nfe-io`) e cai para a +`lib/` do repositório quando rodando a partir do checkout — não é preciso +instalar a gem para experimentar. + +## Variáveis de ambiente + +| Variável | Obrigatória | Usada por | +| -------------------- | ----------- | ------------------------------------------- | +| `NFE_API_KEY` | sim | todos os exemplos | +| `NFE_DATA_API_KEY` | não | consultas (CEP/CNPJ/CPF); cai para a principal | +| `NFE_COMPANY_ID` | depende | emissão e CRUD de empresa/pessoas | +| `NFE_WEBHOOK_SECRET` | depende | `webhook_verify.rb` | + +> Use sempre uma conta/empresa de **testes**. Alguns exemplos criam e removem +> recursos (ex.: `company_crud.rb`) ou emitem documentos fiscais. + +## Exemplos + +| Arquivo | O que demonstra | +| ---------------------------- | ---------------------------------------------------------------------- | +| `service_invoice_issue.rb` | NFS-e: emissão + polling manual (`FlowStatus.terminal?`) + PDF binário | +| `product_invoice_issue.rb` | NF-e: emissão assíncrona (conclusão via webhook) | +| `consumer_invoice_issue.rb` | NFC-e: emissão com resultado discriminado (pendente x emitida) | +| `rtc_service_invoice.rb` | NFS-e RTC: emissão com grupo `ibsCbs` + polling | +| `company_crud.rb` | Empresa: create + list + retrieve + update + remove | +| `legal_person_create.rb` | Pessoa jurídica: criação | +| `legal_person_update.rb` | Pessoa jurídica: atualização | +| `webhook_verify.rb` | Verificação de assinatura de webhook (HMAC-SHA1, bytes brutos) | +| `cnpj_lookup.rb` | Consulta de CNPJ: dados básicos + inscrição estadual para emissão | +| `cpf_lookup.rb` | Consulta de CPF: situação cadastral | +| `cep_lookup.rb` | Consulta de CEP | +| `tax_calculation.rb` | Motor de cálculo de impostos por tenant | + +## Notas + +- A emissão é **assíncrona** (HTTP 202). Não há `create_and_wait`/`create_batch` + na v1.0 — faça polling chamando `retrieve` em laço até + `Nfe::FlowStatus.terminal?(invoice.flow_status)` (estados terminais: + `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`). +- Downloads de NFS-e/NFC-e retornam **bytes** (`ASCII-8BIT`) — grave com + `File.binwrite`. Já os downloads de **NF-e** retornam um + `Nfe::NfeFileResource` (objeto com a URI do arquivo), não os bytes. +- Webhooks: passe sempre os **bytes brutos** do corpo (antes de parsear JSON). + A assinatura prova autenticidade, não atualidade — handlers devem ser + idempotentes e deduplicar pelo id do evento/nota. diff --git a/samples/cep_lookup.rb b/samples/cep_lookup.rb new file mode 100644 index 0000000..0165554 --- /dev/null +++ b/samples/cep_lookup.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# Consulta de CEP (endereço) por código postal. +# +# Usa a família de dados: prefere NFE_DATA_API_KEY, caindo para NFE_API_KEY. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_DATA_API_KEY — chave de dados (opcional; cai para NFE_API_KEY) +# +# Uso: +# ruby samples/cep_lookup.rb [CEP] + +require_relative "config" + +cep = ARGV[0] || "01310-100" + +# lookup_by_postal_code — aceita o CEP em qualquer formato. +result = $nfe.addresses.lookup_by_postal_code(cep) + +# A resposta envolve um array de endereços em .addresses. +result.addresses.each do |address| + city_name = address.city&.name + puts "#{address.street}, #{address.district} — #{city_name}/#{address.state}" +end + +puts "Nenhum endereço encontrado para #{cep}." if result.addresses.empty? diff --git a/samples/cnpj_lookup.rb b/samples/cnpj_lookup.rb new file mode 100644 index 0000000..6dcaa61 --- /dev/null +++ b/samples/cnpj_lookup.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# Consulta de CNPJ (pessoa jurídica): dados cadastrais básicos e a inscrição +# estadual adequada para emissão. +# +# Usa a família de dados: prefere NFE_DATA_API_KEY, caindo para NFE_API_KEY. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_DATA_API_KEY — chave de dados (opcional; cai para NFE_API_KEY) +# +# Uso: +# ruby samples/cnpj_lookup.rb [CNPJ] [UF] + +require_relative "config" + +cnpj = ARGV[0] || "19101009000199" +state = ARGV[1] || "SP" + +# Dados cadastrais básicos do CNPJ. +basic = $nfe.legal_entity_lookup.get_basic_info(cnpj) +puts "Razão social: #{basic.name}" if basic.respond_to?(:name) +puts "Resposta (basicInfo): #{basic.inspect}" + +# Inscrição estadual adequada para emissão (estado + CNPJ). +state_tax = $nfe.legal_entity_lookup.get_state_tax_for_invoice(state, cnpj) +puts "Resposta (stateTaxForInvoice/#{state}): #{state_tax.inspect}" diff --git a/samples/company_crud.rb b/samples/company_crud.rb new file mode 100644 index 0000000..63fbc59 --- /dev/null +++ b/samples/company_crud.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Ciclo completo de empresa (company): create, list, retrieve, update, remove. +# +# ATENÇÃO: este exemplo CRIA e depois REMOVE uma empresa. Rode apenas em uma +# conta de testes. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# +# Uso: +# ruby samples/company_crud.rb + +require_relative "config" + +# create — recebe um Hash posicional com chaves camelCase. +company = $nfe.companies.create( + name: "Empresa Exemplo SDK", + tradeName: "Exemplo SDK", + federalTaxNumber: "19101009000199", + email: "contato@exemplo-sdk.com.br", + address: { + country: "BRA", + postalCode: "01310-100", + street: "Avenida Paulista", + number: "1000", + district: "Bela Vista", + city: { code: "3550308", name: "São Paulo" }, + state: "SP" + } +) +puts "Criada: #{company.id} — #{company.name}" + +# list — paginada por página (page_index é 0-based). +page = $nfe.companies.list(page_index: 0, page_count: 10) +puts "Empresas na primeira página: #{page.data.size}" + +# retrieve — id posicional. +fetched = $nfe.companies.retrieve(company.id) +puts "Recuperada: #{fetched.id} — #{fetched.name}" + +# update — id + Hash posicionais. +updated = $nfe.companies.update(company.id, { tradeName: "Exemplo SDK (atualizado)" }) +puts "Atualizada: tradeName=#{updated.trade_name}" + +# remove — note o nome `remove` (não `delete`). +removed = $nfe.companies.remove(company.id) +puts "Removida: #{removed.inspect}" diff --git a/samples/config.rb b/samples/config.rb new file mode 100644 index 0000000..c3a6575 --- /dev/null +++ b/samples/config.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +# Configuração compartilhada por todos os exemplos. +# +# Carregue com `require_relative "config"` no topo de cada exemplo. Ele: +# * carrega a gem (preferindo a instalada; caindo para lib/ do repositório); +# * lê as variáveis de ambiente (de um samples/.env opcional); +# * monta um Nfe::Client global em $nfe; +# * expõe $company_id; +# * aborta com uma mensagem clara se NFE_API_KEY não estiver definida. +# +# Variáveis de ambiente (veja samples/.env.example): +# NFE_API_KEY — chave principal (obrigatória) +# NFE_DATA_API_KEY — chave de dados (opcional; cai para NFE_API_KEY) +# NFE_COMPANY_ID — id da empresa usada nos exemplos +# NFE_WEBHOOK_SECRET — segredo do webhook (apenas webhook_verify.rb) + +# Carrega um samples/.env simples (KEY=VALUE por linha), sem dependências +# externas. Variáveis já presentes no ambiente têm precedência. +env_path = File.join(__dir__, ".env") +if File.file?(env_path) + File.foreach(env_path) do |line| + line = line.strip + next if line.empty? || line.start_with?("#") + + key, _, value = line.partition("=") + key = key.strip + next if key.empty? + + ENV[key] ||= value.strip + end +end + +# Prefere a gem instalada; cai para a lib/ do repositório quando rodando a +# partir do checkout (sem `gem install nfe-io`). +begin + require "nfe" +rescue LoadError + $LOAD_PATH.unshift(File.expand_path("../lib", __dir__)) + require "nfe" +end + +if ENV["NFE_API_KEY"].nil? || ENV["NFE_API_KEY"].strip.empty? + abort <<~MSG + NFE_API_KEY não definida. + + Copie samples/.env.example para samples/.env e preencha NFE_API_KEY, + ou exporte a variável antes de rodar: + + export NFE_API_KEY="sua-chave" + ruby samples/.rb + MSG +end + +# Cliente global compartilhado pelos exemplos. +$nfe = Nfe::Client.new( + api_key: ENV["NFE_API_KEY"], + data_api_key: ENV["NFE_DATA_API_KEY"] +) + +# Id da empresa usada nos exemplos de emissão/CRUD (pode ser nil em exemplos +# que não precisam dela, como as consultas de CEP/CNPJ/CPF). +$company_id = ENV["NFE_COMPANY_ID"] diff --git a/samples/consumer_invoice_issue.rb b/samples/consumer_invoice_issue.rb new file mode 100644 index 0000000..c4ff997 --- /dev/null +++ b/samples/consumer_invoice_issue.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Emite uma NFC-e (nota fiscal de consumidor) e trata o resultado +# discriminado (pendente x emitida). Útil para PDV e e-commerce. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_COMPANY_ID — empresa de testes habilitada para NFC-e +# +# Uso: +# ruby samples/consumer_invoice_issue.rb + +require_relative "config" +require "securerandom" + +abort "Defina NFE_COMPANY_ID para emitir a NFC-e." if $company_id.nil? + +# Payload em camelCase. Exemplo mínimo: ambiente de testes, um item e +# pagamento à vista. Ajuste para a operação real. +payload = { + id: SecureRandom.uuid, + environmentType: "Test", + items: [ + { + code: "001", + description: "Produto de balcão", + ncm: "21069090", + cfop: "5102", + unit: "UN", + quantity: 1.0, + unitAmount: 9.90, + totalAmount: 9.90 + } + ], + payment: [ + { method: "Cash", amount: 9.90 } + ] +} + +result = $nfe.consumer_invoices.create(company_id: $company_id, data: payload) + +# Discriminação por pattern matching (também há result.pending?/result.issued?). +case result +in Nfe::Resources::ConsumerInvoiceIssued => issued + invoice = issued.resource + puts "NFC-e emitida: #{invoice.id} (status #{invoice.flow_status})" +in Nfe::Resources::ConsumerInvoicePending => pending + puts "NFC-e em processamento (202): #{pending.invoice_id}" + puts "Location: #{pending.location}" + puts "Acompanhe com $nfe.consumer_invoices.retrieve(...)." +end diff --git a/samples/cpf_lookup.rb b/samples/cpf_lookup.rb new file mode 100644 index 0000000..8644cd9 --- /dev/null +++ b/samples/cpf_lookup.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# Consulta de CPF (pessoa física): situação cadastral na Receita Federal. +# Requer o CPF e a data de nascimento. +# +# Usa a família de dados: prefere NFE_DATA_API_KEY, caindo para NFE_API_KEY. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_DATA_API_KEY — chave de dados (opcional; cai para NFE_API_KEY) +# +# Uso: +# ruby samples/cpf_lookup.rb [CPF] [YYYY-MM-DD] + +require_relative "config" + +cpf = ARGV[0] || "00000000000" +birth_date = ARGV[1] || "1990-01-31" + +# get_status — (federal_tax_number, birth_date) posicionais. A data aceita +# String ISO, Date, Time ou DateTime (normalizada para YYYY-MM-DD). +status = $nfe.natural_person_lookup.get_status(cpf, birth_date) + +if status.nil? + puts "Nenhum status retornado para o CPF informado." +else + puts "Nome: #{status.name}" + puts "Situação: #{status.status}" + puts "Resposta completa: #{status.inspect}" +end diff --git a/samples/legal_person_create.rb b/samples/legal_person_create.rb new file mode 100644 index 0000000..0afbb90 --- /dev/null +++ b/samples/legal_person_create.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# Cria uma pessoa jurídica (legal person) escopada a uma empresa. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_COMPANY_ID — empresa de testes +# +# Uso: +# ruby samples/legal_person_create.rb + +require_relative "config" + +abort "Defina NFE_COMPANY_ID." if $company_id.nil? + +# create — (company_id, data) posicionais; data em camelCase. +person = $nfe.legal_people.create($company_id, { + name: "Fornecedor Exemplo LTDA", + federalTaxNumber: "19101009000199", + email: "contato@fornecedor-exemplo.com.br", + address: { + country: "BRA", + postalCode: "01310-100", + street: "Avenida Paulista", + number: "1000", + district: "Bela Vista", + city: { code: "3550308", name: "São Paulo" }, + state: "SP" + } +}) + +puts "Pessoa jurídica criada: #{person.id} — #{person.name}" +puts "Guarde o id para atualizar depois: #{person.id}" diff --git a/samples/legal_person_update.rb b/samples/legal_person_update.rb new file mode 100644 index 0000000..c249e17 --- /dev/null +++ b/samples/legal_person_update.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# Atualiza uma pessoa jurídica (legal person) existente. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_COMPANY_ID — empresa de testes +# * NFE_LEGAL_PERSON_ID — id da pessoa jurídica (ex.: do legal_person_create.rb) +# +# Uso: +# NFE_LEGAL_PERSON_ID= ruby samples/legal_person_update.rb + +require_relative "config" + +abort "Defina NFE_COMPANY_ID." if $company_id.nil? + +legal_person_id = ENV["NFE_LEGAL_PERSON_ID"] +abort "Defina NFE_LEGAL_PERSON_ID (rode legal_person_create.rb primeiro)." if legal_person_id.nil? + +# update — (company_id, legal_person_id, data) posicionais; data em camelCase. +updated = $nfe.legal_people.update($company_id, legal_person_id, { + email: "novo-contato@fornecedor-exemplo.com.br" +}) + +puts "Pessoa jurídica atualizada: #{updated.id}" +puts "Novo e-mail: #{updated.email}" diff --git a/samples/product_invoice_issue.rb b/samples/product_invoice_issue.rb new file mode 100644 index 0000000..52dd96d --- /dev/null +++ b/samples/product_invoice_issue.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +# Emite uma NF-e (nota fiscal de produto). A emissão é assíncrona (HTTP 202): +# a conclusão chega via webhook (veja samples/webhook_verify.rb). Este exemplo +# dispara a emissão e imprime o id para você acompanhar. +# +# Observação: para NF-e os métodos download_* retornam um Nfe::NfeFileResource +# (um objeto com a URI do arquivo), e NÃO os bytes do arquivo. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_COMPANY_ID — empresa de testes habilitada para NF-e +# +# Uso: +# ruby samples/product_invoice_issue.rb + +require_relative "config" +require "securerandom" + +abort "Defina NFE_COMPANY_ID para emitir a NF-e." if $company_id.nil? + +# Payload em camelCase. Exemplo mínimo: ambiente de testes, um destinatário e +# um item. Ajuste para a operação fiscal real da sua empresa. +payload = { + id: SecureRandom.uuid, + operationNature: "Venda de mercadoria", + environmentType: "Test", + buyer: { + type: "LegalEntity", + name: "Cliente Exemplo LTDA", + federalTaxNumber: "19101009000199", + email: "compras@cliente-exemplo.com.br", + address: { + country: "BRA", + postalCode: "01310-100", + street: "Avenida Paulista", + number: "1000", + district: "Bela Vista", + city: { code: "3550308", name: "São Paulo" }, + state: "SP" + } + }, + items: [ + { + code: "001", + description: "Produto de exemplo", + ncm: "84713012", + cfop: "5102", + unit: "UN", + quantity: 1.0, + unitAmount: 100.0, + totalAmount: 100.0 + } + ] +} + +result = $nfe.product_invoices.create(company_id: $company_id, data: payload) + +if result.issued? + invoice = result.resource + puts "NF-e emitida imediatamente: #{invoice.id} (status #{invoice.flow_status})" +else + puts "NF-e em processamento (202): #{result.invoice_id}" + puts "Location: #{result.location}" + puts "A conclusão será notificada por webhook. Acompanhe com:" + puts " $nfe.product_invoices.retrieve(company_id: ..., invoice_id: \"#{result.invoice_id}\")" +end diff --git a/samples/rtc_service_invoice.rb b/samples/rtc_service_invoice.rb new file mode 100644 index 0000000..d8f5833 --- /dev/null +++ b/samples/rtc_service_invoice.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# Emite uma NFS-e no layout RTC (Reforma Tributária do Consumo) e acompanha o +# processamento via polling manual. +# +# O RTC usa o MESMO endpoint da NFS-e clássica. Não há header/parâmetro +# discriminador: a API seleciona o layout RTC pela PRESENÇA do grupo `ibsCbs` +# no payload de criação. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_COMPANY_ID — empresa de testes habilitada para RTC +# +# Uso: +# ruby samples/rtc_service_invoice.rb + +require_relative "config" + +abort "Defina NFE_COMPANY_ID para emitir a NFS-e RTC." if $company_id.nil? + +# Payload em camelCase. A presença do grupo `ibsCbs` seleciona o layout RTC. +payload = { + cityServiceCode: "2690", + description: "Serviço com tributação RTC (IBS/CBS).", + servicesAmount: 100.0, + borrower: { + type: "LegalEntity", + name: "Cliente Exemplo LTDA", + federalTaxNumber: "19101009000199", + email: "financeiro@cliente-exemplo.com.br", + address: { + country: "BRA", + postalCode: "01310-100", + street: "Avenida Paulista", + number: "1000", + district: "Bela Vista", + city: { code: "3550308", name: "São Paulo" }, + state: "SP" + } + }, + # Grupo RTC: indicador de operação + classe tributária do IBS/CBS. + ibsCbs: { + operationIndicator: 1, + classCode: "000001" + } +} + +result = $nfe.service_invoices_rtc.create(company_id: $company_id, data: payload) + +if result.issued? + invoice = result.resource + puts "NFS-e RTC emitida imediatamente: #{invoice.id} (status #{invoice.flow_status})" +else + invoice_id = result.invoice_id + puts "NFS-e RTC em processamento (202): #{invoice_id}" + puts "Location: #{result.location}" + + # Polling manual: retrieve até flow_status terminal. + invoice = nil + 60.times do + invoice = $nfe.service_invoices_rtc.retrieve(company_id: $company_id, invoice_id: invoice_id) + puts " flow_status=#{invoice.flow_status}" + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + + sleep 3 + end + + unless invoice && Nfe::FlowStatus.terminal?(invoice.flow_status) + abort "Tempo de processamento esgotado; consulte mais tarde." + end +end + +puts "Status final: #{invoice.flow_status}" diff --git a/samples/service_invoice_issue.rb b/samples/service_invoice_issue.rb new file mode 100644 index 0000000..5ee7a28 --- /dev/null +++ b/samples/service_invoice_issue.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# Emite uma NFS-e (nota fiscal de serviço), acompanha o processamento +# assíncrono via polling manual e baixa o PDF. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal +# * NFE_COMPANY_ID — empresa de testes com certificado válido e habilitada +# para NFS-e na prefeitura +# +# Uso: +# ruby samples/service_invoice_issue.rb + +require_relative "config" + +abort "Defina NFE_COMPANY_ID para emitir a NFS-e." if $company_id.nil? + +# Payload em camelCase, como a API espera. Ajuste os valores para a sua +# empresa/cidade. Este é um exemplo mínimo de tomador + serviço. +payload = { + cityServiceCode: "2690", + description: "Desenvolvimento de software sob encomenda.", + servicesAmount: 100.0, + borrower: { + type: "LegalEntity", + name: "Cliente Exemplo LTDA", + federalTaxNumber: "19101009000199", + email: "financeiro@cliente-exemplo.com.br", + address: { + country: "BRA", + postalCode: "01310-100", + street: "Avenida Paulista", + number: "1000", + district: "Bela Vista", + city: { code: "3550308", name: "São Paulo" }, + state: "SP" + } + } +} + +result = $nfe.service_invoices.create(company_id: $company_id, data: payload) + +# A emissão é discriminada: pendente (202, assíncrona) ou já emitida (201). +if result.issued? + invoice = result.resource + puts "NFS-e emitida imediatamente: #{invoice.id} (status #{invoice.flow_status})" +else + invoice_id = result.invoice_id + puts "NFS-e em processamento (202): #{invoice_id}" + puts "Location: #{result.location}" + + # Polling manual: consulta retrieve até o flow_status ficar terminal. + invoice = nil + 60.times do + invoice = $nfe.service_invoices.retrieve(company_id: $company_id, invoice_id: invoice_id) + puts " flow_status=#{invoice.flow_status}" + break if Nfe::FlowStatus.terminal?(invoice.flow_status) + + sleep 3 + end + + unless invoice && Nfe::FlowStatus.terminal?(invoice.flow_status) + abort "Tempo de processamento esgotado; tente consultar mais tarde." + end +end + +abort "Emissão falhou: flow_status=#{invoice.flow_status}" if invoice.flow_status != "Issued" + +# Baixa o PDF (bytes binários ASCII-8BIT) e grava com File.binwrite. +pdf_bytes = $nfe.service_invoices.download_pdf(company_id: $company_id, invoice_id: invoice.id) +path = "nfse-#{invoice.id}.pdf" +File.binwrite(path, pdf_bytes) +puts "PDF salvo em #{path} (#{pdf_bytes.bytesize} bytes)" diff --git a/samples/smoke_readonly.rb b/samples/smoke_readonly.rb new file mode 100644 index 0000000..22f5781 --- /dev/null +++ b/samples/smoke_readonly.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +# Smoke test READ-ONLY contra a API real (sandbox). +# NÃO emite, cancela ou grava nada — só consultas/listagens. +# +# Valida, contra respostas reais: autenticação, roteamento multi-host, o modelo +# de duas chaves e o mapeamento dos DTOs corrigidos na revisão (Address#district, +# LegalEntity#status_on/#size, etc.). +# +# 1) preencha samples/.env 2) ruby samples/smoke_readonly.rb + +require_relative "config" + +PASS = [] +FAIL = [] + +def check(label) + result = yield + puts " \e[32m✓\e[0m #{label}" + puts " #{result}" if result && !result.to_s.empty? + PASS << label +rescue StandardError => e + puts " \e[31m✗\e[0m #{label}" + puts " #{e.class}: #{e.message.to_s[0, 160]}" + FAIL << label +end + +def short(obj, max = 260) + obj.inspect[0, max] +end + +def count(result) + return result.data.size if result.respond_to?(:data) + + result.respond_to?(:size) ? result.size : "?" +end + +puts "Smoke test READ-ONLY — sandbox — nfe-io #{Nfe::VERSION} (não grava nada)" +puts + +check("addresses.lookup_by_postal_code('01310100') [DTO Address: district/city]") do + short($nfe.addresses.lookup_by_postal_code("01310100").addresses.first) +end + +check("tax_codes.list_operation_codes [:cte, page-style]") do + r = $nfe.tax_codes.list_operation_codes + "itens=#{r.items.size} current_page=#{r.current_page} total_pages=#{r.total_pages}" +end + +check("companies.list [:main, DTO Company]") do + "data=#{count($nfe.companies.list(page_count: 5))}" +end + +cnpj = ENV["NFE_TEST_CNPJ"].to_s.strip +cnpj = "00000000000191" if cnpj.empty? # Banco do Brasil (público) +check("legal_entity_lookup.get_basic_info('#{cnpj}') [DTO LegalEntity: status_on/size]") do + short($nfe.legal_entity_lookup.get_basic_info(cnpj).legal_entity) +end + +if $company_id.to_s.strip.empty? + puts " \e[33m–\e[0m list NFS-e/NF-e: pulado (defina NFE_COMPANY_ID no samples/.env)" +else + check("service_invoices.list(company_id) [page-style]") do + r = $nfe.service_invoices.list(company_id: $company_id) + "data=#{r.data.size} page_index=#{r.page&.page_index}" + end + check("product_invoices.list(company_id, environment: 'Test') [cursor]") do + r = $nfe.product_invoices.list(company_id: $company_id, environment: "Test") + "data=#{r.data.size} starting_after=#{r.page&.starting_after.inspect}" + end + check("consumer_invoices.list(company_id:, environment: 'Test') [:cte, DTO ConsumerInvoice]") do + "data=#{count($nfe.consumer_invoices.list(company_id: $company_id, environment: 'Test'))}" + end + check("state_taxes.list(company_id) [:cte, DTO NfeStateTax]") do + "data=#{count($nfe.state_taxes.list($company_id))}" + end + check("companies.retrieve(company_id) [DTO Company]") do + short($nfe.companies.retrieve($company_id)) + end + check("legal_people.list(company_id) [DTO LegalPerson]") do + "data=#{count($nfe.legal_people.list($company_id))}" + end + check("natural_people.list(company_id) [DTO NaturalPerson]") do + "data=#{count($nfe.natural_people.list($company_id))}" + end +end + +puts +puts "Resumo: #{PASS.size} OK, #{FAIL.size} falha(s)" +exit(FAIL.empty? ? 0 : 1) diff --git a/samples/smoke_write.rb b/samples/smoke_write.rb new file mode 100644 index 0000000..e5152ec --- /dev/null +++ b/samples/smoke_write.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true + +# Smoke test de ESCRITA contra a API real (sandbox). +# +# Dois blocos: +# +# A) Caminhos de erro — NÃO gravam nada. Validam, contra respostas reais, o +# mapeamento de exceções do SDK: 401 -> AuthenticationError, +# 404 -> NotFoundError, 422 -> InvalidRequestError. Rodam sempre. +# +# B) Emissão de NF-e + idempotência — GRAVAM um documento de teste +# (environmentType: "Test"). Só rodam com a trava SMOKE_WRITE=1, para +# evitar emissão acidental. +# +# Pré-requisitos (samples/.env): +# NFE_API_KEY — chave principal +# NFE_DATA_API_KEY — chave de dados (opcional) +# NFE_COMPANY_ID — empresa de teste habilitada para NF-e (host api.nfse.io) +# +# Uso: +# ruby samples/smoke_write.rb # só os caminhos de erro +# SMOKE_WRITE=1 ruby samples/smoke_write.rb # + emissão de NF-e de teste +# +# Payload da NF-e: usa um exemplo embutido (mesmo de product_invoice_issue.rb). +# Para usar o seu, aponte NFE_NFE_PAYLOAD para um arquivo .json em camelCase. + +require_relative "config" +require "json" +require "securerandom" + +PASS = [] +FAIL = [] + +# Executa o bloco e considera OK se NÃO levantar erro. +def check(label) + result = yield + puts " \e[32m✓\e[0m #{label}" + puts " #{result}" if result && !result.to_s.empty? + PASS << label +rescue StandardError => e + puts " \e[31m✗\e[0m #{label}" + puts " #{e.class}: #{e.message.to_s[0, 200]}" + FAIL << label +end + +# Considera OK quando o bloco levanta EXATAMENTE a exceção esperada (ou uma +# subclasse). Qualquer outra exceção — ou nenhuma — é falha. +def expect_error(label, klass) + yield + puts " \e[31m✗\e[0m #{label}" + puts " não levantou erro algum (esperava #{klass})" + FAIL << label +rescue klass => e + detail = e.message.to_s.gsub(/\s+/, " ")[0, 160] + puts " \e[32m✓\e[0m #{label}" + puts " #{e.class}#{" — #{detail}" unless detail.empty?}" + PASS << label +rescue StandardError => e + puts " \e[31m✗\e[0m #{label}" + puts " esperava #{klass}, veio #{e.class}: #{e.message.to_s[0, 160]}" + FAIL << label +end + +def section(title) + puts + puts "\e[1m#{title}\e[0m" +end + +NFE_PAYLOAD = { + id: SecureRandom.uuid, + operationNature: "Venda de mercadoria", + environmentType: "Test", + buyer: { + type: "LegalEntity", + name: "Cliente Exemplo LTDA", + federalTaxNumber: "11222333000181", + email: "compras@cliente-exemplo.com.br", + address: { + country: "BRA", postalCode: "01310-100", street: "Avenida Paulista", + number: "1000", district: "Bela Vista", + city: { code: "3550308", name: "São Paulo" }, state: "SP" + } + }, + items: [ + { + code: "001", description: "Produto de exemplo", ncm: "84713012", + cfop: "5102", unit: "UN", quantity: 1.0, unitAmount: 100.0, totalAmount: 100.0 + } + ] +}.freeze + +def load_nfe_payload + path = ENV["NFE_NFE_PAYLOAD"].to_s.strip + return NFE_PAYLOAD if path.empty? + + JSON.parse(File.read(path), symbolize_names: true) +end + +puts "Smoke test de ESCRITA — sandbox — nfe-io #{Nfe::VERSION}" + +company = $company_id.to_s.strip +abort "\nDefina NFE_COMPANY_ID no samples/.env para rodar este smoke." if company.empty? + +# --------------------------------------------------------------------------- +# Bloco A — caminhos de erro (não gravam nada) +# --------------------------------------------------------------------------- +section "A) Caminhos de erro (sem escrita)" + +expect_error("401 chave inválida -> AuthenticationError", Nfe::AuthenticationError) do + bad = Nfe::Client.new(api_key: "chave-invalida-#{SecureRandom.hex(4)}", + data_api_key: "chave-invalida-#{SecureRandom.hex(4)}") + bad.product_invoices.list(company_id: company, environment: "Test") +end + +expect_error("404 invoice inexistente -> NotFoundError", Nfe::NotFoundError) do + $nfe.product_invoices.retrieve(company_id: company, invoice_id: "0" * 24) +end + +expect_error("422 payload inválido -> InvalidRequestError", Nfe::InvalidRequestError) do + $nfe.product_invoices.create(company_id: company, data: { environmentType: "Test" }) +end + +# --------------------------------------------------------------------------- +# Bloco B — emissão de NF-e + idempotência (GRAVA doc de teste) +# --------------------------------------------------------------------------- +section "B) Emissão de NF-e de teste (grava documento)" + +unless ENV["SMOKE_WRITE"] == "1" + puts " \e[33m–\e[0m pulado: defina SMOKE_WRITE=1 para emitir (grava NF-e de teste)." + puts + puts "Resumo: #{PASS.size} OK, #{FAIL.size} falha(s)" + exit(FAIL.empty? ? 0 : 1) +end + +issued_invoice_id = nil +idempotency_key = "smoke-#{SecureRandom.uuid}" + +check("create NF-e (environmentType: Test) -> Pending/Issued") do + result = $nfe.product_invoices.create( + company_id: company, data: load_nfe_payload, idempotency_key: idempotency_key + ) + if result.issued? + issued_invoice_id = result.resource.id + "Issued imediato: #{result.resource.id} (status #{result.resource.flow_status})" + else + issued_invoice_id = result.invoice_id + "Pending (202): invoice_id=#{result.invoice_id} location=#{result.location}" + end +end + +if issued_invoice_id + check("idempotency-key reusado -> mesma NF-e (sem duplicar)") do + again = $nfe.product_invoices.create( + company_id: company, data: load_nfe_payload, idempotency_key: idempotency_key + ) + repeated_id = again.issued? ? again.resource.id : again.invoice_id + same = repeated_id == issued_invoice_id + raise "id divergiu: #{repeated_id.inspect} != #{issued_invoice_id.inspect}" unless same + + "mesmo invoice_id=#{repeated_id}" + end + + check("retrieve + poll até estado terminal (máx ~60s)") do + final = nil + 20.times do + inv = $nfe.product_invoices.retrieve(company_id: company, invoice_id: issued_invoice_id) + final = inv.flow_status + break if Nfe::FlowStatus.terminal?(final) + + sleep 3 + end + "flow_status final=#{final.inspect}#{" (terminal)" if Nfe::FlowStatus.terminal?(final)}" + end + + check("download_pdf -> NfeFileResource (URI, não bytes)") do + res = $nfe.product_invoices.download_pdf(company_id: company, invoice_id: issued_invoice_id) + "uri=#{res.respond_to?(:uri) ? res.uri.inspect : res.inspect[0, 120]}" + end +end + +puts +puts "Resumo: #{PASS.size} OK, #{FAIL.size} falha(s)" +exit(FAIL.empty? ? 0 : 1) diff --git a/samples/tax_calculation.rb b/samples/tax_calculation.rb new file mode 100644 index 0000000..011f882 --- /dev/null +++ b/samples/tax_calculation.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Executa o motor de cálculo de impostos para um tenant sobre uma requisição +# com um ou mais itens. +# +# Pré-requisitos: +# * NFE_API_KEY — chave principal (a família :cte usa a chave principal) +# * NFE_TENANT_ID — identificador do tenant (passe como 1º argumento) +# +# Uso: +# ruby samples/tax_calculation.rb + +require_relative "config" + +tenant_id = ARGV[0] || ENV["NFE_TENANT_ID"] +abort "Informe o tenant_id: ruby samples/tax_calculation.rb " if tenant_id.nil? + +# A requisição é um Hash. Validação client-side (fail-fast, sem HTTP): +# precisa conter operation_type (ou operationType) e items (Array não vazio). +request = { + operationType: "Sale", + items: [ + { + code: "001", + description: "Produto de exemplo", + ncm: "84713012", + cfop: "5102", + quantity: 1.0, + unitAmount: 100.0, + totalAmount: 100.0, + origin: "0" + } + ] +} + +# calculate — (tenant_id, request) posicionais. +result = $nfe.tax_calculation.calculate(tenant_id, request) + +puts "Resposta do cálculo:" +puts result.inspect diff --git a/samples/webhook_verify.rb b/samples/webhook_verify.rb new file mode 100644 index 0000000..7ee1c8e --- /dev/null +++ b/samples/webhook_verify.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +# Verifica a assinatura de um webhook da NFE.io usando apenas a biblioteca +# padrão (sem frameworks). A NFE.io assina os BYTES EXATOS entregues +# (HMAC-SHA1, cabeçalho X-Hub-Signature) — leia o corpo bruto ANTES de +# parsear JSON e passe esses bytes. +# +# A assinatura prova autenticidade, NÃO atualidade (não há timestamp/nonce): +# handlers devem ser idempotentes e deduplicar pelo id do evento/nota. +# +# Pré-requisitos: +# * NFE_WEBHOOK_SECRET — segredo configurado no destino do webhook +# +# Uso (demonstração com um corpo de exemplo assinado localmente): +# ruby samples/webhook_verify.rb +# +# Em produção, dentro do seu handler HTTP (Rack/Sinatra/Rails): +# raw = request.body.read # BYTES BRUTOS, antes do JSON +# sig = request.get_header("HTTP_X_HUB_SIGNATURE") +# if Nfe::Webhook.verify_signature(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) +# event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: ENV["NFE_WEBHOOK_SECRET"]) +# # dedupe em event.id antes de processar event.type / event.data +# end + +require_relative "config" +require "openssl" + +secret = ENV["NFE_WEBHOOK_SECRET"] +abort "Defina NFE_WEBHOOK_SECRET." if secret.nil? || secret.strip.empty? + +# --- Demonstração: simula uma entrega assinando um corpo de exemplo. --- +# Em produção estes vêm da requisição HTTP, não são gerados aqui. +raw_payload = JSON.generate( + { + "id" => "evt_123", + "action" => "invoice.issued", + "payload" => { "id" => "inv_456", "flowStatus" => "Issued" } + } +) +signature = "sha1=" + OpenSSL::HMAC.hexdigest("SHA1", secret, raw_payload) + +# --- Verificação (nunca levanta exceção; retorna true/false). --- +valid = Nfe::Webhook.verify_signature(payload: raw_payload, signature: signature, secret: secret) +puts "Assinatura válida? #{valid}" + +unless valid + warn "Assinatura inválida — descarte a entrega." + exit 1 +end + +# construct_event verifica de novo e, se válido, devolve um WebhookEvent. +event = Nfe::Webhook.construct_event(payload: raw_payload, signature: signature, secret: secret) +puts "Evento: type=#{event.type} id=#{event.id}" +puts "Dados: #{event.data.inspect}" +puts "Lembre: deduplique por event.id (#{event.id}) — o handler deve ser idempotente." diff --git a/scripts/generate.rb b/scripts/generate.rb new file mode 100755 index 0000000..131ee08 --- /dev/null +++ b/scripts/generate.rb @@ -0,0 +1,85 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "optparse" +require_relative "generator/generator" +require_relative "generator/check_mode" + +# CLI entry point for the OpenAPI -> Ruby generator. Default writes generation; +# --check runs the sync guard (exit 1 on drift). Not shipped in the gem. +module Nfe + module Build + # Parses argv and runs the generator in write or check mode. + class CLI + ROOT = File.expand_path("..", __dir__) + + def self.run(argv) + new(argv).run + end + + def initialize(argv) + @options = { check: false, spec: nil, verbose: false } + parse(argv) + end + + def run + @options[:check] ? run_check : run_write + end + + private + + def parse(argv) + OptionParser.new do |o| + o.on("--check", "Verify checked-in output matches the specs") { @options[:check] = true } + o.on("--spec NAME", "Limit to a single spec basename") { |v| @options[:spec] = v } + o.on("--verbose", "Print warnings and skipped specs") { @options[:verbose] = true } + end.parse(argv) + end + + def generator + @generator ||= Generator.new(openapi_dir: File.join(ROOT, "openapi")) + end + + def lib_root + File.join(ROOT, "lib") + end + + def sig_root + File.join(ROOT, "sig") + end + + def run_write + written = generator.write_to(lib_root: lib_root, sig_root: sig_root) + report + puts "Generated #{written.length} files." + end + + def run_check + result = CheckMode.diff(generator: generator, lib_root: lib_root, sig_root: sig_root) + report + if result[:ok] + puts "Generated output is in sync." + exit 0 + end + print_drift(result) + exit 1 + end + + def print_drift(result) + puts "Generated output is OUT OF SYNC. Run `rake generate`." + %i[added removed changed].each do |key| + result[key].each { |path| puts " #{key}: #{path}" } + end + end + + def report + return unless @options[:verbose] + + generator.skipped.each { |s| warn "skipped (no schemas): #{s}" } + generator.warnings.uniq.each { |w| warn "warning: #{w}" } + end + end + end +end + +Nfe::Build::CLI.run(ARGV) if $PROGRAM_NAME == __FILE__ diff --git a/scripts/generator/check_mode.rb b/scripts/generator/check_mode.rb new file mode 100644 index 0000000..9795122 --- /dev/null +++ b/scripts/generator/check_mode.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require_relative "file_layout" + +module Nfe + module Build + # Compares the generator's in-memory output against checked-in files in + # both lib_root and sig_root. ok only when nothing is added/removed/changed. + module CheckMode + module_function + + GENERATED_AT = /^\s*generated_at:\s*.*$/ + + def diff(generator:, lib_root:, sig_root:) + expected = generator.generate + rels = (expected.keys + disk_rels(lib_root, sig_root)).uniq + on_disk = read_disk(rels, lib_root, sig_root) + + added = (expected.keys - on_disk.keys).sort + removed = (on_disk.keys - expected.keys).sort + changed = changed_files(expected, on_disk) + + { ok: added.empty? && removed.empty? && changed.empty?, added: added, removed: removed, changed: changed } + end + + # Relative paths (lib/.. or sig/..) of every committed generated file, so + # files on disk that the generator no longer emits surface as "removed". + def disk_rels(lib_root, sig_root) + rels = [] + rels << "#{FileLayout::LIB_PREFIX}.rb" + FileLayout.generated_dirs(lib_root, sig_root).each do |dir| + root = dir.start_with?(sig_root) ? sig_root : lib_root + prefix = dir.start_with?(sig_root) ? "sig" : "lib" + Dir.glob(File.join(dir, "**", "*.{rb,rbs}")).each do |path| + rels << "#{prefix}/#{path.delete_prefix("#{root}/")}" + end + end + rels + end + + def read_disk(rels, lib_root, sig_root) + result = {} + rels.each do |rel| + path = FileLayout.absolute_path(rel, lib_root, sig_root) + result[rel] = File.read(path) if File.exist?(path) + end + result + end + + def changed_files(expected, on_disk) + (expected.keys & on_disk.keys).reject do |rel| + normalize(rel, expected[rel]) == normalize(rel, on_disk[rel]) + end.sort + end + + # The marker's generated_at line is normalized so it never causes drift. + def normalize(rel, contents) + return contents unless rel.end_with?("generated_marker.rb") + + contents.gsub(GENERATED_AT, " generated_at: nil,") + end + end + end +end diff --git a/scripts/generator/enum_compiler.rb b/scripts/generator/enum_compiler.rb new file mode 100644 index 0000000..383ae2d --- /dev/null +++ b/scripts/generator/enum_compiler.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require_relative "name_mapper" + +module Nfe + module Build + # Compiles an OpenAPI schema declaring "enum: [...]" into an :enum model + # (frozen-constant module). Returns nil when the schema has no enum key. + class EnumCompiler + def initialize(name_mapper: NameMapper) + @name_mapper = name_mapper + end + + def compile(schema_name, schema, namespace:, module_path:, source_spec:, spec_hash:) + return nil unless schema.is_a?(Hash) + + values = schema["enum"] + return nil unless values.is_a?(Array) && !values.empty? + + backing = backing_for(values) + { + kind: :enum, + const: @name_mapper.class_name(schema_name), + namespace: namespace, + module_path: module_path, + file_snake: @name_mapper.file_snake(schema_name), + source_spec: source_spec, + spec_hash: spec_hash, + backing: backing, + entries: entries_for(values, backing) + } + end + + private + + def backing_for(values) + values.all?(Integer) ? :integer : :string + end + + def entries_for(values, backing) + seen = {} + values.map do |value| + base = constant_base(value, backing) + name = dedupe(base, seen) + { const_name: name, value: value } + end + end + + def constant_base(value, backing) + return integer_const(value) if backing == :integer + + string_const(value) + end + + def integer_const(value) + value.negative? ? "Value_#{value.abs}" : "Value#{value}" + end + + def string_const(value) + token = value.to_s.gsub(/[^A-Za-z0-9]+/, " ").strip + return "Value" if token.empty? + + const = token.split(/\s+/).map { |w| w[0].upcase + w[1..].to_s }.join + const = "_#{const}" if const.match?(/\A[0-9]/) + const + end + + def dedupe(base, seen) + seen[base] = (seen[base] || 0) + 1 + seen[base] == 1 ? base : "#{base}_#{seen[base]}" + end + end + end +end diff --git a/scripts/generator/file_layout.rb b/scripts/generator/file_layout.rb new file mode 100644 index 0000000..8e9cd1c --- /dev/null +++ b/scripts/generator/file_layout.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require "fileutils" + +module Nfe + module Build + # Maps relative generated paths to absolute paths under lib_root/sig_root, + # writes files, and prunes stale generated files. Shared by Generator and + # CheckMode so the path convention lives in one place. + module FileLayout + LIB_PREFIX = "lib/nfe/generated" + SIG_PREFIX = "sig/nfe/generated" + + module_function + + def absolute_path(rel, lib_root, sig_root) + if rel.start_with?("#{SIG_PREFIX}/") + File.join(sig_root, rel.sub(%r{\Asig/}, "")) + else + File.join(lib_root, rel.sub(%r{\Alib/}, "")) + end + end + + def write_file(rel, contents, lib_root, sig_root) + path = absolute_path(rel, lib_root, sig_root) + FileUtils.mkdir_p(File.dirname(path)) + File.write(path, contents) + path + end + + def prune_stale(current_rels, lib_root, sig_root) + keep = current_rels.to_set { |rel| absolute_path(rel, lib_root, sig_root) } + generated_dirs(lib_root, sig_root).each do |dir| + next unless Dir.exist?(dir) + + Dir.glob(File.join(dir, "**", "*.{rb,rbs}")).each do |path| + File.delete(path) unless keep.include?(path) + end + end + end + + def generated_dirs(lib_root, sig_root) + [File.join(lib_root, "nfe/generated"), File.join(sig_root, "nfe/generated")] + end + end + end +end diff --git a/scripts/generator/generator.rb b/scripts/generator/generator.rb new file mode 100644 index 0000000..6cd2e8a --- /dev/null +++ b/scripts/generator/generator.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +require_relative "file_layout" +require_relative "spec_loader" +require_relative "name_mapper" +require_relative "type_mapper" +require_relative "schema_compiler" +require_relative "enum_compiler" +require_relative "ruby_emitter" +require_relative "rbs_emitter" + +module Nfe + module Build + # Orchestrates discovery -> load -> compile -> emit across all specs in + # openapi_dir, producing the full in-memory file map and writing it out. + class Generator + LIB_PREFIX = FileLayout::LIB_PREFIX + SIG_PREFIX = FileLayout::SIG_PREFIX + + def initialize(openapi_dir:, name_mapper: NameMapper) + @openapi_dir = openapi_dir.to_s + @name_mapper = name_mapper + @warnings = [] + @skipped = [] + end + + attr_reader :warnings, :skipped + + # relative path => contents, covering .rb + .rbs + loader + marker. + def generate + models = compile_all + files = {} + models.each { |m| emit_model(m, files) } + files["#{LIB_PREFIX}.rb"] = loader_file(models) + files["#{LIB_PREFIX}/generated_marker.rb"] = marker_file + files.sort.to_h + end + + def write_to(lib_root:, sig_root:) + files = generate + written = files.map { |rel, contents| FileLayout.write_file(rel, contents, lib_root, sig_root) } + FileLayout.prune_stale(files.keys, lib_root, sig_root) + written.sort + end + + def spec_loaders + @spec_loaders ||= spec_paths.map { |path| SpecLoader.new(path) } + end + + private + + def spec_paths + Dir.glob(File.join(@openapi_dir, "*.{yaml,json}")) + end + + def compile_all + spec_loaders.flat_map { |loader| compile_spec(loader) }.sort_by { |m| [m[:module_path], m[:file_snake]] } + end + + def compile_spec(loader) + schemas = loader.schemas + if schemas.empty? + @skipped << loader.basename + return [] + end + + context = context_for(loader, schemas) + schemas.sort.flat_map { |name, schema| compile_schema(name, schema, context) } + end + + def context_for(loader, schemas) + type_mapper = TypeMapper.new(schema_names: schemas.keys, schemas: schemas) + { + type_mapper: type_mapper, + schema_compiler: SchemaCompiler.new(name_mapper: @name_mapper, type_mapper: type_mapper), + enum_compiler: EnumCompiler.new(name_mapper: @name_mapper), + namespace: @name_mapper.namespace_from_spec(loader.basename), + module_path: @name_mapper.module_path_from_spec(loader.basename), + source_spec: "openapi/#{loader.basename}", + spec_hash: loader.hash + } + end + + def compile_schema(name, schema, context) + kwargs = { + namespace: context[:namespace], module_path: context[:module_path], + source_spec: context[:source_spec], spec_hash: context[:spec_hash] + } + model = context[:enum_compiler].compile(name, schema, **kwargs) || + context[:schema_compiler].compile(name, schema, **kwargs) + @warnings.concat(context[:type_mapper].warnings) + model ? [model] : [] + end + + def emit_model(model, files) + rel = "#{model[:module_path]}/#{model[:file_snake]}" + files["#{LIB_PREFIX}/#{rel}.rb"] = RubyEmitter.emit(model) + files["#{SIG_PREFIX}/#{rel}.rbs"] = RbsEmitter.emit(model) + end + + def loader_file(models) + requires = models.map do |m| + "require_relative \"generated/#{m[:module_path]}/#{m[:file_snake]}\"" + end.sort.uniq + lines = ["# frozen_string_literal: true", "# AUTO-GENERATED — do not edit", "", + "require_relative \"generated/generated_marker\""] + lines.concat(requires) + "#{lines.join("\n")}\n" + end + + def marker_file + specs = spec_loaders.reject { |l| l.schemas.empty? } + .sort_by(&:basename) + .map { |l| " #{l.basename.inspect} => #{l.hash.inspect}" } + lines = ["# frozen_string_literal: true", "# AUTO-GENERATED — do not edit", "", + "module Nfe", " module Generated", " MARKER = {", " generated_at: nil,"] + lines << " specs: {" + lines << specs.join(",\n") + lines.push(" }", " }.freeze", " end", "end") + "#{lines.join("\n")}\n" + end + end + end +end diff --git a/scripts/generator/name_mapper.rb b/scripts/generator/name_mapper.rb new file mode 100644 index 0000000..d9d4332 --- /dev/null +++ b/scripts/generator/name_mapper.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +module Nfe + module Build + # Pure, deterministic name derivation: spec filenames -> namespaces/paths, + # schema names -> Ruby constants/filenames, property names -> attr names. + # + # All methods are module_function (call as Nfe::Build::NameMapper.x(...)). + module NameMapper + module_function + + RUBY_KEYWORDS = %w[ + BEGIN END alias and begin break case class def defined? do else elsif + end ensure false for if in module next nil not or redo rescue retry + return self super then true undef unless until when while yield __FILE__ + __LINE__ __ENCODING__ + ].freeze + + # "service-invoice-rtc-v1.yaml" => "ServiceInvoiceRtcV1" + def namespace_from_spec(filename) + stem(filename).split(/[-_.]+/).reject(&:empty?).map { |part| pascal_segment(part) }.join + end + + # "service-invoice-rtc-v1.yaml" => "service_invoice_rtc_v1" + def module_path_from_spec(filename) + stem(filename).split(/[-_.]+/).reject(&:empty?).join("_").downcase + end + + # Schema name => a valid Ruby/RBS constant. "NFSeRequest" stays as-is; + # a camelCase name like "ibsCbs" is capitalised to "IbsCbs"; a name that + # does not start with a letter is prefixed with "N" so the result is always + # a legal constant (Ruby constants must begin with an uppercase letter). + def class_name(schema_name) + const = schema_name.to_s.gsub(/[^A-Za-z0-9_]/, "_") + const = "N#{const}" unless const.match?(/\A[A-Za-z]/) + const.sub(/\A[a-z]/, &:upcase) + end + + # "NFSeRequest" => "nfse_request" (snake_case filename for the const). + def file_snake(schema_name) + snake(class_name(schema_name)) + end + + # "federalTaxNumber" => "federal_tax_number" (valid Ruby identifier). + def attr_name(property_name) + name = snake(property_name.to_s.gsub(/[^A-Za-z0-9_]/, "_")) + name = "_#{name}" if name.match?(/\A[0-9]/) + name = "attr" if name.empty? + name = "#{name}_" if RUBY_KEYWORDS.include?(name) + name + end + + def stem(filename) + File.basename(filename.to_s, ".*") + end + + # Pascal-case a single token, preserving version suffix ("v1" => "V1"). + def pascal_segment(part) + return part.upcase if part.match?(/\A[a-z]\d+\z/) + + part[0].upcase + part[1..] + end + + # CamelCase/PascalCase -> snake_case. Only a lowercase/digit -> uppercase + # boundary inserts an underscore, so an acronym run glues to the word it + # leads ("NFSeRequest" -> "nfse_request", "federalTaxNumber" -> + # "federal_tax_number"). + def snake(identifier) + identifier.to_s + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .tr("-", "_") + .downcase + end + end + end +end diff --git a/scripts/generator/rbs_emitter.rb b/scripts/generator/rbs_emitter.rb new file mode 100644 index 0000000..bff43e7 --- /dev/null +++ b/scripts/generator/rbs_emitter.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module Nfe + module Build + # Renders an internal model to .rbs signature contents mirroring the .rb. + # Output must pass `rbs validate`. + module RbsEmitter + module_function + + def emit(model) + case model[:kind] + when :data then emit_data(model) + when :enum then emit_enum(model) + when :alias then emit_alias(model) + else + raise ArgumentError, "Unknown model kind: #{model[:kind].inspect}" + end + end + + def banner(model) + [ + "# AUTO-GENERATED — do not edit", + "# Source: #{model[:source_spec]}", + "# Hash: #{model[:spec_hash]}" + ].join("\n") + end + + def emit_data(model) + body = ["#{banner(model)}\n", "module Nfe", " module Generated", " module #{model[:namespace]}", + " class #{model[:const]} < Data"] + model[:attributes].each { |a| body << " attr_reader #{a[:ruby_name]}: #{a[:rbs_type]}" } + body << new_signature(model, "self.new", "instance") + body << new_signature(model, "initialize", "void") + body << " def self.from_api: (Hash[String, untyped]? payload) -> instance?" + body.push(" end", " end", " end", "end") + "#{body.join("\n")}\n" + end + + def new_signature(model, method, return_type) + params = model[:attributes].map do |attr| + prefix = attr[:required] ? "" : "?" + "#{prefix}#{attr[:ruby_name]}: #{attr[:rbs_type]}" + end.join(", ") + " def #{method}: (#{params}) -> #{return_type}" + end + + def emit_enum(model) + body = ["#{banner(model)}\n", "module Nfe", " module Generated", " module #{model[:namespace]}", + " module #{model[:const]}"] + literal = model[:backing] == :integer ? "Integer" : "String" + model[:entries].each { |e| body << " #{e[:const_name]}: #{literal}" } + body << " ALL: Array[#{literal}]" + body.push(" end", " end", " end", "end") + "#{body.join("\n")}\n" + end + + def emit_alias(model) + body = [ + "#{banner(model)}\n", + "module Nfe", + " module Generated", + " module #{model[:namespace]}", + " #{model[:const]}: Hash[String, untyped]", + " end", + " end", + "end" + ] + "#{body.join("\n")}\n" + end + end + end +end diff --git a/scripts/generator/ruby_emitter.rb b/scripts/generator/ruby_emitter.rb new file mode 100644 index 0000000..52617e1 --- /dev/null +++ b/scripts/generator/ruby_emitter.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +module Nfe + module Build + # Renders an internal model (:data / :enum / :alias) to .rb file contents. + # Deterministic indentation and ordering; from_api is the only method on + # data value objects. + module RubyEmitter + module_function + + def emit(model) + case model[:kind] + when :data then emit_data(model) + when :enum then emit_enum(model) + when :alias then emit_alias(model) + else + raise ArgumentError, "Unknown model kind: #{model[:kind].inspect}" + end + end + + def banner(model) + [ + "# frozen_string_literal: true", + "# AUTO-GENERATED — do not edit", + "# Source: #{model[:source_spec]}", + "# Hash: #{model[:spec_hash]}" + ].join("\n") + end + + def emit_data(model) + body = [ + "#{banner(model)}\n", + "module Nfe", + " module Generated", + " module #{model[:namespace]}", + data_define(model), + " end", + " end", + "end" + ] + "#{body.join("\n")}\n" + end + + def data_define(model) + members = model[:attributes].map { |a| ":#{a[:ruby_name]}" }.join(", ") + [ + " #{model[:const]} = Data.define(#{members}) do", + from_api_method(model), + " end" + ].join("\n") + end + + def from_api_method(model) + lines = [" def self.from_api(payload)", " return nil if payload.nil?", "", " new("] + model[:attributes].each { |attr| lines << " #{attr[:ruby_name]}: #{from_api_value(attr)}," } + lines << " )" + lines << " end" + lines.join("\n") + end + + def from_api_value(attr) + key = attr[:original_name].inspect + if attr[:ref_target] + "#{attr[:ref_target]}.from_api(payload[#{key}])" + elsif attr[:array_ref_target] + "(payload[#{key}] || []).map { |e| #{attr[:array_ref_target]}.from_api(e) }" + else + "payload[#{key}]" + end + end + + def emit_enum(model) + body = ["#{banner(model)}\n", "module Nfe", " module Generated", " module #{model[:namespace]}", + " module #{model[:const]}"] + model[:entries].each { |e| body << " #{e[:const_name]} = #{enum_literal(e[:value], model[:backing])}" } + body << " ALL = [#{model[:entries].map { |e| e[:const_name] }.join(', ')}].freeze" + body.push(" end", " end", " end", "end") + "#{body.join("\n")}\n" + end + + def enum_literal(value, backing) + backing == :integer ? value.to_s : value.to_s.inspect + end + + def emit_alias(model) + body = [ + "#{banner(model)}\n", + "module Nfe", + " module Generated", + " module #{model[:namespace]}", + " # free-form object: #{model[:rbs_type]}", + " #{model[:const]} = Hash", + " end", + " end", + "end" + ] + "#{body.join("\n")}\n" + end + end + end +end diff --git a/scripts/generator/schema_compiler.rb b/scripts/generator/schema_compiler.rb new file mode 100644 index 0000000..3ab9022 --- /dev/null +++ b/scripts/generator/schema_compiler.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require_relative "name_mapper" + +module Nfe + module Build + # Compiles an OpenAPI object schema into an internal :data or :alias model. + # Object-with-named-properties -> :data; additionalProperties-only / no + # named properties -> :alias (Hash[String, untyped]). allOf shallow-merges. + class SchemaCompiler + def initialize(type_mapper:, name_mapper: NameMapper) + @name_mapper = name_mapper + @type_mapper = type_mapper + end + + def compile(schema_name, schema, namespace:, module_path:, source_spec:, spec_hash:) + return nil unless schema.is_a?(Hash) + + properties, required = resolve_properties(schema) + meta = meta_for(schema_name, namespace, module_path, source_spec, spec_hash) + + return data_model(meta, properties, required) unless properties.empty? + return alias_model(meta) if free_form_object?(schema) + + nil # bare primitive / array / typeless top-level schema -> no generated file + end + + private + + def meta_for(schema_name, namespace, module_path, source_spec, spec_hash) + { + const: @name_mapper.class_name(schema_name), + namespace: namespace, + module_path: module_path, + file_snake: @name_mapper.file_snake(schema_name), + source_spec: source_spec, + spec_hash: spec_hash + } + end + + def data_model(meta, properties, required) + attributes = properties.sort_by(&:first).map do |name, fragment| + build_attr(name, fragment, required.include?(name)) + end + meta.merge(kind: :data, attributes: attributes) + end + + def alias_model(meta) + meta.merge(kind: :alias, rbs_type: "Hash[String, untyped]") + end + + # A no-named-properties schema that is still an object (free-form / + # additionalProperties) is modelled as Hash. Bare primitives/arrays are + # NOT free-form objects, so the compiler returns nil (no file) for them. + def free_form_object?(schema) + schema["type"] == "object" || schema.key?("additionalProperties") + end + + # Flattens allOf into a single (properties, required) pair. Last member + # wins on property collision (warn-worthy); required is the union. + def resolve_properties(schema) + members = schema.key?("allOf") ? Array(schema["allOf"]) : [schema] + properties = {} + required = [] + members.each do |member| + next unless member.is_a?(Hash) + + properties.merge!(member["properties"]) if member["properties"].is_a?(Hash) + required.concat(Array(member["required"])) + end + [properties, required.uniq] + end + + def build_attr(original_name, fragment, required) + fragment = {} unless fragment.is_a?(Hash) + nullable = fragment["nullable"] == true + { + ruby_name: @name_mapper.attr_name(original_name), + original_name: original_name, + rbs_type: @type_mapper.rbs_type(fragment), + nullable: nullable, + required: required && !nullable, + ref_target: @type_mapper.ref_target(fragment), + array_ref_target: @type_mapper.array_ref_target(fragment), + doc: fragment["description"] + } + end + end + end +end diff --git a/scripts/generator/spec_loader.rb b/scripts/generator/spec_loader.rb new file mode 100644 index 0000000..3301a80 --- /dev/null +++ b/scripts/generator/spec_loader.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require "psych" +require "digest" + +module Nfe + module Build + # Raised when the generator cannot proceed (broken spec, invalid shape, etc.). + class Error < StandardError; end + + # Loads and validates a single OpenAPI/Swagger spec file (YAML or JSON). + # + # Psych parses both YAML and JSON (JSON is valid YAML), so one loader path + # covers ".yaml" and ".json". The raw file bytes are SHA-256 hashed for the + # AUTO-GENERATED banner and sync guard. + class SpecLoader + def initialize(path) + @path = path.to_s + @raw = read_raw + @document = parse + validate! + end + + attr_reader :path + + def basename + File.basename(@path) + end + + def hash + "sha256:#{Digest::SHA256.hexdigest(@raw)}" + end + + # The components.schemas map. Returns {} when absent (does NOT raise). + def schemas + components = @document["components"] + return {} unless components.is_a?(Hash) + + schemas = components["schemas"] + schemas.is_a?(Hash) ? schemas : {} + end + + private + + def read_raw + File.binread(@path) + rescue SystemCallError => e + raise Error, "Cannot read spec #{@path}: #{e.message}" + end + + def parse + Psych.safe_load(@raw, aliases: true) + rescue Psych::Exception => e + raise Error, "Cannot parse spec #{@path}: #{e.message}" + end + + def validate! + raise Error, "Spec root is not a Hash: #{@path}" unless @document.is_a?(Hash) + return if @document.key?("openapi") || @document.key?("swagger") + + raise Error, "Spec #{@path} lacks an \"openapi\"/\"swagger\" version key" + end + end + end +end diff --git a/scripts/generator/type_mapper.rb b/scripts/generator/type_mapper.rb new file mode 100644 index 0000000..1905b51 --- /dev/null +++ b/scripts/generator/type_mapper.rb @@ -0,0 +1,152 @@ +# frozen_string_literal: true + +require_relative "name_mapper" + +module Nfe + module Build + # Maps an OpenAPI schema fragment to an RBS type string. Conservative: + # ambiguous/complex constructs fall back to "untyped" rather than fail. + class TypeMapper + PRIMITIVES = { + "string" => "String", + "integer" => "Integer", + "number" => "Float", + "boolean" => "bool" + }.freeze + + LOCAL_REF = %r{\A#/components/schemas/(.+)\z} + + def initialize(schema_names:, schemas: {}) + @schema_names = schema_names.to_a.to_set { |n| NameMapper.class_name(n) } + @schemas = schemas + @warnings = [] + end + + attr_reader :warnings + + def rbs_type(fragment) + return "untyped" unless fragment.is_a?(Hash) + + base = base_rbs_type(fragment) + nullable?(fragment) ? nullable(base) : base + end + + # Referenced class name when fragment is a local $ref to a known schema. + def ref_target(fragment) + return nil unless fragment.is_a?(Hash) + + ref = fragment["$ref"] + return nil unless ref.is_a?(String) + + match = LOCAL_REF.match(ref) + return nil unless match + + const = NameMapper.class_name(match[1]) + return nil unless @schema_names.include?(const) + + target = @schemas[match[1]] + return const if target.nil? # no schema map (unit tests): assume a generated class + + data_class?(target) ? const : nil + end + + # Item class name when fragment is an array whose items is a known $ref. + def array_ref_target(fragment) + return nil unless fragment.is_a?(Hash) && fragment["type"] == "array" + + ref_target(fragment["items"]) + end + + private + + def base_rbs_type(fragment) + return ref_rbs(fragment) if fragment.key?("$ref") + return one_of_rbs(fragment) if fragment.key?("oneOf") || fragment.key?("anyOf") + return "untyped" if fragment.key?("allOf") + + type = fragment["type"] + return array_rbs(fragment) if type == "array" + return object_rbs(fragment) if type == "object" + return PRIMITIVES[type] if PRIMITIVES.key?(type) + + "untyped" + end + + def ref_rbs(fragment) + ref = fragment["$ref"] + match = LOCAL_REF.match(ref.to_s) + unless match + warn("cross-file or unresolved $ref: #{ref.inspect}") + return "untyped" + end + + resolve_ref_type(match[1]) + end + + # Resolve a local $ref to the RBS type the target schema actually compiles + # to: a Data class for object schemas, the primitive for bare primitives, + # Hash for free-form objects, and untyped for enums / unknowns. + def resolve_ref_type(name) + const = NameMapper.class_name(name) + target = @schemas[name] + if target.is_a?(Hash) + return const if data_class?(target) + return "untyped" if target.key?("enum") || target.key?("$ref") + + return rbs_type(target) + end + return const if @schema_names.include?(const) + + warn("unknown local $ref: ##{name}") + "untyped" + end + + # A schema that compiles to a generated Data class (object with named + # properties, or an allOf composition) — distinct from enums, free-form + # objects (Hash), and bare primitives. + def data_class?(schema) + return false unless schema.is_a?(Hash) + return false if schema.key?("enum") + + props = schema["properties"] + (props.is_a?(Hash) && !props.empty?) || schema.key?("allOf") + end + + def array_rbs(fragment) + items = fragment["items"] + return "Array[untyped]" unless items.is_a?(Hash) + + "Array[#{rbs_type(items)}]" + end + + def object_rbs(_fragment) + "Hash[String, untyped]" + end + + def one_of_rbs(fragment) + members = fragment["oneOf"] || fragment["anyOf"] + return "untyped" unless members.is_a?(Array) && !members.empty? + + return "untyped" unless members.all? { |m| primitive_member?(m) } + + members.map { |m| PRIMITIVES[m["type"]] }.uniq.join(" | ") + end + + def primitive_member?(member) + member.is_a?(Hash) && PRIMITIVES.key?(member["type"]) + end + + def nullable?(fragment) + fragment["nullable"] == true + end + + def nullable(base) + base.end_with?("?") || base == "untyped" ? base : "#{base}?" + end + + def warn(message) + @warnings << message + end + end + end +end diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..d0783a1 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,312 @@ +#!/usr/bin/env bash +# +# release.sh — preparação de release do gem nfe-io (uso do mantenedor). +# +# Faz apenas a PREPARAÇÃO local de um release: bump de versão, rotação do +# CHANGELOG, commit, tag anotada e push. A PUBLICAÇÃO no RubyGems acontece no +# workflow .github/workflows/release.yml, disparado pelo push da tag (via OIDC). +# Este script NUNCA executa `gem push`. +# +# Forma das versões: +# - tag git: forma com HÍFEN -> vX.Y.Z, vX.Y.Z-rc.N, vX.Y.Z-beta.N +# - Nfe::VERSION / gem: forma com PONTO -> X.Y.Z, X.Y.Z.rc.N (exigido pelo RubyGems) +# +# Uso: +# scripts/release.sh [--dry-run] [--skip-tests] [--skip-git] [--help] +# +set -euo pipefail + +# --- Cores ------------------------------------------------------------------ +if [[ -t 1 ]]; then + C_RESET=$'\033[0m' + C_BOLD=$'\033[1m' + C_RED=$'\033[31m' + C_GREEN=$'\033[32m' + C_YELLOW=$'\033[33m' + C_BLUE=$'\033[34m' + C_DIM=$'\033[2m' +else + C_RESET="" C_BOLD="" C_RED="" C_GREEN="" C_YELLOW="" C_BLUE="" C_DIM="" +fi + +info() { printf '%s==>%s %s\n' "$C_BLUE" "$C_RESET" "$*"; } +ok() { printf '%s ✓ %s %s\n' "$C_GREEN" "$C_RESET" "$*"; } +warn() { printf '%s ! %s %s\n' "$C_YELLOW" "$C_RESET" "$*" >&2; } +err() { printf '%s ✗ %s %s\n' "$C_RED" "$C_RESET" "$*" >&2; } +dry() { printf '%s[dry-run]%s %s\n' "$C_DIM" "$C_RESET" "$*"; } +die() { err "$*"; exit 1; } + +# --- Localização ------------------------------------------------------------ +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +VERSION_FILE="$REPO_ROOT/lib/nfe/version.rb" +CHANGELOG_FILE="$REPO_ROOT/CHANGELOG.md" + +# --- Flags ------------------------------------------------------------------ +DRY_RUN=0 +SKIP_TESTS=0 +SKIP_GIT=0 + +usage() { + cat < [X.Y.Z] - data). + 6. Roda o gate local (a menos que --skip-tests). + 7. Commita chore(release): vX.Y.Z, cria tag anotada vX.Y.Z e dá push. + +${C_BOLD}NÃO FAZ${C_RESET} + - Nunca executa 'gem push'. A publicação no RubyGems acontece no workflow + release.yml após o push da tag (trusted publishing via OIDC). +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --dry-run) DRY_RUN=1 ;; + --skip-tests) SKIP_TESTS=1 ;; + --skip-git) SKIP_GIT=1 ;; + -h|--help) usage; exit 0 ;; + *) err "Opção desconhecida: $1"; echo; usage; exit 2 ;; + esac + shift +done + +cd "$REPO_ROOT" + +# --- Helpers ---------------------------------------------------------------- + +# Converte a forma de tag (hífen) para a forma de gem (ponto): +# 1.0.0 -> 1.0.0 +# 1.0.0-rc.1 -> 1.0.0.rc.1 +# 1.2.3-beta.4 -> 1.2.3.beta.4 +to_dotted() { printf '%s\n' "${1/-/.}"; } + +# Extrai a seção de notas do CHANGELOG para a versão informada (forma pontilhada), +# do cabeçalho "## [X.Y.Z]" até o próximo "## " (exclusivo). Stdout. +changelog_notes() { + local ver="$1" + awk -v ver="$ver" ' + $0 ~ "^## \\[" ver "\\]" { capture = 1; next } + capture && /^## / { exit } + capture { print } + ' "$CHANGELOG_FILE" +} + +# --- Pre-flight ------------------------------------------------------------- +info "Pre-flight" + +for tool in git ruby bundle; do + command -v "$tool" >/dev/null 2>&1 || die "Ferramenta obrigatória ausente no PATH: $tool" +done +ok "ferramentas presentes: git, ruby, bundle" + +# gh só é obrigatório quando vamos checar o CI (ou seja, quando não pulamos o git). +HAVE_GH=0 +if command -v gh >/dev/null 2>&1; then + HAVE_GH=1 +fi + +[[ -f "$VERSION_FILE" ]] || die "Arquivo de versão não encontrado: $VERSION_FILE" +[[ -f "$CHANGELOG_FILE" ]] || die "CHANGELOG não encontrado: $CHANGELOG_FILE" + +CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)" +if [[ "$CURRENT_BRANCH" != "master" ]]; then + if [[ $SKIP_GIT -eq 1 ]]; then + warn "branch atual é '$CURRENT_BRANCH' (não master); --skip-git ativo, prosseguindo." + else + die "Releases são cortados a partir de 'master' (branch atual: '$CURRENT_BRANCH')." + fi +else + ok "na branch master" +fi + +if [[ $SKIP_GIT -eq 0 ]]; then + if [[ -n "$(git status --porcelain)" ]]; then + die "Working tree sujo. Commite ou descarte as mudanças antes de cortar o release (ou use --skip-git)." + fi + ok "working tree limpo" + + if [[ $HAVE_GH -eq 1 ]]; then + CI_CONCLUSION="$(gh run list --branch master --limit 1 --json conclusion --jq '.[0].conclusion' 2>/dev/null || true)" + case "$CI_CONCLUSION" in + success) + ok "último CI em master: success" ;; + "" | null) + warn "não foi possível determinar o status do último CI em master; prosseguindo com cautela." ;; + *) + die "Último CI em master não passou (conclusion='$CI_CONCLUSION'). Corrija antes de cortar o release." ;; + esac + else + warn "gh não encontrado; pulando a verificação do CI em master." + fi +else + warn "--skip-git ativo: pulando checagem de working tree e CI." +fi + +# --- Versão ----------------------------------------------------------------- +echo +CURRENT_VERSION="$(ruby -r "$VERSION_FILE" -e 'print Nfe::VERSION' 2>/dev/null || true)" +[[ -n "$CURRENT_VERSION" ]] && info "Versão atual (Nfe::VERSION): ${C_BOLD}${CURRENT_VERSION}${C_RESET}" + +VERSION_REGEX='^[0-9]+\.[0-9]+\.[0-9]+(-(rc|beta)\.[0-9]+)?$' +VERSION="" +if [[ $DRY_RUN -eq 1 ]] && [[ ! -t 0 ]]; then + # Em dry-run não-interativo, use um placeholder explícito para conseguir + # imprimir todos os passos sem travar num prompt. + VERSION="${RELEASE_VERSION:-1.0.0-rc.1}" + dry "usando versão de exemplo para o ensaio: $VERSION (defina RELEASE_VERSION para mudar)" +else + read -rp "Versão a lançar (ex.: 1.0.0, 1.0.0-rc.1, 1.0.0-beta.2): " VERSION +fi + +[[ "$VERSION" =~ $VERSION_REGEX ]] || die "Versão inválida: '$VERSION'. Esperado X.Y.Z, X.Y.Z-rc.N ou X.Y.Z-beta.N." + +TAG="v$VERSION" # forma com hífen (git tag) +DOTTED_VERSION="$(to_dotted "$VERSION")" # forma com ponto (Nfe::VERSION / gem) + +IS_PRERELEASE=0 +[[ "$VERSION" == *-* ]] && IS_PRERELEASE=1 + +ok "versão validada: tag=${C_BOLD}${TAG}${C_RESET} gem=${C_BOLD}${DOTTED_VERSION}${C_RESET} prerelease=${IS_PRERELEASE}" + +# Recusa se a tag já existir (local ou remota). +if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null 2>&1; then + die "A tag '$TAG' já existe localmente. Aborte (delete a tag se for um retag intencional)." +fi +if [[ $SKIP_GIT -eq 0 ]] && git ls-remote --exit-code --tags origin "refs/tags/$TAG" >/dev/null 2>&1; then + die "A tag '$TAG' já existe em origin. Aborte." +fi +ok "tag '$TAG' está livre" + +DATE="$(date +%F)" + +# --- Atualizar lib/nfe/version.rb ------------------------------------------- +echo +info "Atualizando Nfe::VERSION -> \"$DOTTED_VERSION\" (forma pontilhada)" +if [[ $DRY_RUN -eq 1 ]]; then + dry "escreveria VERSION = \"$DOTTED_VERSION\" em $VERSION_FILE" +else + # Substitui o literal entre aspas após VERSION =, preservando o resto do arquivo. + ruby -e ' + file, ver = ARGV + src = File.read(file) + updated = src.sub(/VERSION\s*=\s*"[^"]*"/, %(VERSION = "#{ver}")) + abort("não encontrei a constante VERSION em #{file}") if updated == src + File.write(file, updated) + ' "$VERSION_FILE" "$DOTTED_VERSION" + # Confirma que o Ruby lê exatamente o valor esperado. + WRITTEN="$(ruby -r "$VERSION_FILE" -e 'print Nfe::VERSION')" + [[ "$WRITTEN" == "$DOTTED_VERSION" ]] || die "Falha ao escrever a versão: Nfe::VERSION='$WRITTEN' != '$DOTTED_VERSION'" + ok "Nfe::VERSION = \"$WRITTEN\"" +fi + +# --- Rotacionar CHANGELOG --------------------------------------------------- +echo +info "Rotacionando CHANGELOG: [Não lançado] -> [$DOTTED_VERSION] - $DATE" +if [[ $DRY_RUN -eq 1 ]]; then + dry "renomearia o cabeçalho de 'não lançado' para '## [$DOTTED_VERSION] - $DATE' e abriria uma nova seção vazia" +else + ruby -e ' + file, ver, date = ARGV + src = File.read(file) + # Aceita o marcador canônico em pt-BR e o legado em inglês. + header_re = /^## \[(Não lançado|Nao lancado|Unreleased)\]\s*$/ + abort("não encontrei o cabeçalho de não-lançado em #{file}") unless src =~ header_re + new_unreleased = "## [Não lançado]\n\n## [#{ver}] - #{date}" + src = src.sub(header_re, new_unreleased) + File.write(file, src) + ' "$CHANGELOG_FILE" "$DOTTED_VERSION" "$DATE" + ok "CHANGELOG rotacionado" +fi + +# --- Gate local ------------------------------------------------------------- +echo +if [[ $SKIP_TESTS -eq 1 ]]; then + warn "--skip-tests ativo: pulando rake spec / rubocop / steep / generate:check (o CI ainda roda após o push)." +else + info "Rodando o gate local (mesmos comandos do CI)" + GATE=( + "bundle exec rake spec" + "bundle exec rubocop" + "bundle exec steep check" + "bundle exec rake generate:check" + ) + for cmd in "${GATE[@]}"; do + if [[ $DRY_RUN -eq 1 ]]; then + dry "$cmd" + else + info "$cmd" + eval "$cmd" || die "Gate falhou em: $cmd" + fi + done + [[ $DRY_RUN -eq 1 ]] || ok "gate local passou" +fi + +# --- Git: commit + tag + push ----------------------------------------------- +echo +if [[ $SKIP_GIT -eq 1 ]]; then + warn "--skip-git ativo: pulando commit, tag e push. Mudanças ficam no working tree." +else + COMMIT_MSG="chore(release): $TAG" + + # Mensagem da tag anotada: título + notas do CHANGELOG da versão. + NOTES="$(changelog_notes "$DOTTED_VERSION" || true)" + TAG_FILE="$(mktemp "${TMPDIR:-/tmp}/nfe-release-tag.XXXXXX")" + trap 'rm -f "$TAG_FILE"' EXIT + { + printf 'nfe-io %s\n' "$TAG" + if [[ -n "${NOTES// /}" ]]; then + printf '\n%s\n' "$NOTES" + fi + } >"$TAG_FILE" + + if [[ $DRY_RUN -eq 1 ]]; then + dry "git add $VERSION_FILE $CHANGELOG_FILE" + dry "git commit -m \"$COMMIT_MSG\"" + dry "git tag -a $TAG -F <(notas do CHANGELOG)" + dry "git push origin master" + dry "git push origin $TAG" + echo + dry "Após o push da tag, .github/workflows/release.yml publica o gem (OIDC) e cria o GitHub Release." + else + info "Commitando: $COMMIT_MSG" + git add "$VERSION_FILE" "$CHANGELOG_FILE" + git commit -m "$COMMIT_MSG" + ok "commit criado" + + info "Criando tag anotada $TAG" + git tag -a "$TAG" -F "$TAG_FILE" + ok "tag $TAG criada" + + info "Enviando commit e tag para origin" + git push origin "$CURRENT_BRANCH" + git push origin "$TAG" + ok "push concluído" + echo + info "Tag '$TAG' enviada. O workflow release.yml vai verificar o CI e publicar o gem via OIDC." + fi +fi + +echo +if [[ $DRY_RUN -eq 1 ]]; then + ok "${C_BOLD}Dry-run concluído.${C_RESET} Nenhum efeito colateral. Rode sem --dry-run para cortar o release." +else + ok "${C_BOLD}Preparação de release concluída para $TAG.${C_RESET}" +fi diff --git a/sig/nfe.rbs b/sig/nfe.rbs new file mode 100644 index 0000000..f2f2932 --- /dev/null +++ b/sig/nfe.rbs @@ -0,0 +1,2 @@ +module Nfe +end diff --git a/sig/nfe/certificate.rbs b/sig/nfe/certificate.rbs new file mode 100644 index 0000000..4199520 --- /dev/null +++ b/sig/nfe/certificate.rbs @@ -0,0 +1,45 @@ +module Nfe + class CertificateInfo < Data + attr_reader subject: String + attr_reader issuer: String + attr_reader not_before: Time? + attr_reader not_after: Time? + attr_reader serial_number: String + + def self.new: (subject: String, issuer: String, not_before: Time?, not_after: Time?, serial_number: String) -> instance + | (String subject, String issuer, Time? not_before, Time? not_after, String serial_number) -> instance + + def initialize: (subject: String, issuer: String, not_before: Time?, not_after: Time?, serial_number: String) -> void + | (String subject, String issuer, Time? not_before, Time? not_after, String serial_number) -> void + end + + class CertificateStatus < Data + attr_reader has_certificate: bool + attr_reader expires_on: String? + attr_reader valid: bool? + attr_reader days_until_expiration: Integer? + attr_reader expiring_soon: bool? + attr_reader details: untyped + + def self.new: (has_certificate: bool, expires_on: String?, valid: bool?, days_until_expiration: Integer?, expiring_soon: bool?, details: untyped) -> instance + | (bool has_certificate, String? expires_on, bool? valid, Integer? days_until_expiration, bool? expiring_soon, untyped details) -> instance + + def initialize: (has_certificate: bool, expires_on: String?, valid: bool?, days_until_expiration: Integer?, expiring_soon: bool?, details: untyped) -> void + | (bool has_certificate, String? expires_on, bool? valid, Integer? days_until_expiration, bool? expiring_soon, untyped details) -> void + end + + module CertificateValidator + DEFAULT_THRESHOLD_DAYS: Integer + SECONDS_PER_DAY: Integer + + def self?.supported_format?: (String? filename) -> bool + + def self?.validate: (String der_bytes, String password) -> Nfe::CertificateInfo + + def self?.days_until_expiration: ((Time | String) not_after) -> Integer + + def self?.expiring_soon?: ((Time | String) not_after, ?Integer threshold_days) -> bool + + def self?.coerce_time: (untyped value) -> Time + end +end diff --git a/sig/nfe/client.rbs b/sig/nfe/client.rbs new file mode 100644 index 0000000..9f446cb --- /dev/null +++ b/sig/nfe/client.rbs @@ -0,0 +1,55 @@ +module Nfe + class Client + RESOURCES: Hash[Symbol, untyped] + + @configuration: Nfe::Configuration + @resources: Hash[Symbol, untyped] + @transports: Hash[Symbol, untyped] + @resource_mutex: Thread::Mutex + @transport_mutex: Thread::Mutex + + attr_reader configuration: Nfe::Configuration + + def initialize: (?api_key: String?, ?data_api_key: String?, + ?configuration: Nfe::Configuration?, ?environment: Symbol, + ?timeout: Integer, ?max_retries: Integer, ?logger: untyped, + ?user_agent_suffix: String?) -> void + + # The 17 core lazy resource accessors. + def service_invoices: () -> Nfe::Resources::ServiceInvoices + def product_invoices: () -> Nfe::Resources::ProductInvoices + def consumer_invoices: () -> Nfe::Resources::ConsumerInvoices + def transportation_invoices: () -> Nfe::Resources::TransportationInvoices + def inbound_product_invoices: () -> Nfe::Resources::InboundProductInvoices + def product_invoice_query: () -> Nfe::Resources::ProductInvoiceQuery + def consumer_invoice_query: () -> Nfe::Resources::ConsumerInvoiceQuery + def companies: () -> Nfe::Resources::Companies + def legal_people: () -> Nfe::Resources::LegalPeople + def natural_people: () -> Nfe::Resources::NaturalPeople + def webhooks: () -> Nfe::Resources::Webhooks + def addresses: () -> Nfe::Resources::Addresses + def legal_entity_lookup: () -> Nfe::Resources::LegalEntityLookup + def natural_person_lookup: () -> Nfe::Resources::NaturalPersonLookup + def tax_calculation: () -> Nfe::Resources::TaxCalculation + def tax_codes: () -> Nfe::Resources::TaxCodes + def state_taxes: () -> Nfe::Resources::StateTaxes + def service_invoices_rtc: () -> Nfe::Resources::ServiceInvoicesRtc + def product_invoices_rtc: () -> Nfe::Resources::ProductInvoicesRtc + + def request: (Symbol | String method, family: Symbol, path: String, + ?query: Hash[untyped, untyped], ?body: untyped, + ?headers: Hash[untyped, untyped], ?idempotency_key: String?, + ?request_options: Nfe::RequestOptions?) -> Nfe::Http::Response + + private + + def build_request: (Symbol | String method, family: Symbol, path: String, + query: Hash[untyped, untyped], body: untyped, + headers: Hash[untyped, untyped], idempotency_key: String?, + request_options: Nfe::RequestOptions?) -> Nfe::Http::Request + def default_headers: (String? api_key) -> Hash[String, untyped] + def resource: (Symbol name) -> untyped + def transport_for: (Symbol family) -> untyped + def build_transport: () -> Nfe::Http::RetryingTransport + end +end diff --git a/sig/nfe/configuration.rbs b/sig/nfe/configuration.rbs new file mode 100644 index 0000000..b804579 --- /dev/null +++ b/sig/nfe/configuration.rbs @@ -0,0 +1,46 @@ +module Nfe + class Configuration + HOSTS: Hash[Symbol, String] + FAMILY_ALIASES: Hash[Symbol, Symbol] + DATA_FAMILIES: Array[Symbol] + VALID_ENVIRONMENTS: Array[Symbol] + DEFAULT_TIMEOUT: Integer + DEFAULT_OPEN_TIMEOUT: Integer + DEFAULT_MAX_RETRIES: Integer + + attr_reader api_key: String? + attr_reader data_api_key: String? + attr_reader environment: Symbol + attr_reader timeout: Integer + attr_reader open_timeout: Integer + attr_reader max_retries: Integer + attr_reader logger: untyped + attr_reader user_agent_suffix: String? + attr_reader base_url_overrides: Hash[Symbol, String] + attr_reader ca_file: String? + attr_reader ca_path: String? + attr_reader proxy: untyped + + def initialize: (?api_key: String?, ?data_api_key: String?, ?environment: Symbol, + ?timeout: Integer, ?open_timeout: Integer, ?max_retries: Integer, + ?logger: untyped, ?user_agent_suffix: String?, + ?base_url_overrides: Hash[Symbol, String], + ?ca_file: String?, ?ca_path: String?, ?proxy: untyped) -> void + + def base_url_for: (Symbol | String family) -> String + + def api_key_for: (Symbol | String family) -> String + + private + + def resolve_key: (String? explicit, String env_name) -> String? + + def validate!: () -> void + + def validate_positive!: (Symbol name, untyped value) -> void + + def blank?: (untyped value) -> bool + + def canonical_family: (Symbol | String family) -> Symbol + end +end diff --git a/sig/nfe/date_normalizer.rbs b/sig/nfe/date_normalizer.rbs new file mode 100644 index 0000000..f4449fd --- /dev/null +++ b/sig/nfe/date_normalizer.rbs @@ -0,0 +1,8 @@ +module Nfe + module DateNormalizer + ISO_DATE: Regexp + + def self?.to_iso_date: (String | Date | Time | DateTime) -> String + def self?.from_string: (String value) -> String + end +end diff --git a/sig/nfe/error_factory.rbs b/sig/nfe/error_factory.rbs new file mode 100644 index 0000000..ee7f616 --- /dev/null +++ b/sig/nfe/error_factory.rbs @@ -0,0 +1,20 @@ +module Nfe + module ErrorFactory + MAX_MESSAGE_LENGTH: Integer + MESSAGE_KEYS: Array[String] + ERROR_CODE_KEYS: Array[String] + CONTROL_CHARS: Regexp + + def self?.from_response: (untyped response) -> Nfe::Error + def self?.from_network_error: (Exception exception) -> Nfe::ApiConnectionError + def self?.error_class_for: (Integer status) -> singleton(Nfe::Error) + def self?.parse_body: (String? body) -> untyped + def self?.extract_message: (untyped parsed) -> String? + def self?.message_from_keys: (Hash[String, untyped] parsed) -> String? + def self?.message_from_errors: (untyped errors) -> untyped + def self?.sanitize_message: (untyped raw) -> String? + def self?.extract_error_code: (untyped parsed) -> String? + def self?.extract_retry_after: (untyped response) -> Integer? + def self?.timeout?: (Exception exception) -> bool + end +end diff --git a/sig/nfe/errors.rbs b/sig/nfe/errors.rbs new file mode 100644 index 0000000..921f0d4 --- /dev/null +++ b/sig/nfe/errors.rbs @@ -0,0 +1,54 @@ +module Nfe + class Error < StandardError + attr_reader status_code: Integer? + attr_reader request_id: String? + attr_reader error_code: String? + attr_reader response_body: String? + attr_reader response_headers: Hash[String, untyped] + + def initialize: (?String? message, ?status_code: Integer?, ?request_id: String?, + ?error_code: String?, ?response_body: String?, + ?response_headers: Hash[String, untyped]) -> void + + def to_h: () -> Hash[Symbol, untyped] + end + + class AuthenticationError < Error + end + + class AuthorizationError < Error + end + + class InvalidRequestError < Error + end + + class NotFoundError < Error + end + + class ConflictError < Error + end + + class RateLimitError < Error + attr_reader retry_after: Integer? + + def initialize: (?String? message, ?retry_after: Integer?, **untyped kwargs) -> void + end + + class ServerError < Error + end + + class ApiConnectionError < Error + end + + class TimeoutError < ApiConnectionError + end + + class SignatureVerificationError < Error + end + + class ConfigurationError < Error + end + + class InvoiceProcessingError < Error + end +end diff --git a/sig/nfe/flow_status.rbs b/sig/nfe/flow_status.rbs new file mode 100644 index 0000000..06e9dba --- /dev/null +++ b/sig/nfe/flow_status.rbs @@ -0,0 +1,9 @@ +module Nfe + module FlowStatus + TERMINAL: Array[String] + NON_TERMINAL: Array[String] + ALL: Array[String] + + def self?.terminal?: (untyped status) -> bool + end +end diff --git a/sig/nfe/generated/.gitkeep b/sig/nfe/generated/.gitkeep new file mode 100644 index 0000000..230182d --- /dev/null +++ b/sig/nfe/generated/.gitkeep @@ -0,0 +1,2 @@ +# Reserved for the .rbs signatures emitted alongside lib/nfe/generated/ (add-openapi-pipeline). +# AUTO-GENERATED — NEVER edit by hand. diff --git a/sig/nfe/generated/calculo_impostos_v1/calculate_item_request.rbs b/sig/nfe/generated/calculo_impostos_v1/calculate_item_request.rbs new file mode 100644 index 0000000..710b2bf --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/calculate_item_request.rbs @@ -0,0 +1,35 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class CalculateItemRequest < Data + attr_reader acquisition_purpose: String? + attr_reader benefit: String? + attr_reader cest: String? + attr_reader discount_amount: Float? + attr_reader ex_tipi: String? + attr_reader freight_amount: Float? + attr_reader gtin: String? + attr_reader icms: Icms + attr_reader id: String + attr_reader ii: Ii + attr_reader insurance_amount: Float? + attr_reader issuer_tax_profile: String? + attr_reader ncm: String? + attr_reader operation_code: Integer + attr_reader origin: untyped + attr_reader others_amount: Float? + attr_reader quantity: Float + attr_reader recipient_tax_profile: String? + attr_reader sku: String? + attr_reader unit_amount: Float + def self.new: (?acquisition_purpose: String?, ?benefit: String?, ?cest: String?, ?discount_amount: Float?, ?ex_tipi: String?, ?freight_amount: Float?, ?gtin: String?, ?icms: Icms, id: String, ?ii: Ii, ?insurance_amount: Float?, ?issuer_tax_profile: String?, ?ncm: String?, operation_code: Integer, origin: untyped, ?others_amount: Float?, quantity: Float, ?recipient_tax_profile: String?, ?sku: String?, unit_amount: Float) -> instance + def initialize: (?acquisition_purpose: String?, ?benefit: String?, ?cest: String?, ?discount_amount: Float?, ?ex_tipi: String?, ?freight_amount: Float?, ?gtin: String?, ?icms: Icms, id: String, ?ii: Ii, ?insurance_amount: Float?, ?issuer_tax_profile: String?, ?ncm: String?, operation_code: Integer, origin: untyped, ?others_amount: Float?, quantity: Float, ?recipient_tax_profile: String?, ?sku: String?, unit_amount: Float) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/calculate_item_response.rbs b/sig/nfe/generated/calculo_impostos_v1/calculate_item_response.rbs new file mode 100644 index 0000000..b45f90a --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/calculate_item_response.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class CalculateItemResponse < Data + attr_reader additional_information: String? + attr_reader benefit: String? + attr_reader cest: String? + attr_reader cfop: Integer + attr_reader cofins: Cofins + attr_reader icms: Icms + attr_reader icms_uf_dest: IcmsUfDest + attr_reader id: String? + attr_reader ii: Ii + attr_reader ipi: Ipi + attr_reader last_modified: String + attr_reader pis: Pis + attr_reader product_id: String? + def self.new: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer, ?cofins: Cofins, ?icms: Icms, ?icms_uf_dest: IcmsUfDest, ?id: String?, ?ii: Ii, ?ipi: Ipi, ?last_modified: String, ?pis: Pis, ?product_id: String?) -> instance + def initialize: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer, ?cofins: Cofins, ?icms: Icms, ?icms_uf_dest: IcmsUfDest, ?id: String?, ?ii: Ii, ?ipi: Ipi, ?last_modified: String, ?pis: Pis, ?product_id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/calculate_request.rbs b/sig/nfe/generated/calculo_impostos_v1/calculate_request.rbs new file mode 100644 index 0000000..d4d7c17 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/calculate_request.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class CalculateRequest < Data + attr_reader collection_id: String? + attr_reader is_product_registration: bool + attr_reader issuer: CalculateRequestIssuer + attr_reader items: Array[CalculateItemRequest] + attr_reader operation_type: untyped + attr_reader recipient: CalculateRequestRecipient + def self.new: (?collection_id: String?, ?is_product_registration: bool, issuer: CalculateRequestIssuer, items: Array[CalculateItemRequest], operation_type: untyped, recipient: CalculateRequestRecipient) -> instance + def initialize: (?collection_id: String?, ?is_product_registration: bool, issuer: CalculateRequestIssuer, items: Array[CalculateItemRequest], operation_type: untyped, recipient: CalculateRequestRecipient) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/calculate_request_issuer.rbs b/sig/nfe/generated/calculo_impostos_v1/calculate_request_issuer.rbs new file mode 100644 index 0000000..626d15b --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/calculate_request_issuer.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class CalculateRequestIssuer < Data + attr_reader state: untyped + attr_reader tax_profile: String? + attr_reader tax_regime: untyped + def self.new: (state: untyped, ?tax_profile: String?, tax_regime: untyped) -> instance + def initialize: (state: untyped, ?tax_profile: String?, tax_regime: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/calculate_request_recipient.rbs b/sig/nfe/generated/calculo_impostos_v1/calculate_request_recipient.rbs new file mode 100644 index 0000000..4be3d46 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/calculate_request_recipient.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class CalculateRequestRecipient < Data + attr_reader state: untyped + attr_reader tax_profile: String? + attr_reader tax_regime: untyped + def self.new: (state: untyped, ?tax_profile: String?, ?tax_regime: untyped) -> instance + def initialize: (state: untyped, ?tax_profile: String?, ?tax_regime: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/calculate_response.rbs b/sig/nfe/generated/calculo_impostos_v1/calculate_response.rbs new file mode 100644 index 0000000..e4a59ae --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/calculate_response.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class CalculateResponse < Data + attr_reader items: Array[CalculateItemResponse]? + def self.new: (?items: Array[CalculateItemResponse]?) -> instance + def initialize: (?items: Array[CalculateItemResponse]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/cofins.rbs b/sig/nfe/generated/calculo_impostos_v1/cofins.rbs new file mode 100644 index 0000000..42c9be5 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/cofins.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class Cofins < Data + attr_reader cst: String? + attr_reader p_cofins: String? + attr_reader q_bcprod: String? + attr_reader v_aliq_prod: String? + attr_reader v_bc: String? + attr_reader v_cofins: String? + def self.new: (?cst: String?, ?p_cofins: String?, ?q_bcprod: String?, ?v_aliq_prod: String?, ?v_bc: String?, ?v_cofins: String?) -> instance + def initialize: (?cst: String?, ?p_cofins: String?, ?q_bcprod: String?, ?v_aliq_prod: String?, ?v_bc: String?, ?v_cofins: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/icms.rbs b/sig/nfe/generated/calculo_impostos_v1/icms.rbs new file mode 100644 index 0000000..aa0b744 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/icms.rbs @@ -0,0 +1,60 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class Icms < Data + attr_reader c_benef_rbc: String? + attr_reader csosn: String? + attr_reader cst: String? + attr_reader ind_deduz_deson: String? + attr_reader mod_bc: String? + attr_reader mod_bcst: String? + attr_reader mot_des_icms: String? + attr_reader mot_des_icmsst: String? + attr_reader orig: String? + attr_reader p_cred_sn: String? + attr_reader p_dif: String? + attr_reader p_fcp: String? + attr_reader p_fcpdif: String? + attr_reader p_fcpst: String? + attr_reader p_fcpstret: String? + attr_reader p_icms: String? + attr_reader p_icmsefet: String? + attr_reader p_icmsst: String? + attr_reader p_mvast: String? + attr_reader p_red_bc: String? + attr_reader p_red_bcefet: String? + attr_reader p_red_bcst: String? + attr_reader p_st: String? + attr_reader v_bc: String? + attr_reader v_bcefet: String? + attr_reader v_bcfcp: String? + attr_reader v_bcfcpst: String? + attr_reader v_bcfcpstret: String? + attr_reader v_bcst: String? + attr_reader v_bcstret: String? + attr_reader v_cred_icmssn: String? + attr_reader v_fcp: String? + attr_reader v_fcpdif: String? + attr_reader v_fcpefet: String? + attr_reader v_fcpst: String? + attr_reader v_fcpstret: String? + attr_reader v_icms: String? + attr_reader v_icmsdeson: String? + attr_reader v_icmsdif: String? + attr_reader v_icmsefet: String? + attr_reader v_icmsop: String? + attr_reader v_icmsst: String? + attr_reader v_icmsstdeson: String? + attr_reader v_icmsstret: String? + attr_reader v_icmssubstituto: String? + def self.new: (?c_benef_rbc: String?, ?csosn: String?, ?cst: String?, ?ind_deduz_deson: String?, ?mod_bc: String?, ?mod_bcst: String?, ?mot_des_icms: String?, ?mot_des_icmsst: String?, ?orig: String?, ?p_cred_sn: String?, ?p_dif: String?, ?p_fcp: String?, ?p_fcpdif: String?, ?p_fcpst: String?, ?p_fcpstret: String?, ?p_icms: String?, ?p_icmsefet: String?, ?p_icmsst: String?, ?p_mvast: String?, ?p_red_bc: String?, ?p_red_bcefet: String?, ?p_red_bcst: String?, ?p_st: String?, ?v_bc: String?, ?v_bcefet: String?, ?v_bcfcp: String?, ?v_bcfcpst: String?, ?v_bcfcpstret: String?, ?v_bcst: String?, ?v_bcstret: String?, ?v_cred_icmssn: String?, ?v_fcp: String?, ?v_fcpdif: String?, ?v_fcpefet: String?, ?v_fcpst: String?, ?v_fcpstret: String?, ?v_icms: String?, ?v_icmsdeson: String?, ?v_icmsdif: String?, ?v_icmsefet: String?, ?v_icmsop: String?, ?v_icmsst: String?, ?v_icmsstdeson: String?, ?v_icmsstret: String?, ?v_icmssubstituto: String?) -> instance + def initialize: (?c_benef_rbc: String?, ?csosn: String?, ?cst: String?, ?ind_deduz_deson: String?, ?mod_bc: String?, ?mod_bcst: String?, ?mot_des_icms: String?, ?mot_des_icmsst: String?, ?orig: String?, ?p_cred_sn: String?, ?p_dif: String?, ?p_fcp: String?, ?p_fcpdif: String?, ?p_fcpst: String?, ?p_fcpstret: String?, ?p_icms: String?, ?p_icmsefet: String?, ?p_icmsst: String?, ?p_mvast: String?, ?p_red_bc: String?, ?p_red_bcefet: String?, ?p_red_bcst: String?, ?p_st: String?, ?v_bc: String?, ?v_bcefet: String?, ?v_bcfcp: String?, ?v_bcfcpst: String?, ?v_bcfcpstret: String?, ?v_bcst: String?, ?v_bcstret: String?, ?v_cred_icmssn: String?, ?v_fcp: String?, ?v_fcpdif: String?, ?v_fcpefet: String?, ?v_fcpst: String?, ?v_fcpstret: String?, ?v_icms: String?, ?v_icmsdeson: String?, ?v_icmsdif: String?, ?v_icmsefet: String?, ?v_icmsop: String?, ?v_icmsst: String?, ?v_icmsstdeson: String?, ?v_icmsstret: String?, ?v_icmssubstituto: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/icms_uf_dest.rbs b/sig/nfe/generated/calculo_impostos_v1/icms_uf_dest.rbs new file mode 100644 index 0000000..f1c7f3b --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/icms_uf_dest.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class IcmsUfDest < Data + attr_reader p_fcpufdest: String? + attr_reader p_icmsinter: String? + attr_reader p_icmsinter_part: String? + attr_reader p_icmsufdest: String? + attr_reader v_bcfcpufdest: String? + attr_reader v_bcufdest: String? + attr_reader v_fcpufdest: String? + attr_reader v_icmsufdest: String? + attr_reader v_icmsufremet: String? + def self.new: (?p_fcpufdest: String?, ?p_icmsinter: String?, ?p_icmsinter_part: String?, ?p_icmsufdest: String?, ?v_bcfcpufdest: String?, ?v_bcufdest: String?, ?v_fcpufdest: String?, ?v_icmsufdest: String?, ?v_icmsufremet: String?) -> instance + def initialize: (?p_fcpufdest: String?, ?p_icmsinter: String?, ?p_icmsinter_part: String?, ?p_icmsufdest: String?, ?v_bcfcpufdest: String?, ?v_bcufdest: String?, ?v_fcpufdest: String?, ?v_icmsufdest: String?, ?v_icmsufremet: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/ii.rbs b/sig/nfe/generated/calculo_impostos_v1/ii.rbs new file mode 100644 index 0000000..42315d7 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/ii.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class Ii < Data + attr_reader inf_custo_aquis: String? + attr_reader p_cred_sn: String? + attr_reader v_bc: String? + attr_reader v_cred_icmssn: String? + attr_reader v_desp_adu: String? + attr_reader v_enc_camb: String? + attr_reader v_ii: String? + attr_reader v_iof: String? + def self.new: (?inf_custo_aquis: String?, ?p_cred_sn: String?, ?v_bc: String?, ?v_cred_icmssn: String?, ?v_desp_adu: String?, ?v_enc_camb: String?, ?v_ii: String?, ?v_iof: String?) -> instance + def initialize: (?inf_custo_aquis: String?, ?p_cred_sn: String?, ?v_bc: String?, ?v_cred_icmssn: String?, ?v_desp_adu: String?, ?v_enc_camb: String?, ?v_ii: String?, ?v_iof: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/ipi.rbs b/sig/nfe/generated/calculo_impostos_v1/ipi.rbs new file mode 100644 index 0000000..1493cb3 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/ipi.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class Ipi < Data + attr_reader c_enq: String? + attr_reader cst: String? + attr_reader p_ipi: String? + attr_reader q_unid: String? + attr_reader v_bc: String? + attr_reader v_ipi: String? + attr_reader v_unid: String? + def self.new: (?c_enq: String?, ?cst: String?, ?p_ipi: String?, ?q_unid: String?, ?v_bc: String?, ?v_ipi: String?, ?v_unid: String?) -> instance + def initialize: (?c_enq: String?, ?cst: String?, ?p_ipi: String?, ?q_unid: String?, ?v_bc: String?, ?v_ipi: String?, ?v_unid: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/operation_type.rbs b/sig/nfe/generated/calculo_impostos_v1/operation_type.rbs new file mode 100644 index 0000000..7285452 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/operation_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module OperationType + Outgoing: String + Incoming: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/origin.rbs b/sig/nfe/generated/calculo_impostos_v1/origin.rbs new file mode 100644 index 0000000..c7d5391 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/origin.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module Origin + National: String + ForeignDirectImport: String + ForeignInternalMarket: String + NationalWith40To70Import: String + NationalPpb: String + NationalWithLess40Import: String + ForeignDirectImportWithoutNationalSimilar: String + ForeignInternalMarketWithoutNationalSimilar: String + NationalWithGreater70Import: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/pis.rbs b/sig/nfe/generated/calculo_impostos_v1/pis.rbs new file mode 100644 index 0000000..9fc923c --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/pis.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class Pis < Data + attr_reader cst: String? + attr_reader p_pis: String? + attr_reader q_bcprod: String? + attr_reader v_aliq_prod: String? + attr_reader v_bc: String? + attr_reader v_pis: String? + def self.new: (?cst: String?, ?p_pis: String?, ?q_bcprod: String?, ?v_aliq_prod: String?, ?v_bc: String?, ?v_pis: String?) -> instance + def initialize: (?cst: String?, ?p_pis: String?, ?q_bcprod: String?, ?v_aliq_prod: String?, ?v_bc: String?, ?v_pis: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/problem_details.rbs b/sig/nfe/generated/calculo_impostos_v1/problem_details.rbs new file mode 100644 index 0000000..370c27c --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/problem_details.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class ProblemDetails < Data + attr_reader detail: String? + attr_reader instance: String? + attr_reader status: Integer? + attr_reader title: String? + attr_reader type: String? + def self.new: (?detail: String?, ?instance: String?, ?status: Integer?, ?title: String?, ?type: String?) -> instance + def initialize: (?detail: String?, ?instance: String?, ?status: Integer?, ?title: String?, ?type: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/state.rbs b/sig/nfe/generated/calculo_impostos_v1/state.rbs new file mode 100644 index 0000000..78ca894 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/state.rbs @@ -0,0 +1,41 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module State + AC: String + AL: String + AP: String + AM: String + BA: String + CE: String + DF: String + ES: String + GO: String + MA: String + MT: String + MS: String + MG: String + PA: String + PB: String + PR: String + PE: String + PI: String + RJ: String + RN: String + RS: String + RO: String + RR: String + SC: String + SP: String + SE: String + TO: String + EX: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/tax_code.rbs b/sig/nfe/generated/calculo_impostos_v1/tax_code.rbs new file mode 100644 index 0000000..c11fce1 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/tax_code.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class TaxCode < Data + attr_reader code: String? + attr_reader description: String? + def self.new: (?code: String?, ?description: String?) -> instance + def initialize: (?code: String?, ?description: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/tax_code_paginated_response.rbs b/sig/nfe/generated/calculo_impostos_v1/tax_code_paginated_response.rbs new file mode 100644 index 0000000..6aaf4a3 --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/tax_code_paginated_response.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + class TaxCodePaginatedResponse < Data + attr_reader current_page: Integer + attr_reader items: Array[TaxCode]? + attr_reader total_count: Integer + attr_reader total_pages: Integer + def self.new: (?current_page: Integer, ?items: Array[TaxCode]?, ?total_count: Integer, ?total_pages: Integer) -> instance + def initialize: (?current_page: Integer, ?items: Array[TaxCode]?, ?total_count: Integer, ?total_pages: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/calculo_impostos_v1/tax_regime.rbs b/sig/nfe/generated/calculo_impostos_v1/tax_regime.rbs new file mode 100644 index 0000000..112e68b --- /dev/null +++ b/sig/nfe/generated/calculo_impostos_v1/tax_regime.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/calculo-impostos-v1.yaml +# Hash: sha256:39f6c3a1112ff3c98d842e172be5007eaa4d0c5f63d300ad263b96c9299ece99 + +module Nfe + module Generated + module CalculoImpostosV1 + module TaxRegime + NationalSimple: String + RealProfit: String + PresumedProfit: String + NationalSimpleSublimitExceeded: String + IndividualMicroEnterprise: String + Exempt: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status.rbs new file mode 100644 index 0000000..c79c16d --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_entity_status.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + module DFe_NetCore_Domain_Enums_EntityStatus + Value0: Integer + Value1: Integer + Value_1: Integer + ALL: Array[Integer] + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type.rbs new file mode 100644 index 0000000..fe99e35 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_enums_metadata_resource_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + module DFe_NetCore_Domain_Enums_MetadataResourceType + Value0: Integer + Value1: Integer + Value2: Integer + Value3: Integer + Value4: Integer + Value5: Integer + ALL: Array[Integer] + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource.rbs new file mode 100644 index 0000000..19242e0 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_company_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_CompanyResource < Data + attr_reader federal_tax_number: String? + attr_reader id: String? + attr_reader state: String? + attr_reader state_tax_number: String? + def self.new: (?federal_tax_number: String?, ?id: String?, ?state: String?, ?state_tax_number: String?) -> instance + def initialize: (?federal_tax_number: String?, ?id: String?, ?state: String?, ?state_tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource.rbs new file mode 100644 index 0000000..0630f95 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_inbound_product_invoice_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_EnableInboundProductInvoiceResource < Data + attr_reader automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource + attr_reader start_from_date: String + attr_reader start_from_nsu: Integer + def self.new: (?automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource, ?start_from_date: String, ?start_from_nsu: Integer) -> instance + def initialize: (?automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource, ?start_from_date: String, ?start_from_nsu: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource.rbs new file mode 100644 index 0000000..da0d7e3 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_enable_transportation_invoice_inbound_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_EnableTransportationInvoiceInboundResource < Data + attr_reader start_from_date: String + attr_reader start_from_nsu: Integer + def self.new: (?start_from_date: String, ?start_from_nsu: Integer) -> instance + def initialize: (?start_from_date: String, ?start_from_nsu: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource.rbs new file mode 100644 index 0000000..bc0f756 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_manifest_automatic_rules_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource < Data + attr_reader minutes_to_wait_awareness_operation: Integer + def self.new: (?minutes_to_wait_awareness_operation: Integer) -> instance + def initialize: (?minutes_to_wait_awareness_operation: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource.rbs new file mode 100644 index 0000000..2c2f4a7 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_metadata_resource.rbs @@ -0,0 +1,29 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_MetadataResource < Data + attr_reader access_key: String? + attr_reader company: DFe_NetCore_Domain_Resources_CompanyResource + attr_reader created_on: String? + attr_reader description: String? + attr_reader federal_tax_number_sender: String? + attr_reader id: String? + attr_reader issued_on: String? + attr_reader name_sender: String? + attr_reader nsu: Integer + attr_reader parent_access_key: String? + attr_reader product_invoices: Array[DFe_NetCore_Domain_Resources_ProductInvoiceResource]? + attr_reader total_invoice_amount: String? + attr_reader type: untyped + attr_reader xml_url: String? + def self.new: (?access_key: String?, ?company: DFe_NetCore_Domain_Resources_CompanyResource, ?created_on: String?, ?description: String?, ?federal_tax_number_sender: String?, ?id: String?, ?issued_on: String?, ?name_sender: String?, ?nsu: Integer, ?parent_access_key: String?, ?product_invoices: Array[DFe_NetCore_Domain_Resources_ProductInvoiceResource]?, ?total_invoice_amount: String?, ?type: untyped, ?xml_url: String?) -> instance + def initialize: (?access_key: String?, ?company: DFe_NetCore_Domain_Resources_CompanyResource, ?created_on: String?, ?description: String?, ?federal_tax_number_sender: String?, ?id: String?, ?issued_on: String?, ?name_sender: String?, ?nsu: Integer, ?parent_access_key: String?, ?product_invoices: Array[DFe_NetCore_Domain_Resources_ProductInvoiceResource]?, ?total_invoice_amount: String?, ?type: untyped, ?xml_url: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource.rbs new file mode 100644 index 0000000..c0f8806 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_inbound_resource.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_ProductInvoiceInboundResource < Data + attr_reader automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource + attr_reader company_id: String? + attr_reader created_on: String + attr_reader modified_on: String? + attr_reader start_from_date: String + attr_reader start_from_nsu: Integer + attr_reader status: untyped + def self.new: (?automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource, ?company_id: String?, ?created_on: String, ?modified_on: String?, ?start_from_date: String, ?start_from_nsu: Integer, ?status: untyped) -> instance + def initialize: (?automatic_manifesting: DFe_NetCore_Domain_Resources_ManifestAutomaticRulesResource, ?company_id: String?, ?created_on: String, ?modified_on: String?, ?start_from_date: String, ?start_from_nsu: Integer, ?status: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource.rbs new file mode 100644 index 0000000..4f94ad1 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_product_invoice_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_ProductInvoiceResource < Data + attr_reader access_key: String? + def self.new: (?access_key: String?) -> instance + def initialize: (?access_key: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource.rbs b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource.rbs new file mode 100644 index 0000000..f2868b1 --- /dev/null +++ b/sig/nfe/generated/consulta_cte_v2/dfe_net_core_domain_resources_transportation_invoice_inbound_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-cte-v2.yaml +# Hash: sha256:6424379a8ca8cdf8129f24ec19b84b260208fc049a7d1d9cb8c45763c07af1a9 + +module Nfe + module Generated + module ConsultaCteV2 + class DFe_NetCore_Domain_Resources_TransportationInvoiceInboundResource < Data + attr_reader company_id: String? + attr_reader created_on: String + attr_reader modified_on: String? + attr_reader start_from_date: String + attr_reader start_from_nsu: Integer + attr_reader status: untyped + def self.new: (?company_id: String?, ?created_on: String, ?modified_on: String?, ?start_from_date: String, ?start_from_nsu: Integer, ?status: untyped) -> instance + def initialize: (?company_id: String?, ?created_on: String, ?modified_on: String?, ?start_from_date: String, ?start_from_nsu: Integer, ?status: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/buyer_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/buyer_resource.rbs new file mode 100644 index 0000000..25388d6 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/buyer_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class BuyerResource < Data + attr_reader federal_tax_number: String + attr_reader name: String + def self.new: (?federal_tax_number: String, ?name: String) -> instance + def initialize: (?federal_tax_number: String, ?name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource.rbs new file mode 100644 index 0000000..8ccc3f8 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/cte_event_metadata_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class CTeEventMetadataResource < Data + attr_reader receipt_on: String + def self.new: (?receipt_on: String) -> instance + def initialize: (?receipt_on: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/cte_metadata_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/cte_metadata_resource.rbs new file mode 100644 index 0000000..3a046df --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/cte_metadata_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class CTeMetadataResource < Data + attr_reader issued_on: String + def self.new: (?issued_on: String) -> instance + def initialize: (?issued_on: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource.rbs new file mode 100644 index 0000000..2d09f52 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/enable_inbound_product_invoice_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class EnableInboundProductInvoiceResource < Data + attr_reader automatic_manifesting: Hash[String, untyped] + attr_reader environment_sefaz: String + attr_reader start_from_date: String + attr_reader start_from_nsu: Integer + def self.new: (?automatic_manifesting: Hash[String, untyped], ?environment_sefaz: String, ?start_from_date: String, ?start_from_nsu: Integer) -> instance + def initialize: (?automatic_manifesting: Hash[String, untyped], ?environment_sefaz: String, ?start_from_date: String, ?start_from_nsu: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource.rbs new file mode 100644 index 0000000..93d7d29 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/enable_transportation_invoice_inbound_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class EnableTransportationInvoiceInboundResource < Data + attr_reader environment_sefaz: String + attr_reader start_from_date: String + attr_reader start_from_nsu: Integer + def self.new: (?environment_sefaz: String, ?start_from_date: String, ?start_from_nsu: Integer) -> instance + def initialize: (?environment_sefaz: String, ?start_from_date: String, ?start_from_nsu: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/error_response.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/error_response.rbs new file mode 100644 index 0000000..7c4f87f --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/error_response.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class ErrorResponse < Data + attr_reader errors: Array[Hash[String, untyped]] + def self.new: (?errors: Array[Hash[String, untyped]]) -> instance + def initialize: (?errors: Array[Hash[String, untyped]]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/inbound_company_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/inbound_company_resource.rbs new file mode 100644 index 0000000..aaff905 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/inbound_company_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class InboundCompanyResource < Data + attr_reader federal_tax_number: String + attr_reader id: String + def self.new: (?federal_tax_number: String, ?id: String) -> instance + def initialize: (?federal_tax_number: String, ?id: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/issuer_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/issuer_resource.rbs new file mode 100644 index 0000000..dfe0647 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/issuer_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class IssuerResource < Data + attr_reader federal_tax_number: String + attr_reader name: String + def self.new: (?federal_tax_number: String, ?name: String) -> instance + def initialize: (?federal_tax_number: String, ?name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/message_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/message_resource.rbs new file mode 100644 index 0000000..b04af72 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/message_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class MessageResource < Data + attr_reader message: String + def self.new: (?message: String) -> instance + def initialize: (?message: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/metadata_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/metadata_resource.rbs new file mode 100644 index 0000000..05f98c1 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/metadata_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class MetadataResource < Data + attr_reader access_key: String + attr_reader company: InboundCompanyResource + attr_reader created_on: String + attr_reader description: String + attr_reader id: String + attr_reader nsu: Integer + attr_reader parent_access_key: String + attr_reader type: String + attr_reader xml_url: String + def self.new: (?access_key: String, ?company: InboundCompanyResource, ?created_on: String, ?description: String, ?id: String, ?nsu: Integer, ?parent_access_key: String, ?type: String, ?xml_url: String) -> instance + def initialize: (?access_key: String, ?company: InboundCompanyResource, ?created_on: String, ?description: String, ?id: String, ?nsu: Integer, ?parent_access_key: String, ?type: String, ?xml_url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource.rbs new file mode 100644 index 0000000..cf874c5 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_event_metadata_odata_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class NFeEventMetadataODataResource < Data + attr_reader access_key: String + attr_reader company: InboundCompanyResource + attr_reader created_on: String + attr_reader description: String + attr_reader id: String + attr_reader nsu: Integer + attr_reader receipt_on: String + attr_reader type: String + attr_reader xml_url: String + def self.new: (?access_key: String, ?company: InboundCompanyResource, ?created_on: String, ?description: String, ?id: String, ?nsu: Integer, ?receipt_on: String, ?type: String, ?xml_url: String) -> instance + def initialize: (?access_key: String, ?company: InboundCompanyResource, ?created_on: String, ?description: String, ?id: String, ?nsu: Integer, ?receipt_on: String, ?type: String, ?xml_url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource.rbs new file mode 100644 index 0000000..e3f3a4b --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_odata_resource.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class NFeMetadataODataResource < Data + attr_reader access_key: String + attr_reader company: InboundCompanyResource + attr_reader created_on: String + attr_reader federal_tax_number_sender: String + attr_reader issued_on: String + attr_reader name_sender: String + attr_reader nfe_number: String + attr_reader nfe_serial_number: String + attr_reader nsu: String + attr_reader operation_type: String + attr_reader total_invoice_amount: String + attr_reader type: String + attr_reader xml_url: String + def self.new: (?access_key: String, ?company: InboundCompanyResource, ?created_on: String, ?federal_tax_number_sender: String, ?issued_on: String, ?name_sender: String, ?nfe_number: String, ?nfe_serial_number: String, ?nsu: String, ?operation_type: String, ?total_invoice_amount: String, ?type: String, ?xml_url: String) -> instance + def initialize: (?access_key: String, ?company: InboundCompanyResource, ?created_on: String, ?federal_tax_number_sender: String, ?issued_on: String, ?name_sender: String, ?nfe_number: String, ?nfe_serial_number: String, ?nsu: String, ?operation_type: String, ?total_invoice_amount: String, ?type: String, ?xml_url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource.rbs new file mode 100644 index 0000000..1098e2d --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/nfe_metadata_resource.rbs @@ -0,0 +1,34 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class NFeMetadataResource < Data + attr_reader access_key: String + attr_reader buyer: BuyerResource + attr_reader company: InboundCompanyResource + attr_reader created_on: String + attr_reader description: String + attr_reader federal_tax_number_sender: String + attr_reader issued_on: String + attr_reader issuer: IssuerResource + attr_reader name_sender: String + attr_reader nfe_number: String + attr_reader nfe_serial_number: String + attr_reader nsu: String + attr_reader nsu_parent: String + attr_reader operation_type: String + attr_reader parent_access_key: String + attr_reader total_invoice_amount: String + attr_reader transportation: TransportationResource + attr_reader type: String + attr_reader xml_url: String + def self.new: (?access_key: String, ?buyer: BuyerResource, ?company: InboundCompanyResource, ?created_on: String, ?description: String, ?federal_tax_number_sender: String, ?issued_on: String, ?issuer: IssuerResource, ?name_sender: String, ?nfe_number: String, ?nfe_serial_number: String, ?nsu: String, ?nsu_parent: String, ?operation_type: String, ?parent_access_key: String, ?total_invoice_amount: String, ?transportation: TransportationResource, ?type: String, ?xml_url: String) -> instance + def initialize: (?access_key: String, ?buyer: BuyerResource, ?company: InboundCompanyResource, ?created_on: String, ?description: String, ?federal_tax_number_sender: String, ?issued_on: String, ?issuer: IssuerResource, ?name_sender: String, ?nfe_number: String, ?nfe_serial_number: String, ?nsu: String, ?nsu_parent: String, ?operation_type: String, ?parent_access_key: String, ?total_invoice_amount: String, ?transportation: TransportationResource, ?type: String, ?xml_url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/process_webhook_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/process_webhook_resource.rbs new file mode 100644 index 0000000..75962c9 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/process_webhook_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class ProcessWebhookResource < Data + attr_reader date: String + attr_reader key: String + def self.new: (?date: String, ?key: String) -> instance + def initialize: (?date: String, ?key: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource.rbs new file mode 100644 index 0000000..846c6ab --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/product_invoice_inbound_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class ProductInvoiceInboundResource < Data + attr_reader environment_sefaz: String + attr_reader start_from_date: String + attr_reader status: String + def self.new: (?environment_sefaz: String, ?start_from_date: String, ?status: String) -> instance + def initialize: (?environment_sefaz: String, ?start_from_date: String, ?status: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource.rbs new file mode 100644 index 0000000..2d0f2c8 --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/transportation_invoice_inbound_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class TransportationInvoiceInboundResource < Data + attr_reader environment_sefaz: String + attr_reader start_from_date: String + attr_reader status: String + def self.new: (?environment_sefaz: String, ?start_from_date: String, ?status: String) -> instance + def initialize: (?environment_sefaz: String, ?start_from_date: String, ?status: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/transportation_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/transportation_resource.rbs new file mode 100644 index 0000000..452786c --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/transportation_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class TransportationResource < Data + attr_reader federal_tax_number: String + attr_reader name: String + def self.new: (?federal_tax_number: String, ?name: String) -> instance + def initialize: (?federal_tax_number: String, ?name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_dfe_distribuicao_v2/xml_file_resource.rbs b/sig/nfe/generated/consulta_dfe_distribuicao_v2/xml_file_resource.rbs new file mode 100644 index 0000000..5decc4d --- /dev/null +++ b/sig/nfe/generated/consulta_dfe_distribuicao_v2/xml_file_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-dfe-distribuicao-v2.yaml +# Hash: sha256:f607124386b9d5210012cd4ac84ed7a0e359939e4176cebe4103b5a525321bdd + +module Nfe + module Generated + module ConsultaDfeDistribuicaoV2 + class XmlFileResource < Data + attr_reader url: String + def self.new: (?url: String) -> instance + def initialize: (?url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request.rbs new file mode 100644 index 0000000..ecad3db --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/ativarbuscaautomticadedocumentose_eventosrelacionadosa_nota_fiscal_eletrnica_nf_e_request.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class AtivarbuscaautomticadedocumentoseEventosrelacionadosaNotaFiscalEletrnicaNF_eRequest < Data + attr_reader automatic_manifesting: AutomaticManifesting + attr_reader environment_sefaz: String + attr_reader start_from_date: String + attr_reader start_from_nsu: String + attr_reader webhook_version: String + def self.new: (automatic_manifesting: AutomaticManifesting, environment_sefaz: String, start_from_date: String, start_from_nsu: String, webhook_version: String) -> instance + def initialize: (automatic_manifesting: AutomaticManifesting, environment_sefaz: String, start_from_date: String, start_from_nsu: String, webhook_version: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/automatic_manifesting.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/automatic_manifesting.rbs new file mode 100644 index 0000000..492f930 --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/automatic_manifesting.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class AutomaticManifesting < Data + attr_reader minutes_to_wait_awareness_operation: String + def self.new: (minutes_to_wait_awareness_operation: String) -> instance + def initialize: (minutes_to_wait_awareness_operation: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/buyer.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/buyer.rbs new file mode 100644 index 0000000..48f9c2e --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/buyer.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Buyer < Data + attr_reader federal_tax_number: String + attr_reader name: String + def self.new: (federal_tax_number: String, name: String) -> instance + def initialize: (federal_tax_number: String, name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/company.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/company.rbs new file mode 100644 index 0000000..4a6b802 --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/company.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Company < Data + attr_reader federal_tax_number: String + attr_reader id: String + def self.new: (federal_tax_number: String, id: String) -> instance + def initialize: (federal_tax_number: String, id: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/issuer.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/issuer.rbs new file mode 100644 index 0000000..3ad443a --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/issuer.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Issuer < Data + attr_reader federal_tax_number: String + attr_reader name: String + def self.new: (federal_tax_number: String, name: String) -> instance + def initialize: (federal_tax_number: String, name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/links.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/links.rbs new file mode 100644 index 0000000..ccdde46 --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/links.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Links < Data + attr_reader pdf: String + attr_reader xml: String + def self.new: (pdf: String, xml: String) -> instance + def initialize: (pdf: String, xml: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/product_invoice.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/product_invoice.rbs new file mode 100644 index 0000000..d66b9cb --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/product_invoice.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class ProductInvoice < Data + attr_reader access_key: String + def self.new: (access_key: String) -> instance + def initialize: (access_key: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio.rbs new file mode 100644 index 0000000..78de49b --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio.rbs @@ -0,0 +1,36 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Sucessonarequisio < Data + attr_reader access_key: String + attr_reader buyer: Buyer + attr_reader company: Company + attr_reader created_on: String + attr_reader description: String + attr_reader federal_tax_number_sender: String + attr_reader id: String + attr_reader issued_on: String + attr_reader issuer: Issuer + attr_reader links: Links + attr_reader name_sender: String + attr_reader nfe_number: String + attr_reader nfe_serial_number: String + attr_reader nsu: String + attr_reader nsu_parent: String + attr_reader operation_type: String? + attr_reader parent_access_key: String + attr_reader total_invoice_amount: String + attr_reader transportation: Transportation + attr_reader type: String? + attr_reader xml_url: String + def self.new: (access_key: String, buyer: Buyer, company: Company, created_on: String, description: String, federal_tax_number_sender: String, id: String, issued_on: String, issuer: Issuer, links: Links, name_sender: String, nfe_number: String, nfe_serial_number: String, nsu: String, nsu_parent: String, ?operation_type: String?, parent_access_key: String, total_invoice_amount: String, transportation: Transportation, ?type: String?, xml_url: String) -> instance + def initialize: (access_key: String, buyer: Buyer, company: Company, created_on: String, description: String, federal_tax_number_sender: String, id: String, issued_on: String, issuer: Issuer, links: Links, name_sender: String, nfe_number: String, nfe_serial_number: String, nsu: String, nsu_parent: String, ?operation_type: String?, parent_access_key: String, total_invoice_amount: String, transportation: Transportation, ?type: String?, xml_url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio2.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio2.rbs new file mode 100644 index 0000000..cfd55b5 --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio2.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Sucessonarequisio2 < Data + attr_reader automatic_manifesting: AutomaticManifesting + attr_reader company_id: String + attr_reader created_on: String + attr_reader environment_sefaz: String? + attr_reader modified_on: String + attr_reader start_from_date: String + attr_reader start_from_nsu: String + attr_reader status: String? + attr_reader webhook_version: String + def self.new: (automatic_manifesting: AutomaticManifesting, company_id: String, created_on: String, ?environment_sefaz: String?, modified_on: String, start_from_date: String, start_from_nsu: String, ?status: String?, webhook_version: String) -> instance + def initialize: (automatic_manifesting: AutomaticManifesting, company_id: String, created_on: String, ?environment_sefaz: String?, modified_on: String, start_from_date: String, start_from_nsu: String, ?status: String?, webhook_version: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio6.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio6.rbs new file mode 100644 index 0000000..113490b --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/sucessonarequisio6.rbs @@ -0,0 +1,34 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Sucessonarequisio6 < Data + attr_reader access_key: String + attr_reader buyer: Buyer + attr_reader company: Company + attr_reader created_on: String + attr_reader description: String + attr_reader federal_tax_number_sender: String + attr_reader id: String + attr_reader issued_on: String + attr_reader issuer: Issuer + attr_reader links: Links + attr_reader name_sender: String + attr_reader nfe_number: String + attr_reader nsu: String + attr_reader parent_access_key: String + attr_reader product_invoices: Array[ProductInvoice] + attr_reader total_invoice_amount: String + attr_reader transportation: Transportation + attr_reader type: String? + attr_reader xml_url: String + def self.new: (access_key: String, buyer: Buyer, company: Company, created_on: String, description: String, federal_tax_number_sender: String, id: String, issued_on: String, issuer: Issuer, links: Links, name_sender: String, nfe_number: String, nsu: String, parent_access_key: String, product_invoices: Array[ProductInvoice], total_invoice_amount: String, transportation: Transportation, ?type: String?, xml_url: String) -> instance + def initialize: (access_key: String, buyer: Buyer, company: Company, created_on: String, description: String, federal_tax_number_sender: String, id: String, issued_on: String, issuer: Issuer, links: Links, name_sender: String, nfe_number: String, nsu: String, parent_access_key: String, product_invoices: Array[ProductInvoice], total_invoice_amount: String, transportation: Transportation, ?type: String?, xml_url: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/consulta_nfe_distribuicao_v1/transportation.rbs b/sig/nfe/generated/consulta_nfe_distribuicao_v1/transportation.rbs new file mode 100644 index 0000000..c3e5936 --- /dev/null +++ b/sig/nfe/generated/consulta_nfe_distribuicao_v1/transportation.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/consulta-nfe-distribuicao-v1.yaml +# Hash: sha256:c28db6c6fed93a58342537de8131850f266d0cdff71873a3bab126b3309e3ea7 + +module Nfe + module Generated + module ConsultaNfeDistribuicaoV1 + class Transportation < Data + attr_reader federal_tax_number: String + attr_reader name: String + def self.new: (federal_tax_number: String, name: String) -> instance + def initialize: (federal_tax_number: String, name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address.rbs new file mode 100644 index 0000000..1783cc4 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_address.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Domain_Entities_Address < Data + attr_reader additional_information: String? + attr_reader city: DFeTech_TaxPayers_Domain_Entities_CityBase + attr_reader country: String? + attr_reader district: String? + attr_reader number: String? + attr_reader postal_code: String? + attr_reader state: String? + attr_reader street: String? + attr_reader street_prefix: String? + def self.new: (?additional_information: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityBase, ?country: String?, ?district: String?, ?number: String?, ?postal_code: String?, ?state: String?, ?street: String?, ?street_prefix: String?) -> instance + def initialize: (?additional_information: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityBase, ?country: String?, ?district: String?, ?number: String?, ?postal_code: String?, ?state: String?, ?street: String?, ?street_prefix: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment.rbs new file mode 100644 index 0000000..596bc09 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_api_environment.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_ApiEnvironment + Development: String + Production: String + Staging: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status.rbs new file mode 100644 index 0000000..d1643ee --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_certificate_status.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_CertificateStatus + None: String + Active: String + Inactive: String + Overdue: String + Pending: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base.rbs new file mode 100644 index 0000000..ed5e3e5 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_base.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Domain_Entities_CityBase < Data + attr_reader code: String? + attr_reader name: String? + def self.new: (?code: String?, ?name: String?) -> instance + def initialize: (?code: String?, ?name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended.rbs new file mode 100644 index 0000000..ab1d012 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_city_extended.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Domain_Entities_CityExtended < Data + attr_reader code: String? + attr_reader country: String? + attr_reader name: String? + attr_reader state: String? + def self.new: (?code: String?, ?country: String?, ?name: String?, ?state: String?) -> instance + def initialize: (?code: String?, ?country: String?, ?name: String?, ?state: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status.rbs new file mode 100644 index 0000000..817234f --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_company_fiscal_status.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_CompanyFiscalStatus + None: String + Active: String + CityNotSupported: String + Pending: String + Inactive: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type.rbs new file mode 100644 index 0000000..480dfb7 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_environment_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_EnvironmentType + None: String + Production: String + Test: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by.rbs new file mode 100644 index 0000000..d788cde --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_federal_tax_determination_by.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_FederalTaxDeterminationBy + NotInformed: String + Default: String + SimplesNacional: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature.rbs new file mode 100644 index 0000000..054a443 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_legal_nature.rbs @@ -0,0 +1,75 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_LegalNature + None: String + EmpresaPublica: String + SociedadeEconomiaMista: String + SociedadeAnonimaAberta: String + SociedadeAnonimaFechada: String + SociedadeEmpresariaLimitada: String + SociedadeEmpresariaEmNomeColetivo: String + SociedadeEmpresariaEmComanditaSimples: String + SociedadeEmpresariaEmComanditaporAcoes: String + SociedadeemContaParticipacao: String + Empresario: String + Cooperativa: String + ConsorcioSociedades: String + GrupoSociedades: String + SociedadeEstrangeiraNoBrasil: String + EmpresaBinacionalArgentinoBrasileira: String + EmpresaDomiciliadaExterior: String + ClubeFundoInvestimento: String + SociedadeSimplesPura: String + SociedadeSimplesLimitada: String + SociedadeSimplesEmNomeColetivo: String + SociedadeSimplesEmComanditaSimples: String + EmpresaBinacional: String + ConsorcioEmpregadores: String + ConsorcioSimples: String + EireliNaturezaEmpresaria: String + EireliNaturezaSimples: String + SociedadeUnipessoaldeAdvogados: String + CooperativaDeConsumo: String + EmpresaSimplesDeInovacao: String + InvestidorNaoResidente: String + ServicoNotarial: String + FundacaoPrivada: String + ServicoSocialAutonomo: String + CondominioEdilicio: String + ComissaoConciliacaoPrevia: String + EntidadeMediacaoArbitragem: String + PartidoPolitico: String + EntidadeSindical: String + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras: String + FundacaoAssociacaoDomiciliadaExterior: String + OrganizacaoReligiosa: String + ComunidadeIndigena: String + FundoPrivado: String + OrgaoDirecaoNacionalPartidoPolitico: String + OrgaoDirecaoRegionalPartidoPolitico: String + OrgaoDirecaoLocalPartidoPolitico: String + ComiteFinanceiroDePartidoPolitico: String + FrentePlebiscitariaOuReferendaria: String + OrganizacaoSocial: String + DemaisCondominios: String + PlanoBeneficiosPrevidenciaComplementarFechada: String + AssociacaoPrivada: String + EmpresaIndividualImobiliaria: String + SeguradoEspecial: String + ContribuinteIndividual: String + CandidatoCargoPoliticoEletivo: String + Leiloeiro: String + ProdutorRural: String + OrganizacaoInternacional: String + RepresentacaoDiplomaticaEstrangeira: String + OutrasInstituicoesExtraterritoriais: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by.rbs new file mode 100644 index 0000000..30576cc --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_determination_by.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_MunicipalTaxDeterminationBy + NotInformed: String + Default: String + SimplesNacional: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status.rbs new file mode 100644 index 0000000..1ee1d85 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_municipal_tax_fiscal_status.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_MunicipalTaxFiscalStatus + None: String + Active: String + CityNotSupported: String + Pending: String + Inactive: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential.rbs new file mode 100644 index 0000000..9ed3065 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_security_credential.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Domain_Entities_SecurityCredential < Data + attr_reader code: String? + attr_reader id: Integer + def self.new: (?code: String?, ?id: Integer) -> instance + def initialize: (?code: String?, ?id: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime.rbs new file mode 100644 index 0000000..f87c6d6 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_special_tax_regime.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_SpecialTaxRegime + Nenhum: String + MicroempresaMunicipal: String + Estimativa: String + SociedadeDeProfissionais: String + Cooperativa: String + MicroempreendedorIndividual: String + MicroempresarioEmpresaPequenoPorte: String + Automatico: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code.rbs new file mode 100644 index 0000000..3df914d --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_code.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_StateCode + NA: String + RO: String + AC: String + AM: String + RR: String + PA: String + AP: String + TO: String + MA: String + PI: String + CE: String + RN: String + PB: String + PE: String + AL: String + SE: String + BA: String + MG: String + ES: String + RJ: String + SP: String + PR: String + SC: String + RS: String + MS: String + MT: String + GO: String + DF: String + EX: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer.rbs new file mode 100644 index 0000000..d311659 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_processing_authorizer.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_StateTaxProcessingAuthorizer + Normal: String + EPEC: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type.rbs new file mode 100644 index 0000000..2fc9572 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_state_tax_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_StateTaxType + Default: String + NFe: String + NFCe: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status.rbs new file mode 100644 index 0000000..4d57af8 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_status.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_Status + None: String + Active: String + Inactive: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime.rbs new file mode 100644 index 0000000..d085e78 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_domain_entities_tax_regime.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Domain_Entities_TaxRegime + None: String + LucroReal: String + LucroPresumido: String + SimplesNacional: String + SimplesNacionalExcessoSublimite: String + MicroempreendedorIndividual: String + Isento: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource.rbs new file mode 100644 index 0000000..cd46a09 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_address_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_AddressResource < Data + attr_reader additional_information: String? + attr_reader city: DFeTech_TaxPayers_Resources_CityBaseResource + attr_reader country: String + attr_reader district: String + attr_reader number: String + attr_reader postal_code: String + attr_reader state: String + attr_reader street: String + def self.new: (?additional_information: String?, city: DFeTech_TaxPayers_Resources_CityBaseResource, country: String, district: String, number: String, postal_code: String, state: String, street: String) -> instance + def initialize: (?additional_information: String?, city: DFeTech_TaxPayers_Resources_CityBaseResource, country: String, district: String, number: String, postal_code: String, state: String, street: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource.rbs new file mode 100644 index 0000000..d7fd921 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CertificateMetadataResource < Data + attr_reader certificate: DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem + def self.new: (?certificate: DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem) -> instance + def initialize: (?certificate: DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item.rbs new file mode 100644 index 0000000..205be17 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificate_metadata_resource_item.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem < Data + attr_reader modified_on: String? + attr_reader status: untyped + attr_reader subject: String? + attr_reader tax_id: String? + attr_reader tax_payer_id: String? + attr_reader thumbprint: String? + attr_reader valid_until: String + def self.new: (?modified_on: String?, ?status: untyped, ?subject: String?, ?tax_id: String?, ?tax_payer_id: String?, ?thumbprint: String?, ?valid_until: String) -> instance + def initialize: (?modified_on: String?, ?status: untyped, ?subject: String?, ?tax_id: String?, ?tax_payer_id: String?, ?thumbprint: String?, ?valid_until: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource.rbs new file mode 100644 index 0000000..2dba6c8 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_certificates_metadata_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CertificatesMetadataResource < Data + attr_reader certificates: Array[DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem]? + def self.new: (?certificates: Array[DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem]?) -> instance + def initialize: (?certificates: Array[DFeTech_TaxPayers_Resources_CertificateMetadataResourceItem]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource.rbs new file mode 100644 index 0000000..abeeba3 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_city_base_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CityBaseResource < Data + attr_reader code: String + attr_reader name: String + def self.new: (code: String, name: String) -> instance + def initialize: (code: String, name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource.rbs new file mode 100644 index 0000000..7dfd78d --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_companies_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompaniesResource < Data + attr_reader companies: Array[DFeTech_TaxPayers_Resources_CompanyResourceItem]? + def self.new: (?companies: Array[DFeTech_TaxPayers_Resources_CompanyResourceItem]?) -> instance + def initialize: (?companies: Array[DFeTech_TaxPayers_Resources_CompanyResourceItem]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1.rbs new file mode 100644 index 0000000..2e8de41 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_certificate_v1.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompanyCertificateV1 < Data + attr_reader expires_on: String? + attr_reader modified_on: String? + attr_reader status: untyped + attr_reader thumbprint: String? + def self.new: (?expires_on: String?, ?modified_on: String?, ?status: untyped, ?thumbprint: String?) -> instance + def initialize: (?expires_on: String?, ?modified_on: String?, ?status: untyped, ?thumbprint: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1.rbs new file mode 100644 index 0000000..b0ddf76 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_collection_resource_v1.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompanyCollectionResourceV1 < Data + attr_reader companies: Array[DFeTech_TaxPayers_Resources_CompanyResourceV1]? + attr_reader page: Integer? + attr_reader total_pages: Integer? + attr_reader total_results: Integer? + def self.new: (?companies: Array[DFeTech_TaxPayers_Resources_CompanyResourceV1]?, ?page: Integer?, ?total_pages: Integer?, ?total_results: Integer?) -> instance + def initialize: (?companies: Array[DFeTech_TaxPayers_Resources_CompanyResourceV1]?, ?page: Integer?, ?total_pages: Integer?, ?total_results: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource.rbs new file mode 100644 index 0000000..06f2749 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompanyResource < Data + attr_reader company: DFeTech_TaxPayers_Resources_CompanyResourceItem + def self.new: (?company: DFeTech_TaxPayers_Resources_CompanyResourceItem) -> instance + def initialize: (?company: DFeTech_TaxPayers_Resources_CompanyResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item.rbs new file mode 100644 index 0000000..ca5859d --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_item.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompanyResourceItem < Data + attr_reader account_id: String? + attr_reader address: DFeTech_TaxPayers_Resources_AddressResource + attr_reader created_on: String + attr_reader federal_tax_number: Integer + attr_reader id: String? + attr_reader modified_on: String? + attr_reader municipal_tax_number: String? + attr_reader municipal_taxes: Array[String]? + attr_reader name: String + attr_reader state_taxes: Array[String]? + attr_reader status: untyped + attr_reader tax_regime: untyped + attr_reader trade_name: String? + def self.new: (?account_id: String?, address: DFeTech_TaxPayers_Resources_AddressResource, ?created_on: String, federal_tax_number: Integer, ?id: String?, ?modified_on: String?, ?municipal_tax_number: String?, ?municipal_taxes: Array[String]?, name: String, ?state_taxes: Array[String]?, ?status: untyped, tax_regime: untyped, ?trade_name: String?) -> instance + def initialize: (?account_id: String?, address: DFeTech_TaxPayers_Resources_AddressResource, ?created_on: String, federal_tax_number: Integer, ?id: String?, ?modified_on: String?, ?municipal_tax_number: String?, ?municipal_taxes: Array[String]?, name: String, ?state_taxes: Array[String]?, ?status: untyped, tax_regime: untyped, ?trade_name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1.rbs new file mode 100644 index 0000000..a172ac1 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_resource_v1.rbs @@ -0,0 +1,43 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompanyResourceV1 < Data + attr_reader address: DFeTech_TaxPayers_Domain_Entities_Address + attr_reader auth_issue_value: String? + attr_reader certificate: DFeTech_TaxPayers_Resources_CompanyCertificateV1 + attr_reader company_registry_number: Integer? + attr_reader created_on: String? + attr_reader email: String? + attr_reader environment: untyped + attr_reader federal_tax_determination: untyped + attr_reader federal_tax_number: Integer? + attr_reader fiscal_status: untyped + attr_reader id: String? + attr_reader iss_rate: Float? + attr_reader last_rps_sent: Integer? + attr_reader legal_nature: untyped + attr_reader login_name: String? + attr_reader login_password: String? + attr_reader modified_on: String? + attr_reader municipal_tax_determination: untyped + attr_reader municipal_tax_number: String? + attr_reader name: String? + attr_reader openning_date: String? + attr_reader regional_tax_number: Integer? + attr_reader rps_number: Integer? + attr_reader rps_serial_number: String? + attr_reader special_tax_regime: untyped + attr_reader status: untyped + attr_reader tax_regime: untyped + attr_reader trade_name: String? + def self.new: (?address: DFeTech_TaxPayers_Domain_Entities_Address, ?auth_issue_value: String?, ?certificate: DFeTech_TaxPayers_Resources_CompanyCertificateV1, ?company_registry_number: Integer?, ?created_on: String?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?federal_tax_number: Integer?, ?fiscal_status: untyped, ?id: String?, ?iss_rate: Float?, ?last_rps_sent: Integer?, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?modified_on: String?, ?municipal_tax_determination: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_tax_number: Integer?, ?rps_number: Integer?, ?rps_serial_number: String?, ?special_tax_regime: untyped, ?status: untyped, ?tax_regime: untyped, ?trade_name: String?) -> instance + def initialize: (?address: DFeTech_TaxPayers_Domain_Entities_Address, ?auth_issue_value: String?, ?certificate: DFeTech_TaxPayers_Resources_CompanyCertificateV1, ?company_registry_number: Integer?, ?created_on: String?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?federal_tax_number: Integer?, ?fiscal_status: untyped, ?id: String?, ?iss_rate: Float?, ?last_rps_sent: Integer?, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?modified_on: String?, ?municipal_tax_determination: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_tax_number: Integer?, ?rps_number: Integer?, ?rps_serial_number: String?, ?special_tax_regime: untyped, ?status: untyped, ?tax_regime: untyped, ?trade_name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1.rbs new file mode 100644 index 0000000..d873b91 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_company_single_resource_v1.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CompanySingleResourceV1 < Data + attr_reader companies: DFeTech_TaxPayers_Resources_CompanyResourceV1 + def self.new: (?companies: DFeTech_TaxPayers_Resources_CompanyResourceV1) -> instance + def initialize: (?companies: DFeTech_TaxPayers_Resources_CompanyResourceV1) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource.rbs new file mode 100644 index 0000000..6f35d54 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateCompanyResource < Data + attr_reader company: DFeTech_TaxPayers_Resources_CreateCompanyResourceItem + def self.new: (?company: DFeTech_TaxPayers_Resources_CreateCompanyResourceItem) -> instance + def initialize: (?company: DFeTech_TaxPayers_Resources_CreateCompanyResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item.rbs new file mode 100644 index 0000000..e870af3 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_company_resource_item.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateCompanyResourceItem < Data + attr_reader account_id: String? + attr_reader address: DFeTech_TaxPayers_Resources_AddressResource + attr_reader federal_tax_number: Integer + attr_reader municipal_tax_number: String? + attr_reader name: String + attr_reader tax_regime: untyped + attr_reader trade_name: String? + def self.new: (?account_id: String?, address: DFeTech_TaxPayers_Resources_AddressResource, federal_tax_number: Integer, ?municipal_tax_number: String?, name: String, tax_regime: untyped, ?trade_name: String?) -> instance + def initialize: (?account_id: String?, address: DFeTech_TaxPayers_Resources_AddressResource, federal_tax_number: Integer, ?municipal_tax_number: String?, name: String, tax_regime: untyped, ?trade_name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource.rbs new file mode 100644 index 0000000..f0baf4a --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateMunicipalTaxResource < Data + attr_reader municipal_tax: DFeTech_TaxPayers_Resources_CreateMunicipalTaxResourceItem + def self.new: (?municipal_tax: DFeTech_TaxPayers_Resources_CreateMunicipalTaxResourceItem) -> instance + def initialize: (?municipal_tax: DFeTech_TaxPayers_Resources_CreateMunicipalTaxResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item.rbs new file mode 100644 index 0000000..d00fca0 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_municipal_tax_resource_item.rbs @@ -0,0 +1,32 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateMunicipalTaxResourceItem < Data + attr_reader auth_issue_value: String? + attr_reader city: DFeTech_TaxPayers_Domain_Entities_CityExtended + attr_reader company_registry_number: Integer? + attr_reader email: String? + attr_reader environment: untyped + attr_reader federal_tax_determination: untyped + attr_reader iss_rate: Float? + attr_reader last_rps_sent: Integer + attr_reader legal_nature: untyped + attr_reader login_name: String? + attr_reader login_password: String? + attr_reader municipal_tax_determination: untyped + attr_reader regional_tax_number: Integer? + attr_reader rps_number: Integer + attr_reader rps_serial_number: String? + attr_reader special_tax_regime: untyped + attr_reader tax_number: String? + def self.new: (?auth_issue_value: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityExtended, ?company_registry_number: Integer?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?iss_rate: Float?, ?last_rps_sent: Integer, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?municipal_tax_determination: untyped, ?regional_tax_number: Integer?, ?rps_number: Integer, ?rps_serial_number: String?, ?special_tax_regime: untyped, ?tax_number: String?) -> instance + def initialize: (?auth_issue_value: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityExtended, ?company_registry_number: Integer?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?iss_rate: Float?, ?last_rps_sent: Integer, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?municipal_tax_determination: untyped, ?regional_tax_number: Integer?, ?rps_number: Integer, ?rps_serial_number: String?, ?special_tax_regime: untyped, ?tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource.rbs new file mode 100644 index 0000000..6c280ab --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_processing_details_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource < Data + attr_reader switch_authorizer_strategy: untyped + def self.new: (?switch_authorizer_strategy: untyped) -> instance + def initialize: (?switch_authorizer_strategy: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource.rbs new file mode 100644 index 0000000..d021a74 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateStateTaxResource < Data + attr_reader state_tax: DFeTech_TaxPayers_Resources_CreateStateTaxResourceItem + def self.new: (?state_tax: DFeTech_TaxPayers_Resources_CreateStateTaxResourceItem) -> instance + def initialize: (?state_tax: DFeTech_TaxPayers_Resources_CreateStateTaxResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item.rbs new file mode 100644 index 0000000..ff466cf --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_create_state_tax_resource_item.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_CreateStateTaxResourceItem < Data + attr_reader code: untyped + attr_reader environment_type: untyped + attr_reader number: Integer? + attr_reader processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource + attr_reader security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential + attr_reader serie: Integer? + attr_reader special_tax_regime: untyped + attr_reader tax_number: String + attr_reader type: untyped + def self.new: (code: untyped, ?environment_type: untyped, ?number: Integer?, ?processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource, ?security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential, ?serie: Integer?, ?special_tax_regime: untyped, tax_number: String, type: untyped) -> instance + def initialize: (code: untyped, ?environment_type: untyped, ?number: Integer?, ?processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource, ?security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential, ?serie: Integer?, ?special_tax_regime: untyped, tax_number: String, type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource.rbs new file mode 100644 index 0000000..e4d80dc --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_error_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_ErrorResource < Data + attr_reader code: Integer? + attr_reader message: String? + def self.new: (?code: Integer?, ?message: String?) -> instance + def initialize: (?code: Integer?, ?message: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource.rbs new file mode 100644 index 0000000..d9d257e --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_errors_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_ErrorsResource < Data + attr_reader errors: Array[DFeTech_TaxPayers_Resources_ErrorResource]? + def self.new: (?errors: Array[DFeTech_TaxPayers_Resources_ErrorResource]?) -> instance + def initialize: (?errors: Array[DFeTech_TaxPayers_Resources_ErrorResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource.rbs new file mode 100644 index 0000000..2f7cf87 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_MunicipalTaxResource < Data + attr_reader municipal_tax: DFeTech_TaxPayers_Resources_MunicipalTaxResourceItem + def self.new: (?municipal_tax: DFeTech_TaxPayers_Resources_MunicipalTaxResourceItem) -> instance + def initialize: (?municipal_tax: DFeTech_TaxPayers_Resources_MunicipalTaxResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item.rbs new file mode 100644 index 0000000..e864f64 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_municipal_tax_resource_item.rbs @@ -0,0 +1,38 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_MunicipalTaxResourceItem < Data + attr_reader account_id: String? + attr_reader auth_issue_value: String? + attr_reader city: DFeTech_TaxPayers_Domain_Entities_CityExtended + attr_reader company_id: String? + attr_reader company_registry_number: Integer? + attr_reader email: String? + attr_reader environment: untyped + attr_reader federal_tax_determination: untyped + attr_reader fiscal_status: untyped + attr_reader id: String? + attr_reader iss_rate: Float? + attr_reader last_rps_sent: Integer + attr_reader legal_nature: untyped + attr_reader login_name: String? + attr_reader login_password: String? + attr_reader municipal_tax_determination: untyped + attr_reader regional_tax_number: Integer? + attr_reader rps_number: Integer + attr_reader rps_serial_number: String? + attr_reader rps_serial_numbers: Array[String]? + attr_reader special_tax_regime: untyped + attr_reader status: untyped + attr_reader tax_number: String? + def self.new: (?account_id: String?, ?auth_issue_value: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityExtended, ?company_id: String?, ?company_registry_number: Integer?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?fiscal_status: untyped, ?id: String?, ?iss_rate: Float?, ?last_rps_sent: Integer, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?municipal_tax_determination: untyped, ?regional_tax_number: Integer?, ?rps_number: Integer, ?rps_serial_number: String?, ?rps_serial_numbers: Array[String]?, ?special_tax_regime: untyped, ?status: untyped, ?tax_number: String?) -> instance + def initialize: (?account_id: String?, ?auth_issue_value: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityExtended, ?company_id: String?, ?company_registry_number: Integer?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?fiscal_status: untyped, ?id: String?, ?iss_rate: Float?, ?last_rps_sent: Integer, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?municipal_tax_determination: untyped, ?regional_tax_number: Integer?, ?rps_number: Integer, ?rps_serial_number: String?, ?rps_serial_numbers: Array[String]?, ?special_tax_regime: untyped, ?status: untyped, ?tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource.rbs new file mode 100644 index 0000000..86a7973 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_SerieResource < Data + attr_reader serie: DFeTech_TaxPayers_Resources_SerieResourceItem + def self.new: (?serie: DFeTech_TaxPayers_Resources_SerieResourceItem) -> instance + def initialize: (?serie: DFeTech_TaxPayers_Resources_SerieResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item.rbs new file mode 100644 index 0000000..088fad7 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_serie_resource_item.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_SerieResourceItem < Data + attr_reader last_rps_sent: Integer + attr_reader rps_number: Integer + def self.new: (?last_rps_sent: Integer, ?rps_number: Integer) -> instance + def initialize: (?last_rps_sent: Integer, ?rps_number: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource.rbs new file mode 100644 index 0000000..574dbfc --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_authorizer_resource.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Resources_StateTaxProcessingAuthorizerResource + Normal: String + EPEC: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource.rbs new file mode 100644 index 0000000..648df1a --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_processing_switch_authorizer_strategy_resource.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module DFeTech_TaxPayers_Resources_StateTaxProcessingSwitchAuthorizerStrategyResource + Manual: String + StateTaxAuthorityStatusUnavailable: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource.rbs new file mode 100644 index 0000000..1f7f6e3 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_StateTaxResource < Data + attr_reader state_tax: DFeTech_TaxPayers_Resources_StateTaxResourceItem + def self.new: (?state_tax: DFeTech_TaxPayers_Resources_StateTaxResourceItem) -> instance + def initialize: (?state_tax: DFeTech_TaxPayers_Resources_StateTaxResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item.rbs new file mode 100644 index 0000000..c8c40ef --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_resource_item.rbs @@ -0,0 +1,31 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_StateTaxResourceItem < Data + attr_reader account_id: String? + attr_reader code: untyped + attr_reader company_id: String? + attr_reader created_on: String + attr_reader environment_type: untyped + attr_reader id: String? + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource + attr_reader security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential + attr_reader serie: Integer? + attr_reader series: Array[Integer]? + attr_reader special_tax_regime: untyped + attr_reader status: untyped + attr_reader tax_number: String + attr_reader type: untyped + def self.new: (?account_id: String?, code: untyped, ?company_id: String?, ?created_on: String, ?environment_type: untyped, ?id: String?, ?modified_on: String?, ?number: Integer?, ?processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource, ?security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential, ?serie: Integer?, ?series: Array[Integer]?, ?special_tax_regime: untyped, ?status: untyped, tax_number: String, type: untyped) -> instance + def initialize: (?account_id: String?, code: untyped, ?company_id: String?, ?created_on: String, ?environment_type: untyped, ?id: String?, ?modified_on: String?, ?number: Integer?, ?processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource, ?security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential, ?serie: Integer?, ?series: Array[Integer]?, ?special_tax_regime: untyped, ?status: untyped, tax_number: String, type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request.rbs new file mode 100644 index 0000000..c297c9f --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_request.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_StateTaxSwitchAuthorizerRequest < Data + attr_reader authorizer: untyped + attr_reader reason: String? + def self.new: (?authorizer: untyped, ?reason: String?) -> instance + def initialize: (?authorizer: untyped, ?reason: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response.rbs new file mode 100644 index 0000000..a3ed17b --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_tax_switch_authorizer_response.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_StateTaxSwitchAuthorizerResponse < Data + attr_reader from_authorizer: untyped + attr_reader modified_on: String + attr_reader reason: String? + attr_reader to_authorizer: untyped + def self.new: (?from_authorizer: untyped, ?modified_on: String, ?reason: String?, ?to_authorizer: untyped) -> instance + def initialize: (?from_authorizer: untyped, ?modified_on: String, ?reason: String?, ?to_authorizer: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource.rbs new file mode 100644 index 0000000..9553dda --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_state_taxes_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_StateTaxesResource < Data + attr_reader state_taxes: Array[DFeTech_TaxPayers_Resources_StateTaxResourceItem]? + def self.new: (?state_taxes: Array[DFeTech_TaxPayers_Resources_StateTaxResourceItem]?) -> instance + def initialize: (?state_taxes: Array[DFeTech_TaxPayers_Resources_StateTaxResourceItem]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource.rbs new file mode 100644 index 0000000..a37d946 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_UpdateCompanyResource < Data + attr_reader company: DFeTech_TaxPayers_Resources_UpdateCompanyResourceItem + def self.new: (?company: DFeTech_TaxPayers_Resources_UpdateCompanyResourceItem) -> instance + def initialize: (?company: DFeTech_TaxPayers_Resources_UpdateCompanyResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item.rbs new file mode 100644 index 0000000..bb6def9 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_company_resource_item.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_UpdateCompanyResourceItem < Data + attr_reader account_id: String? + attr_reader address: DFeTech_TaxPayers_Resources_AddressResource + attr_reader federal_tax_number: Integer + attr_reader id: String? + attr_reader municipal_tax_number: String? + attr_reader name: String + attr_reader tax_regime: untyped + attr_reader trade_name: String? + def self.new: (?account_id: String?, address: DFeTech_TaxPayers_Resources_AddressResource, federal_tax_number: Integer, ?id: String?, ?municipal_tax_number: String?, name: String, tax_regime: untyped, ?trade_name: String?) -> instance + def initialize: (?account_id: String?, address: DFeTech_TaxPayers_Resources_AddressResource, federal_tax_number: Integer, ?id: String?, ?municipal_tax_number: String?, name: String, tax_regime: untyped, ?trade_name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource.rbs new file mode 100644 index 0000000..836ad8c --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResource < Data + attr_reader municipal_tax: DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResourceItem + def self.new: (?municipal_tax: DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResourceItem) -> instance + def initialize: (?municipal_tax: DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item.rbs new file mode 100644 index 0000000..583dbd8 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_municipal_tax_resource_item.rbs @@ -0,0 +1,32 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_UpdateMunicipalTaxResourceItem < Data + attr_reader auth_issue_value: String? + attr_reader city: DFeTech_TaxPayers_Domain_Entities_CityExtended + attr_reader company_registry_number: Integer? + attr_reader email: String? + attr_reader environment: untyped + attr_reader federal_tax_determination: untyped + attr_reader iss_rate: Float? + attr_reader last_rps_sent: Integer + attr_reader legal_nature: untyped + attr_reader login_name: String? + attr_reader login_password: String? + attr_reader municipal_tax_determination: untyped + attr_reader regional_tax_number: Integer? + attr_reader rps_number: Integer + attr_reader rps_serial_number: String? + attr_reader special_tax_regime: untyped + attr_reader tax_number: String? + def self.new: (?auth_issue_value: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityExtended, ?company_registry_number: Integer?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?iss_rate: Float?, ?last_rps_sent: Integer, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?municipal_tax_determination: untyped, ?regional_tax_number: Integer?, ?rps_number: Integer, ?rps_serial_number: String?, ?special_tax_regime: untyped, ?tax_number: String?) -> instance + def initialize: (?auth_issue_value: String?, ?city: DFeTech_TaxPayers_Domain_Entities_CityExtended, ?company_registry_number: Integer?, ?email: String?, ?environment: untyped, ?federal_tax_determination: untyped, ?iss_rate: Float?, ?last_rps_sent: Integer, ?legal_nature: untyped, ?login_name: String?, ?login_password: String?, ?municipal_tax_determination: untyped, ?regional_tax_number: Integer?, ?rps_number: Integer, ?rps_serial_number: String?, ?special_tax_regime: untyped, ?tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource.rbs new file mode 100644 index 0000000..9d59779 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_UpdateStateTaxResource < Data + attr_reader state_tax: DFeTech_TaxPayers_Resources_UpdateStateTaxResourceItem + def self.new: (?state_tax: DFeTech_TaxPayers_Resources_UpdateStateTaxResourceItem) -> instance + def initialize: (?state_tax: DFeTech_TaxPayers_Resources_UpdateStateTaxResourceItem) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item.rbs b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item.rbs new file mode 100644 index 0000000..f75200c --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/dfe_tech_tax_payers_resources_update_state_tax_resource_item.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class DFeTech_TaxPayers_Resources_UpdateStateTaxResourceItem < Data + attr_reader code: untyped + attr_reader environment_type: untyped + attr_reader number: Integer? + attr_reader processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource + attr_reader security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential + attr_reader serie: Integer? + attr_reader special_tax_regime: untyped + attr_reader tax_number: String + attr_reader type: untyped + def self.new: (code: untyped, ?environment_type: untyped, ?number: Integer?, ?processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource, ?security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential, ?serie: Integer?, ?special_tax_regime: untyped, tax_number: String, type: untyped) -> instance + def initialize: (code: untyped, ?environment_type: untyped, ?number: Integer?, ?processing_details: DFeTech_TaxPayers_Resources_CreateStateTaxProcessingDetailsResource, ?security_credential: DFeTech_TaxPayers_Domain_Entities_SecurityCredential, ?serie: Integer?, ?special_tax_regime: untyped, tax_number: String, type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind.rbs new file mode 100644 index 0000000..f720ee2 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_container_element_kind.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmContainerElementKind + None: String + EntitySet: String + ActionImport: String + FunctionImport: String + Singleton: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind.rbs new file mode 100644 index 0000000..75c5790 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_expression_kind.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmExpressionKind + None: String + BinaryConstant: String + BooleanConstant: String + DateTimeOffsetConstant: String + DecimalConstant: String + FloatingConstant: String + GuidConstant: String + IntegerConstant: String + StringConstant: String + DurationConstant: String + Null: String + Record: String + Collection: String + Path: String + If: String + Cast: String + IsOf: String + FunctionApplication: String + LabeledExpressionReference: String + Labeled: String + PropertyPath: String + NavigationPropertyPath: String + DateConstant: String + TimeOfDayConstant: String + EnumMember: String + AnnotationPath: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind.rbs new file mode 100644 index 0000000..3f4ec37 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_schema_element_kind.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmSchemaElementKind + None: String + TypeDefinition: String + Term: String + Action: String + EntityContainer: String + Function: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind.rbs new file mode 100644 index 0000000..49aada7 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_edm_type_kind.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + module Microsoft_OData_Edm_EdmTypeKind + None: String + Primitive: String + Entity: String + Complex: String + Collection: String + EntityReference: String + Enum: String + TypeDefinition: String + Untyped: String + Path: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container.rbs new file mode 100644 index 0000000..b495d33 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmEntityContainer < Data + attr_reader elements: Array[Microsoft_OData_Edm_IEdmEntityContainerElement]? + attr_reader name: String? + attr_reader namespace: String? + attr_reader schema_element_kind: untyped + def self.new: (?elements: Array[Microsoft_OData_Edm_IEdmEntityContainerElement]?, ?name: String?, ?namespace: String?, ?schema_element_kind: untyped) -> instance + def initialize: (?elements: Array[Microsoft_OData_Edm_IEdmEntityContainerElement]?, ?name: String?, ?namespace: String?, ?schema_element_kind: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element.rbs new file mode 100644 index 0000000..f7b17f4 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_entity_container_element.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmEntityContainerElement < Data + attr_reader container: Microsoft_OData_Edm_IEdmEntityContainer + attr_reader container_element_kind: untyped + attr_reader name: String? + def self.new: (?container: Microsoft_OData_Edm_IEdmEntityContainer, ?container_element_kind: untyped, ?name: String?) -> instance + def initialize: (?container: Microsoft_OData_Edm_IEdmEntityContainer, ?container_element_kind: untyped, ?name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_expression.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_expression.rbs new file mode 100644 index 0000000..e5e2070 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_expression.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmExpression < Data + attr_reader expression_kind: untyped + def self.new: (?expression_kind: untyped) -> instance + def initialize: (?expression_kind: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_model.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_model.rbs new file mode 100644 index 0000000..72c56cb --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_model.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmModel < Data + attr_reader declared_namespaces: Array[String]? + attr_reader direct_value_annotations_manager: Hash[String, untyped] + attr_reader entity_container: Microsoft_OData_Edm_IEdmEntityContainer + attr_reader referenced_models: Array[Microsoft_OData_Edm_IEdmModel]? + attr_reader schema_elements: Array[Microsoft_OData_Edm_IEdmSchemaElement]? + attr_reader vocabulary_annotations: Array[Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotation]? + def self.new: (?declared_namespaces: Array[String]?, ?direct_value_annotations_manager: Hash[String, untyped], ?entity_container: Microsoft_OData_Edm_IEdmEntityContainer, ?referenced_models: Array[Microsoft_OData_Edm_IEdmModel]?, ?schema_elements: Array[Microsoft_OData_Edm_IEdmSchemaElement]?, ?vocabulary_annotations: Array[Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotation]?) -> instance + def initialize: (?declared_namespaces: Array[String]?, ?direct_value_annotations_manager: Hash[String, untyped], ?entity_container: Microsoft_OData_Edm_IEdmEntityContainer, ?referenced_models: Array[Microsoft_OData_Edm_IEdmModel]?, ?schema_elements: Array[Microsoft_OData_Edm_IEdmSchemaElement]?, ?vocabulary_annotations: Array[Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotation]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element.rbs new file mode 100644 index 0000000..29d6909 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_schema_element.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmSchemaElement < Data + attr_reader name: String? + attr_reader namespace: String? + attr_reader schema_element_kind: untyped + def self.new: (?name: String?, ?namespace: String?, ?schema_element_kind: untyped) -> instance + def initialize: (?name: String?, ?namespace: String?, ?schema_element_kind: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type.rbs new file mode 100644 index 0000000..dc696df --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmType < Data + attr_reader type_kind: untyped + def self.new: (?type_kind: untyped) -> instance + def initialize: (?type_kind: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference.rbs new file mode 100644 index 0000000..7f4834b --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_iedm_type_reference.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_IEdmTypeReference < Data + attr_reader definition: Microsoft_OData_Edm_IEdmType + attr_reader is_nullable: bool + def self.new: (?definition: Microsoft_OData_Edm_IEdmType, ?is_nullable: bool) -> instance + def initialize: (?definition: Microsoft_OData_Edm_IEdmType, ?is_nullable: bool) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager.rbs new file mode 100644 index 0000000..faae7f3 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_direct_value_annotations_manager.rbs @@ -0,0 +1,11 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_Vocabularies_IEdmDirectValueAnnotationsManager: Hash[String, untyped] + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term.rbs new file mode 100644 index 0000000..4676397 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_term.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_Vocabularies_IEdmTerm < Data + attr_reader applies_to: String? + attr_reader default_value: String? + attr_reader name: String? + attr_reader namespace: String? + attr_reader schema_element_kind: untyped + attr_reader type: Microsoft_OData_Edm_IEdmTypeReference + def self.new: (?applies_to: String?, ?default_value: String?, ?name: String?, ?namespace: String?, ?schema_element_kind: untyped, ?type: Microsoft_OData_Edm_IEdmTypeReference) -> instance + def initialize: (?applies_to: String?, ?default_value: String?, ?name: String?, ?namespace: String?, ?schema_element_kind: untyped, ?type: Microsoft_OData_Edm_IEdmTypeReference) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable.rbs new file mode 100644 index 0000000..35190d7 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotatable.rbs @@ -0,0 +1,11 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotatable: Hash[String, untyped] + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation.rbs new file mode 100644 index 0000000..c3ab572 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_edm_vocabularies_iedm_vocabulary_annotation.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_Edm_Vocabularies_IEdmVocabularyAnnotation < Data + attr_reader qualifier: String? + attr_reader target: Hash[String, untyped] + attr_reader term: Microsoft_OData_Edm_Vocabularies_IEdmTerm + attr_reader uses_default: bool + attr_reader value: Microsoft_OData_Edm_IEdmExpression + def self.new: (?qualifier: String?, ?target: Hash[String, untyped], ?term: Microsoft_OData_Edm_Vocabularies_IEdmTerm, ?uses_default: bool, ?value: Microsoft_OData_Edm_IEdmExpression) -> instance + def initialize: (?qualifier: String?, ?target: Hash[String, untyped], ?term: Microsoft_OData_Edm_Vocabularies_IEdmTerm, ?uses_default: bool, ?value: Microsoft_OData_Edm_IEdmExpression) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_entity_set_info.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_entity_set_info.rbs new file mode 100644 index 0000000..02f751c --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_entity_set_info.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_ODataEntitySetInfo < Data + attr_reader name: String? + attr_reader title: String? + attr_reader type_annotation: Microsoft_OData_ODataTypeAnnotation + attr_reader url: String? + def self.new: (?name: String?, ?title: String?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation, ?url: String?) -> instance + def initialize: (?name: String?, ?title: String?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation, ?url: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_function_import_info.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_function_import_info.rbs new file mode 100644 index 0000000..2f45d5f --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_function_import_info.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_ODataFunctionImportInfo < Data + attr_reader name: String? + attr_reader title: String? + attr_reader type_annotation: Microsoft_OData_ODataTypeAnnotation + attr_reader url: String? + def self.new: (?name: String?, ?title: String?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation, ?url: String?) -> instance + def initialize: (?name: String?, ?title: String?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation, ?url: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_service_document.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_service_document.rbs new file mode 100644 index 0000000..7fb5a8c --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_service_document.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_ODataServiceDocument < Data + attr_reader entity_sets: Array[Microsoft_OData_ODataEntitySetInfo]? + attr_reader function_imports: Array[Microsoft_OData_ODataFunctionImportInfo]? + attr_reader singletons: Array[Microsoft_OData_ODataSingletonInfo]? + attr_reader type_annotation: Microsoft_OData_ODataTypeAnnotation + def self.new: (?entity_sets: Array[Microsoft_OData_ODataEntitySetInfo]?, ?function_imports: Array[Microsoft_OData_ODataFunctionImportInfo]?, ?singletons: Array[Microsoft_OData_ODataSingletonInfo]?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation) -> instance + def initialize: (?entity_sets: Array[Microsoft_OData_ODataEntitySetInfo]?, ?function_imports: Array[Microsoft_OData_ODataFunctionImportInfo]?, ?singletons: Array[Microsoft_OData_ODataSingletonInfo]?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_singleton_info.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_singleton_info.rbs new file mode 100644 index 0000000..f64b394 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_singleton_info.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_ODataSingletonInfo < Data + attr_reader name: String? + attr_reader title: String? + attr_reader type_annotation: Microsoft_OData_ODataTypeAnnotation + attr_reader url: String? + def self.new: (?name: String?, ?title: String?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation, ?url: String?) -> instance + def initialize: (?name: String?, ?title: String?, ?type_annotation: Microsoft_OData_ODataTypeAnnotation, ?url: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_type_annotation.rbs b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_type_annotation.rbs new file mode 100644 index 0000000..d044793 --- /dev/null +++ b/sig/nfe/generated/contribuintes_v2/microsoft_odata_odata_type_annotation.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/contribuintes-v2.json +# Hash: sha256:e2d215a19f5dc85c08067d51644e807aae32b6c4754390872670f2e18a938102 + +module Nfe + module Generated + module ContribuintesV2 + class Microsoft_OData_ODataTypeAnnotation < Data + attr_reader type_name: String? + def self.new: (?type_name: String?) -> instance + def initialize: (?type_name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/activity_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/activity_resource.rbs new file mode 100644 index 0000000..5169a04 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/activity_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ActivityResource < Data + attr_reader data: untyped + attr_reader sequence: Integer? + attr_reader type: String? + def self.new: (?data: untyped, ?sequence: Integer?, ?type: String?) -> instance + def initialize: (?data: untyped, ?sequence: Integer?, ?type: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/addition_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/addition_resource.rbs new file mode 100644 index 0000000..0e2ff4d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/addition_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class AdditionResource < Data + attr_reader amount: Float? + attr_reader code: Integer? + attr_reader drawback: Integer? + attr_reader manufacturer: String? + def self.new: (?amount: Float?, ?code: Integer?, ?drawback: Integer?, ?manufacturer: String?) -> instance + def initialize: (?amount: Float?, ?code: Integer?, ?drawback: Integer?, ?manufacturer: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/additional_information_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/additional_information_resource.rbs new file mode 100644 index 0000000..4685807 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/additional_information_resource.rbs @@ -0,0 +1,25 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class AdditionalInformationResource < Data + attr_reader advance_payment: Array[AdvancePaymentItemResource]? + attr_reader contract: String? + attr_reader effort: String? + attr_reader fisco: String? + attr_reader order: String? + attr_reader referenced_process: Array[ReferencedProcessResource]? + attr_reader tax_documents_reference: Array[TaxDocumentsReferenceResource]? + attr_reader taxpayer: String? + attr_reader taxpayer_comments: Array[TaxpayerCommentsResource]? + attr_reader xml_authorized: Array[Integer]? + def self.new: (?advance_payment: Array[AdvancePaymentItemResource]?, ?contract: String?, ?effort: String?, ?fisco: String?, ?order: String?, ?referenced_process: Array[ReferencedProcessResource]?, ?tax_documents_reference: Array[TaxDocumentsReferenceResource]?, ?taxpayer: String?, ?taxpayer_comments: Array[TaxpayerCommentsResource]?, ?xml_authorized: Array[Integer]?) -> instance + def initialize: (?advance_payment: Array[AdvancePaymentItemResource]?, ?contract: String?, ?effort: String?, ?fisco: String?, ?order: String?, ?referenced_process: Array[ReferencedProcessResource]?, ?tax_documents_reference: Array[TaxDocumentsReferenceResource]?, ?taxpayer: String?, ?taxpayer_comments: Array[TaxpayerCommentsResource]?, ?xml_authorized: Array[Integer]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/address_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/address_resource.rbs new file mode 100644 index 0000000..b36619f --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/address_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class AddressResource < Data + attr_reader additional_information: String? + attr_reader city: CityResource + attr_reader country: String? + attr_reader district: String? + attr_reader number: String? + attr_reader phone: String? + attr_reader postal_code: String? + attr_reader state: String? + attr_reader street: String? + def self.new: (?additional_information: String?, ?city: CityResource, ?country: String?, ?district: String?, ?number: String?, ?phone: String?, ?postal_code: String?, ?state: String?, ?street: String?) -> instance + def initialize: (?additional_information: String?, ?city: CityResource, ?country: String?, ?district: String?, ?number: String?, ?phone: String?, ?postal_code: String?, ?state: String?, ?street: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/advance_payment_item_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/advance_payment_item_resource.rbs new file mode 100644 index 0000000..83f2689 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/advance_payment_item_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class AdvancePaymentItemResource < Data + attr_reader access_key: String? + def self.new: (?access_key: String?) -> instance + def initialize: (?access_key: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/authorization_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/authorization_resource.rbs new file mode 100644 index 0000000..d49b6a2 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/authorization_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class AuthorizationResource < Data + attr_reader access_key: String? + attr_reader message: String? + attr_reader receipt_on: String? + def self.new: (?access_key: String?, ?message: String?, ?receipt_on: String?) -> instance + def initialize: (?access_key: String?, ?message: String?, ?receipt_on: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/bill_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/bill_resource.rbs new file mode 100644 index 0000000..eefa25b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/bill_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class BillResource < Data + attr_reader discount_amount: Float? + attr_reader net_amount: Float? + attr_reader number: String? + attr_reader original_amount: Float? + def self.new: (?discount_amount: Float?, ?net_amount: Float?, ?number: String?, ?original_amount: Float?) -> instance + def initialize: (?discount_amount: Float?, ?net_amount: Float?, ?number: String?, ?original_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/billing_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/billing_resource.rbs new file mode 100644 index 0000000..0b66d46 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/billing_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class BillingResource < Data + attr_reader bill: BillResource + attr_reader duplicates: Array[DuplicateResource]? + def self.new: (?bill: BillResource, ?duplicates: Array[DuplicateResource]?) -> instance + def initialize: (?bill: BillResource, ?duplicates: Array[DuplicateResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/buyer_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/buyer_resource.rbs new file mode 100644 index 0000000..9f634c7 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/buyer_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class BuyerResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader state_tax_number_indicator: untyped + attr_reader tax_regime: untyped + attr_reader trade_name: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?state_tax_number_indicator: untyped, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?state_tax_number_indicator: untyped, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/card_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/card_resource.rbs new file mode 100644 index 0000000..cdf5e00 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/card_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CardResource < Data + attr_reader authorization: String? + attr_reader federal_tax_number: String? + attr_reader federal_tax_number_recipient: String? + attr_reader flag: untyped + attr_reader id_payment_terminal: String? + attr_reader integration_payment_type: untyped + def self.new: (?authorization: String?, ?federal_tax_number: String?, ?federal_tax_number_recipient: String?, ?flag: untyped, ?id_payment_terminal: String?, ?integration_payment_type: untyped) -> instance + def initialize: (?authorization: String?, ?federal_tax_number: String?, ?federal_tax_number_recipient: String?, ?flag: untyped, ?id_payment_terminal: String?, ?integration_payment_type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/cbstax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/cbstax_resource.rbs new file mode 100644 index 0000000..39ee165 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/cbstax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CBSTaxResource < Data + attr_reader amount: Float? + attr_reader deferment: DefermentTaxResource + attr_reader rate: Float? + attr_reader reduction: ReductionTaxResource + attr_reader returned_amount: ReturnedTaxResource + def self.new: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> instance + def initialize: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/cbstotals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/cbstotals_resource.rbs new file mode 100644 index 0000000..fbf1775 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/cbstotals_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CBSTotalsResource < Data + attr_reader amount: Float? + attr_reader deferment_amount: Float? + attr_reader presumed_credit_amount: Float? + attr_reader presumed_credit_conditional_amount: Float? + attr_reader returned_amount: Float? + def self.new: (?amount: Float?, ?deferment_amount: Float?, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?returned_amount: Float?) -> instance + def initialize: (?amount: Float?, ?deferment_amount: Float?, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?returned_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/cideresource.rbs b/sig/nfe/generated/nf_consumidor_v2/cideresource.rbs new file mode 100644 index 0000000..99e8648 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/cideresource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CIDEResource < Data + attr_reader bc: Float? + attr_reader cide_amount: Float? + attr_reader rate: Float? + def self.new: (?bc: Float?, ?cide_amount: Float?, ?rate: Float?) -> instance + def initialize: (?bc: Float?, ?cide_amount: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/city_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/city_resource.rbs new file mode 100644 index 0000000..8e60aa6 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/city_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CityResource < Data + attr_reader code: String? + attr_reader name: String? + def self.new: (?code: String?, ?name: String?) -> instance + def initialize: (?code: String?, ?name: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/cofins_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/cofins_tax_resource.rbs new file mode 100644 index 0000000..4a3da3d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/cofins_tax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CofinsTaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: Float? + attr_reader base_tax_product_quantity: Float? + attr_reader cst: String? + attr_reader product_rate: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/competence_adjustment_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/competence_adjustment_resource.rbs new file mode 100644 index 0000000..5339869 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/competence_adjustment_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CompetenceAdjustmentResource < Data + attr_reader assessment_period: String? + attr_reader cbs_amount: Float? + attr_reader ibs_amount: Float? + def self.new: (?assessment_period: String?, ?cbs_amount: Float?, ?ibs_amount: Float?) -> instance + def initialize: (?assessment_period: String?, ?cbs_amount: Float?, ?ibs_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/consumer_invoice_request.rbs b/sig/nfe/generated/nf_consumidor_v2/consumer_invoice_request.rbs new file mode 100644 index 0000000..1dfb1a5 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/consumer_invoice_request.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ConsumerInvoiceRequest < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader consumer_type: untyped + attr_reader consumption_city_code: Integer? + attr_reader contingency_justification: String? + attr_reader contingency_on: String? + attr_reader credit_type: untyped + attr_reader debit_type: untyped + attr_reader destination: untyped + attr_reader government_purchase: GovernmentPurchaseResource + attr_reader ibs_consumption_city_code: Integer? + attr_reader id: String? + attr_reader issuer: IssuerFromRequestResource + attr_reader items: Array[InvoiceItemResource] + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource]? + attr_reader presence_type: untyped + attr_reader print_type: untyped + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?consumer_type: untyped, ?consumption_city_code: Integer?, ?contingency_justification: String?, ?contingency_on: String?, ?credit_type: untyped, ?debit_type: untyped, ?destination: untyped, ?government_purchase: GovernmentPurchaseResource, ?ibs_consumption_city_code: Integer?, ?id: String?, ?issuer: IssuerFromRequestResource, items: Array[InvoiceItemResource], ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?presence_type: untyped, ?print_type: untyped, ?purpose_type: untyped, ?serie: Integer?, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?consumer_type: untyped, ?consumption_city_code: Integer?, ?contingency_justification: String?, ?contingency_on: String?, ?credit_type: untyped, ?debit_type: untyped, ?destination: untyped, ?government_purchase: GovernmentPurchaseResource, ?ibs_consumption_city_code: Integer?, ?id: String?, ?issuer: IssuerFromRequestResource, items: Array[InvoiceItemResource], ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?presence_type: untyped, ?print_type: untyped, ?purpose_type: untyped, ?serie: Integer?, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/consumer_invoices_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/consumer_invoices_resource.rbs new file mode 100644 index 0000000..cc73722 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/consumer_invoices_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ConsumerInvoicesResource < Data + attr_reader consumer_invoices: Array[InvoiceWithoutEventsResource]? + attr_reader has_more: bool + def self.new: (?consumer_invoices: Array[InvoiceWithoutEventsResource]?, ?has_more: bool) -> instance + def initialize: (?consumer_invoices: Array[InvoiceWithoutEventsResource]?, ?has_more: bool) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/consumer_presence_type.rbs b/sig/nfe/generated/nf_consumidor_v2/consumer_presence_type.rbs new file mode 100644 index 0000000..2dd2e06 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/consumer_presence_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ConsumerPresenceType + None: String + Presence: String + Internet: String + Telephone: String + Delivery: String + OthersNonPresenceOperation: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/consumer_type.rbs b/sig/nfe/generated/nf_consumidor_v2/consumer_type.rbs new file mode 100644 index 0000000..1e9f947 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/consumer_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ConsumerType + FinalConsumer: String + Normal: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/contingency_details.rbs b/sig/nfe/generated/nf_consumidor_v2/contingency_details.rbs new file mode 100644 index 0000000..a53e52a --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/contingency_details.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ContingencyDetails < Data + attr_reader authorizer: untyped + attr_reader reason: String? + attr_reader started_on: String + def self.new: (?authorizer: untyped, ?reason: String?, ?started_on: String) -> instance + def initialize: (?authorizer: untyped, ?reason: String?, ?started_on: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/credit_reversal_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/credit_reversal_resource.rbs new file mode 100644 index 0000000..8893adc --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/credit_reversal_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CreditReversalResource < Data + attr_reader cbs_reversal_amount: Float? + attr_reader ibs_reversal_amount: Float? + def self.new: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> instance + def initialize: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/credit_reversal_totals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/credit_reversal_totals_resource.rbs new file mode 100644 index 0000000..af521bb --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/credit_reversal_totals_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CreditReversalTotalsResource < Data + attr_reader cbs_reversal_amount: Float? + attr_reader ibs_reversal_amount: Float? + def self.new: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> instance + def initialize: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/credit_transfer_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/credit_transfer_tax_resource.rbs new file mode 100644 index 0000000..e1f34e3 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/credit_transfer_tax_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class CreditTransferTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader ibs_amount: Float? + def self.new: (?cbs_amount: Float?, ?ibs_amount: Float?) -> instance + def initialize: (?cbs_amount: Float?, ?ibs_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/credit_type.rbs b/sig/nfe/generated/nf_consumidor_v2/credit_type.rbs new file mode 100644 index 0000000..c051dcb --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/credit_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module CreditType + FinesAndInterest: String + IbsPresumedCreditAppropriationZfm: String + ReturnDeliveryRefusedOrNotFound: String + ValueReduction: String + TransferCreditSuccession: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/debit_type.rbs b/sig/nfe/generated/nf_consumidor_v2/debit_type.rbs new file mode 100644 index 0000000..5dd425d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/debit_type.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module DebitType + TransferCreditsToCooperatives: String + CancelCreditsExemptImmuneSales: String + UnprocessedInvoicesDebits: String + FinesAndInterest: String + TransferInheritanceCredit: String + AdvancePayment: String + InventoryLoss: String + SnDisqualification: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/deferment_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/deferment_tax_resource.rbs new file mode 100644 index 0000000..e350c92 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/deferment_tax_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class DefermentTaxResource < Data + attr_reader amount: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/delivery_information_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/delivery_information_resource.rbs new file mode 100644 index 0000000..d9f0605 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/delivery_information_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class DeliveryInformationResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/destination.rbs b/sig/nfe/generated/nf_consumidor_v2/destination.rbs new file mode 100644 index 0000000..ad4d306 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/destination.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module Destination + None: String + InternalOperation: String + InterstateOperation: String + InternationalOperation: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/disablement_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/disablement_resource.rbs new file mode 100644 index 0000000..0fc0ee1 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/disablement_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class DisablementResource < Data + attr_reader begin_number: Integer + attr_reader environment: untyped + attr_reader last_number: Integer + attr_reader reason: String? + attr_reader serie: Integer + attr_reader state: untyped + def self.new: (?begin_number: Integer, ?environment: untyped, ?last_number: Integer, ?reason: String?, ?serie: Integer, ?state: untyped) -> instance + def initialize: (?begin_number: Integer, ?environment: untyped, ?last_number: Integer, ?reason: String?, ?serie: Integer, ?state: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/document_electronic_invoice_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/document_electronic_invoice_resource.rbs new file mode 100644 index 0000000..c878922 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/document_electronic_invoice_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class DocumentElectronicInvoiceResource < Data + attr_reader access_key: String? + def self.new: (?access_key: String?) -> instance + def initialize: (?access_key: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/document_invoice_reference_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/document_invoice_reference_resource.rbs new file mode 100644 index 0000000..f3a1748 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/document_invoice_reference_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class DocumentInvoiceReferenceResource < Data + attr_reader federal_tax_number: String? + attr_reader model: String? + attr_reader number: String? + attr_reader series: String? + attr_reader state: Float? + attr_reader year_month: String? + def self.new: (?federal_tax_number: String?, ?model: String?, ?number: String?, ?series: String?, ?state: Float?, ?year_month: String?) -> instance + def initialize: (?federal_tax_number: String?, ?model: String?, ?number: String?, ?series: String?, ?state: Float?, ?year_month: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/duduction_indicator.rbs b/sig/nfe/generated/nf_consumidor_v2/duduction_indicator.rbs new file mode 100644 index 0000000..c96bf65 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/duduction_indicator.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module DuductionIndicator + NotDeduct: String + Deduce: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/duplicate_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/duplicate_resource.rbs new file mode 100644 index 0000000..3573540 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/duplicate_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class DuplicateResource < Data + attr_reader amount: Float? + attr_reader expiration_on: String? + attr_reader number: String? + def self.new: (?amount: Float?, ?expiration_on: String?, ?number: String?) -> instance + def initialize: (?amount: Float?, ?expiration_on: String?, ?number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/economic_activity_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/economic_activity_resource.rbs new file mode 100644 index 0000000..8e5a6ce --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/economic_activity_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class EconomicActivityResource < Data + attr_reader code: Integer? + attr_reader type: untyped + def self.new: (?code: Integer?, ?type: untyped) -> instance + def initialize: (?code: Integer?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/economic_activity_type.rbs b/sig/nfe/generated/nf_consumidor_v2/economic_activity_type.rbs new file mode 100644 index 0000000..a0529b6 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/economic_activity_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module EconomicActivityType + Main: String + Secondary: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/environment_type.rbs b/sig/nfe/generated/nf_consumidor_v2/environment_type.rbs new file mode 100644 index 0000000..6f1dcce --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/environment_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module EnvironmentType + None: String + Production: String + Test: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/error_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/error_resource.rbs new file mode 100644 index 0000000..759e240 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/error_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ErrorResource < Data + attr_reader code: Integer? + attr_reader message: String? + def self.new: (?code: Integer?, ?message: String?) -> instance + def initialize: (?code: Integer?, ?message: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/errors_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/errors_resource.rbs new file mode 100644 index 0000000..7ae5627 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/errors_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ErrorsResource < Data + attr_reader errors: Array[ErrorResource]? + def self.new: (?errors: Array[ErrorResource]?) -> instance + def initialize: (?errors: Array[ErrorResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/exempt_reason.rbs b/sig/nfe/generated/nf_consumidor_v2/exempt_reason.rbs new file mode 100644 index 0000000..0181b65 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/exempt_reason.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ExemptReason + Agriculture: String + Others: String + DevelopmentEntities: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/export_detail_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/export_detail_resource.rbs new file mode 100644 index 0000000..5fa4f91 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/export_detail_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ExportDetailResource < Data + attr_reader drawback: String? + attr_reader hint_information: ExportHintResource + def self.new: (?drawback: String?, ?hint_information: ExportHintResource) -> instance + def initialize: (?drawback: String?, ?hint_information: ExportHintResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/export_hint_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/export_hint_resource.rbs new file mode 100644 index 0000000..4a9f835 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/export_hint_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ExportHintResource < Data + attr_reader access_key: String? + attr_reader quantity: Float? + attr_reader registry_id: String? + def self.new: (?access_key: String?, ?quantity: Float?, ?registry_id: String?) -> instance + def initialize: (?access_key: String?, ?quantity: Float?, ?registry_id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/export_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/export_resource.rbs new file mode 100644 index 0000000..bdcfb17 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/export_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ExportResource < Data + attr_reader local: String? + attr_reader office: String? + attr_reader state: untyped + def self.new: (?local: String?, ?office: String?, ?state: untyped) -> instance + def initialize: (?local: String?, ?office: String?, ?state: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/file_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/file_resource.rbs new file mode 100644 index 0000000..26ab202 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/file_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class FileResource < Data + attr_reader uri: String? + def self.new: (?uri: String?) -> instance + def initialize: (?uri: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/flag_card.rbs b/sig/nfe/generated/nf_consumidor_v2/flag_card.rbs new file mode 100644 index 0000000..0f87bbc --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/flag_card.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module FlagCard + None: String + Visa: String + Mastercard: String + AmericanExpress: String + Sorocred: String + DinersClub: String + Elo: String + Hipercard: String + Aura: String + Cabal: String + Alelo: String + BanesCard: String + CalCard: String + Credz: String + Discover: String + GoodCard: String + GreenCard: String + Hiper: String + JCB: String + Mais: String + MaxVan: String + Policard: String + RedeCompras: String + Sodexo: String + ValeCard: String + Verocheque: String + VR: String + Ticket: String + Other: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/fuel_origin_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/fuel_origin_resource.rbs new file mode 100644 index 0000000..2ddc509 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/fuel_origin_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class FuelOriginResource < Data + attr_reader c_uforig: Integer? + attr_reader ind_import: Integer? + attr_reader p_orig: Float? + def self.new: (?c_uforig: Integer?, ?ind_import: Integer?, ?p_orig: Float?) -> instance + def initialize: (?c_uforig: Integer?, ?ind_import: Integer?, ?p_orig: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/fuel_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/fuel_resource.rbs new file mode 100644 index 0000000..c3f0849 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/fuel_resource.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class FuelResource < Data + attr_reader amount_temp: Float? + attr_reader cide: CIDEResource + attr_reader code_anp: String? + attr_reader codif: String? + attr_reader description_anp: String? + attr_reader fuel_origin: FuelOriginResource + attr_reader percentage_glp: Float? + attr_reader percentage_gni: Float? + attr_reader percentage_ng: Float? + attr_reader percentage_ngn: Float? + attr_reader pump: PumpResource + attr_reader starting_amount: Float? + attr_reader state_buyer: String? + def self.new: (?amount_temp: Float?, ?cide: CIDEResource, ?code_anp: String?, ?codif: String?, ?description_anp: String?, ?fuel_origin: FuelOriginResource, ?percentage_glp: Float?, ?percentage_gni: Float?, ?percentage_ng: Float?, ?percentage_ngn: Float?, ?pump: PumpResource, ?starting_amount: Float?, ?state_buyer: String?) -> instance + def initialize: (?amount_temp: Float?, ?cide: CIDEResource, ?code_anp: String?, ?codif: String?, ?description_anp: String?, ?fuel_origin: FuelOriginResource, ?percentage_glp: Float?, ?percentage_gni: Float?, ?percentage_ng: Float?, ?percentage_ngn: Float?, ?pump: PumpResource, ?starting_amount: Float?, ?state_buyer: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/government_purchase_entity_type.rbs b/sig/nfe/generated/nf_consumidor_v2/government_purchase_entity_type.rbs new file mode 100644 index 0000000..56b2f0a --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/government_purchase_entity_type.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module GovernmentPurchaseEntityType + Union: String + State: String + FederalDistrict: String + Municipality: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/government_purchase_operation_type.rbs b/sig/nfe/generated/nf_consumidor_v2/government_purchase_operation_type.rbs new file mode 100644 index 0000000..42dd6a3 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/government_purchase_operation_type.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module GovernmentPurchaseOperationType + Supply: String + Payment: String + SupplyThenPay: String + PayForPastSupply: String + SupplyAfterPay: String + PayNowSupplyLater: String + SupplyAndPayNow: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/government_purchase_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/government_purchase_resource.rbs new file mode 100644 index 0000000..d835e35 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/government_purchase_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class GovernmentPurchaseResource < Data + attr_reader entity_type: untyped + attr_reader operation_type: untyped + attr_reader rate_reduction: Float? + def self.new: (?entity_type: untyped, ?operation_type: untyped, ?rate_reduction: Float?) -> instance + def initialize: (?entity_type: untyped, ?operation_type: untyped, ?rate_reduction: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/government_purchase_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/government_purchase_tax_resource.rbs new file mode 100644 index 0000000..591e4e7 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/government_purchase_tax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class GovernmentPurchaseTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader cbs_rate: Float? + attr_reader municipal_amount: Float? + attr_reader municipal_rate: Float? + attr_reader state_amount: Float? + attr_reader state_rate: Float? + def self.new: (?cbs_amount: Float?, ?cbs_rate: Float?, ?municipal_amount: Float?, ?municipal_rate: Float?, ?state_amount: Float?, ?state_rate: Float?) -> instance + def initialize: (?cbs_amount: Float?, ?cbs_rate: Float?, ?municipal_amount: Float?, ?municipal_rate: Float?, ?state_amount: Float?, ?state_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification.rbs b/sig/nfe/generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification.rbs new file mode 100644 index 0000000..8cce356 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibs_zfm_presumed_credit_classification.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module IbsZfmPresumedCreditClassification + NoPresumedCredit: String + FinalConsumptionGoods: String + CapitalGoods: String + IntermediateGoods: String + ItAndOtherGoods: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibscbstax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibscbstax_resource.rbs new file mode 100644 index 0000000..2b3a1c0 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibscbstax_resource.rbs @@ -0,0 +1,31 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSCBSTaxResource < Data + attr_reader basis: Float? + attr_reader calculation_mode: String? + attr_reader cbs: CBSTaxResource + attr_reader class_code: String? + attr_reader credit_reversal: CreditReversalResource + attr_reader credit_transfer: CreditTransferTaxResource + attr_reader donation_indicator: String? + attr_reader government_purchase: GovernmentPurchaseTaxResource + attr_reader ibs_total_amount: Float? + attr_reader monophase: MonophaseIBSCBSTaxResource + attr_reader municipal: IBSMunicipalTaxResource + attr_reader operational_presumed_credit: OperationalPresumedCreditResource + attr_reader regular_taxation: RegularTaxationResource + attr_reader situation_code: String? + attr_reader state: IBSStateTaxResource + attr_reader zfm_presumed_credit: ZfmPresumedCreditResource + def self.new: (?basis: Float?, ?calculation_mode: String?, ?cbs: CBSTaxResource, ?class_code: String?, ?credit_reversal: CreditReversalResource, ?credit_transfer: CreditTransferTaxResource, ?donation_indicator: String?, ?government_purchase: GovernmentPurchaseTaxResource, ?ibs_total_amount: Float?, ?monophase: MonophaseIBSCBSTaxResource, ?municipal: IBSMunicipalTaxResource, ?operational_presumed_credit: OperationalPresumedCreditResource, ?regular_taxation: RegularTaxationResource, ?situation_code: String?, ?state: IBSStateTaxResource, ?zfm_presumed_credit: ZfmPresumedCreditResource) -> instance + def initialize: (?basis: Float?, ?calculation_mode: String?, ?cbs: CBSTaxResource, ?class_code: String?, ?credit_reversal: CreditReversalResource, ?credit_transfer: CreditTransferTaxResource, ?donation_indicator: String?, ?government_purchase: GovernmentPurchaseTaxResource, ?ibs_total_amount: Float?, ?monophase: MonophaseIBSCBSTaxResource, ?municipal: IBSMunicipalTaxResource, ?operational_presumed_credit: OperationalPresumedCreditResource, ?regular_taxation: RegularTaxationResource, ?situation_code: String?, ?state: IBSStateTaxResource, ?zfm_presumed_credit: ZfmPresumedCreditResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibscbstotals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibscbstotals_resource.rbs new file mode 100644 index 0000000..c78e5d3 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibscbstotals_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSCBSTotalsResource < Data + attr_reader basis: Float? + attr_reader cbs: CBSTotalsResource + attr_reader credit_reversal: CreditReversalTotalsResource + attr_reader ibs: IBSTotalsResource + attr_reader monophase: MonophaseTotalsResource + def self.new: (?basis: Float?, ?cbs: CBSTotalsResource, ?credit_reversal: CreditReversalTotalsResource, ?ibs: IBSTotalsResource, ?monophase: MonophaseTotalsResource) -> instance + def initialize: (?basis: Float?, ?cbs: CBSTotalsResource, ?credit_reversal: CreditReversalTotalsResource, ?ibs: IBSTotalsResource, ?monophase: MonophaseTotalsResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibsmunicipal_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibsmunicipal_tax_resource.rbs new file mode 100644 index 0000000..9d2dc1f --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibsmunicipal_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSMunicipalTaxResource < Data + attr_reader amount: Float? + attr_reader deferment: DefermentTaxResource + attr_reader rate: Float? + attr_reader reduction: ReductionTaxResource + attr_reader returned_amount: ReturnedTaxResource + def self.new: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> instance + def initialize: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibsmunicipal_totals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibsmunicipal_totals_resource.rbs new file mode 100644 index 0000000..86db8d1 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibsmunicipal_totals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSMunicipalTotalsResource < Data + attr_reader amount: Float? + attr_reader deferment_amount: Float? + attr_reader returned_amount: Float? + def self.new: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> instance + def initialize: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibsstate_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibsstate_tax_resource.rbs new file mode 100644 index 0000000..2a7c732 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibsstate_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSStateTaxResource < Data + attr_reader amount: Float? + attr_reader deferment: DefermentTaxResource + attr_reader rate: Float? + attr_reader reduction: ReductionTaxResource + attr_reader returned_amount: ReturnedTaxResource + def self.new: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> instance + def initialize: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibsstate_totals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibsstate_totals_resource.rbs new file mode 100644 index 0000000..b8b124d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibsstate_totals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSStateTotalsResource < Data + attr_reader amount: Float? + attr_reader deferment_amount: Float? + attr_reader returned_amount: Float? + def self.new: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> instance + def initialize: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ibstotals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ibstotals_resource.rbs new file mode 100644 index 0000000..6a87165 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ibstotals_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IBSTotalsResource < Data + attr_reader municipal: IBSMunicipalTotalsResource + attr_reader presumed_credit_amount: Float? + attr_reader presumed_credit_conditional_amount: Float? + attr_reader state: IBSStateTotalsResource + attr_reader total_amount: Float? + def self.new: (?municipal: IBSMunicipalTotalsResource, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?state: IBSStateTotalsResource, ?total_amount: Float?) -> instance + def initialize: (?municipal: IBSMunicipalTotalsResource, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?state: IBSStateTotalsResource, ?total_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/icms_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/icms_tax_resource.rbs new file mode 100644 index 0000000..42b9f4c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/icms_tax_resource.rbs @@ -0,0 +1,62 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IcmsTaxResource < Data + attr_reader amount: Float? + attr_reader amount_operation: String? + attr_reader amount_streason: String? + attr_reader base_deferred: String? + attr_reader base_snretention_amount: String? + attr_reader base_stretention_amount: String? + attr_reader base_tax: Float? + attr_reader base_tax_fcpstamount: Float? + attr_reader base_tax_modality: String? + attr_reader base_tax_operation_percentual: String? + attr_reader base_tax_reduction: Float? + attr_reader base_tax_st: Float? + attr_reader base_tax_stmodality: String? + attr_reader base_tax_streduction: String? + attr_reader basis_benefit_code: String? + attr_reader csosn: String? + attr_reader cst: String? + attr_reader deduction_indicator: untyped + attr_reader effective_amount: Float? + attr_reader effective_base_tax_amount: Float? + attr_reader effective_base_tax_reduction_rate: Float? + attr_reader effective_rate: Float? + attr_reader exempt_amount: Float? + attr_reader exempt_amount_st: Float? + attr_reader exempt_reason: untyped + attr_reader exempt_reason_st: untyped + attr_reader fcp_amount: Float? + attr_reader fcp_rate: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_rate: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpst_ret_rate: Float? + attr_reader origin: String? + attr_reader percentual: Float? + attr_reader percentual_deferment: String? + attr_reader rate: Float? + attr_reader sn_credit_amount: Float? + attr_reader sn_credit_rate: Float? + attr_reader sn_retention_amount: String? + attr_reader st_amount: Float? + attr_reader st_final_consumer_rate: Float? + attr_reader st_margin_added_amount: String? + attr_reader st_margin_amount: Float? + attr_reader st_rate: Float? + attr_reader st_retention_amount: String? + attr_reader substitute_amount: Float? + attr_reader ufst: String? + def self.new: (?amount: Float?, ?amount_operation: String?, ?amount_streason: String?, ?base_deferred: String?, ?base_snretention_amount: String?, ?base_stretention_amount: String?, ?base_tax: Float?, ?base_tax_fcpstamount: Float?, ?base_tax_modality: String?, ?base_tax_operation_percentual: String?, ?base_tax_reduction: Float?, ?base_tax_st: Float?, ?base_tax_stmodality: String?, ?base_tax_streduction: String?, ?basis_benefit_code: String?, ?csosn: String?, ?cst: String?, ?deduction_indicator: untyped, ?effective_amount: Float?, ?effective_base_tax_amount: Float?, ?effective_base_tax_reduction_rate: Float?, ?effective_rate: Float?, ?exempt_amount: Float?, ?exempt_amount_st: Float?, ?exempt_reason: untyped, ?exempt_reason_st: untyped, ?fcp_amount: Float?, ?fcp_rate: Float?, ?fcpst_amount: Float?, ?fcpst_rate: Float?, ?fcpst_ret_amount: Float?, ?fcpst_ret_rate: Float?, ?origin: String?, ?percentual: Float?, ?percentual_deferment: String?, ?rate: Float?, ?sn_credit_amount: Float?, ?sn_credit_rate: Float?, ?sn_retention_amount: String?, ?st_amount: Float?, ?st_final_consumer_rate: Float?, ?st_margin_added_amount: String?, ?st_margin_amount: Float?, ?st_rate: Float?, ?st_retention_amount: String?, ?substitute_amount: Float?, ?ufst: String?) -> instance + def initialize: (?amount: Float?, ?amount_operation: String?, ?amount_streason: String?, ?base_deferred: String?, ?base_snretention_amount: String?, ?base_stretention_amount: String?, ?base_tax: Float?, ?base_tax_fcpstamount: Float?, ?base_tax_modality: String?, ?base_tax_operation_percentual: String?, ?base_tax_reduction: Float?, ?base_tax_st: Float?, ?base_tax_stmodality: String?, ?base_tax_streduction: String?, ?basis_benefit_code: String?, ?csosn: String?, ?cst: String?, ?deduction_indicator: untyped, ?effective_amount: Float?, ?effective_base_tax_amount: Float?, ?effective_base_tax_reduction_rate: Float?, ?effective_rate: Float?, ?exempt_amount: Float?, ?exempt_amount_st: Float?, ?exempt_reason: untyped, ?exempt_reason_st: untyped, ?fcp_amount: Float?, ?fcp_rate: Float?, ?fcpst_amount: Float?, ?fcpst_rate: Float?, ?fcpst_ret_amount: Float?, ?fcpst_ret_rate: Float?, ?origin: String?, ?percentual: Float?, ?percentual_deferment: String?, ?rate: Float?, ?sn_credit_amount: Float?, ?sn_credit_rate: Float?, ?sn_retention_amount: String?, ?st_amount: Float?, ?st_final_consumer_rate: Float?, ?st_margin_added_amount: String?, ?st_margin_amount: Float?, ?st_rate: Float?, ?st_retention_amount: String?, ?substitute_amount: Float?, ?ufst: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/icmstotal_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/icmstotal_resource.rbs new file mode 100644 index 0000000..cba6dd9 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/icmstotal_resource.rbs @@ -0,0 +1,44 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ICMSTotalResource < Data + attr_reader base_tax: Float? + attr_reader cofins_amount: Float? + attr_reader discount_amount: Float? + attr_reader fcp_amount: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpuf_destination_amount: Float? + attr_reader federal_taxes_amount: Float? + attr_reader freight_amount: Float? + attr_reader icms_amount: Float? + attr_reader icms_exempt_amount: Float? + attr_reader icmsuf_destination_amount: Float? + attr_reader icmsuf_sender_amount: Float? + attr_reader ii_amount: Float? + attr_reader insurance_amount: Float? + attr_reader invoice_amount: Float? + attr_reader ipi_amount: Float? + attr_reader ipi_devol_amount: Float? + attr_reader others_amount: Float? + attr_reader pis_amount: Float? + attr_reader product_amount: Float? + attr_reader q_bcmono: Float? + attr_reader q_bcmono_ret: Float? + attr_reader q_bcmono_reten: Float? + attr_reader st_amount: Float? + attr_reader st_calculation_basis_amount: Float? + attr_reader v_icmsmono: Float? + attr_reader v_icmsmono_ret: Float? + attr_reader v_icmsmono_reten: Float? + def self.new: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float?, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float?, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float?, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> instance + def initialize: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float?, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float?, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float?, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/icmsufdestination_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/icmsufdestination_tax_resource.rbs new file mode 100644 index 0000000..d7e2a1c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/icmsufdestination_tax_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ICMSUFDestinationTaxResource < Data + attr_reader p_fcpufdest: Float? + attr_reader p_icmsinter: Float? + attr_reader p_icmsinter_part: Float? + attr_reader p_icmsufdest: Float? + attr_reader v_bcfcpufdest: Float? + attr_reader v_bcufdest: Float? + attr_reader v_fcpufdest: Float? + attr_reader v_icmsufdest: Float? + attr_reader v_icmsufremet: Float? + def self.new: (?p_fcpufdest: Float?, ?p_icmsinter: Float?, ?p_icmsinter_part: Float?, ?p_icmsufdest: Float?, ?v_bcfcpufdest: Float?, ?v_bcufdest: Float?, ?v_fcpufdest: Float?, ?v_icmsufdest: Float?, ?v_icmsufremet: Float?) -> instance + def initialize: (?p_fcpufdest: Float?, ?p_icmsinter: Float?, ?p_icmsinter_part: Float?, ?p_icmsufdest: Float?, ?v_bcfcpufdest: Float?, ?v_bcufdest: Float?, ?v_fcpufdest: Float?, ?v_icmsufdest: Float?, ?v_icmsufremet: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/iitax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/iitax_resource.rbs new file mode 100644 index 0000000..07a6525 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/iitax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IITaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: String? + attr_reader customs_expenditure_amount: String? + attr_reader iof_amount: Float? + attr_reader v_enq_camb: Float? + def self.new: (?amount: Float?, ?base_tax: String?, ?customs_expenditure_amount: String?, ?iof_amount: Float?, ?v_enq_camb: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: String?, ?customs_expenditure_amount: String?, ?iof_amount: Float?, ?v_enq_camb: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/import_declaration_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/import_declaration_resource.rbs new file mode 100644 index 0000000..de6474a --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/import_declaration_resource.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ImportDeclarationResource < Data + attr_reader acquirer_federal_tax_number: String? + attr_reader additions: Array[AdditionResource]? + attr_reader afrmm_amount: Float? + attr_reader code: String? + attr_reader customs_clearance_name: String? + attr_reader customs_clearance_state: untyped + attr_reader customs_clearanced_on: String? + attr_reader exporter: String? + attr_reader intermediation: untyped + attr_reader international_transport: untyped + attr_reader registered_on: String? + attr_reader state_third: String? + def self.new: (?acquirer_federal_tax_number: String?, ?additions: Array[AdditionResource]?, ?afrmm_amount: Float?, ?code: String?, ?customs_clearance_name: String?, ?customs_clearance_state: untyped, ?customs_clearanced_on: String?, ?exporter: String?, ?intermediation: untyped, ?international_transport: untyped, ?registered_on: String?, ?state_third: String?) -> instance + def initialize: (?acquirer_federal_tax_number: String?, ?additions: Array[AdditionResource]?, ?afrmm_amount: Float?, ?code: String?, ?customs_clearance_name: String?, ?customs_clearance_state: untyped, ?customs_clearanced_on: String?, ?exporter: String?, ?intermediation: untyped, ?international_transport: untyped, ?registered_on: String?, ?state_third: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/integration_payment_type.rbs b/sig/nfe/generated/nf_consumidor_v2/integration_payment_type.rbs new file mode 100644 index 0000000..b7eee4b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/integration_payment_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module IntegrationPaymentType + Integrated: String + NotIntegrated: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/intermediate_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/intermediate_resource.rbs new file mode 100644 index 0000000..5a969cf --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/intermediate_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IntermediateResource < Data + attr_reader federal_tax_number: Integer? + attr_reader identifier: String? + def self.new: (?federal_tax_number: Integer?, ?identifier: String?) -> instance + def initialize: (?federal_tax_number: Integer?, ?identifier: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/intermediation_type.rbs b/sig/nfe/generated/nf_consumidor_v2/intermediation_type.rbs new file mode 100644 index 0000000..fc5dd04 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/intermediation_type.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module IntermediationType + None: String + ByOwn: String + ImportOnBehalf: String + ByOrder: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/international_transport_type.rbs b/sig/nfe/generated/nf_consumidor_v2/international_transport_type.rbs new file mode 100644 index 0000000..d91cf70 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/international_transport_type.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module InternationalTransportType + None: String + Maritime: String + River: String + Lake: String + Airline: String + Postal: String + Railway: String + Highway: String + Network: String + Own: String + Ficta: String + Courier: String + Handcarry: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_events_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_events_resource.rbs new file mode 100644 index 0000000..4f7363f --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_events_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceEventsResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader events: Array[ActivityResource]? + attr_reader has_more: bool? + attr_reader id: String? + def self.new: (?account_id: String?, ?company_id: String?, ?events: Array[ActivityResource]?, ?has_more: bool?, ?id: String?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?events: Array[ActivityResource]?, ?has_more: bool?, ?id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_events_resource_base.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_events_resource_base.rbs new file mode 100644 index 0000000..f96a9d4 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_events_resource_base.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceEventsResourceBase < Data + attr_reader events: Array[ActivityResource]? + attr_reader has_more: bool? + def self.new: (?events: Array[ActivityResource]?, ?has_more: bool?) -> instance + def initialize: (?events: Array[ActivityResource]?, ?has_more: bool?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_item_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_item_resource.rbs new file mode 100644 index 0000000..0c0b011 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_item_resource.rbs @@ -0,0 +1,52 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceItemResource < Data + attr_reader additional_information: String? + attr_reader benefit: String? + attr_reader cest: String? + attr_reader cfop: Integer? + attr_reader code: String? + attr_reader code_gtin: String? + attr_reader code_tax_gtin: String? + attr_reader description: String? + attr_reader discount_amount: Float? + attr_reader export_details: Array[ExportDetailResource]? + attr_reader extipi: String? + attr_reader freight_amount: Float? + attr_reader fuel_detail: FuelResource + attr_reader ibs_zfm_presumed_credit_classification: untyped + attr_reader import_control_sheet_number: String? + attr_reader import_declarations: Array[ImportDeclarationResource]? + attr_reader insurance_amount: Float? + attr_reader item_amount: Float? + attr_reader item_number_order_buy: Integer? + attr_reader ncm: String? + attr_reader number_order_buy: String? + attr_reader nve: Array[String]? + attr_reader others_amount: Float? + attr_reader presumed_credit: PresumedCreditResource + attr_reader quantity: Float? + attr_reader quantity_tax: Float? + attr_reader referenced_dfe: ReferencedDFeResource + attr_reader tax: InvoiceItemTaxResource + attr_reader tax_determination: TaxDeterminationResource + attr_reader tax_unit_amount: Float? + attr_reader total_amount: Float? + attr_reader total_indicator: bool? + attr_reader unit: String? + attr_reader unit_amount: Float? + attr_reader unit_tax: String? + attr_reader used_movable_asset_indicator: bool + attr_reader vehicle_detail: VehicleDetailResource + def self.new: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer?, ?code: String?, ?code_gtin: String?, ?code_tax_gtin: String?, ?description: String?, ?discount_amount: Float?, ?export_details: Array[ExportDetailResource]?, ?extipi: String?, ?freight_amount: Float?, ?fuel_detail: FuelResource, ?ibs_zfm_presumed_credit_classification: untyped, ?import_control_sheet_number: String?, ?import_declarations: Array[ImportDeclarationResource]?, ?insurance_amount: Float?, ?item_amount: Float?, ?item_number_order_buy: Integer?, ?ncm: String?, ?number_order_buy: String?, ?nve: Array[String]?, ?others_amount: Float?, ?presumed_credit: PresumedCreditResource, ?quantity: Float?, ?quantity_tax: Float?, ?referenced_dfe: ReferencedDFeResource, ?tax: InvoiceItemTaxResource, ?tax_determination: TaxDeterminationResource, ?tax_unit_amount: Float?, ?total_amount: Float?, ?total_indicator: bool?, ?unit: String?, ?unit_amount: Float?, ?unit_tax: String?, ?used_movable_asset_indicator: bool, ?vehicle_detail: VehicleDetailResource) -> instance + def initialize: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer?, ?code: String?, ?code_gtin: String?, ?code_tax_gtin: String?, ?description: String?, ?discount_amount: Float?, ?export_details: Array[ExportDetailResource]?, ?extipi: String?, ?freight_amount: Float?, ?fuel_detail: FuelResource, ?ibs_zfm_presumed_credit_classification: untyped, ?import_control_sheet_number: String?, ?import_declarations: Array[ImportDeclarationResource]?, ?insurance_amount: Float?, ?item_amount: Float?, ?item_number_order_buy: Integer?, ?ncm: String?, ?number_order_buy: String?, ?nve: Array[String]?, ?others_amount: Float?, ?presumed_credit: PresumedCreditResource, ?quantity: Float?, ?quantity_tax: Float?, ?referenced_dfe: ReferencedDFeResource, ?tax: InvoiceItemTaxResource, ?tax_determination: TaxDeterminationResource, ?tax_unit_amount: Float?, ?total_amount: Float?, ?total_indicator: bool?, ?unit: String?, ?unit_amount: Float?, ?unit_tax: String?, ?used_movable_asset_indicator: bool, ?vehicle_detail: VehicleDetailResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_item_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_item_tax_resource.rbs new file mode 100644 index 0000000..5808317 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_item_tax_resource.rbs @@ -0,0 +1,25 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceItemTaxResource < Data + attr_reader ibscbs: IBSCBSTaxResource + attr_reader is: ISTaxResource + attr_reader cofins: CofinsTaxResource + attr_reader competence_adjustment: CompetenceAdjustmentResource + attr_reader icms: IcmsTaxResource + attr_reader icms_destination: ICMSUFDestinationTaxResource + attr_reader ii: IITaxResource + attr_reader ipi: IPITaxResource + attr_reader pis: PISTaxResource + attr_reader total_tax: Float? + def self.new: (?ibscbs: IBSCBSTaxResource, ?is: ISTaxResource, ?cofins: CofinsTaxResource, ?competence_adjustment: CompetenceAdjustmentResource, ?icms: IcmsTaxResource, ?icms_destination: ICMSUFDestinationTaxResource, ?ii: IITaxResource, ?ipi: IPITaxResource, ?pis: PISTaxResource, ?total_tax: Float?) -> instance + def initialize: (?ibscbs: IBSCBSTaxResource, ?is: ISTaxResource, ?cofins: CofinsTaxResource, ?competence_adjustment: CompetenceAdjustmentResource, ?icms: IcmsTaxResource, ?icms_destination: ICMSUFDestinationTaxResource, ?ii: IITaxResource, ?ipi: IPITaxResource, ?pis: PISTaxResource, ?total_tax: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_items_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_items_resource.rbs new file mode 100644 index 0000000..649858e --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_items_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceItemsResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader has_more: bool? + attr_reader id: String? + attr_reader items: Array[InvoiceItemResource]? + def self.new: (?account_id: String?, ?company_id: String?, ?has_more: bool?, ?id: String?, ?items: Array[InvoiceItemResource]?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?has_more: bool?, ?id: String?, ?items: Array[InvoiceItemResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_resource.rbs new file mode 100644 index 0000000..4df45fe --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_resource.rbs @@ -0,0 +1,40 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader authorization: AuthorizationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader contingency_details: ContingencyDetails + attr_reader created_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader environment_type: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerResource + attr_reader last_events: InvoiceEventsResourceBase + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource]? + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader status: untyped + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?last_events: InvoiceEventsResourceBase, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?last_events: InvoiceEventsResourceBase, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_status.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_status.rbs new file mode 100644 index 0000000..cc3b514 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_status.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module InvoiceStatus + None: String + Created: String + Processing: String + Issued: String + IssuedContingency: String + Cancelled: String + Disabled: String + IssueDenied: String + Error: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/invoice_without_events_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/invoice_without_events_resource.rbs new file mode 100644 index 0000000..5eca9be --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/invoice_without_events_resource.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class InvoiceWithoutEventsResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader authorization: AuthorizationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader contingency_details: ContingencyDetails + attr_reader created_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader environment_type: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerResource + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource]? + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader status: untyped + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/ipitax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/ipitax_resource.rbs new file mode 100644 index 0000000..31f4c8d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/ipitax_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IPITaxResource < Data + attr_reader amount: Float? + attr_reader base: Float? + attr_reader classification: String? + attr_reader classification_code: String? + attr_reader cst: String? + attr_reader producer_cnpj: String? + attr_reader rate: Float? + attr_reader stamp_code: String? + attr_reader stamp_quantity: Float? + attr_reader unit_amount: Float? + attr_reader unit_quantity: Float? + def self.new: (?amount: Float?, ?base: Float?, ?classification: String?, ?classification_code: String?, ?cst: String?, ?producer_cnpj: String?, ?rate: Float?, ?stamp_code: String?, ?stamp_quantity: Float?, ?unit_amount: Float?, ?unit_quantity: Float?) -> instance + def initialize: (?amount: Float?, ?base: Float?, ?classification: String?, ?classification_code: String?, ?cst: String?, ?producer_cnpj: String?, ?rate: Float?, ?stamp_code: String?, ?stamp_quantity: Float?, ?unit_amount: Float?, ?unit_quantity: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/issqntotal_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/issqntotal_resource.rbs new file mode 100644 index 0000000..9da0602 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/issqntotal_resource.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ISSQNTotalResource < Data + attr_reader base_rate_iss: Float? + attr_reader code_tax_regime: Float? + attr_reader deduction_reduction_bc: Float? + attr_reader discount_conditioning: Float? + attr_reader discount_unconditional: Float? + attr_reader provision_service: String? + attr_reader total_iss: Float? + attr_reader total_retention_iss: Float? + attr_reader total_service_not_taxed_icms: Float? + attr_reader value_other_retention: Float? + attr_reader value_service_cofins: Float? + attr_reader value_service_pis: Float? + def self.new: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> instance + def initialize: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/issuer_from_request_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/issuer_from_request_resource.rbs new file mode 100644 index 0000000..6e6bfd9 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/issuer_from_request_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IssuerFromRequestResource < Data + attr_reader st_state_tax_number: String? + def self.new: (?st_state_tax_number: String?) -> instance + def initialize: (?st_state_tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/issuer_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/issuer_resource.rbs new file mode 100644 index 0000000..91aa815 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/issuer_resource.rbs @@ -0,0 +1,33 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class IssuerResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader company_registry_number: Integer? + attr_reader economic_activities: Array[EconomicActivityResource]? + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader legal_nature: untyped + attr_reader municipal_tax_number: String? + attr_reader name: String? + attr_reader openning_date: String? + attr_reader regional_sttax_number: Integer? + attr_reader regional_tax_number: Integer? + attr_reader special_tax_regime: untyped + attr_reader st_state_tax_number: String? + attr_reader tax_regime: untyped + attr_reader trade_name: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?company_registry_number: Integer?, ?economic_activities: Array[EconomicActivityResource]?, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?legal_nature: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_sttax_number: Integer?, ?regional_tax_number: Integer?, ?special_tax_regime: untyped, ?st_state_tax_number: String?, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?company_registry_number: Integer?, ?economic_activities: Array[EconomicActivityResource]?, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?legal_nature: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_sttax_number: Integer?, ?regional_tax_number: Integer?, ?special_tax_regime: untyped, ?st_state_tax_number: String?, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/istax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/istax_resource.rbs new file mode 100644 index 0000000..3cf5e55 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/istax_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ISTaxResource < Data + attr_reader amount: Float? + attr_reader basis: Float? + attr_reader classification_code: String? + attr_reader quantity: Float? + attr_reader rate: Float? + attr_reader situation_code: String? + attr_reader unit: String? + attr_reader unit_rate: Float? + def self.new: (?amount: Float?, ?basis: Float?, ?classification_code: String?, ?quantity: Float?, ?rate: Float?, ?situation_code: String?, ?unit: String?, ?unit_rate: Float?) -> instance + def initialize: (?amount: Float?, ?basis: Float?, ?classification_code: String?, ?quantity: Float?, ?rate: Float?, ?situation_code: String?, ?unit: String?, ?unit_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/istotals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/istotals_resource.rbs new file mode 100644 index 0000000..ac78c3c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/istotals_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ISTotalsResource < Data + attr_reader amount: Float? + def self.new: (?amount: Float?) -> instance + def initialize: (?amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/legal_nature.rbs b/sig/nfe/generated/nf_consumidor_v2/legal_nature.rbs new file mode 100644 index 0000000..88fa737 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/legal_nature.rbs @@ -0,0 +1,51 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module LegalNature + EmpresaPublica: String + SociedadeEconomiaMista: String + SociedadeAnonimaAberta: String + SociedadeAnonimaFechada: String + SociedadeEmpresariaLimitada: String + SociedadeEmpresariaEmNomeColetivo: String + SociedadeEmpresariaEmComanditaSimples: String + SociedadeEmpresariaEmComanditaporAcoes: String + SociedadeemContaParticipacao: String + Empresario: String + Cooperativa: String + ConsorcioSociedades: String + GrupoSociedades: String + EmpresaDomiciliadaExterior: String + ClubeFundoInvestimento: String + SociedadeSimplesPura: String + SociedadeSimplesLimitada: String + SociedadeSimplesEmNomeColetivo: String + SociedadeSimplesEmComanditaSimples: String + EmpresaBinacional: String + ConsorcioEmpregadores: String + ConsorcioSimples: String + EireliNaturezaEmpresaria: String + EireliNaturezaSimples: String + ServicoNotarial: String + FundacaoPrivada: String + ServicoSocialAutonomo: String + CondominioEdilicio: String + ComissaoConciliacaoPrevia: String + EntidadeMediacaoArbitragem: String + PartidoPolitico: String + EntidadeSindical: String + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras: String + FundacaoAssociacaoDomiciliadaExterior: String + OrganizacaoReligiosa: String + ComunidadeIndigena: String + FundoPrivado: String + AssociacaoPrivada: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_cbstotals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_cbstotals_resource.rbs new file mode 100644 index 0000000..76a9345 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_cbstotals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseCBSTotalsResource < Data + attr_reader amount: Float? + attr_reader previously_withheld_amount: Float? + attr_reader withheld_amount: Float? + def self.new: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> instance + def initialize: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_deferment_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_deferment_tax_resource.rbs new file mode 100644 index 0000000..a0d5628 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_deferment_tax_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseDefermentTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader cbs_rate: Float? + attr_reader ibs_amount: Float? + attr_reader ibs_rate: Float? + def self.new: (?cbs_amount: Float?, ?cbs_rate: Float?, ?ibs_amount: Float?, ?ibs_rate: Float?) -> instance + def initialize: (?cbs_amount: Float?, ?cbs_rate: Float?, ?ibs_amount: Float?, ?ibs_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_ibscbstax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_ibscbstax_resource.rbs new file mode 100644 index 0000000..9decab4 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_ibscbstax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseIBSCBSTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader deferment: MonophaseDefermentTaxResource + attr_reader ibs_amount: Float? + attr_reader previously_withheld: MonophasePreviouslyWithheldTaxResource + attr_reader standart: MonophaseStandardTaxResource + attr_reader withholding: MonophaseWithholdingTaxResource + def self.new: (?cbs_amount: Float?, ?deferment: MonophaseDefermentTaxResource, ?ibs_amount: Float?, ?previously_withheld: MonophasePreviouslyWithheldTaxResource, ?standart: MonophaseStandardTaxResource, ?withholding: MonophaseWithholdingTaxResource) -> instance + def initialize: (?cbs_amount: Float?, ?deferment: MonophaseDefermentTaxResource, ?ibs_amount: Float?, ?previously_withheld: MonophasePreviouslyWithheldTaxResource, ?standart: MonophaseStandardTaxResource, ?withholding: MonophaseWithholdingTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_ibstotals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_ibstotals_resource.rbs new file mode 100644 index 0000000..c69d9aa --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_ibstotals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseIBSTotalsResource < Data + attr_reader amount: Float? + attr_reader previously_withheld_amount: Float? + attr_reader withheld_amount: Float? + def self.new: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> instance + def initialize: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource.rbs new file mode 100644 index 0000000..1c29f7b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_previously_withheld_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophasePreviouslyWithheldTaxResource < Data + attr_reader cbs_ad_rem_rate: Float? + attr_reader cbs_amount: Float? + attr_reader ibs_ad_rem_rate: Float? + attr_reader ibs_amount: Float? + attr_reader quantity_basis: Float? + def self.new: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> instance + def initialize: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_standard_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_standard_tax_resource.rbs new file mode 100644 index 0000000..80b4185 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_standard_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseStandardTaxResource < Data + attr_reader cbs_ad_rem_rate: Float? + attr_reader cbs_amount: Float? + attr_reader ibs_ad_rem_rate: Float? + attr_reader ibs_amount: Float? + attr_reader quantity_basis: Float? + def self.new: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> instance + def initialize: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_totals_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_totals_resource.rbs new file mode 100644 index 0000000..435391d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_totals_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseTotalsResource < Data + attr_reader cbs: MonophaseCBSTotalsResource + attr_reader ibs: MonophaseIBSTotalsResource + def self.new: (?cbs: MonophaseCBSTotalsResource, ?ibs: MonophaseIBSTotalsResource) -> instance + def initialize: (?cbs: MonophaseCBSTotalsResource, ?ibs: MonophaseIBSTotalsResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/monophase_withholding_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/monophase_withholding_tax_resource.rbs new file mode 100644 index 0000000..01c3bdc --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/monophase_withholding_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class MonophaseWithholdingTaxResource < Data + attr_reader cbs_ad_rem_rate: Float? + attr_reader cbs_amount: Float? + attr_reader ibs_ad_rem_rate: Float? + attr_reader ibs_amount: Float? + attr_reader quantity_basis: Float? + def self.new: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> instance + def initialize: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/operation_type.rbs b/sig/nfe/generated/nf_consumidor_v2/operation_type.rbs new file mode 100644 index 0000000..2071928 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/operation_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module OperationType + Outgoing: String + Incoming: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/operational_presumed_credit_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/operational_presumed_credit_resource.rbs new file mode 100644 index 0000000..cf24cf4 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/operational_presumed_credit_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class OperationalPresumedCreditResource < Data + attr_reader basis: Float? + attr_reader cbs: PresumedCreditDetailsResource + attr_reader classification_code: untyped + attr_reader ibs: PresumedCreditDetailsResource + def self.new: (?basis: Float?, ?cbs: PresumedCreditDetailsResource, ?classification_code: untyped, ?ibs: PresumedCreditDetailsResource) -> instance + def initialize: (?basis: Float?, ?cbs: PresumedCreditDetailsResource, ?classification_code: untyped, ?ibs: PresumedCreditDetailsResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/payment_detail_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/payment_detail_resource.rbs new file mode 100644 index 0000000..b5b0e74 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/payment_detail_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class PaymentDetailResource < Data + attr_reader amount: Float? + attr_reader card: CardResource + attr_reader federal_tax_number_pag: String? + attr_reader method: untyped + attr_reader method_description: String? + attr_reader payment_date: String? + attr_reader payment_type: untyped + attr_reader state_pag: String? + def self.new: (?amount: Float?, ?card: CardResource, ?federal_tax_number_pag: String?, ?method: untyped, ?method_description: String?, ?payment_date: String?, ?payment_type: untyped, ?state_pag: String?) -> instance + def initialize: (?amount: Float?, ?card: CardResource, ?federal_tax_number_pag: String?, ?method: untyped, ?method_description: String?, ?payment_date: String?, ?payment_type: untyped, ?state_pag: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/payment_method.rbs b/sig/nfe/generated/nf_consumidor_v2/payment_method.rbs new file mode 100644 index 0000000..536fd4d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/payment_method.rbs @@ -0,0 +1,32 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PaymentMethod + Cash: String + Cheque: String + CreditCard: String + DebitCard: String + StoreCredict: String + FoodVouchers: String + MealVouchers: String + GiftVouchers: String + FuelVouchers: String + BankBill: String + BankDeposit: String + InstantPayment: String + WireTransfer: String + Cashback: String + StaticInstantPayment: String + StoreCredit: String + ElectronicPaymentNotInformed: String + WithoutPayment: String + Others: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/payment_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/payment_resource.rbs new file mode 100644 index 0000000..9edae6c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/payment_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class PaymentResource < Data + attr_reader pay_back: Float? + attr_reader payment_detail: Array[PaymentDetailResource]? + def self.new: (?pay_back: Float?, ?payment_detail: Array[PaymentDetailResource]?) -> instance + def initialize: (?pay_back: Float?, ?payment_detail: Array[PaymentDetailResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/payment_type.rbs b/sig/nfe/generated/nf_consumidor_v2/payment_type.rbs new file mode 100644 index 0000000..38ba290 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/payment_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PaymentType + InCash: String + Term: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/person_type.rbs b/sig/nfe/generated/nf_consumidor_v2/person_type.rbs new file mode 100644 index 0000000..3750023 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/person_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PersonType + Undefined: String + NaturalPerson: String + LegalEntity: String + Company: String + Customer: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/pistax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/pistax_resource.rbs new file mode 100644 index 0000000..0a8f0f8 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/pistax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class PISTaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: Float? + attr_reader base_tax_product_quantity: Float? + attr_reader cst: String? + attr_reader product_rate: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/presumed_credit_classification_code.rbs b/sig/nfe/generated/nf_consumidor_v2/presumed_credit_classification_code.rbs new file mode 100644 index 0000000..188c83b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/presumed_credit_classification_code.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PresumedCreditClassificationCode + RuralProducerNonTaxpayer: String + TacPfTransportServiceNonTaxpayer: String + RecyclingFromIndividual: String + UsedMovableGoodsFromIndividualForResale: String + OptionalRegimeForCooperative: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/presumed_credit_details_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/presumed_credit_details_resource.rbs new file mode 100644 index 0000000..138177c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/presumed_credit_details_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class PresumedCreditDetailsResource < Data + attr_reader amount: Float? + attr_reader rate: Float? + attr_reader suspensive_condition_amount: Float? + def self.new: (?amount: Float?, ?rate: Float?, ?suspensive_condition_amount: Float?) -> instance + def initialize: (?amount: Float?, ?rate: Float?, ?suspensive_condition_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/presumed_credit_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/presumed_credit_resource.rbs new file mode 100644 index 0000000..474403e --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/presumed_credit_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class PresumedCreditResource < Data + attr_reader amount: Float? + attr_reader code: String? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?code: String?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?code: String?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/print_type.rbs b/sig/nfe/generated/nf_consumidor_v2/print_type.rbs new file mode 100644 index 0000000..f89772d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/print_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PrintType + None: String + NFeNormalPortrait: String + NFeNormalLandscape: String + NFeSimplified: String + DANFENFCE: String + DANFENFCEMSGELETRONICA: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/pump_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/pump_resource.rbs new file mode 100644 index 0000000..e3eb8ef --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/pump_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class PumpResource < Data + attr_reader beginning_amount: Float? + attr_reader end_amount: Float? + attr_reader number: Integer? + attr_reader percentage_bio: Float? + attr_reader spout_number: Integer? + attr_reader tank_number: Integer? + def self.new: (?beginning_amount: Float?, ?end_amount: Float?, ?number: Integer?, ?percentage_bio: Float?, ?spout_number: Integer?, ?tank_number: Integer?) -> instance + def initialize: (?beginning_amount: Float?, ?end_amount: Float?, ?number: Integer?, ?percentage_bio: Float?, ?spout_number: Integer?, ?tank_number: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/purpose_type.rbs b/sig/nfe/generated/nf_consumidor_v2/purpose_type.rbs new file mode 100644 index 0000000..9d1d9ea --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/purpose_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module PurposeType + None: String + Normal: String + Complement: String + Adjustment: String + Devolution: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/reboque_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/reboque_resource.rbs new file mode 100644 index 0000000..82ee165 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/reboque_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ReboqueResource < Data + attr_reader ferry: String? + attr_reader plate: String? + attr_reader rntc: String? + attr_reader uf: String? + attr_reader wagon: String? + def self.new: (?ferry: String?, ?plate: String?, ?rntc: String?, ?uf: String?, ?wagon: String?) -> instance + def initialize: (?ferry: String?, ?plate: String?, ?rntc: String?, ?uf: String?, ?wagon: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/receiver_state_tax_indicator.rbs b/sig/nfe/generated/nf_consumidor_v2/receiver_state_tax_indicator.rbs new file mode 100644 index 0000000..6135e63 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/receiver_state_tax_indicator.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ReceiverStateTaxIndicator + None: String + TaxPayer: String + Exempt: String + NonTaxPayer: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/reduction_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/reduction_tax_resource.rbs new file mode 100644 index 0000000..c37a738 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/reduction_tax_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ReductionTaxResource < Data + attr_reader effective_rate: Float? + attr_reader rate_reduction: Float? + def self.new: (?effective_rate: Float?, ?rate_reduction: Float?) -> instance + def initialize: (?effective_rate: Float?, ?rate_reduction: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/referenced_dfe_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/referenced_dfe_resource.rbs new file mode 100644 index 0000000..2dc9b0d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/referenced_dfe_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ReferencedDFeResource < Data + attr_reader access_key: String + attr_reader item_number: Integer? + def self.new: (access_key: String, ?item_number: Integer?) -> instance + def initialize: (access_key: String, ?item_number: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/referenced_process_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/referenced_process_resource.rbs new file mode 100644 index 0000000..296a33d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/referenced_process_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ReferencedProcessResource < Data + attr_reader concession_act_type: Integer? + attr_reader identifier_concessory: String? + attr_reader identifier_origin: Integer? + def self.new: (?concession_act_type: Integer?, ?identifier_concessory: String?, ?identifier_origin: Integer?) -> instance + def initialize: (?concession_act_type: Integer?, ?identifier_concessory: String?, ?identifier_origin: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/regular_taxation_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/regular_taxation_resource.rbs new file mode 100644 index 0000000..f381611 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/regular_taxation_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class RegularTaxationResource < Data + attr_reader amount: Float? + attr_reader cbs_amount: Float? + attr_reader cbs_effective_rate: Float? + attr_reader class_code: String? + attr_reader municipal_amount: Float? + attr_reader municipal_effective_rate: Float? + attr_reader situation_code: String? + attr_reader state_effective_rate: Float? + def self.new: (?amount: Float?, ?cbs_amount: Float?, ?cbs_effective_rate: Float?, ?class_code: String?, ?municipal_amount: Float?, ?municipal_effective_rate: Float?, ?situation_code: String?, ?state_effective_rate: Float?) -> instance + def initialize: (?amount: Float?, ?cbs_amount: Float?, ?cbs_effective_rate: Float?, ?class_code: String?, ?municipal_amount: Float?, ?municipal_effective_rate: Float?, ?situation_code: String?, ?state_effective_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/request_cancellation_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/request_cancellation_resource.rbs new file mode 100644 index 0000000..a0a04c0 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/request_cancellation_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class RequestCancellationResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader product_invoice_id: String? + attr_reader reason: String? + def self.new: (?account_id: String?, ?company_id: String?, ?product_invoice_id: String?, ?reason: String?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?product_invoice_id: String?, ?reason: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/returned_tax_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/returned_tax_resource.rbs new file mode 100644 index 0000000..e412929 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/returned_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ReturnedTaxResource < Data + attr_reader amount: Float? + def self.new: (?amount: Float?) -> instance + def initialize: (?amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/shipping_modality.rbs b/sig/nfe/generated/nf_consumidor_v2/shipping_modality.rbs new file mode 100644 index 0000000..d0f2013 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/shipping_modality.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module ShippingModality + ByIssuer: String + ByReceiver: String + ByThirdParties: String + OwnBySender: String + OwnByBuyer: String + Free: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/special_tax_regime.rbs b/sig/nfe/generated/nf_consumidor_v2/special_tax_regime.rbs new file mode 100644 index 0000000..5f646cb --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/special_tax_regime.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module SpecialTaxRegime + Nenhum: String + MicroempresaMunicipal: String + Estimativa: String + SociedadeDeProfissionais: String + Cooperativa: String + MicroempreendedorIndividual: String + MicroempresarioEmpresaPequenoPorte: String + Automatico: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/state_code.rbs b/sig/nfe/generated/nf_consumidor_v2/state_code.rbs new file mode 100644 index 0000000..40021d4 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/state_code.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module StateCode + NA: String + RO: String + AC: String + AM: String + RR: String + PA: String + AP: String + TO: String + MA: String + PI: String + CE: String + RN: String + PB: String + PE: String + AL: String + SE: String + BA: String + MG: String + ES: String + RJ: String + SP: String + PR: String + SC: String + RS: String + MS: String + MT: String + GO: String + DF: String + EX: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/state_tax_processing_authorizer.rbs b/sig/nfe/generated/nf_consumidor_v2/state_tax_processing_authorizer.rbs new file mode 100644 index 0000000..6cd994d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/state_tax_processing_authorizer.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module StateTaxProcessingAuthorizer + Normal: String + EPEC: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/tax_coupon_information_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/tax_coupon_information_resource.rbs new file mode 100644 index 0000000..244788d --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/tax_coupon_information_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TaxCouponInformationResource < Data + attr_reader model_document_fiscal: String? + attr_reader order_count_operation: Integer? + attr_reader order_ecf: String? + def self.new: (?model_document_fiscal: String?, ?order_count_operation: Integer?, ?order_ecf: String?) -> instance + def initialize: (?model_document_fiscal: String?, ?order_count_operation: Integer?, ?order_ecf: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/tax_determination_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/tax_determination_resource.rbs new file mode 100644 index 0000000..941f94f --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/tax_determination_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TaxDeterminationResource < Data + attr_reader acquisition_purpose: String? + attr_reader buyer_tax_profile: String? + attr_reader issuer_tax_profile: String? + attr_reader operation_code: Integer? + attr_reader origin: String? + def self.new: (?acquisition_purpose: String?, ?buyer_tax_profile: String?, ?issuer_tax_profile: String?, ?operation_code: Integer?, ?origin: String?) -> instance + def initialize: (?acquisition_purpose: String?, ?buyer_tax_profile: String?, ?issuer_tax_profile: String?, ?operation_code: Integer?, ?origin: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/tax_documents_reference_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/tax_documents_reference_resource.rbs new file mode 100644 index 0000000..0053d9c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/tax_documents_reference_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TaxDocumentsReferenceResource < Data + attr_reader document_electronic_invoice: DocumentElectronicInvoiceResource + attr_reader document_invoice_reference: DocumentInvoiceReferenceResource + attr_reader tax_coupon_information: TaxCouponInformationResource + def self.new: (?document_electronic_invoice: DocumentElectronicInvoiceResource, ?document_invoice_reference: DocumentInvoiceReferenceResource, ?tax_coupon_information: TaxCouponInformationResource) -> instance + def initialize: (?document_electronic_invoice: DocumentElectronicInvoiceResource, ?document_invoice_reference: DocumentInvoiceReferenceResource, ?tax_coupon_information: TaxCouponInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/tax_regime.rbs b/sig/nfe/generated/nf_consumidor_v2/tax_regime.rbs new file mode 100644 index 0000000..fa66792 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/tax_regime.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + module TaxRegime + None: String + LucroReal: String + LucroPresumido: String + SimplesNacional: String + SimplesNacionalExcessoSublimite: String + MicroempreendedorIndividual: String + Isento: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/taxpayer_comments_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/taxpayer_comments_resource.rbs new file mode 100644 index 0000000..92fb7c7 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/taxpayer_comments_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TaxpayerCommentsResource < Data + attr_reader field: String? + attr_reader text: String? + def self.new: (?field: String?, ?text: String?) -> instance + def initialize: (?field: String?, ?text: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/total_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/total_resource.rbs new file mode 100644 index 0000000..bc35109 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/total_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TotalResource < Data + attr_reader ibs_cbs_totals: IBSCBSTotalsResource + attr_reader icms: ICMSTotalResource + attr_reader is_totals: ISTotalsResource + attr_reader issqn: ISSQNTotalResource + attr_reader total_invoice_amount: Float? + attr_reader withheld_taxes: TotalsWithholdings + def self.new: (?ibs_cbs_totals: IBSCBSTotalsResource, ?icms: ICMSTotalResource, ?is_totals: ISTotalsResource, ?issqn: ISSQNTotalResource, ?total_invoice_amount: Float?, ?withheld_taxes: TotalsWithholdings) -> instance + def initialize: (?ibs_cbs_totals: IBSCBSTotalsResource, ?icms: ICMSTotalResource, ?is_totals: ISTotalsResource, ?issqn: ISSQNTotalResource, ?total_invoice_amount: Float?, ?withheld_taxes: TotalsWithholdings) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/totals_withholdings.rbs b/sig/nfe/generated/nf_consumidor_v2/totals_withholdings.rbs new file mode 100644 index 0000000..e4bb3e6 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/totals_withholdings.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TotalsWithholdings < Data + attr_reader cofins_amount: Float? + attr_reader csll_amount: Float? + attr_reader irrf_amount: Float? + attr_reader irrf_basis: Float? + attr_reader pis_amount: Float? + attr_reader social_secutiry_amount: Float? + attr_reader social_secutiry_basis: Float? + def self.new: (?cofins_amount: Float?, ?csll_amount: Float?, ?irrf_amount: Float?, ?irrf_basis: Float?, ?pis_amount: Float?, ?social_secutiry_amount: Float?, ?social_secutiry_basis: Float?) -> instance + def initialize: (?cofins_amount: Float?, ?csll_amount: Float?, ?irrf_amount: Float?, ?irrf_basis: Float?, ?pis_amount: Float?, ?social_secutiry_amount: Float?, ?social_secutiry_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/transport_group_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/transport_group_resource.rbs new file mode 100644 index 0000000..97efb79 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/transport_group_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TransportGroupResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader transport_retention: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?transport_retention: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?transport_retention: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/transport_information_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/transport_information_resource.rbs new file mode 100644 index 0000000..70f884b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/transport_information_resource.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TransportInformationResource < Data + attr_reader freight_modality: untyped + attr_reader reboque: ReboqueResource + attr_reader seal_number: String? + attr_reader transp_rate: TransportRateResource + attr_reader transport_group: TransportGroupResource + attr_reader transport_vehicle: TransportVehicleResource + attr_reader volume: VolumeResource + def self.new: (?freight_modality: untyped, ?reboque: ReboqueResource, ?seal_number: String?, ?transp_rate: TransportRateResource, ?transport_group: TransportGroupResource, ?transport_vehicle: TransportVehicleResource, ?volume: VolumeResource) -> instance + def initialize: (?freight_modality: untyped, ?reboque: ReboqueResource, ?seal_number: String?, ?transp_rate: TransportRateResource, ?transport_group: TransportGroupResource, ?transport_vehicle: TransportVehicleResource, ?volume: VolumeResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/transport_rate_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/transport_rate_resource.rbs new file mode 100644 index 0000000..d9a53cb --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/transport_rate_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TransportRateResource < Data + attr_reader bc_retention_amount: Float? + attr_reader cfop: Integer? + attr_reader city_generator_fact_code: Integer? + attr_reader icms_retention_amount: Float? + attr_reader icms_retention_rate: Float? + attr_reader service_amount: Float? + def self.new: (?bc_retention_amount: Float?, ?cfop: Integer?, ?city_generator_fact_code: Integer?, ?icms_retention_amount: Float?, ?icms_retention_rate: Float?, ?service_amount: Float?) -> instance + def initialize: (?bc_retention_amount: Float?, ?cfop: Integer?, ?city_generator_fact_code: Integer?, ?icms_retention_amount: Float?, ?icms_retention_rate: Float?, ?service_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/transport_vehicle_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/transport_vehicle_resource.rbs new file mode 100644 index 0000000..3dcb230 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/transport_vehicle_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class TransportVehicleResource < Data + attr_reader plate: String? + attr_reader rntc: String? + attr_reader state: String? + def self.new: (?plate: String?, ?rntc: String?, ?state: String?) -> instance + def initialize: (?plate: String?, ?rntc: String?, ?state: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/vehicle_detail_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/vehicle_detail_resource.rbs new file mode 100644 index 0000000..6216c05 --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/vehicle_detail_resource.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class VehicleDetailResource < Data + attr_reader brand_model_code: String? + attr_reader chassis: String? + attr_reader color_code: String? + attr_reader color_description: String? + attr_reader denatran_color_code: String? + attr_reader engine_displacement: String? + attr_reader engine_number: String? + attr_reader engine_power: String? + attr_reader fuel_type: String? + attr_reader gross_weight: String? + attr_reader manufacture_year: Integer? + attr_reader maximum_traction_capacity: String? + attr_reader model_year: Integer? + attr_reader net_weight: String? + attr_reader operation_type: Integer? + attr_reader paint_type: String? + attr_reader restriction_type: Integer? + attr_reader seating_capacity: Integer? + attr_reader serial_number: String? + attr_reader vehicle_condition: Integer? + attr_reader vehicle_species: Integer? + attr_reader vehicle_type: String? + attr_reader vin_condition: String? + attr_reader wheel_base: String? + def self.new: (?brand_model_code: String?, ?chassis: String?, ?color_code: String?, ?color_description: String?, ?denatran_color_code: String?, ?engine_displacement: String?, ?engine_number: String?, ?engine_power: String?, ?fuel_type: String?, ?gross_weight: String?, ?manufacture_year: Integer?, ?maximum_traction_capacity: String?, ?model_year: Integer?, ?net_weight: String?, ?operation_type: Integer?, ?paint_type: String?, ?restriction_type: Integer?, ?seating_capacity: Integer?, ?serial_number: String?, ?vehicle_condition: Integer?, ?vehicle_species: Integer?, ?vehicle_type: String?, ?vin_condition: String?, ?wheel_base: String?) -> instance + def initialize: (?brand_model_code: String?, ?chassis: String?, ?color_code: String?, ?color_description: String?, ?denatran_color_code: String?, ?engine_displacement: String?, ?engine_number: String?, ?engine_power: String?, ?fuel_type: String?, ?gross_weight: String?, ?manufacture_year: Integer?, ?maximum_traction_capacity: String?, ?model_year: Integer?, ?net_weight: String?, ?operation_type: Integer?, ?paint_type: String?, ?restriction_type: Integer?, ?seating_capacity: Integer?, ?serial_number: String?, ?vehicle_condition: Integer?, ?vehicle_species: Integer?, ?vehicle_type: String?, ?vin_condition: String?, ?wheel_base: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/volume_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/volume_resource.rbs new file mode 100644 index 0000000..beaf05b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/volume_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class VolumeResource < Data + attr_reader brand: String? + attr_reader gross_weight: Float? + attr_reader net_weight: Float? + attr_reader species: String? + attr_reader volume_numeration: String? + attr_reader volume_quantity: Integer? + def self.new: (?brand: String?, ?gross_weight: Float?, ?net_weight: Float?, ?species: String?, ?volume_numeration: String?, ?volume_quantity: Integer?) -> instance + def initialize: (?brand: String?, ?gross_weight: Float?, ?net_weight: Float?, ?species: String?, ?volume_numeration: String?, ?volume_quantity: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/withdrawal_information_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/withdrawal_information_resource.rbs new file mode 100644 index 0000000..beb1a2b --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/withdrawal_information_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class WithdrawalInformationResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_consumidor_v2/zfm_presumed_credit_resource.rbs b/sig/nfe/generated/nf_consumidor_v2/zfm_presumed_credit_resource.rbs new file mode 100644 index 0000000..f4ebb1c --- /dev/null +++ b/sig/nfe/generated/nf_consumidor_v2/zfm_presumed_credit_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-consumidor-v2.yaml +# Hash: sha256:8c39e692ff794ccb2587ebe142be040e44d76cbf970f45e65b28d56a6165bdb5 + +module Nfe + module Generated + module NfConsumidorV2 + class ZfmPresumedCreditResource < Data + attr_reader amount: Float? + attr_reader classification_code: untyped + def self.new: (?amount: Float?, ?classification_code: untyped) -> instance + def initialize: (?amount: Float?, ?classification_code: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/activity_resource.rbs b/sig/nfe/generated/nf_produto_v2/activity_resource.rbs new file mode 100644 index 0000000..68545ac --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/activity_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ActivityResource < Data + attr_reader data: untyped + attr_reader sequence: Integer? + attr_reader type: String? + def self.new: (?data: untyped, ?sequence: Integer?, ?type: String?) -> instance + def initialize: (?data: untyped, ?sequence: Integer?, ?type: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/addition_resource.rbs b/sig/nfe/generated/nf_produto_v2/addition_resource.rbs new file mode 100644 index 0000000..25c0c14 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/addition_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class AdditionResource < Data + attr_reader amount: Float? + attr_reader code: Integer? + attr_reader drawback: Integer? + attr_reader manufacturer: String? + def self.new: (?amount: Float?, ?code: Integer?, ?drawback: Integer?, ?manufacturer: String?) -> instance + def initialize: (?amount: Float?, ?code: Integer?, ?drawback: Integer?, ?manufacturer: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/additional_information_resource.rbs b/sig/nfe/generated/nf_produto_v2/additional_information_resource.rbs new file mode 100644 index 0000000..4fde4fa --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/additional_information_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class AdditionalInformationResource < Data + attr_reader contract: String? + attr_reader effort: String? + attr_reader fisco: String? + attr_reader order: String? + attr_reader referenced_process: Array[ReferencedProcessResource]? + attr_reader tax_documents_reference: Array[TaxDocumentsReferenceResource]? + attr_reader taxpayer: String? + attr_reader taxpayer_comments: Array[TaxpayerCommentsResource]? + attr_reader xml_authorized: Array[Integer]? + def self.new: (?contract: String?, ?effort: String?, ?fisco: String?, ?order: String?, ?referenced_process: Array[ReferencedProcessResource]?, ?tax_documents_reference: Array[TaxDocumentsReferenceResource]?, ?taxpayer: String?, ?taxpayer_comments: Array[TaxpayerCommentsResource]?, ?xml_authorized: Array[Integer]?) -> instance + def initialize: (?contract: String?, ?effort: String?, ?fisco: String?, ?order: String?, ?referenced_process: Array[ReferencedProcessResource]?, ?tax_documents_reference: Array[TaxDocumentsReferenceResource]?, ?taxpayer: String?, ?taxpayer_comments: Array[TaxpayerCommentsResource]?, ?xml_authorized: Array[Integer]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/address_resource.rbs b/sig/nfe/generated/nf_produto_v2/address_resource.rbs new file mode 100644 index 0000000..a9c7517 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/address_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class AddressResource < Data + attr_reader additional_information: String? + attr_reader city: CityResource + attr_reader country: String? + attr_reader district: String + attr_reader number: String + attr_reader phone: String? + attr_reader postal_code: String? + attr_reader state: String + attr_reader street: String + def self.new: (?additional_information: String?, city: CityResource, ?country: String?, district: String, number: String, ?phone: String?, ?postal_code: String?, state: String, street: String) -> instance + def initialize: (?additional_information: String?, city: CityResource, ?country: String?, district: String, number: String, ?phone: String?, ?postal_code: String?, state: String, street: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/authorization_resource.rbs b/sig/nfe/generated/nf_produto_v2/authorization_resource.rbs new file mode 100644 index 0000000..4e03237 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/authorization_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class AuthorizationResource < Data + attr_reader access_key: String? + attr_reader message: String? + attr_reader receipt_on: String? + def self.new: (?access_key: String?, ?message: String?, ?receipt_on: String?) -> instance + def initialize: (?access_key: String?, ?message: String?, ?receipt_on: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/bill_resource.rbs b/sig/nfe/generated/nf_produto_v2/bill_resource.rbs new file mode 100644 index 0000000..96a6a4b --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/bill_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class BillResource < Data + attr_reader discount_amount: Float? + attr_reader net_amount: Float? + attr_reader number: String? + attr_reader original_amount: Float? + def self.new: (?discount_amount: Float?, ?net_amount: Float?, ?number: String?, ?original_amount: Float?) -> instance + def initialize: (?discount_amount: Float?, ?net_amount: Float?, ?number: String?, ?original_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/billing_resource.rbs b/sig/nfe/generated/nf_produto_v2/billing_resource.rbs new file mode 100644 index 0000000..d072ae0 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/billing_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class BillingResource < Data + attr_reader bill: BillResource + attr_reader duplicates: Array[DuplicateResource]? + def self.new: (?bill: BillResource, ?duplicates: Array[DuplicateResource]?) -> instance + def initialize: (?bill: BillResource, ?duplicates: Array[DuplicateResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/buyer_resource.rbs b/sig/nfe/generated/nf_produto_v2/buyer_resource.rbs new file mode 100644 index 0000000..bf5ff83 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/buyer_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class BuyerResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer + attr_reader id: String? + attr_reader name: String + attr_reader state_tax_number: String? + attr_reader state_tax_number_indicator: untyped + attr_reader tax_regime: untyped + attr_reader trade_name: String? + attr_reader type: untyped + def self.new: (?account_id: String?, address: AddressResource, ?email: String?, federal_tax_number: Integer, ?id: String?, name: String, ?state_tax_number: String?, ?state_tax_number_indicator: untyped, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, address: AddressResource, ?email: String?, federal_tax_number: Integer, ?id: String?, name: String, ?state_tax_number: String?, ?state_tax_number_indicator: untyped, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/card_resource.rbs b/sig/nfe/generated/nf_produto_v2/card_resource.rbs new file mode 100644 index 0000000..b37da78 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/card_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class CardResource < Data + attr_reader authorization: String? + attr_reader federal_tax_number: String? + attr_reader federal_tax_number_recipient: String? + attr_reader flag: untyped + attr_reader id_payment_terminal: String? + attr_reader integration_payment_type: untyped + def self.new: (?authorization: String?, ?federal_tax_number: String?, ?federal_tax_number_recipient: String?, ?flag: untyped, ?id_payment_terminal: String?, ?integration_payment_type: untyped) -> instance + def initialize: (?authorization: String?, ?federal_tax_number: String?, ?federal_tax_number_recipient: String?, ?flag: untyped, ?id_payment_terminal: String?, ?integration_payment_type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/cideresource.rbs b/sig/nfe/generated/nf_produto_v2/cideresource.rbs new file mode 100644 index 0000000..be5a409 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/cideresource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class CIDEResource < Data + attr_reader bc: Float? + attr_reader cide_amount: Float? + attr_reader rate: Float? + def self.new: (?bc: Float?, ?cide_amount: Float?, ?rate: Float?) -> instance + def initialize: (?bc: Float?, ?cide_amount: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/city_resource.rbs b/sig/nfe/generated/nf_produto_v2/city_resource.rbs new file mode 100644 index 0000000..240b820 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/city_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class CityResource < Data + attr_reader code: String + attr_reader name: String + def self.new: (code: String, name: String) -> instance + def initialize: (code: String, name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/cofins_tax_resource.rbs b/sig/nfe/generated/nf_produto_v2/cofins_tax_resource.rbs new file mode 100644 index 0000000..523e2b3 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/cofins_tax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class CofinsTaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: Float? + attr_reader base_tax_product_quantity: Float? + attr_reader cst: String? + attr_reader product_rate: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/consumer_presence_type.rbs b/sig/nfe/generated/nf_produto_v2/consumer_presence_type.rbs new file mode 100644 index 0000000..c221c28 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/consumer_presence_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ConsumerPresenceType + None: String + Presence: String + Internet: String + Telephone: String + Delivery: String + OthersNonPresenceOperation: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/consumer_type.rbs b/sig/nfe/generated/nf_produto_v2/consumer_type.rbs new file mode 100644 index 0000000..1908a04 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/consumer_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ConsumerType + FinalConsumer: String + Normal: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/contingency_details.rbs b/sig/nfe/generated/nf_produto_v2/contingency_details.rbs new file mode 100644 index 0000000..1d5d329 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/contingency_details.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ContingencyDetails < Data + attr_reader authorizer: untyped + attr_reader reason: String? + attr_reader started_on: String + def self.new: (?authorizer: untyped, ?reason: String?, ?started_on: String) -> instance + def initialize: (?authorizer: untyped, ?reason: String?, ?started_on: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/delivery_information_resource.rbs b/sig/nfe/generated/nf_produto_v2/delivery_information_resource.rbs new file mode 100644 index 0000000..c9faa15 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/delivery_information_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class DeliveryInformationResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/destination.rbs b/sig/nfe/generated/nf_produto_v2/destination.rbs new file mode 100644 index 0000000..a1a0498 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/destination.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module Destination + None: String + InternalOperation: String + InterstateOperation: String + InternationalOperation: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/disablement_resource.rbs b/sig/nfe/generated/nf_produto_v2/disablement_resource.rbs new file mode 100644 index 0000000..cba9ec4 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/disablement_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class DisablementResource < Data + attr_reader begin_number: Integer + attr_reader environment: untyped + attr_reader last_number: Integer + attr_reader reason: String? + attr_reader serie: Integer + attr_reader state: untyped + def self.new: (?begin_number: Integer, ?environment: untyped, ?last_number: Integer, ?reason: String?, ?serie: Integer, ?state: untyped) -> instance + def initialize: (?begin_number: Integer, ?environment: untyped, ?last_number: Integer, ?reason: String?, ?serie: Integer, ?state: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/document_electronic_invoice_resource.rbs b/sig/nfe/generated/nf_produto_v2/document_electronic_invoice_resource.rbs new file mode 100644 index 0000000..e402774 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/document_electronic_invoice_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class DocumentElectronicInvoiceResource < Data + attr_reader access_key: String? + def self.new: (?access_key: String?) -> instance + def initialize: (?access_key: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/document_invoice_reference_resource.rbs b/sig/nfe/generated/nf_produto_v2/document_invoice_reference_resource.rbs new file mode 100644 index 0000000..9dfbb7c --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/document_invoice_reference_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class DocumentInvoiceReferenceResource < Data + attr_reader federal_tax_number: String? + attr_reader model: String? + attr_reader number: String? + attr_reader series: String? + attr_reader state: Float? + attr_reader year_month: String? + def self.new: (?federal_tax_number: String?, ?model: String?, ?number: String?, ?series: String?, ?state: Float?, ?year_month: String?) -> instance + def initialize: (?federal_tax_number: String?, ?model: String?, ?number: String?, ?series: String?, ?state: Float?, ?year_month: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/duduction_indicator.rbs b/sig/nfe/generated/nf_produto_v2/duduction_indicator.rbs new file mode 100644 index 0000000..884f5ef --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/duduction_indicator.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module DuductionIndicator + NotDeduct: String + Deduce: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/duplicate_resource.rbs b/sig/nfe/generated/nf_produto_v2/duplicate_resource.rbs new file mode 100644 index 0000000..6cfd517 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/duplicate_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class DuplicateResource < Data + attr_reader amount: Float? + attr_reader expiration_on: String? + attr_reader number: String? + def self.new: (?amount: Float?, ?expiration_on: String?, ?number: String?) -> instance + def initialize: (?amount: Float?, ?expiration_on: String?, ?number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/economic_activity_resource.rbs b/sig/nfe/generated/nf_produto_v2/economic_activity_resource.rbs new file mode 100644 index 0000000..f9fa51d --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/economic_activity_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class EconomicActivityResource < Data + attr_reader code: Integer? + attr_reader type: untyped + def self.new: (?code: Integer?, ?type: untyped) -> instance + def initialize: (?code: Integer?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/economic_activity_type.rbs b/sig/nfe/generated/nf_produto_v2/economic_activity_type.rbs new file mode 100644 index 0000000..68e8b63 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/economic_activity_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module EconomicActivityType + Main: String + Secondary: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/environment_type.rbs b/sig/nfe/generated/nf_produto_v2/environment_type.rbs new file mode 100644 index 0000000..7fc8092 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/environment_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module EnvironmentType + None: String + Production: String + Test: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/error_resource.rbs b/sig/nfe/generated/nf_produto_v2/error_resource.rbs new file mode 100644 index 0000000..e6c5b90 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/error_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ErrorResource < Data + attr_reader code: Integer? + attr_reader message: String? + def self.new: (?code: Integer?, ?message: String?) -> instance + def initialize: (?code: Integer?, ?message: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/errors_resource.rbs b/sig/nfe/generated/nf_produto_v2/errors_resource.rbs new file mode 100644 index 0000000..bbe4c91 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/errors_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ErrorsResource < Data + attr_reader errors: Array[ErrorResource]? + def self.new: (?errors: Array[ErrorResource]?) -> instance + def initialize: (?errors: Array[ErrorResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/exempt_reason.rbs b/sig/nfe/generated/nf_produto_v2/exempt_reason.rbs new file mode 100644 index 0000000..22b9bb4 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/exempt_reason.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ExemptReason + Agriculture: String + Others: String + DevelopmentEntities: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/export_detail_resource.rbs b/sig/nfe/generated/nf_produto_v2/export_detail_resource.rbs new file mode 100644 index 0000000..589d1e6 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/export_detail_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ExportDetailResource < Data + attr_reader drawback: String? + attr_reader hint_information: ExportHintResource + def self.new: (?drawback: String?, ?hint_information: ExportHintResource) -> instance + def initialize: (?drawback: String?, ?hint_information: ExportHintResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/export_hint_resource.rbs b/sig/nfe/generated/nf_produto_v2/export_hint_resource.rbs new file mode 100644 index 0000000..c4662ca --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/export_hint_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ExportHintResource < Data + attr_reader access_key: String? + attr_reader quantity: Float? + attr_reader registry_id: String? + def self.new: (?access_key: String?, ?quantity: Float?, ?registry_id: String?) -> instance + def initialize: (?access_key: String?, ?quantity: Float?, ?registry_id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/export_resource.rbs b/sig/nfe/generated/nf_produto_v2/export_resource.rbs new file mode 100644 index 0000000..39ce751 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/export_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ExportResource < Data + attr_reader local: String? + attr_reader office: String? + attr_reader state: untyped + def self.new: (?local: String?, ?office: String?, ?state: untyped) -> instance + def initialize: (?local: String?, ?office: String?, ?state: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/file_resource.rbs b/sig/nfe/generated/nf_produto_v2/file_resource.rbs new file mode 100644 index 0000000..b12173d --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/file_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class FileResource < Data + attr_reader uri: String? + def self.new: (?uri: String?) -> instance + def initialize: (?uri: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/flag_card.rbs b/sig/nfe/generated/nf_produto_v2/flag_card.rbs new file mode 100644 index 0000000..1799033 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/flag_card.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module FlagCard + None: String + Visa: String + Mastercard: String + AmericanExpress: String + Sorocred: String + DinersClub: String + Elo: String + Hipercard: String + Aura: String + Cabal: String + Alelo: String + BanesCard: String + CalCard: String + Credz: String + Discover: String + GoodCard: String + GreenCard: String + Hiper: String + JCB: String + Mais: String + MaxVan: String + Policard: String + RedeCompras: String + Sodexo: String + ValeCard: String + Verocheque: String + VR: String + Ticket: String + Other: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/fuel_origin_resource.rbs b/sig/nfe/generated/nf_produto_v2/fuel_origin_resource.rbs new file mode 100644 index 0000000..5a58bf9 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/fuel_origin_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class FuelOriginResource < Data + attr_reader c_uforig: Integer? + attr_reader ind_import: Integer? + attr_reader p_orig: Float? + def self.new: (?c_uforig: Integer?, ?ind_import: Integer?, ?p_orig: Float?) -> instance + def initialize: (?c_uforig: Integer?, ?ind_import: Integer?, ?p_orig: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/fuel_resource.rbs b/sig/nfe/generated/nf_produto_v2/fuel_resource.rbs new file mode 100644 index 0000000..a17eae3 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/fuel_resource.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class FuelResource < Data + attr_reader amount_temp: Float? + attr_reader cide: CIDEResource + attr_reader code_anp: String? + attr_reader codif: String? + attr_reader description_anp: String? + attr_reader fuel_origin: FuelOriginResource + attr_reader percentage_glp: Float? + attr_reader percentage_gni: Float? + attr_reader percentage_ng: Float? + attr_reader percentage_ngn: Float? + attr_reader pump: PumpResource + attr_reader starting_amount: Float? + attr_reader state_buyer: String? + def self.new: (?amount_temp: Float?, ?cide: CIDEResource, ?code_anp: String?, ?codif: String?, ?description_anp: String?, ?fuel_origin: FuelOriginResource, ?percentage_glp: Float?, ?percentage_gni: Float?, ?percentage_ng: Float?, ?percentage_ngn: Float?, ?pump: PumpResource, ?starting_amount: Float?, ?state_buyer: String?) -> instance + def initialize: (?amount_temp: Float?, ?cide: CIDEResource, ?code_anp: String?, ?codif: String?, ?description_anp: String?, ?fuel_origin: FuelOriginResource, ?percentage_glp: Float?, ?percentage_gni: Float?, ?percentage_ng: Float?, ?percentage_ngn: Float?, ?pump: PumpResource, ?starting_amount: Float?, ?state_buyer: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/icms_tax_resource.rbs b/sig/nfe/generated/nf_produto_v2/icms_tax_resource.rbs new file mode 100644 index 0000000..ac69090 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/icms_tax_resource.rbs @@ -0,0 +1,61 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class IcmsTaxResource < Data + attr_reader amount: Float? + attr_reader amount_operation: String? + attr_reader amount_streason: String? + attr_reader base_deferred: String? + attr_reader base_snretention_amount: String? + attr_reader base_stretention_amount: String? + attr_reader base_tax: Float? + attr_reader base_tax_fcpstamount: Float? + attr_reader base_tax_modality: String? + attr_reader base_tax_operation_percentual: String? + attr_reader base_tax_reduction: Float? + attr_reader base_tax_st: Float? + attr_reader base_tax_stmodality: String? + attr_reader base_tax_streduction: String? + attr_reader csosn: String? + attr_reader cst: String? + attr_reader deduction_indicator: untyped + attr_reader effective_amount: Float? + attr_reader effective_base_tax_amount: Float? + attr_reader effective_base_tax_reduction_rate: Float? + attr_reader effective_rate: Float? + attr_reader exempt_amount: Float? + attr_reader exempt_amount_st: Float? + attr_reader exempt_reason: untyped + attr_reader exempt_reason_st: untyped + attr_reader fcp_amount: Float? + attr_reader fcp_rate: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_rate: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpst_ret_rate: Float? + attr_reader origin: String + attr_reader percentual: Float? + attr_reader percentual_deferment: String? + attr_reader rate: Float? + attr_reader sn_credit_amount: Float? + attr_reader sn_credit_rate: Float? + attr_reader sn_retention_amount: String? + attr_reader st_amount: Float? + attr_reader st_final_consumer_rate: Float? + attr_reader st_margin_added_amount: String? + attr_reader st_margin_amount: Float? + attr_reader st_rate: Float? + attr_reader st_retention_amount: String? + attr_reader substitute_amount: Float? + attr_reader ufst: String? + def self.new: (?amount: Float?, ?amount_operation: String?, ?amount_streason: String?, ?base_deferred: String?, ?base_snretention_amount: String?, ?base_stretention_amount: String?, ?base_tax: Float?, ?base_tax_fcpstamount: Float?, ?base_tax_modality: String?, ?base_tax_operation_percentual: String?, ?base_tax_reduction: Float?, ?base_tax_st: Float?, ?base_tax_stmodality: String?, ?base_tax_streduction: String?, ?csosn: String?, ?cst: String?, ?deduction_indicator: untyped, ?effective_amount: Float?, ?effective_base_tax_amount: Float?, ?effective_base_tax_reduction_rate: Float?, ?effective_rate: Float?, ?exempt_amount: Float?, ?exempt_amount_st: Float?, ?exempt_reason: untyped, ?exempt_reason_st: untyped, ?fcp_amount: Float?, ?fcp_rate: Float?, ?fcpst_amount: Float?, ?fcpst_rate: Float?, ?fcpst_ret_amount: Float?, ?fcpst_ret_rate: Float?, origin: String, ?percentual: Float?, ?percentual_deferment: String?, ?rate: Float?, ?sn_credit_amount: Float?, ?sn_credit_rate: Float?, ?sn_retention_amount: String?, ?st_amount: Float?, ?st_final_consumer_rate: Float?, ?st_margin_added_amount: String?, ?st_margin_amount: Float?, ?st_rate: Float?, ?st_retention_amount: String?, ?substitute_amount: Float?, ?ufst: String?) -> instance + def initialize: (?amount: Float?, ?amount_operation: String?, ?amount_streason: String?, ?base_deferred: String?, ?base_snretention_amount: String?, ?base_stretention_amount: String?, ?base_tax: Float?, ?base_tax_fcpstamount: Float?, ?base_tax_modality: String?, ?base_tax_operation_percentual: String?, ?base_tax_reduction: Float?, ?base_tax_st: Float?, ?base_tax_stmodality: String?, ?base_tax_streduction: String?, ?csosn: String?, ?cst: String?, ?deduction_indicator: untyped, ?effective_amount: Float?, ?effective_base_tax_amount: Float?, ?effective_base_tax_reduction_rate: Float?, ?effective_rate: Float?, ?exempt_amount: Float?, ?exempt_amount_st: Float?, ?exempt_reason: untyped, ?exempt_reason_st: untyped, ?fcp_amount: Float?, ?fcp_rate: Float?, ?fcpst_amount: Float?, ?fcpst_rate: Float?, ?fcpst_ret_amount: Float?, ?fcpst_ret_rate: Float?, origin: String, ?percentual: Float?, ?percentual_deferment: String?, ?rate: Float?, ?sn_credit_amount: Float?, ?sn_credit_rate: Float?, ?sn_retention_amount: String?, ?st_amount: Float?, ?st_final_consumer_rate: Float?, ?st_margin_added_amount: String?, ?st_margin_amount: Float?, ?st_rate: Float?, ?st_retention_amount: String?, ?substitute_amount: Float?, ?ufst: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/icmstotal.rbs b/sig/nfe/generated/nf_produto_v2/icmstotal.rbs new file mode 100644 index 0000000..b00c62a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/icmstotal.rbs @@ -0,0 +1,44 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ICMSTotal < Data + attr_reader base_tax: Float? + attr_reader cofins_amount: Float? + attr_reader discount_amount: Float? + attr_reader fcp_amount: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpuf_destination_amount: Float? + attr_reader federal_taxes_amount: Float + attr_reader freight_amount: Float? + attr_reader icms_amount: Float? + attr_reader icms_exempt_amount: Float? + attr_reader icmsuf_destination_amount: Float? + attr_reader icmsuf_sender_amount: Float? + attr_reader ii_amount: Float? + attr_reader insurance_amount: Float? + attr_reader invoice_amount: Float + attr_reader ipi_amount: Float? + attr_reader ipi_devol_amount: Float? + attr_reader others_amount: Float? + attr_reader pis_amount: Float? + attr_reader product_amount: Float + attr_reader q_bcmono: Float? + attr_reader q_bcmono_ret: Float? + attr_reader q_bcmono_reten: Float? + attr_reader st_amount: Float? + attr_reader st_calculation_basis_amount: Float? + attr_reader v_icmsmono: Float? + attr_reader v_icmsmono_ret: Float? + attr_reader v_icmsmono_reten: Float? + def self.new: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> instance + def initialize: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/icmstotal_resource.rbs b/sig/nfe/generated/nf_produto_v2/icmstotal_resource.rbs new file mode 100644 index 0000000..e11befa --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/icmstotal_resource.rbs @@ -0,0 +1,44 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ICMSTotalResource < Data + attr_reader base_tax: Float? + attr_reader cofins_amount: Float? + attr_reader discount_amount: Float? + attr_reader fcp_amount: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpuf_destination_amount: Float? + attr_reader federal_taxes_amount: Float? + attr_reader freight_amount: Float? + attr_reader icms_amount: Float? + attr_reader icms_exempt_amount: Float? + attr_reader icmsuf_destination_amount: Float? + attr_reader icmsuf_sender_amount: Float? + attr_reader ii_amount: Float? + attr_reader insurance_amount: Float? + attr_reader invoice_amount: Float? + attr_reader ipi_amount: Float? + attr_reader ipi_devol_amount: Float? + attr_reader others_amount: Float? + attr_reader pis_amount: Float? + attr_reader product_amount: Float? + attr_reader q_bcmono: Float? + attr_reader q_bcmono_ret: Float? + attr_reader q_bcmono_reten: Float? + attr_reader st_amount: Float? + attr_reader st_calculation_basis_amount: Float? + attr_reader v_icmsmono: Float? + attr_reader v_icmsmono_ret: Float? + attr_reader v_icmsmono_reten: Float? + def self.new: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float?, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float?, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float?, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> instance + def initialize: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float?, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float?, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float?, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/icmsufdestination_tax_resource.rbs b/sig/nfe/generated/nf_produto_v2/icmsufdestination_tax_resource.rbs new file mode 100644 index 0000000..7e7a971 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/icmsufdestination_tax_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ICMSUFDestinationTaxResource < Data + attr_reader p_fcpufdest: Float? + attr_reader p_icmsinter: Float? + attr_reader p_icmsinter_part: Float? + attr_reader p_icmsufdest: Float? + attr_reader v_bcfcpufdest: Float? + attr_reader v_bcufdest: Float? + attr_reader v_fcpufdest: Float? + attr_reader v_icmsufdest: Float? + attr_reader v_icmsufremet: Float? + def self.new: (?p_fcpufdest: Float?, ?p_icmsinter: Float?, ?p_icmsinter_part: Float?, ?p_icmsufdest: Float?, ?v_bcfcpufdest: Float?, ?v_bcufdest: Float?, ?v_fcpufdest: Float?, ?v_icmsufdest: Float?, ?v_icmsufremet: Float?) -> instance + def initialize: (?p_fcpufdest: Float?, ?p_icmsinter: Float?, ?p_icmsinter_part: Float?, ?p_icmsufdest: Float?, ?v_bcfcpufdest: Float?, ?v_bcufdest: Float?, ?v_fcpufdest: Float?, ?v_icmsufdest: Float?, ?v_icmsufremet: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/iitax_resource.rbs b/sig/nfe/generated/nf_produto_v2/iitax_resource.rbs new file mode 100644 index 0000000..5ef13e1 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/iitax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class IITaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: String? + attr_reader customs_expenditure_amount: String? + attr_reader iof_amount: Float? + attr_reader v_enq_camb: Float? + def self.new: (?amount: Float?, ?base_tax: String?, ?customs_expenditure_amount: String?, ?iof_amount: Float?, ?v_enq_camb: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: String?, ?customs_expenditure_amount: String?, ?iof_amount: Float?, ?v_enq_camb: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/import_declaration_resource.rbs b/sig/nfe/generated/nf_produto_v2/import_declaration_resource.rbs new file mode 100644 index 0000000..7649773 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/import_declaration_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ImportDeclarationResource < Data + attr_reader acquirer_federal_tax_number: String? + attr_reader additions: Array[AdditionResource]? + attr_reader code: String? + attr_reader customs_clearance_name: String? + attr_reader customs_clearance_state: untyped + attr_reader customs_clearanced_on: String? + attr_reader exporter: String? + attr_reader intermediation: untyped + attr_reader international_transport: untyped + attr_reader registered_on: String? + attr_reader state_third: String? + def self.new: (?acquirer_federal_tax_number: String?, ?additions: Array[AdditionResource]?, ?code: String?, ?customs_clearance_name: String?, ?customs_clearance_state: untyped, ?customs_clearanced_on: String?, ?exporter: String?, ?intermediation: untyped, ?international_transport: untyped, ?registered_on: String?, ?state_third: String?) -> instance + def initialize: (?acquirer_federal_tax_number: String?, ?additions: Array[AdditionResource]?, ?code: String?, ?customs_clearance_name: String?, ?customs_clearance_state: untyped, ?customs_clearanced_on: String?, ?exporter: String?, ?intermediation: untyped, ?international_transport: untyped, ?registered_on: String?, ?state_third: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/integration_payment_type.rbs b/sig/nfe/generated/nf_produto_v2/integration_payment_type.rbs new file mode 100644 index 0000000..8f1ba4b --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/integration_payment_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module IntegrationPaymentType + Integrated: String + NotIntegrated: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/intermediate_resource.rbs b/sig/nfe/generated/nf_produto_v2/intermediate_resource.rbs new file mode 100644 index 0000000..452d2f7 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/intermediate_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class IntermediateResource < Data + attr_reader federal_tax_number: Integer? + attr_reader identifier: String? + def self.new: (?federal_tax_number: Integer?, ?identifier: String?) -> instance + def initialize: (?federal_tax_number: Integer?, ?identifier: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/intermediation_type.rbs b/sig/nfe/generated/nf_produto_v2/intermediation_type.rbs new file mode 100644 index 0000000..fde55a5 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/intermediation_type.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module IntermediationType + None: String + ByOwn: String + ImportOnBehalf: String + ByOrder: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/international_transport_type.rbs b/sig/nfe/generated/nf_produto_v2/international_transport_type.rbs new file mode 100644 index 0000000..7e51093 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/international_transport_type.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module InternationalTransportType + None: String + Maritime: String + River: String + Lake: String + Airline: String + Postal: String + Railway: String + Highway: String + Network: String + Own: String + Ficta: String + Courier: String + Handcarry: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_events_resource_base.rbs b/sig/nfe/generated/nf_produto_v2/invoice_events_resource_base.rbs new file mode 100644 index 0000000..5ef2f8a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_events_resource_base.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class InvoiceEventsResourceBase < Data + attr_reader events: Array[ActivityResource]? + attr_reader has_more: bool? + def self.new: (?events: Array[ActivityResource]?, ?has_more: bool?) -> instance + def initialize: (?events: Array[ActivityResource]?, ?has_more: bool?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_item_resource.rbs b/sig/nfe/generated/nf_produto_v2/invoice_item_resource.rbs new file mode 100644 index 0000000..ff31efd --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_item_resource.rbs @@ -0,0 +1,47 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class InvoiceItemResource < Data + attr_reader additional_information: String? + attr_reader benefit: String? + attr_reader cest: String? + attr_reader cfop: Integer? + attr_reader code: String + attr_reader code_gtin: String? + attr_reader code_tax_gtin: String? + attr_reader description: String + attr_reader discount_amount: Float? + attr_reader export_details: Array[ExportDetailResource]? + attr_reader extipi: String? + attr_reader freight_amount: Float? + attr_reader fuel_detail: FuelResource + attr_reader import_control_sheet_number: String? + attr_reader import_declarations: Array[ImportDeclarationResource]? + attr_reader insurance_amount: Float? + attr_reader item_number_order_buy: Integer? + attr_reader ncm: String + attr_reader number_order_buy: String? + attr_reader nve: Array[String]? + attr_reader others_amount: Float? + attr_reader quantity: Float + attr_reader quantity_tax: Float? + attr_reader tax: InvoiceItemTaxResource + attr_reader tax_determination: TaxDeterminationResource + attr_reader tax_unit_amount: Float? + attr_reader total_amount: Float + attr_reader total_indicator: bool? + attr_reader unit: String + attr_reader unit_amount: Float + attr_reader unit_tax: String + attr_reader vehicle_detail: VehicleDetailResource + def self.new: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer?, code: String, ?code_gtin: String?, ?code_tax_gtin: String?, description: String, ?discount_amount: Float?, ?export_details: Array[ExportDetailResource]?, ?extipi: String?, ?freight_amount: Float?, ?fuel_detail: FuelResource, ?import_control_sheet_number: String?, ?import_declarations: Array[ImportDeclarationResource]?, ?insurance_amount: Float?, ?item_number_order_buy: Integer?, ncm: String, ?number_order_buy: String?, ?nve: Array[String]?, ?others_amount: Float?, quantity: Float, ?quantity_tax: Float?, tax: InvoiceItemTaxResource, ?tax_determination: TaxDeterminationResource, ?tax_unit_amount: Float?, total_amount: Float, ?total_indicator: bool?, unit: String, unit_amount: Float, unit_tax: String, ?vehicle_detail: VehicleDetailResource) -> instance + def initialize: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer?, code: String, ?code_gtin: String?, ?code_tax_gtin: String?, description: String, ?discount_amount: Float?, ?export_details: Array[ExportDetailResource]?, ?extipi: String?, ?freight_amount: Float?, ?fuel_detail: FuelResource, ?import_control_sheet_number: String?, ?import_declarations: Array[ImportDeclarationResource]?, ?insurance_amount: Float?, ?item_number_order_buy: Integer?, ncm: String, ?number_order_buy: String?, ?nve: Array[String]?, ?others_amount: Float?, quantity: Float, ?quantity_tax: Float?, tax: InvoiceItemTaxResource, ?tax_determination: TaxDeterminationResource, ?tax_unit_amount: Float?, total_amount: Float, ?total_indicator: bool?, unit: String, unit_amount: Float, unit_tax: String, ?vehicle_detail: VehicleDetailResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_item_tax_resource.rbs b/sig/nfe/generated/nf_produto_v2/invoice_item_tax_resource.rbs new file mode 100644 index 0000000..1224792 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_item_tax_resource.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class InvoiceItemTaxResource < Data + attr_reader cofins: CofinsTaxResource + attr_reader icms: IcmsTaxResource + attr_reader icms_destination: ICMSUFDestinationTaxResource + attr_reader ii: IITaxResource + attr_reader ipi: IPITaxResource + attr_reader pis: PISTaxResource + attr_reader total_tax: Float? + def self.new: (?cofins: CofinsTaxResource, icms: IcmsTaxResource, ?icms_destination: ICMSUFDestinationTaxResource, ?ii: IITaxResource, ?ipi: IPITaxResource, ?pis: PISTaxResource, ?total_tax: Float?) -> instance + def initialize: (?cofins: CofinsTaxResource, icms: IcmsTaxResource, ?icms_destination: ICMSUFDestinationTaxResource, ?ii: IITaxResource, ?ipi: IPITaxResource, ?pis: PISTaxResource, ?total_tax: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_items_resource.rbs b/sig/nfe/generated/nf_produto_v2/invoice_items_resource.rbs new file mode 100644 index 0000000..726bd16 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_items_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class InvoiceItemsResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader has_more: bool? + attr_reader id: String? + attr_reader items: Array[InvoiceItemResource]? + def self.new: (?account_id: String?, ?company_id: String?, ?has_more: bool?, ?id: String?, ?items: Array[InvoiceItemResource]?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?has_more: bool?, ?id: String?, ?items: Array[InvoiceItemResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_resource.rbs b/sig/nfe/generated/nf_produto_v2/invoice_resource.rbs new file mode 100644 index 0000000..59f0ee9 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_resource.rbs @@ -0,0 +1,40 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class InvoiceResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader authorization: AuthorizationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader contingency_details: ContingencyDetails + attr_reader created_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader environment_type: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerResource + attr_reader last_events: InvoiceEventsResourceBase + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource]? + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader status: untyped + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?last_events: InvoiceEventsResourceBase, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?last_events: InvoiceEventsResourceBase, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_status.rbs b/sig/nfe/generated/nf_produto_v2/invoice_status.rbs new file mode 100644 index 0000000..600afa2 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_status.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module InvoiceStatus + None: String + Created: String + Processing: String + Issued: String + IssuedContingency: String + Cancelled: String + Disabled: String + IssueDenied: String + Error: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/invoice_without_events_resource.rbs b/sig/nfe/generated/nf_produto_v2/invoice_without_events_resource.rbs new file mode 100644 index 0000000..7b2ff7a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/invoice_without_events_resource.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class InvoiceWithoutEventsResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader authorization: AuthorizationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader contingency_details: ContingencyDetails + attr_reader created_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader environment_type: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerResource + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource]? + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader status: untyped + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource]?, ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/ipitax_resource.rbs b/sig/nfe/generated/nf_produto_v2/ipitax_resource.rbs new file mode 100644 index 0000000..61fecf2 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/ipitax_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class IPITaxResource < Data + attr_reader amount: Float? + attr_reader base: Float? + attr_reader classification: String? + attr_reader classification_code: String? + attr_reader cst: String? + attr_reader producer_cnpj: String? + attr_reader rate: Float? + attr_reader stamp_code: String? + attr_reader stamp_quantity: Float? + attr_reader unit_amount: Float? + attr_reader unit_quantity: Float? + def self.new: (?amount: Float?, ?base: Float?, ?classification: String?, ?classification_code: String?, ?cst: String?, ?producer_cnpj: String?, ?rate: Float?, ?stamp_code: String?, ?stamp_quantity: Float?, ?unit_amount: Float?, ?unit_quantity: Float?) -> instance + def initialize: (?amount: Float?, ?base: Float?, ?classification: String?, ?classification_code: String?, ?cst: String?, ?producer_cnpj: String?, ?rate: Float?, ?stamp_code: String?, ?stamp_quantity: Float?, ?unit_amount: Float?, ?unit_quantity: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/issqntotal.rbs b/sig/nfe/generated/nf_produto_v2/issqntotal.rbs new file mode 100644 index 0000000..e82ff03 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/issqntotal.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ISSQNTotal < Data + attr_reader base_rate_iss: Float? + attr_reader code_tax_regime: Float? + attr_reader deduction_reduction_bc: Float? + attr_reader discount_conditioning: Float? + attr_reader discount_unconditional: Float? + attr_reader provision_service: String? + attr_reader total_iss: Float? + attr_reader total_retention_iss: Float? + attr_reader total_service_not_taxed_icms: Float? + attr_reader value_other_retention: Float? + attr_reader value_service_cofins: Float? + attr_reader value_service_pis: Float? + def self.new: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> instance + def initialize: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/issqntotal_resource.rbs b/sig/nfe/generated/nf_produto_v2/issqntotal_resource.rbs new file mode 100644 index 0000000..f708ac1 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/issqntotal_resource.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ISSQNTotalResource < Data + attr_reader base_rate_iss: Float? + attr_reader code_tax_regime: Float? + attr_reader deduction_reduction_bc: Float? + attr_reader discount_conditioning: Float? + attr_reader discount_unconditional: Float? + attr_reader provision_service: String? + attr_reader total_iss: Float? + attr_reader total_retention_iss: Float? + attr_reader total_service_not_taxed_icms: Float? + attr_reader value_other_retention: Float? + attr_reader value_service_cofins: Float? + attr_reader value_service_pis: Float? + def self.new: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> instance + def initialize: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/issuer_from_request_resource.rbs b/sig/nfe/generated/nf_produto_v2/issuer_from_request_resource.rbs new file mode 100644 index 0000000..00cb578 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/issuer_from_request_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class IssuerFromRequestResource < Data + attr_reader st_state_tax_number: String? + def self.new: (?st_state_tax_number: String?) -> instance + def initialize: (?st_state_tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/issuer_resource.rbs b/sig/nfe/generated/nf_produto_v2/issuer_resource.rbs new file mode 100644 index 0000000..34a447b --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/issuer_resource.rbs @@ -0,0 +1,33 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class IssuerResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader company_registry_number: Integer? + attr_reader economic_activities: Array[EconomicActivityResource]? + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader legal_nature: untyped + attr_reader municipal_tax_number: String? + attr_reader name: String? + attr_reader openning_date: String? + attr_reader regional_sttax_number: Integer? + attr_reader regional_tax_number: Integer? + attr_reader special_tax_regime: untyped + attr_reader st_state_tax_number: String? + attr_reader tax_regime: untyped + attr_reader trade_name: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?company_registry_number: Integer?, ?economic_activities: Array[EconomicActivityResource]?, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?legal_nature: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_sttax_number: Integer?, ?regional_tax_number: Integer?, ?special_tax_regime: untyped, ?st_state_tax_number: String?, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?company_registry_number: Integer?, ?economic_activities: Array[EconomicActivityResource]?, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?legal_nature: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_sttax_number: Integer?, ?regional_tax_number: Integer?, ?special_tax_regime: untyped, ?st_state_tax_number: String?, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/legal_nature.rbs b/sig/nfe/generated/nf_produto_v2/legal_nature.rbs new file mode 100644 index 0000000..ee9976b --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/legal_nature.rbs @@ -0,0 +1,51 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module LegalNature + EmpresaPublica: String + SociedadeEconomiaMista: String + SociedadeAnonimaAberta: String + SociedadeAnonimaFechada: String + SociedadeEmpresariaLimitada: String + SociedadeEmpresariaEmNomeColetivo: String + SociedadeEmpresariaEmComanditaSimples: String + SociedadeEmpresariaEmComanditaporAcoes: String + SociedadeemContaParticipacao: String + Empresario: String + Cooperativa: String + ConsorcioSociedades: String + GrupoSociedades: String + EmpresaDomiciliadaExterior: String + ClubeFundoInvestimento: String + SociedadeSimplesPura: String + SociedadeSimplesLimitada: String + SociedadeSimplesEmNomeColetivo: String + SociedadeSimplesEmComanditaSimples: String + EmpresaBinacional: String + ConsorcioEmpregadores: String + ConsorcioSimples: String + EireliNaturezaEmpresaria: String + EireliNaturezaSimples: String + ServicoNotarial: String + FundacaoPrivada: String + ServicoSocialAutonomo: String + CondominioEdilicio: String + ComissaoConciliacaoPrevia: String + EntidadeMediacaoArbitragem: String + PartidoPolitico: String + EntidadeSindical: String + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras: String + FundacaoAssociacaoDomiciliadaExterior: String + OrganizacaoReligiosa: String + ComunidadeIndigena: String + FundoPrivado: String + AssociacaoPrivada: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/operation_type.rbs b/sig/nfe/generated/nf_produto_v2/operation_type.rbs new file mode 100644 index 0000000..6e8235f --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/operation_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module OperationType + Outgoing: String + Incoming: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/payment_detail_resource.rbs b/sig/nfe/generated/nf_produto_v2/payment_detail_resource.rbs new file mode 100644 index 0000000..e377212 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/payment_detail_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class PaymentDetailResource < Data + attr_reader amount: Float? + attr_reader card: CardResource + attr_reader federal_tax_number_pag: String? + attr_reader method: untyped + attr_reader method_description: String? + attr_reader payment_date: String? + attr_reader payment_type: untyped + attr_reader state_pag: String? + def self.new: (?amount: Float?, ?card: CardResource, ?federal_tax_number_pag: String?, method: untyped, ?method_description: String?, ?payment_date: String?, ?payment_type: untyped, ?state_pag: String?) -> instance + def initialize: (?amount: Float?, ?card: CardResource, ?federal_tax_number_pag: String?, method: untyped, ?method_description: String?, ?payment_date: String?, ?payment_type: untyped, ?state_pag: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/payment_method.rbs b/sig/nfe/generated/nf_produto_v2/payment_method.rbs new file mode 100644 index 0000000..d0915bd --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/payment_method.rbs @@ -0,0 +1,29 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PaymentMethod + Cash: String + Cheque: String + CreditCard: String + DebitCard: String + StoreCredict: String + FoodVouchers: String + MealVouchers: String + GiftVouchers: String + FuelVouchers: String + BankBill: String + BankDeposit: String + InstantPayment: String + WireTransfer: String + Cashback: String + WithoutPayment: String + Others: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/payment_resource.rbs b/sig/nfe/generated/nf_produto_v2/payment_resource.rbs new file mode 100644 index 0000000..a3ee49d --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/payment_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class PaymentResource < Data + attr_reader pay_back: Float? + attr_reader payment_detail: Array[PaymentDetailResource] + def self.new: (?pay_back: Float?, payment_detail: Array[PaymentDetailResource]) -> instance + def initialize: (?pay_back: Float?, payment_detail: Array[PaymentDetailResource]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/payment_type.rbs b/sig/nfe/generated/nf_produto_v2/payment_type.rbs new file mode 100644 index 0000000..f43326a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/payment_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PaymentType + InCash: String + Term: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/person_type.rbs b/sig/nfe/generated/nf_produto_v2/person_type.rbs new file mode 100644 index 0000000..46a94e2 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/person_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PersonType + Undefined: String + NaturalPerson: String + LegalEntity: String + Company: String + Customer: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/pistax_resource.rbs b/sig/nfe/generated/nf_produto_v2/pistax_resource.rbs new file mode 100644 index 0000000..ed0b1bd --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/pistax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class PISTaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: Float? + attr_reader base_tax_product_quantity: Float? + attr_reader cst: String? + attr_reader product_rate: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/print_type.rbs b/sig/nfe/generated/nf_produto_v2/print_type.rbs new file mode 100644 index 0000000..e861c64 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/print_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PrintType + None: String + NFeNormalPortrait: String + NFeNormalLandscape: String + NFeSimplified: String + DANFENFCE: String + DANFENFCEMSGELETRONICA: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/product_invoice_events_resource.rbs b/sig/nfe/generated/nf_produto_v2/product_invoice_events_resource.rbs new file mode 100644 index 0000000..49dd711 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/product_invoice_events_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ProductInvoiceEventsResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader events: Array[ActivityResource]? + attr_reader has_more: bool? + attr_reader id: String? + def self.new: (?account_id: String?, ?company_id: String?, ?events: Array[ActivityResource]?, ?has_more: bool?, ?id: String?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?events: Array[ActivityResource]?, ?has_more: bool?, ?id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/product_invoice_queue_issue_resource.rbs b/sig/nfe/generated/nf_produto_v2/product_invoice_queue_issue_resource.rbs new file mode 100644 index 0000000..0bba20c --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/product_invoice_queue_issue_resource.rbs @@ -0,0 +1,40 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ProductInvoiceQueueIssueResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader consumer_type: untyped + attr_reader contingency_justification: String? + attr_reader contingency_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader destination: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerFromRequestResource + attr_reader items: Array[InvoiceItemResource] + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource] + attr_reader presence_type: untyped + attr_reader print_type: untyped + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader totals: Total + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?billing: BillingResource, buyer: BuyerResource, ?consumer_type: untyped, ?contingency_justification: String?, ?contingency_on: String?, ?delivery: DeliveryInformationResource, ?destination: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerFromRequestResource, items: Array[InvoiceItemResource], ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, payment: Array[PaymentResource], ?presence_type: untyped, ?print_type: untyped, ?purpose_type: untyped, ?serie: Integer?, ?totals: Total, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?billing: BillingResource, buyer: BuyerResource, ?consumer_type: untyped, ?contingency_justification: String?, ?contingency_on: String?, ?delivery: DeliveryInformationResource, ?destination: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerFromRequestResource, items: Array[InvoiceItemResource], ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, payment: Array[PaymentResource], ?presence_type: untyped, ?print_type: untyped, ?purpose_type: untyped, ?serie: Integer?, ?totals: Total, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/product_invoices_resource.rbs b/sig/nfe/generated/nf_produto_v2/product_invoices_resource.rbs new file mode 100644 index 0000000..9c38d2a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/product_invoices_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ProductInvoicesResource < Data + attr_reader has_more: bool + attr_reader product_invoices: Array[InvoiceWithoutEventsResource]? + def self.new: (?has_more: bool, ?product_invoices: Array[InvoiceWithoutEventsResource]?) -> instance + def initialize: (?has_more: bool, ?product_invoices: Array[InvoiceWithoutEventsResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/pump_resource.rbs b/sig/nfe/generated/nf_produto_v2/pump_resource.rbs new file mode 100644 index 0000000..fd55550 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/pump_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class PumpResource < Data + attr_reader beginning_amount: Float? + attr_reader end_amount: Float? + attr_reader number: Integer? + attr_reader percentage_bio: Float? + attr_reader spout_number: Integer? + attr_reader tank_number: Integer? + def self.new: (?beginning_amount: Float?, ?end_amount: Float?, ?number: Integer?, ?percentage_bio: Float?, ?spout_number: Integer?, ?tank_number: Integer?) -> instance + def initialize: (?beginning_amount: Float?, ?end_amount: Float?, ?number: Integer?, ?percentage_bio: Float?, ?spout_number: Integer?, ?tank_number: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/purpose_type.rbs b/sig/nfe/generated/nf_produto_v2/purpose_type.rbs new file mode 100644 index 0000000..b278117 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/purpose_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module PurposeType + None: String + Normal: String + Complement: String + Adjustment: String + Devolution: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/queue_event_resource.rbs b/sig/nfe/generated/nf_produto_v2/queue_event_resource.rbs new file mode 100644 index 0000000..cace943 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/queue_event_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class QueueEventResource < Data + attr_reader reason: String? + def self.new: (?reason: String?) -> instance + def initialize: (?reason: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/reboque_resource.rbs b/sig/nfe/generated/nf_produto_v2/reboque_resource.rbs new file mode 100644 index 0000000..9fe230a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/reboque_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ReboqueResource < Data + attr_reader ferry: String? + attr_reader plate: String? + attr_reader rntc: String? + attr_reader uf: String? + attr_reader wagon: String? + def self.new: (?ferry: String?, ?plate: String?, ?rntc: String?, ?uf: String?, ?wagon: String?) -> instance + def initialize: (?ferry: String?, ?plate: String?, ?rntc: String?, ?uf: String?, ?wagon: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/receiver_state_tax_indicator.rbs b/sig/nfe/generated/nf_produto_v2/receiver_state_tax_indicator.rbs new file mode 100644 index 0000000..a82b0c1 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/receiver_state_tax_indicator.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ReceiverStateTaxIndicator + None: String + TaxPayer: String + Exempt: String + NonTaxPayer: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/referenced_process_resource.rbs b/sig/nfe/generated/nf_produto_v2/referenced_process_resource.rbs new file mode 100644 index 0000000..1b0b539 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/referenced_process_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class ReferencedProcessResource < Data + attr_reader concession_act_type: Integer? + attr_reader identifier_concessory: String? + attr_reader identifier_origin: Integer? + def self.new: (?concession_act_type: Integer?, ?identifier_concessory: String?, ?identifier_origin: Integer?) -> instance + def initialize: (?concession_act_type: Integer?, ?identifier_concessory: String?, ?identifier_origin: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/request_cancellation_resource.rbs b/sig/nfe/generated/nf_produto_v2/request_cancellation_resource.rbs new file mode 100644 index 0000000..fac52ae --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/request_cancellation_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class RequestCancellationResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader product_invoice_id: String? + attr_reader reason: String? + def self.new: (?account_id: String?, ?company_id: String?, ?product_invoice_id: String?, ?reason: String?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?product_invoice_id: String?, ?reason: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/shipping_modality.rbs b/sig/nfe/generated/nf_produto_v2/shipping_modality.rbs new file mode 100644 index 0000000..28e03a9 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/shipping_modality.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module ShippingModality + ByIssuer: String + ByReceiver: String + ByThirdParties: String + OwnBySender: String + OwnByBuyer: String + Free: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/special_tax_regime.rbs b/sig/nfe/generated/nf_produto_v2/special_tax_regime.rbs new file mode 100644 index 0000000..176beab --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/special_tax_regime.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module SpecialTaxRegime + Nenhum: String + MicroempresaMunicipal: String + Estimativa: String + SociedadeDeProfissionais: String + Cooperativa: String + MicroempreendedorIndividual: String + MicroempresarioEmpresaPequenoPorte: String + Automatico: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/state_code.rbs b/sig/nfe/generated/nf_produto_v2/state_code.rbs new file mode 100644 index 0000000..57a4ab5 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/state_code.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module StateCode + NA: String + RO: String + AC: String + AM: String + RR: String + PA: String + AP: String + TO: String + MA: String + PI: String + CE: String + RN: String + PB: String + PE: String + AL: String + SE: String + BA: String + MG: String + ES: String + RJ: String + SP: String + PR: String + SC: String + RS: String + MS: String + MT: String + GO: String + DF: String + EX: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/state_tax_processing_authorizer.rbs b/sig/nfe/generated/nf_produto_v2/state_tax_processing_authorizer.rbs new file mode 100644 index 0000000..1ea77b1 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/state_tax_processing_authorizer.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module StateTaxProcessingAuthorizer + Normal: String + EPEC: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/tax_coupon_information_resource.rbs b/sig/nfe/generated/nf_produto_v2/tax_coupon_information_resource.rbs new file mode 100644 index 0000000..1ca8615 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/tax_coupon_information_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TaxCouponInformationResource < Data + attr_reader model_document_fiscal: String? + attr_reader order_count_operation: Integer? + attr_reader order_ecf: String? + def self.new: (?model_document_fiscal: String?, ?order_count_operation: Integer?, ?order_ecf: String?) -> instance + def initialize: (?model_document_fiscal: String?, ?order_count_operation: Integer?, ?order_ecf: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/tax_determination_resource.rbs b/sig/nfe/generated/nf_produto_v2/tax_determination_resource.rbs new file mode 100644 index 0000000..77c358b --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/tax_determination_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TaxDeterminationResource < Data + attr_reader acquisition_purpose: String? + attr_reader buyer_tax_profile: String? + attr_reader issuer_tax_profile: String? + attr_reader operation_code: Integer? + attr_reader origin: String? + def self.new: (?acquisition_purpose: String?, ?buyer_tax_profile: String?, ?issuer_tax_profile: String?, ?operation_code: Integer?, ?origin: String?) -> instance + def initialize: (?acquisition_purpose: String?, ?buyer_tax_profile: String?, ?issuer_tax_profile: String?, ?operation_code: Integer?, ?origin: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/tax_documents_reference_resource.rbs b/sig/nfe/generated/nf_produto_v2/tax_documents_reference_resource.rbs new file mode 100644 index 0000000..05b134e --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/tax_documents_reference_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TaxDocumentsReferenceResource < Data + attr_reader document_electronic_invoice: DocumentElectronicInvoiceResource + attr_reader document_invoice_reference: DocumentInvoiceReferenceResource + attr_reader tax_coupon_information: TaxCouponInformationResource + def self.new: (?document_electronic_invoice: DocumentElectronicInvoiceResource, ?document_invoice_reference: DocumentInvoiceReferenceResource, ?tax_coupon_information: TaxCouponInformationResource) -> instance + def initialize: (?document_electronic_invoice: DocumentElectronicInvoiceResource, ?document_invoice_reference: DocumentInvoiceReferenceResource, ?tax_coupon_information: TaxCouponInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/tax_regime.rbs b/sig/nfe/generated/nf_produto_v2/tax_regime.rbs new file mode 100644 index 0000000..0d7e7ac --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/tax_regime.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + module TaxRegime + None: String + LucroReal: String + LucroPresumido: String + SimplesNacional: String + SimplesNacionalExcessoSublimite: String + MicroempreendedorIndividual: String + Isento: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/taxpayer_comments_resource.rbs b/sig/nfe/generated/nf_produto_v2/taxpayer_comments_resource.rbs new file mode 100644 index 0000000..96f27fb --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/taxpayer_comments_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TaxpayerCommentsResource < Data + attr_reader field: String? + attr_reader text: String? + def self.new: (?field: String?, ?text: String?) -> instance + def initialize: (?field: String?, ?text: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/total.rbs b/sig/nfe/generated/nf_produto_v2/total.rbs new file mode 100644 index 0000000..9948ccd --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/total.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class Total < Data + attr_reader icms: ICMSTotal + attr_reader issqn: ISSQNTotal + def self.new: (?icms: ICMSTotal, ?issqn: ISSQNTotal) -> instance + def initialize: (?icms: ICMSTotal, ?issqn: ISSQNTotal) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/total_resource.rbs b/sig/nfe/generated/nf_produto_v2/total_resource.rbs new file mode 100644 index 0000000..098e18a --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/total_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TotalResource < Data + attr_reader icms: ICMSTotalResource + attr_reader issqn: ISSQNTotalResource + def self.new: (?icms: ICMSTotalResource, ?issqn: ISSQNTotalResource) -> instance + def initialize: (?icms: ICMSTotalResource, ?issqn: ISSQNTotalResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/transport_group_resource.rbs b/sig/nfe/generated/nf_produto_v2/transport_group_resource.rbs new file mode 100644 index 0000000..be50af3 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/transport_group_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TransportGroupResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader transport_retention: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?transport_retention: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?transport_retention: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/transport_information_resource.rbs b/sig/nfe/generated/nf_produto_v2/transport_information_resource.rbs new file mode 100644 index 0000000..7b3c3a8 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/transport_information_resource.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TransportInformationResource < Data + attr_reader freight_modality: untyped + attr_reader reboque: ReboqueResource + attr_reader seal_number: String? + attr_reader transp_rate: TransportRateResource + attr_reader transport_group: TransportGroupResource + attr_reader transport_vehicle: TransportVehicleResource + attr_reader volume: VolumeResource + def self.new: (?freight_modality: untyped, ?reboque: ReboqueResource, ?seal_number: String?, ?transp_rate: TransportRateResource, ?transport_group: TransportGroupResource, ?transport_vehicle: TransportVehicleResource, ?volume: VolumeResource) -> instance + def initialize: (?freight_modality: untyped, ?reboque: ReboqueResource, ?seal_number: String?, ?transp_rate: TransportRateResource, ?transport_group: TransportGroupResource, ?transport_vehicle: TransportVehicleResource, ?volume: VolumeResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/transport_rate_resource.rbs b/sig/nfe/generated/nf_produto_v2/transport_rate_resource.rbs new file mode 100644 index 0000000..8069753 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/transport_rate_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TransportRateResource < Data + attr_reader bc_retention_amount: Float? + attr_reader cfop: Integer? + attr_reader city_generator_fact_code: Integer? + attr_reader icms_retention_amount: Float? + attr_reader icms_retention_rate: Float? + attr_reader service_amount: Float? + def self.new: (?bc_retention_amount: Float?, ?cfop: Integer?, ?city_generator_fact_code: Integer?, ?icms_retention_amount: Float?, ?icms_retention_rate: Float?, ?service_amount: Float?) -> instance + def initialize: (?bc_retention_amount: Float?, ?cfop: Integer?, ?city_generator_fact_code: Integer?, ?icms_retention_amount: Float?, ?icms_retention_rate: Float?, ?service_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/transport_vehicle_resource.rbs b/sig/nfe/generated/nf_produto_v2/transport_vehicle_resource.rbs new file mode 100644 index 0000000..1314287 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/transport_vehicle_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class TransportVehicleResource < Data + attr_reader plate: String? + attr_reader rntc: String? + attr_reader state: String? + def self.new: (?plate: String?, ?rntc: String?, ?state: String?) -> instance + def initialize: (?plate: String?, ?rntc: String?, ?state: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/vehicle_detail_resource.rbs b/sig/nfe/generated/nf_produto_v2/vehicle_detail_resource.rbs new file mode 100644 index 0000000..c1458bf --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/vehicle_detail_resource.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class VehicleDetailResource < Data + attr_reader brand_model_code: String? + attr_reader chassis: String? + attr_reader color_code: String? + attr_reader color_description: String? + attr_reader denatran_color_code: String? + attr_reader engine_displacement: String? + attr_reader engine_number: String? + attr_reader engine_power: String? + attr_reader fuel_type: String? + attr_reader gross_weight: String? + attr_reader manufacture_year: Integer? + attr_reader maximum_traction_capacity: String? + attr_reader model_year: Integer? + attr_reader net_weight: String? + attr_reader operation_type: Integer? + attr_reader paint_type: String? + attr_reader restriction_type: Integer? + attr_reader seating_capacity: Integer? + attr_reader serial_number: String? + attr_reader vehicle_condition: Integer? + attr_reader vehicle_species: Integer? + attr_reader vehicle_type: String? + attr_reader vin_condition: String? + attr_reader wheel_base: String? + def self.new: (?brand_model_code: String?, ?chassis: String?, ?color_code: String?, ?color_description: String?, ?denatran_color_code: String?, ?engine_displacement: String?, ?engine_number: String?, ?engine_power: String?, ?fuel_type: String?, ?gross_weight: String?, ?manufacture_year: Integer?, ?maximum_traction_capacity: String?, ?model_year: Integer?, ?net_weight: String?, ?operation_type: Integer?, ?paint_type: String?, ?restriction_type: Integer?, ?seating_capacity: Integer?, ?serial_number: String?, ?vehicle_condition: Integer?, ?vehicle_species: Integer?, ?vehicle_type: String?, ?vin_condition: String?, ?wheel_base: String?) -> instance + def initialize: (?brand_model_code: String?, ?chassis: String?, ?color_code: String?, ?color_description: String?, ?denatran_color_code: String?, ?engine_displacement: String?, ?engine_number: String?, ?engine_power: String?, ?fuel_type: String?, ?gross_weight: String?, ?manufacture_year: Integer?, ?maximum_traction_capacity: String?, ?model_year: Integer?, ?net_weight: String?, ?operation_type: Integer?, ?paint_type: String?, ?restriction_type: Integer?, ?seating_capacity: Integer?, ?serial_number: String?, ?vehicle_condition: Integer?, ?vehicle_species: Integer?, ?vehicle_type: String?, ?vin_condition: String?, ?wheel_base: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/volume_resource.rbs b/sig/nfe/generated/nf_produto_v2/volume_resource.rbs new file mode 100644 index 0000000..f3af976 --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/volume_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class VolumeResource < Data + attr_reader brand: String? + attr_reader gross_weight: Float? + attr_reader net_weight: Float? + attr_reader species: String? + attr_reader volume_numeration: String? + attr_reader volume_quantity: Integer? + def self.new: (?brand: String?, ?gross_weight: Float?, ?net_weight: Float?, ?species: String?, ?volume_numeration: String?, ?volume_quantity: Integer?) -> instance + def initialize: (?brand: String?, ?gross_weight: Float?, ?net_weight: Float?, ?species: String?, ?volume_numeration: String?, ?volume_quantity: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nf_produto_v2/withdrawal_information_resource.rbs b/sig/nfe/generated/nf_produto_v2/withdrawal_information_resource.rbs new file mode 100644 index 0000000..b7d087b --- /dev/null +++ b/sig/nfe/generated/nf_produto_v2/withdrawal_information_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nf-produto-v2.yaml +# Hash: sha256:e565b47e4d8b17255f99efc2b6354d589d2903c4ba9b97caabd74f84de59e4e2 + +module Nfe + module Generated + module NfProdutoV2 + class WithdrawalInformationResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/batch_process_response.rbs b/sig/nfe/generated/nfeio/batch_process_response.rbs new file mode 100644 index 0000000..8f1eb0f --- /dev/null +++ b/sig/nfe/generated/nfeio/batch_process_response.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class BatchProcessResponse < Data + attr_reader created_at: String + attr_reader input: String? + attr_reader out_puts: Array[OutPutResponse]? + attr_reader status: String? + attr_reader status_reason: String? + attr_reader updated_at: String? + def self.new: (created_at: String, ?input: String?, ?out_puts: Array[OutPutResponse]?, ?status: String?, ?status_reason: String?, ?updated_at: String?) -> instance + def initialize: (created_at: String, ?input: String?, ?out_puts: Array[OutPutResponse]?, ?status: String?, ?status_reason: String?, ?updated_at: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/environment.rbs b/sig/nfe/generated/nfeio/environment.rbs new file mode 100644 index 0000000..8a4ba3b --- /dev/null +++ b/sig/nfe/generated/nfeio/environment.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module Environment + Test: String + Production: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nfeio/file_parsing_options_request.rbs b/sig/nfe/generated/nfeio/file_parsing_options_request.rbs new file mode 100644 index 0000000..74787c0 --- /dev/null +++ b/sig/nfe/generated/nfeio/file_parsing_options_request.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class FileParsingOptionsRequest < Data + attr_reader column_to_parse: Integer + attr_reader parsing_type: untyped + def self.new: (?column_to_parse: Integer, ?parsing_type: untyped) -> instance + def initialize: (?column_to_parse: Integer, ?parsing_type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/guid_pagination_cursor.rbs b/sig/nfe/generated/nfeio/guid_pagination_cursor.rbs new file mode 100644 index 0000000..1a38ec7 --- /dev/null +++ b/sig/nfe/generated/nfeio/guid_pagination_cursor.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class GuidPaginationCursor < Data + attr_reader value: String + def self.new: (?value: String) -> instance + def initialize: (?value: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/input_info_request.rbs b/sig/nfe/generated/nfeio/input_info_request.rbs new file mode 100644 index 0000000..39e863f --- /dev/null +++ b/sig/nfe/generated/nfeio/input_info_request.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class InputInfoRequest < Data + attr_reader parsing_options: FileParsingOptionsRequest + attr_reader url: String? + attr_reader use_cache: bool + def self.new: (?parsing_options: FileParsingOptionsRequest, ?url: String?, ?use_cache: bool) -> instance + def initialize: (?parsing_options: FileParsingOptionsRequest, ?url: String?, ?use_cache: bool) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/inputs_response.rbs b/sig/nfe/generated/nfeio/inputs_response.rbs new file mode 100644 index 0000000..ed6eed1 --- /dev/null +++ b/sig/nfe/generated/nfeio/inputs_response.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class InputsResponse < Data + attr_reader outputs: Array[String]? + attr_reader total_inputs: Integer + def self.new: (?outputs: Array[String]?, ?total_inputs: Integer) -> instance + def initialize: (?outputs: Array[String]?, ?total_inputs: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/out_put_link_response.rbs b/sig/nfe/generated/nfeio/out_put_link_response.rbs new file mode 100644 index 0000000..c78684c --- /dev/null +++ b/sig/nfe/generated/nfeio/out_put_link_response.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class OutPutLinkResponse < Data + attr_reader file_name: String? + attr_reader url: String? + def self.new: (?file_name: String?, ?url: String?) -> instance + def initialize: (?file_name: String?, ?url: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/out_put_response.rbs b/sig/nfe/generated/nfeio/out_put_response.rbs new file mode 100644 index 0000000..fae1065 --- /dev/null +++ b/sig/nfe/generated/nfeio/out_put_response.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class OutPutResponse < Data + attr_reader out_put_link: OutPutLinkResponse + attr_reader status: String? + attr_reader type: String? + def self.new: (?out_put_link: OutPutLinkResponse, ?status: String?, ?type: String?) -> instance + def initialize: (?out_put_link: OutPutLinkResponse, ?status: String?, ?type: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/output_type.rbs b/sig/nfe/generated/nfeio/output_type.rbs new file mode 100644 index 0000000..4f92710 --- /dev/null +++ b/sig/nfe/generated/nfeio/output_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module OutputType + PDF: String + XML: String + Csv: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nfeio/parsing_type.rbs b/sig/nfe/generated/nfeio/parsing_type.rbs new file mode 100644 index 0000000..af49762 --- /dev/null +++ b/sig/nfe/generated/nfeio/parsing_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module ParsingType + Csv: String + Xls: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nfeio/problem_details.rbs b/sig/nfe/generated/nfeio/problem_details.rbs new file mode 100644 index 0000000..333146a --- /dev/null +++ b/sig/nfe/generated/nfeio/problem_details.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ProblemDetails < Data + attr_reader detail: String? + attr_reader instance: String? + attr_reader status: Integer? + attr_reader title: String? + attr_reader type: String? + def self.new: (?detail: String?, ?instance: String?, ?status: Integer?, ?title: String?, ?type: String?) -> instance + def initialize: (?detail: String?, ?instance: String?, ?status: Integer?, ?title: String?, ?type: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/processing_batch_detail_response.rbs b/sig/nfe/generated/nfeio/processing_batch_detail_response.rbs new file mode 100644 index 0000000..8b414b3 --- /dev/null +++ b/sig/nfe/generated/nfeio/processing_batch_detail_response.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ProcessingBatchDetailResponse < Data + attr_reader batch_processes: Array[BatchProcessResponse]? + attr_reader created_at: String + attr_reader created_by: String? + attr_reader id: String + attr_reader inputs: InputsResponse + attr_reader metrics: ProcessingMetricsResponse + attr_reader name: String? + attr_reader resource_name: String? + attr_reader stage: String? + attr_reader status: String? + attr_reader updated_at: String? + def self.new: (?batch_processes: Array[BatchProcessResponse]?, ?created_at: String, ?created_by: String?, ?id: String, ?inputs: InputsResponse, ?metrics: ProcessingMetricsResponse, ?name: String?, ?resource_name: String?, ?stage: String?, ?status: String?, ?updated_at: String?) -> instance + def initialize: (?batch_processes: Array[BatchProcessResponse]?, ?created_at: String, ?created_by: String?, ?id: String, ?inputs: InputsResponse, ?metrics: ProcessingMetricsResponse, ?name: String?, ?resource_name: String?, ?stage: String?, ?status: String?, ?updated_at: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/processing_batch_summary_response.rbs b/sig/nfe/generated/nfeio/processing_batch_summary_response.rbs new file mode 100644 index 0000000..7bef3c8 --- /dev/null +++ b/sig/nfe/generated/nfeio/processing_batch_summary_response.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ProcessingBatchSummaryResponse < Data + attr_reader auto_generated: bool + attr_reader created_at: String + attr_reader created_by: String? + attr_reader id: String + attr_reader inputs: InputsResponse + attr_reader metrics: ProcessingMetricsResponse + attr_reader name: String? + attr_reader out_puts: Array[OutPutResponse]? + attr_reader parent_id: String? + attr_reader resource_name: String? + attr_reader stage: String? + attr_reader status: String? + attr_reader updated_at: String? + def self.new: (?auto_generated: bool, ?created_at: String, ?created_by: String?, ?id: String, ?inputs: InputsResponse, ?metrics: ProcessingMetricsResponse, ?name: String?, ?out_puts: Array[OutPutResponse]?, ?parent_id: String?, ?resource_name: String?, ?stage: String?, ?status: String?, ?updated_at: String?) -> instance + def initialize: (?auto_generated: bool, ?created_at: String, ?created_by: String?, ?id: String, ?inputs: InputsResponse, ?metrics: ProcessingMetricsResponse, ?name: String?, ?out_puts: Array[OutPutResponse]?, ?parent_id: String?, ?resource_name: String?, ?stage: String?, ?status: String?, ?updated_at: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/processing_batch_summary_response_page.rbs b/sig/nfe/generated/nfeio/processing_batch_summary_response_page.rbs new file mode 100644 index 0000000..a26819a --- /dev/null +++ b/sig/nfe/generated/nfeio/processing_batch_summary_response_page.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ProcessingBatchSummaryResponsePage < Data + attr_reader has_next: bool + attr_reader has_previous: bool + attr_reader items: Array[ProcessingBatchSummaryResponse]? + attr_reader next_cursor: GuidPaginationCursor + attr_reader previous_cursor: GuidPaginationCursor + def self.new: (?has_next: bool, ?has_previous: bool, ?items: Array[ProcessingBatchSummaryResponse]?, ?next_cursor: GuidPaginationCursor, ?previous_cursor: GuidPaginationCursor) -> instance + def initialize: (?has_next: bool, ?has_previous: bool, ?items: Array[ProcessingBatchSummaryResponse]?, ?next_cursor: GuidPaginationCursor, ?previous_cursor: GuidPaginationCursor) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/processing_batches_response.rbs b/sig/nfe/generated/nfeio/processing_batches_response.rbs new file mode 100644 index 0000000..9223e88 --- /dev/null +++ b/sig/nfe/generated/nfeio/processing_batches_response.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ProcessingBatchesResponse < Data + attr_reader created_at: String + attr_reader id: String + attr_reader status: String? + attr_reader updated_at: String? + def self.new: (?created_at: String, ?id: String, ?status: String?, ?updated_at: String?) -> instance + def initialize: (?created_at: String, ?id: String, ?status: String?, ?updated_at: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/processing_metrics_response.rbs b/sig/nfe/generated/nfeio/processing_metrics_response.rbs new file mode 100644 index 0000000..b683eaa --- /dev/null +++ b/sig/nfe/generated/nfeio/processing_metrics_response.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ProcessingMetricsResponse < Data + attr_reader total: Integer + attr_reader total_error: Integer + attr_reader total_success: Integer + def self.new: (?total: Integer, ?total_error: Integer, ?total_success: Integer) -> instance + def initialize: (?total: Integer, ?total_error: Integer, ?total_success: Integer) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/resource_info.rbs b/sig/nfe/generated/nfeio/resource_info.rbs new file mode 100644 index 0000000..6b82933 --- /dev/null +++ b/sig/nfe/generated/nfeio/resource_info.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ResourceInfo < Data + attr_reader id: Integer + attr_reader name: String? + attr_reader outputs: Array[untyped]? + def self.new: (?id: Integer, ?name: String?, ?outputs: Array[untyped]?) -> instance + def initialize: (?id: Integer, ?name: String?, ?outputs: Array[untyped]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/resource_info_request.rbs b/sig/nfe/generated/nfeio/resource_info_request.rbs new file mode 100644 index 0000000..aa8f0aa --- /dev/null +++ b/sig/nfe/generated/nfeio/resource_info_request.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ResourceInfoRequest < Data + attr_reader id: Integer + attr_reader name: String? + attr_reader outputs: Array[untyped]? + def self.new: (?id: Integer, ?name: String?, ?outputs: Array[untyped]?) -> instance + def initialize: (?id: Integer, ?name: String?, ?outputs: Array[untyped]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/sort_direction.rbs b/sig/nfe/generated/nfeio/sort_direction.rbs new file mode 100644 index 0000000..80f0174 --- /dev/null +++ b/sig/nfe/generated/nfeio/sort_direction.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module SortDirection + Forward: String + Backward: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nfeio/sort_order.rbs b/sig/nfe/generated/nfeio/sort_order.rbs new file mode 100644 index 0000000..089ff65 --- /dev/null +++ b/sig/nfe/generated/nfeio/sort_order.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module SortOrder + Asc: String + Desc: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nfeio/start_processing_job_request.rbs b/sig/nfe/generated/nfeio/start_processing_job_request.rbs new file mode 100644 index 0000000..c86b77c --- /dev/null +++ b/sig/nfe/generated/nfeio/start_processing_job_request.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class StartProcessingJobRequest < Data + attr_reader created_by: String? + attr_reader environment: untyped + attr_reader input: InputInfoRequest + attr_reader name: String? + attr_reader resource: ResourceInfoRequest + def self.new: (?created_by: String?, ?environment: untyped, ?input: InputInfoRequest, ?name: String?, ?resource: ResourceInfoRequest) -> instance + def initialize: (?created_by: String?, ?environment: untyped, ?input: InputInfoRequest, ?name: String?, ?resource: ResourceInfoRequest) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/nfeio/status_process.rbs b/sig/nfe/generated/nfeio/status_process.rbs new file mode 100644 index 0000000..b14e975 --- /dev/null +++ b/sig/nfe/generated/nfeio/status_process.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + module StatusProcess + Pending: String + Running: String + Completed: String + Duplicated: String + Error: String + PartialSuccess: String + Succeed: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/nfeio/zip_request.rbs b/sig/nfe/generated/nfeio/zip_request.rbs new file mode 100644 index 0000000..eebf7e6 --- /dev/null +++ b/sig/nfe/generated/nfeio/zip_request.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/nfeio.yaml +# Hash: sha256:813bda287538f8599c3565485eb523d1b1311b26b5be94ead62ba0b7a17f6af3 + +module Nfe + module Generated + module Nfeio + class ZipRequest < Data + attr_reader blob_name: String? + attr_reader id: String + attr_reader type: untyped + def self.new: (?blob_name: String?, ?id: String, ?type: untyped) -> instance + def initialize: (?blob_name: String?, ?id: String, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/activity_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/activity_resource.rbs new file mode 100644 index 0000000..8a3b77a --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/activity_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ActivityResource < Data + attr_reader data: untyped + attr_reader sequence: Integer? + attr_reader type: String? + def self.new: (?data: untyped, ?sequence: Integer?, ?type: String?) -> instance + def initialize: (?data: untyped, ?sequence: Integer?, ?type: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/addition_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/addition_resource.rbs new file mode 100644 index 0000000..2face35 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/addition_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class AdditionResource < Data + attr_reader amount: Float? + attr_reader code: Integer? + attr_reader drawback: Integer? + attr_reader manufacturer: String? + def self.new: (?amount: Float?, ?code: Integer?, ?drawback: Integer?, ?manufacturer: String?) -> instance + def initialize: (?amount: Float?, ?code: Integer?, ?drawback: Integer?, ?manufacturer: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/additional_information_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/additional_information_resource.rbs new file mode 100644 index 0000000..f51f419 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/additional_information_resource.rbs @@ -0,0 +1,25 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class AdditionalInformationResource < Data + attr_reader advance_payment: Array[AdvancePaymentItemResource]? + attr_reader contract: String? + attr_reader effort: String? + attr_reader fisco: String? + attr_reader order: String? + attr_reader referenced_process: Array[ReferencedProcessResource]? + attr_reader tax_documents_reference: Array[TaxDocumentsReferenceResource]? + attr_reader taxpayer: String? + attr_reader taxpayer_comments: Array[TaxpayerCommentsResource]? + attr_reader xml_authorized: Array[Integer]? + def self.new: (?advance_payment: Array[AdvancePaymentItemResource]?, ?contract: String?, ?effort: String?, ?fisco: String?, ?order: String?, ?referenced_process: Array[ReferencedProcessResource]?, ?tax_documents_reference: Array[TaxDocumentsReferenceResource]?, ?taxpayer: String?, ?taxpayer_comments: Array[TaxpayerCommentsResource]?, ?xml_authorized: Array[Integer]?) -> instance + def initialize: (?advance_payment: Array[AdvancePaymentItemResource]?, ?contract: String?, ?effort: String?, ?fisco: String?, ?order: String?, ?referenced_process: Array[ReferencedProcessResource]?, ?tax_documents_reference: Array[TaxDocumentsReferenceResource]?, ?taxpayer: String?, ?taxpayer_comments: Array[TaxpayerCommentsResource]?, ?xml_authorized: Array[Integer]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/address_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/address_resource.rbs new file mode 100644 index 0000000..f7e77d7 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/address_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class AddressResource < Data + attr_reader additional_information: String? + attr_reader city: CityResource + attr_reader country: String? + attr_reader district: String + attr_reader number: String + attr_reader phone: String? + attr_reader postal_code: String? + attr_reader state: String + attr_reader street: String + def self.new: (?additional_information: String?, city: CityResource, ?country: String?, district: String, number: String, ?phone: String?, ?postal_code: String?, state: String, street: String) -> instance + def initialize: (?additional_information: String?, city: CityResource, ?country: String?, district: String, number: String, ?phone: String?, ?postal_code: String?, state: String, street: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/advance_payment_item_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/advance_payment_item_resource.rbs new file mode 100644 index 0000000..063061c --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/advance_payment_item_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class AdvancePaymentItemResource < Data + attr_reader access_key: String? + def self.new: (?access_key: String?) -> instance + def initialize: (?access_key: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/authorization_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/authorization_resource.rbs new file mode 100644 index 0000000..1a97497 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/authorization_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class AuthorizationResource < Data + attr_reader access_key: String? + attr_reader description: String + attr_reader message: String? + attr_reader receipt_on: String? + def self.new: (?access_key: String?, ?description: String, ?message: String?, ?receipt_on: String?) -> instance + def initialize: (?access_key: String?, ?description: String, ?message: String?, ?receipt_on: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/bill_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/bill_resource.rbs new file mode 100644 index 0000000..0b306a0 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/bill_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class BillResource < Data + attr_reader discount_amount: Float? + attr_reader net_amount: Float? + attr_reader number: String? + attr_reader original_amount: Float? + def self.new: (?discount_amount: Float?, ?net_amount: Float?, ?number: String?, ?original_amount: Float?) -> instance + def initialize: (?discount_amount: Float?, ?net_amount: Float?, ?number: String?, ?original_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/billing_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/billing_resource.rbs new file mode 100644 index 0000000..f34e79d --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/billing_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class BillingResource < Data + attr_reader bill: BillResource + attr_reader duplicates: Array[DuplicateResource]? + def self.new: (?bill: BillResource, ?duplicates: Array[DuplicateResource]?) -> instance + def initialize: (?bill: BillResource, ?duplicates: Array[DuplicateResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/buyer_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/buyer_resource.rbs new file mode 100644 index 0000000..bb85fdb --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/buyer_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class BuyerResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer + attr_reader id: String? + attr_reader name: String + attr_reader state_tax_number: String? + attr_reader state_tax_number_indicator: untyped + attr_reader tax_regime: untyped + attr_reader trade_name: String? + attr_reader type: untyped + def self.new: (?account_id: String?, address: AddressResource, ?email: String?, federal_tax_number: Integer, ?id: String?, name: String, ?state_tax_number: String?, ?state_tax_number_indicator: untyped, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, address: AddressResource, ?email: String?, federal_tax_number: Integer, ?id: String?, name: String, ?state_tax_number: String?, ?state_tax_number_indicator: untyped, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/card_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/card_resource.rbs new file mode 100644 index 0000000..0bc4da8 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/card_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CardResource < Data + attr_reader authorization: String? + attr_reader federal_tax_number: String? + attr_reader federal_tax_number_recipient: String? + attr_reader flag: untyped + attr_reader id_payment_terminal: String? + attr_reader integration_payment_type: untyped + def self.new: (?authorization: String?, ?federal_tax_number: String?, ?federal_tax_number_recipient: String?, ?flag: untyped, ?id_payment_terminal: String?, ?integration_payment_type: untyped) -> instance + def initialize: (?authorization: String?, ?federal_tax_number: String?, ?federal_tax_number_recipient: String?, ?flag: untyped, ?id_payment_terminal: String?, ?integration_payment_type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/cbstax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/cbstax_resource.rbs new file mode 100644 index 0000000..3331717 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/cbstax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CBSTaxResource < Data + attr_reader amount: Float? + attr_reader deferment: DefermentTaxResource + attr_reader rate: Float? + attr_reader reduction: ReductionTaxResource + attr_reader returned_amount: ReturnedTaxResource + def self.new: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> instance + def initialize: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/cbstotals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/cbstotals_resource.rbs new file mode 100644 index 0000000..9b66ab9 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/cbstotals_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CBSTotalsResource < Data + attr_reader amount: Float? + attr_reader deferment_amount: Float? + attr_reader presumed_credit_amount: Float? + attr_reader presumed_credit_conditional_amount: Float? + attr_reader returned_amount: Float? + def self.new: (?amount: Float?, ?deferment_amount: Float?, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?returned_amount: Float?) -> instance + def initialize: (?amount: Float?, ?deferment_amount: Float?, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?returned_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/cideresource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/cideresource.rbs new file mode 100644 index 0000000..ef727d3 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/cideresource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CIDEResource < Data + attr_reader bc: Float? + attr_reader cide_amount: Float? + attr_reader rate: Float? + def self.new: (?bc: Float?, ?cide_amount: Float?, ?rate: Float?) -> instance + def initialize: (?bc: Float?, ?cide_amount: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/city_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/city_resource.rbs new file mode 100644 index 0000000..b3dfd16 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/city_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CityResource < Data + attr_reader code: String + attr_reader name: String + def self.new: (code: String, name: String) -> instance + def initialize: (code: String, name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/cofins_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/cofins_tax_resource.rbs new file mode 100644 index 0000000..fb1908e --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/cofins_tax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CofinsTaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: Float? + attr_reader base_tax_product_quantity: Float? + attr_reader cst: String + attr_reader product_rate: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, cst: String, ?product_rate: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, cst: String, ?product_rate: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/competence_adjustment_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/competence_adjustment_resource.rbs new file mode 100644 index 0000000..79b5260 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/competence_adjustment_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CompetenceAdjustmentResource < Data + attr_reader assessment_period: String? + attr_reader cbs_amount: Float? + attr_reader ibs_amount: Float? + def self.new: (?assessment_period: String?, ?cbs_amount: Float?, ?ibs_amount: Float?) -> instance + def initialize: (?assessment_period: String?, ?cbs_amount: Float?, ?ibs_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/consumer_presence_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/consumer_presence_type.rbs new file mode 100644 index 0000000..bd6fbe2 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/consumer_presence_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ConsumerPresenceType + None: String + Presence: String + Internet: String + Telephone: String + Delivery: String + OthersNonPresenceOperation: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/consumer_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/consumer_type.rbs new file mode 100644 index 0000000..631f1ae --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/consumer_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ConsumerType + FinalConsumer: String + Normal: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/contingency_details.rbs b/sig/nfe/generated/product_invoice_rtc_v1/contingency_details.rbs new file mode 100644 index 0000000..3c2e774 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/contingency_details.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ContingencyDetails < Data + attr_reader authorizer: untyped + attr_reader reason: String? + attr_reader started_on: String + def self.new: (?authorizer: untyped, ?reason: String?, ?started_on: String) -> instance + def initialize: (?authorizer: untyped, ?reason: String?, ?started_on: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/credit_reversal_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/credit_reversal_resource.rbs new file mode 100644 index 0000000..eedc88a --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/credit_reversal_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CreditReversalResource < Data + attr_reader cbs_reversal_amount: Float? + attr_reader ibs_reversal_amount: Float? + def self.new: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> instance + def initialize: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/credit_reversal_totals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/credit_reversal_totals_resource.rbs new file mode 100644 index 0000000..c989c54 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/credit_reversal_totals_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CreditReversalTotalsResource < Data + attr_reader cbs_reversal_amount: Float? + attr_reader ibs_reversal_amount: Float? + def self.new: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> instance + def initialize: (?cbs_reversal_amount: Float?, ?ibs_reversal_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/credit_transfer_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/credit_transfer_tax_resource.rbs new file mode 100644 index 0000000..f44aa4d --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/credit_transfer_tax_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class CreditTransferTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader ibs_amount: Float? + def self.new: (?cbs_amount: Float?, ?ibs_amount: Float?) -> instance + def initialize: (?cbs_amount: Float?, ?ibs_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/credit_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/credit_type.rbs new file mode 100644 index 0000000..53d70e9 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/credit_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module CreditType + FinesAndInterest: String + IbsPresumedCreditAppropriationZfm: String + ReturnDeliveryRefusedOrNotFound: String + ValueReduction: String + TransferCreditSuccession: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/debit_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/debit_type.rbs new file mode 100644 index 0000000..475f002 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/debit_type.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module DebitType + TransferCreditsToCooperatives: String + CancelCreditsExemptImmuneSales: String + UnprocessedInvoicesDebits: String + FinesAndInterest: String + TransferInheritanceCredit: String + AdvancePayment: String + InventoryLoss: String + SnDisqualification: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/deferment_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/deferment_tax_resource.rbs new file mode 100644 index 0000000..64facbb --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/deferment_tax_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class DefermentTaxResource < Data + attr_reader amount: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/delivery_information_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/delivery_information_resource.rbs new file mode 100644 index 0000000..32e41f8 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/delivery_information_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class DeliveryInformationResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/destination.rbs b/sig/nfe/generated/product_invoice_rtc_v1/destination.rbs new file mode 100644 index 0000000..89dbcc0 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/destination.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module Destination + None: String + InternalOperation: String + InterstateOperation: String + InternationalOperation: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/disablement_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/disablement_resource.rbs new file mode 100644 index 0000000..607a285 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/disablement_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class DisablementResource < Data + attr_reader begin_number: Integer + attr_reader environment: untyped + attr_reader last_number: Integer + attr_reader reason: String? + attr_reader serie: Integer + attr_reader state: untyped + def self.new: (?begin_number: Integer, ?environment: untyped, ?last_number: Integer, ?reason: String?, ?serie: Integer, ?state: untyped) -> instance + def initialize: (?begin_number: Integer, ?environment: untyped, ?last_number: Integer, ?reason: String?, ?serie: Integer, ?state: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/document_electronic_invoice_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/document_electronic_invoice_resource.rbs new file mode 100644 index 0000000..5be5639 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/document_electronic_invoice_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class DocumentElectronicInvoiceResource < Data + attr_reader access_key: String? + def self.new: (?access_key: String?) -> instance + def initialize: (?access_key: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/document_invoice_reference_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/document_invoice_reference_resource.rbs new file mode 100644 index 0000000..91a4f67 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/document_invoice_reference_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class DocumentInvoiceReferenceResource < Data + attr_reader federal_tax_number: String? + attr_reader model: String? + attr_reader number: String? + attr_reader series: String? + attr_reader state: Float? + attr_reader year_month: String? + def self.new: (?federal_tax_number: String?, ?model: String?, ?number: String?, ?series: String?, ?state: Float?, ?year_month: String?) -> instance + def initialize: (?federal_tax_number: String?, ?model: String?, ?number: String?, ?series: String?, ?state: Float?, ?year_month: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/duduction_indicator.rbs b/sig/nfe/generated/product_invoice_rtc_v1/duduction_indicator.rbs new file mode 100644 index 0000000..ac35e29 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/duduction_indicator.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module DuductionIndicator + NotDeduct: String + Deduce: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/duplicate_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/duplicate_resource.rbs new file mode 100644 index 0000000..5fd7d38 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/duplicate_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class DuplicateResource < Data + attr_reader amount: Float? + attr_reader expiration_on: String? + attr_reader number: String? + def self.new: (?amount: Float?, ?expiration_on: String?, ?number: String?) -> instance + def initialize: (?amount: Float?, ?expiration_on: String?, ?number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/economic_activity_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/economic_activity_resource.rbs new file mode 100644 index 0000000..c0199c2 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/economic_activity_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class EconomicActivityResource < Data + attr_reader code: Integer? + attr_reader type: untyped + def self.new: (?code: Integer?, ?type: untyped) -> instance + def initialize: (?code: Integer?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/economic_activity_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/economic_activity_type.rbs new file mode 100644 index 0000000..bc128e7 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/economic_activity_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module EconomicActivityType + Main: String + Secondary: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/environment_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/environment_type.rbs new file mode 100644 index 0000000..2416c08 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/environment_type.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module EnvironmentType + None: String + Production: String + Test: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/error_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/error_resource.rbs new file mode 100644 index 0000000..f2f132d --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/error_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ErrorResource < Data + attr_reader code: Integer? + attr_reader message: String? + def self.new: (?code: Integer?, ?message: String?) -> instance + def initialize: (?code: Integer?, ?message: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/errors_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/errors_resource.rbs new file mode 100644 index 0000000..8e1a2dc --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/errors_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ErrorsResource < Data + attr_reader errors: Array[ErrorResource]? + def self.new: (?errors: Array[ErrorResource]?) -> instance + def initialize: (?errors: Array[ErrorResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/exempt_reason.rbs b/sig/nfe/generated/product_invoice_rtc_v1/exempt_reason.rbs new file mode 100644 index 0000000..7503257 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/exempt_reason.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ExemptReason + Agriculture: String + Others: String + DevelopmentEntities: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/export_detail_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/export_detail_resource.rbs new file mode 100644 index 0000000..cac96ae --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/export_detail_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ExportDetailResource < Data + attr_reader drawback: String? + attr_reader hint_information: ExportHintResource + def self.new: (?drawback: String?, ?hint_information: ExportHintResource) -> instance + def initialize: (?drawback: String?, ?hint_information: ExportHintResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/export_hint_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/export_hint_resource.rbs new file mode 100644 index 0000000..3e386d4 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/export_hint_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ExportHintResource < Data + attr_reader access_key: String? + attr_reader quantity: Float? + attr_reader registry_id: String? + def self.new: (?access_key: String?, ?quantity: Float?, ?registry_id: String?) -> instance + def initialize: (?access_key: String?, ?quantity: Float?, ?registry_id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/export_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/export_resource.rbs new file mode 100644 index 0000000..9485fd5 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/export_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ExportResource < Data + attr_reader local: String? + attr_reader office: String? + attr_reader state: untyped + def self.new: (?local: String?, ?office: String?, ?state: untyped) -> instance + def initialize: (?local: String?, ?office: String?, ?state: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/file_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/file_resource.rbs new file mode 100644 index 0000000..89ec822 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/file_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class FileResource < Data + attr_reader uri: String? + def self.new: (?uri: String?) -> instance + def initialize: (?uri: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/flag_card.rbs b/sig/nfe/generated/product_invoice_rtc_v1/flag_card.rbs new file mode 100644 index 0000000..90c6781 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/flag_card.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module FlagCard + None: String + Visa: String + Mastercard: String + AmericanExpress: String + Sorocred: String + DinersClub: String + Elo: String + Hipercard: String + Aura: String + Cabal: String + Alelo: String + BanesCard: String + CalCard: String + Credz: String + Discover: String + GoodCard: String + GreenCard: String + Hiper: String + JCB: String + Mais: String + MaxVan: String + Policard: String + RedeCompras: String + Sodexo: String + ValeCard: String + Verocheque: String + VR: String + Ticket: String + Other: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/fuel_origin_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/fuel_origin_resource.rbs new file mode 100644 index 0000000..adc7462 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/fuel_origin_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class FuelOriginResource < Data + attr_reader c_uforig: Integer? + attr_reader ind_import: Integer? + attr_reader p_orig: Float? + def self.new: (?c_uforig: Integer?, ?ind_import: Integer?, ?p_orig: Float?) -> instance + def initialize: (?c_uforig: Integer?, ?ind_import: Integer?, ?p_orig: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/fuel_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/fuel_resource.rbs new file mode 100644 index 0000000..d865f0f --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/fuel_resource.rbs @@ -0,0 +1,28 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class FuelResource < Data + attr_reader amount_temp: Float? + attr_reader cide: CIDEResource + attr_reader code_anp: String? + attr_reader codif: String? + attr_reader description_anp: String? + attr_reader fuel_origin: FuelOriginResource + attr_reader percentage_glp: Float? + attr_reader percentage_gni: Float? + attr_reader percentage_ng: Float? + attr_reader percentage_ngn: Float? + attr_reader pump: PumpResource + attr_reader starting_amount: Float? + attr_reader state_buyer: String? + def self.new: (?amount_temp: Float?, ?cide: CIDEResource, ?code_anp: String?, ?codif: String?, ?description_anp: String?, ?fuel_origin: FuelOriginResource, ?percentage_glp: Float?, ?percentage_gni: Float?, ?percentage_ng: Float?, ?percentage_ngn: Float?, ?pump: PumpResource, ?starting_amount: Float?, ?state_buyer: String?) -> instance + def initialize: (?amount_temp: Float?, ?cide: CIDEResource, ?code_anp: String?, ?codif: String?, ?description_anp: String?, ?fuel_origin: FuelOriginResource, ?percentage_glp: Float?, ?percentage_gni: Float?, ?percentage_ng: Float?, ?percentage_ngn: Float?, ?pump: PumpResource, ?starting_amount: Float?, ?state_buyer: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_entity_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_entity_type.rbs new file mode 100644 index 0000000..d3784d7 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_entity_type.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module GovernmentPurchaseEntityType + Union: String + State: String + FederalDistrict: String + Municipality: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_operation_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_operation_type.rbs new file mode 100644 index 0000000..aa8e442 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_operation_type.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module GovernmentPurchaseOperationType + Supply: String + Payment: String + SupplyThenPay: String + PayForPastSupply: String + SupplyAfterPay: String + PayNowSupplyLater: String + SupplyAndPayNow: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_resource.rbs new file mode 100644 index 0000000..93f8293 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class GovernmentPurchaseResource < Data + attr_reader entity_type: untyped + attr_reader operation_type: untyped + attr_reader rate_reduction: Float? + def self.new: (?entity_type: untyped, ?operation_type: untyped, ?rate_reduction: Float?) -> instance + def initialize: (?entity_type: untyped, ?operation_type: untyped, ?rate_reduction: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_tax_resource.rbs new file mode 100644 index 0000000..7452a72 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/government_purchase_tax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class GovernmentPurchaseTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader cbs_rate: Float? + attr_reader municipal_amount: Float? + attr_reader municipal_rate: Float? + attr_reader state_amount: Float? + attr_reader state_rate: Float? + def self.new: (?cbs_amount: Float?, ?cbs_rate: Float?, ?municipal_amount: Float?, ?municipal_rate: Float?, ?state_amount: Float?, ?state_rate: Float?) -> instance + def initialize: (?cbs_amount: Float?, ?cbs_rate: Float?, ?municipal_amount: Float?, ?municipal_rate: Float?, ?state_amount: Float?, ?state_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification.rbs new file mode 100644 index 0000000..6d34bb7 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibs_zfm_presumed_credit_classification.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module IbsZfmPresumedCreditClassification + NoPresumedCredit: String + FinalConsumptionGoods: String + CapitalGoods: String + IntermediateGoods: String + ItAndOtherGoods: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibscbstax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibscbstax_resource.rbs new file mode 100644 index 0000000..bf8f5c0 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibscbstax_resource.rbs @@ -0,0 +1,31 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSCBSTaxResource < Data + attr_reader basis: Float? + attr_reader calculation_mode: String? + attr_reader cbs: CBSTaxResource + attr_reader class_code: String? + attr_reader credit_reversal: CreditReversalResource + attr_reader credit_transfer: CreditTransferTaxResource + attr_reader donation_indicator: String? + attr_reader government_purchase: GovernmentPurchaseTaxResource + attr_reader ibs_total_amount: Float? + attr_reader monophase: MonophaseIBSCBSTaxResource + attr_reader municipal: IBSMunicipalTaxResource + attr_reader operational_presumed_credit: OperationalPresumedCreditResource + attr_reader regular_taxation: RegularTaxationResource + attr_reader situation_code: String? + attr_reader state: IBSStateTaxResource + attr_reader zfm_presumed_credit: ZfmPresumedCreditResource + def self.new: (?basis: Float?, ?calculation_mode: String?, ?cbs: CBSTaxResource, ?class_code: String?, ?credit_reversal: CreditReversalResource, ?credit_transfer: CreditTransferTaxResource, ?donation_indicator: String?, ?government_purchase: GovernmentPurchaseTaxResource, ?ibs_total_amount: Float?, ?monophase: MonophaseIBSCBSTaxResource, ?municipal: IBSMunicipalTaxResource, ?operational_presumed_credit: OperationalPresumedCreditResource, ?regular_taxation: RegularTaxationResource, ?situation_code: String?, ?state: IBSStateTaxResource, ?zfm_presumed_credit: ZfmPresumedCreditResource) -> instance + def initialize: (?basis: Float?, ?calculation_mode: String?, ?cbs: CBSTaxResource, ?class_code: String?, ?credit_reversal: CreditReversalResource, ?credit_transfer: CreditTransferTaxResource, ?donation_indicator: String?, ?government_purchase: GovernmentPurchaseTaxResource, ?ibs_total_amount: Float?, ?monophase: MonophaseIBSCBSTaxResource, ?municipal: IBSMunicipalTaxResource, ?operational_presumed_credit: OperationalPresumedCreditResource, ?regular_taxation: RegularTaxationResource, ?situation_code: String?, ?state: IBSStateTaxResource, ?zfm_presumed_credit: ZfmPresumedCreditResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibscbstotals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibscbstotals_resource.rbs new file mode 100644 index 0000000..c1e8b8b --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibscbstotals_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSCBSTotalsResource < Data + attr_reader basis: Float? + attr_reader cbs: CBSTotalsResource + attr_reader credit_reversal: CreditReversalTotalsResource + attr_reader ibs: IBSTotalsResource + attr_reader monophase: MonophaseTotalsResource + def self.new: (?basis: Float?, ?cbs: CBSTotalsResource, ?credit_reversal: CreditReversalTotalsResource, ?ibs: IBSTotalsResource, ?monophase: MonophaseTotalsResource) -> instance + def initialize: (?basis: Float?, ?cbs: CBSTotalsResource, ?credit_reversal: CreditReversalTotalsResource, ?ibs: IBSTotalsResource, ?monophase: MonophaseTotalsResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource.rbs new file mode 100644 index 0000000..4a614f3 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSMunicipalTaxResource < Data + attr_reader amount: Float? + attr_reader deferment: DefermentTaxResource + attr_reader rate: Float? + attr_reader reduction: ReductionTaxResource + attr_reader returned_amount: ReturnedTaxResource + def self.new: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> instance + def initialize: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource.rbs new file mode 100644 index 0000000..cbc91d3 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibsmunicipal_totals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSMunicipalTotalsResource < Data + attr_reader amount: Float? + attr_reader deferment_amount: Float? + attr_reader returned_amount: Float? + def self.new: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> instance + def initialize: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibsstate_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibsstate_tax_resource.rbs new file mode 100644 index 0000000..bd5d11e --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibsstate_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSStateTaxResource < Data + attr_reader amount: Float? + attr_reader deferment: DefermentTaxResource + attr_reader rate: Float? + attr_reader reduction: ReductionTaxResource + attr_reader returned_amount: ReturnedTaxResource + def self.new: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> instance + def initialize: (?amount: Float?, ?deferment: DefermentTaxResource, ?rate: Float?, ?reduction: ReductionTaxResource, ?returned_amount: ReturnedTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibsstate_totals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibsstate_totals_resource.rbs new file mode 100644 index 0000000..eab16b5 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibsstate_totals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSStateTotalsResource < Data + attr_reader amount: Float? + attr_reader deferment_amount: Float? + attr_reader returned_amount: Float? + def self.new: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> instance + def initialize: (?amount: Float?, ?deferment_amount: Float?, ?returned_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ibstotals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ibstotals_resource.rbs new file mode 100644 index 0000000..0bb7188 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ibstotals_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IBSTotalsResource < Data + attr_reader municipal: IBSMunicipalTotalsResource + attr_reader presumed_credit_amount: Float? + attr_reader presumed_credit_conditional_amount: Float? + attr_reader state: IBSStateTotalsResource + attr_reader total_amount: Float? + def self.new: (?municipal: IBSMunicipalTotalsResource, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?state: IBSStateTotalsResource, ?total_amount: Float?) -> instance + def initialize: (?municipal: IBSMunicipalTotalsResource, ?presumed_credit_amount: Float?, ?presumed_credit_conditional_amount: Float?, ?state: IBSStateTotalsResource, ?total_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/icms_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/icms_tax_resource.rbs new file mode 100644 index 0000000..44be358 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/icms_tax_resource.rbs @@ -0,0 +1,62 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IcmsTaxResource < Data + attr_reader amount: Float? + attr_reader amount_operation: String? + attr_reader amount_streason: String? + attr_reader base_deferred: String? + attr_reader base_snretention_amount: String? + attr_reader base_stretention_amount: String? + attr_reader base_tax: Float? + attr_reader base_tax_fcpstamount: Float? + attr_reader base_tax_modality: String? + attr_reader base_tax_operation_percentual: String? + attr_reader base_tax_reduction: Float? + attr_reader base_tax_st: Float? + attr_reader base_tax_stmodality: String? + attr_reader base_tax_streduction: String? + attr_reader basis_benefit_code: String? + attr_reader csosn: String? + attr_reader cst: String? + attr_reader deduction_indicator: untyped + attr_reader effective_amount: Float? + attr_reader effective_base_tax_amount: Float? + attr_reader effective_base_tax_reduction_rate: Float? + attr_reader effective_rate: Float? + attr_reader exempt_amount: Float? + attr_reader exempt_amount_st: Float? + attr_reader exempt_reason: untyped + attr_reader exempt_reason_st: untyped + attr_reader fcp_amount: Float? + attr_reader fcp_rate: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_rate: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpst_ret_rate: Float? + attr_reader origin: String + attr_reader percentual: Float? + attr_reader percentual_deferment: String? + attr_reader rate: Float? + attr_reader sn_credit_amount: Float? + attr_reader sn_credit_rate: Float? + attr_reader sn_retention_amount: String? + attr_reader st_amount: Float? + attr_reader st_final_consumer_rate: Float? + attr_reader st_margin_added_amount: String? + attr_reader st_margin_amount: Float? + attr_reader st_rate: Float? + attr_reader st_retention_amount: String? + attr_reader substitute_amount: Float? + attr_reader ufst: String? + def self.new: (?amount: Float?, ?amount_operation: String?, ?amount_streason: String?, ?base_deferred: String?, ?base_snretention_amount: String?, ?base_stretention_amount: String?, ?base_tax: Float?, ?base_tax_fcpstamount: Float?, ?base_tax_modality: String?, ?base_tax_operation_percentual: String?, ?base_tax_reduction: Float?, ?base_tax_st: Float?, ?base_tax_stmodality: String?, ?base_tax_streduction: String?, ?basis_benefit_code: String?, ?csosn: String?, ?cst: String?, ?deduction_indicator: untyped, ?effective_amount: Float?, ?effective_base_tax_amount: Float?, ?effective_base_tax_reduction_rate: Float?, ?effective_rate: Float?, ?exempt_amount: Float?, ?exempt_amount_st: Float?, ?exempt_reason: untyped, ?exempt_reason_st: untyped, ?fcp_amount: Float?, ?fcp_rate: Float?, ?fcpst_amount: Float?, ?fcpst_rate: Float?, ?fcpst_ret_amount: Float?, ?fcpst_ret_rate: Float?, origin: String, ?percentual: Float?, ?percentual_deferment: String?, ?rate: Float?, ?sn_credit_amount: Float?, ?sn_credit_rate: Float?, ?sn_retention_amount: String?, ?st_amount: Float?, ?st_final_consumer_rate: Float?, ?st_margin_added_amount: String?, ?st_margin_amount: Float?, ?st_rate: Float?, ?st_retention_amount: String?, ?substitute_amount: Float?, ?ufst: String?) -> instance + def initialize: (?amount: Float?, ?amount_operation: String?, ?amount_streason: String?, ?base_deferred: String?, ?base_snretention_amount: String?, ?base_stretention_amount: String?, ?base_tax: Float?, ?base_tax_fcpstamount: Float?, ?base_tax_modality: String?, ?base_tax_operation_percentual: String?, ?base_tax_reduction: Float?, ?base_tax_st: Float?, ?base_tax_stmodality: String?, ?base_tax_streduction: String?, ?basis_benefit_code: String?, ?csosn: String?, ?cst: String?, ?deduction_indicator: untyped, ?effective_amount: Float?, ?effective_base_tax_amount: Float?, ?effective_base_tax_reduction_rate: Float?, ?effective_rate: Float?, ?exempt_amount: Float?, ?exempt_amount_st: Float?, ?exempt_reason: untyped, ?exempt_reason_st: untyped, ?fcp_amount: Float?, ?fcp_rate: Float?, ?fcpst_amount: Float?, ?fcpst_rate: Float?, ?fcpst_ret_amount: Float?, ?fcpst_ret_rate: Float?, origin: String, ?percentual: Float?, ?percentual_deferment: String?, ?rate: Float?, ?sn_credit_amount: Float?, ?sn_credit_rate: Float?, ?sn_retention_amount: String?, ?st_amount: Float?, ?st_final_consumer_rate: Float?, ?st_margin_added_amount: String?, ?st_margin_amount: Float?, ?st_rate: Float?, ?st_retention_amount: String?, ?substitute_amount: Float?, ?ufst: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/icmstotal.rbs b/sig/nfe/generated/product_invoice_rtc_v1/icmstotal.rbs new file mode 100644 index 0000000..d3d42b1 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/icmstotal.rbs @@ -0,0 +1,44 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ICMSTotal < Data + attr_reader base_tax: Float? + attr_reader cofins_amount: Float? + attr_reader discount_amount: Float? + attr_reader fcp_amount: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpuf_destination_amount: Float? + attr_reader federal_taxes_amount: Float + attr_reader freight_amount: Float? + attr_reader icms_amount: Float? + attr_reader icms_exempt_amount: Float? + attr_reader icmsuf_destination_amount: Float? + attr_reader icmsuf_sender_amount: Float? + attr_reader ii_amount: Float? + attr_reader insurance_amount: Float? + attr_reader invoice_amount: Float + attr_reader ipi_amount: Float? + attr_reader ipi_devol_amount: Float? + attr_reader others_amount: Float? + attr_reader pis_amount: Float? + attr_reader product_amount: Float + attr_reader q_bcmono: Float? + attr_reader q_bcmono_ret: Float? + attr_reader q_bcmono_reten: Float? + attr_reader st_amount: Float? + attr_reader st_calculation_basis_amount: Float? + attr_reader v_icmsmono: Float? + attr_reader v_icmsmono_ret: Float? + attr_reader v_icmsmono_reten: Float? + def self.new: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> instance + def initialize: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/icmstotal_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/icmstotal_resource.rbs new file mode 100644 index 0000000..381a2cb --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/icmstotal_resource.rbs @@ -0,0 +1,44 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ICMSTotalResource < Data + attr_reader base_tax: Float? + attr_reader cofins_amount: Float? + attr_reader discount_amount: Float? + attr_reader fcp_amount: Float? + attr_reader fcpst_amount: Float? + attr_reader fcpst_ret_amount: Float? + attr_reader fcpuf_destination_amount: Float? + attr_reader federal_taxes_amount: Float? + attr_reader freight_amount: Float? + attr_reader icms_amount: Float? + attr_reader icms_exempt_amount: Float? + attr_reader icmsuf_destination_amount: Float? + attr_reader icmsuf_sender_amount: Float? + attr_reader ii_amount: Float? + attr_reader insurance_amount: Float? + attr_reader invoice_amount: Float? + attr_reader ipi_amount: Float? + attr_reader ipi_devol_amount: Float? + attr_reader others_amount: Float? + attr_reader pis_amount: Float? + attr_reader product_amount: Float? + attr_reader q_bcmono: Float? + attr_reader q_bcmono_ret: Float? + attr_reader q_bcmono_reten: Float? + attr_reader st_amount: Float? + attr_reader st_calculation_basis_amount: Float? + attr_reader v_icmsmono: Float? + attr_reader v_icmsmono_ret: Float? + attr_reader v_icmsmono_reten: Float? + def self.new: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float?, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float?, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float?, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> instance + def initialize: (?base_tax: Float?, ?cofins_amount: Float?, ?discount_amount: Float?, ?fcp_amount: Float?, ?fcpst_amount: Float?, ?fcpst_ret_amount: Float?, ?fcpuf_destination_amount: Float?, ?federal_taxes_amount: Float?, ?freight_amount: Float?, ?icms_amount: Float?, ?icms_exempt_amount: Float?, ?icmsuf_destination_amount: Float?, ?icmsuf_sender_amount: Float?, ?ii_amount: Float?, ?insurance_amount: Float?, ?invoice_amount: Float?, ?ipi_amount: Float?, ?ipi_devol_amount: Float?, ?others_amount: Float?, ?pis_amount: Float?, ?product_amount: Float?, ?q_bcmono: Float?, ?q_bcmono_ret: Float?, ?q_bcmono_reten: Float?, ?st_amount: Float?, ?st_calculation_basis_amount: Float?, ?v_icmsmono: Float?, ?v_icmsmono_ret: Float?, ?v_icmsmono_reten: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/icmsufdestination_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/icmsufdestination_tax_resource.rbs new file mode 100644 index 0000000..8409bce --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/icmsufdestination_tax_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ICMSUFDestinationTaxResource < Data + attr_reader p_fcpufdest: Float? + attr_reader p_icmsinter: Float? + attr_reader p_icmsinter_part: Float? + attr_reader p_icmsufdest: Float? + attr_reader v_bcfcpufdest: Float? + attr_reader v_bcufdest: Float? + attr_reader v_fcpufdest: Float? + attr_reader v_icmsufdest: Float? + attr_reader v_icmsufremet: Float? + def self.new: (?p_fcpufdest: Float?, ?p_icmsinter: Float?, ?p_icmsinter_part: Float?, ?p_icmsufdest: Float?, ?v_bcfcpufdest: Float?, ?v_bcufdest: Float?, ?v_fcpufdest: Float?, ?v_icmsufdest: Float?, ?v_icmsufremet: Float?) -> instance + def initialize: (?p_fcpufdest: Float?, ?p_icmsinter: Float?, ?p_icmsinter_part: Float?, ?p_icmsufdest: Float?, ?v_bcfcpufdest: Float?, ?v_bcufdest: Float?, ?v_fcpufdest: Float?, ?v_icmsufdest: Float?, ?v_icmsufremet: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/iitax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/iitax_resource.rbs new file mode 100644 index 0000000..137b147 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/iitax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IITaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: String? + attr_reader customs_expenditure_amount: String? + attr_reader iof_amount: Float? + attr_reader v_enq_camb: Float? + def self.new: (?amount: Float?, ?base_tax: String?, ?customs_expenditure_amount: String?, ?iof_amount: Float?, ?v_enq_camb: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: String?, ?customs_expenditure_amount: String?, ?iof_amount: Float?, ?v_enq_camb: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/import_declaration_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/import_declaration_resource.rbs new file mode 100644 index 0000000..08e5bd7 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/import_declaration_resource.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ImportDeclarationResource < Data + attr_reader acquirer_federal_tax_number: String? + attr_reader additions: Array[AdditionResource]? + attr_reader afrmm_amount: Float? + attr_reader code: String? + attr_reader customs_clearance_name: String? + attr_reader customs_clearance_state: untyped + attr_reader customs_clearanced_on: String? + attr_reader exporter: String? + attr_reader intermediation: untyped + attr_reader international_transport: untyped + attr_reader registered_on: String? + attr_reader state_third: String? + def self.new: (?acquirer_federal_tax_number: String?, ?additions: Array[AdditionResource]?, ?afrmm_amount: Float?, ?code: String?, ?customs_clearance_name: String?, ?customs_clearance_state: untyped, ?customs_clearanced_on: String?, ?exporter: String?, ?intermediation: untyped, ?international_transport: untyped, ?registered_on: String?, ?state_third: String?) -> instance + def initialize: (?acquirer_federal_tax_number: String?, ?additions: Array[AdditionResource]?, ?afrmm_amount: Float?, ?code: String?, ?customs_clearance_name: String?, ?customs_clearance_state: untyped, ?customs_clearanced_on: String?, ?exporter: String?, ?intermediation: untyped, ?international_transport: untyped, ?registered_on: String?, ?state_third: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/integration_payment_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/integration_payment_type.rbs new file mode 100644 index 0000000..3e9008c --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/integration_payment_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module IntegrationPaymentType + Integrated: String + NotIntegrated: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/intermediate_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/intermediate_resource.rbs new file mode 100644 index 0000000..9b76f80 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/intermediate_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IntermediateResource < Data + attr_reader federal_tax_number: Integer? + attr_reader identifier: String? + def self.new: (?federal_tax_number: Integer?, ?identifier: String?) -> instance + def initialize: (?federal_tax_number: Integer?, ?identifier: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/intermediation_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/intermediation_type.rbs new file mode 100644 index 0000000..5260246 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/intermediation_type.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module IntermediationType + None: String + ByOwn: String + ImportOnBehalf: String + ByOrder: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/international_transport_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/international_transport_type.rbs new file mode 100644 index 0000000..b8aeaa2 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/international_transport_type.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module InternationalTransportType + None: String + Maritime: String + River: String + Lake: String + Airline: String + Postal: String + Railway: String + Highway: String + Network: String + Own: String + Ficta: String + Courier: String + Handcarry: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_events_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_events_resource.rbs new file mode 100644 index 0000000..e392991 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_events_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceEventsResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader events: Array[ActivityResource]? + attr_reader has_more: bool? + attr_reader id: String? + def self.new: (?account_id: String?, ?company_id: String?, ?events: Array[ActivityResource]?, ?has_more: bool?, ?id: String?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?events: Array[ActivityResource]?, ?has_more: bool?, ?id: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_events_resource_base.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_events_resource_base.rbs new file mode 100644 index 0000000..fed869d --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_events_resource_base.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceEventsResourceBase < Data + attr_reader events: Array[ActivityResource]? + attr_reader has_more: bool? + def self.new: (?events: Array[ActivityResource]?, ?has_more: bool?) -> instance + def initialize: (?events: Array[ActivityResource]?, ?has_more: bool?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_item_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_item_resource.rbs new file mode 100644 index 0000000..0851709 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_item_resource.rbs @@ -0,0 +1,52 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceItemResource < Data + attr_reader additional_information: String? + attr_reader benefit: String? + attr_reader cest: String? + attr_reader cfop: Integer? + attr_reader code: String + attr_reader code_gtin: String? + attr_reader code_tax_gtin: String? + attr_reader description: String + attr_reader discount_amount: Float? + attr_reader export_details: Array[ExportDetailResource]? + attr_reader extipi: String? + attr_reader freight_amount: Float? + attr_reader fuel_detail: FuelResource + attr_reader ibs_zfm_presumed_credit_classification: untyped + attr_reader import_control_sheet_number: String? + attr_reader import_declarations: Array[ImportDeclarationResource]? + attr_reader insurance_amount: Float? + attr_reader item_amount: Float? + attr_reader item_number_order_buy: Integer? + attr_reader ncm: String + attr_reader number_order_buy: String? + attr_reader nve: Array[String]? + attr_reader others_amount: Float? + attr_reader presumed_credit: PresumedCreditResource + attr_reader quantity: Float + attr_reader quantity_tax: Float? + attr_reader referenced_dfe: ReferencedDFeResource + attr_reader tax: InvoiceItemTaxResource + attr_reader tax_determination: TaxDeterminationResource + attr_reader tax_unit_amount: Float? + attr_reader total_amount: Float + attr_reader total_indicator: bool? + attr_reader unit: String + attr_reader unit_amount: Float + attr_reader unit_tax: String + attr_reader used_movable_asset_indicator: bool + attr_reader vehicle_detail: VehicleDetailResource + def self.new: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer?, code: String, ?code_gtin: String?, ?code_tax_gtin: String?, description: String, ?discount_amount: Float?, ?export_details: Array[ExportDetailResource]?, ?extipi: String?, ?freight_amount: Float?, ?fuel_detail: FuelResource, ?ibs_zfm_presumed_credit_classification: untyped, ?import_control_sheet_number: String?, ?import_declarations: Array[ImportDeclarationResource]?, ?insurance_amount: Float?, ?item_amount: Float?, ?item_number_order_buy: Integer?, ncm: String, ?number_order_buy: String?, ?nve: Array[String]?, ?others_amount: Float?, ?presumed_credit: PresumedCreditResource, quantity: Float, ?quantity_tax: Float?, ?referenced_dfe: ReferencedDFeResource, tax: InvoiceItemTaxResource, ?tax_determination: TaxDeterminationResource, ?tax_unit_amount: Float?, total_amount: Float, ?total_indicator: bool?, unit: String, unit_amount: Float, unit_tax: String, ?used_movable_asset_indicator: bool, ?vehicle_detail: VehicleDetailResource) -> instance + def initialize: (?additional_information: String?, ?benefit: String?, ?cest: String?, ?cfop: Integer?, code: String, ?code_gtin: String?, ?code_tax_gtin: String?, description: String, ?discount_amount: Float?, ?export_details: Array[ExportDetailResource]?, ?extipi: String?, ?freight_amount: Float?, ?fuel_detail: FuelResource, ?ibs_zfm_presumed_credit_classification: untyped, ?import_control_sheet_number: String?, ?import_declarations: Array[ImportDeclarationResource]?, ?insurance_amount: Float?, ?item_amount: Float?, ?item_number_order_buy: Integer?, ncm: String, ?number_order_buy: String?, ?nve: Array[String]?, ?others_amount: Float?, ?presumed_credit: PresumedCreditResource, quantity: Float, ?quantity_tax: Float?, ?referenced_dfe: ReferencedDFeResource, tax: InvoiceItemTaxResource, ?tax_determination: TaxDeterminationResource, ?tax_unit_amount: Float?, total_amount: Float, ?total_indicator: bool?, unit: String, unit_amount: Float, unit_tax: String, ?used_movable_asset_indicator: bool, ?vehicle_detail: VehicleDetailResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_item_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_item_tax_resource.rbs new file mode 100644 index 0000000..1731736 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_item_tax_resource.rbs @@ -0,0 +1,25 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceItemTaxResource < Data + attr_reader ibscbs: IBSCBSTaxResource + attr_reader is: ISTaxResource + attr_reader cofins: CofinsTaxResource + attr_reader competence_adjustment: CompetenceAdjustmentResource + attr_reader icms: IcmsTaxResource + attr_reader icms_destination: ICMSUFDestinationTaxResource + attr_reader ii: IITaxResource + attr_reader ipi: IPITaxResource + attr_reader pis: PISTaxResource + attr_reader total_tax: Float? + def self.new: (?ibscbs: IBSCBSTaxResource, ?is: ISTaxResource, ?cofins: CofinsTaxResource, ?competence_adjustment: CompetenceAdjustmentResource, icms: IcmsTaxResource, ?icms_destination: ICMSUFDestinationTaxResource, ?ii: IITaxResource, ?ipi: IPITaxResource, ?pis: PISTaxResource, ?total_tax: Float?) -> instance + def initialize: (?ibscbs: IBSCBSTaxResource, ?is: ISTaxResource, ?cofins: CofinsTaxResource, ?competence_adjustment: CompetenceAdjustmentResource, icms: IcmsTaxResource, ?icms_destination: ICMSUFDestinationTaxResource, ?ii: IITaxResource, ?ipi: IPITaxResource, ?pis: PISTaxResource, ?total_tax: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_items_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_items_resource.rbs new file mode 100644 index 0000000..15b7727 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_items_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceItemsResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader has_more: bool? + attr_reader id: String? + attr_reader items: Array[InvoiceItemResource]? + def self.new: (?account_id: String?, ?company_id: String?, ?has_more: bool?, ?id: String?, ?items: Array[InvoiceItemResource]?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?has_more: bool?, ?id: String?, ?items: Array[InvoiceItemResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_resource.rbs new file mode 100644 index 0000000..b5b1a5b --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_resource.rbs @@ -0,0 +1,40 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader authorization: AuthorizationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader contingency_details: ContingencyDetails + attr_reader created_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader environment_type: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerResource + attr_reader last_events: InvoiceEventsResourceBase + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource] + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader status: untyped + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?last_events: InvoiceEventsResourceBase, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource], ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?last_events: InvoiceEventsResourceBase, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource], ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_status.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_status.rbs new file mode 100644 index 0000000..d1afd5c --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_status.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module InvoiceStatus + None: String + Created: String + Processing: String + Issued: String + IssuedContingency: String + Cancelled: String + Disabled: String + IssueDenied: String + Error: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/invoice_without_events_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/invoice_without_events_resource.rbs new file mode 100644 index 0000000..24f9e55 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/invoice_without_events_resource.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class InvoiceWithoutEventsResource < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader authorization: AuthorizationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader contingency_details: ContingencyDetails + attr_reader created_on: String? + attr_reader delivery: DeliveryInformationResource + attr_reader environment_type: untyped + attr_reader export: ExportResource + attr_reader id: String? + attr_reader issuer: IssuerResource + attr_reader modified_on: String? + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource] + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader status: untyped + attr_reader totals: TotalResource + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource], ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?authorization: AuthorizationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?contingency_details: ContingencyDetails, ?created_on: String?, ?delivery: DeliveryInformationResource, ?environment_type: untyped, ?export: ExportResource, ?id: String?, ?issuer: IssuerResource, ?modified_on: String?, ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, ?payment: Array[PaymentResource], ?purpose_type: untyped, ?serie: Integer?, ?status: untyped, ?totals: TotalResource, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/ipitax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/ipitax_resource.rbs new file mode 100644 index 0000000..85aa3b6 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/ipitax_resource.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IPITaxResource < Data + attr_reader amount: Float? + attr_reader base: Float? + attr_reader classification: String? + attr_reader classification_code: String? + attr_reader cst: String? + attr_reader producer_cnpj: String? + attr_reader rate: Float? + attr_reader stamp_code: String? + attr_reader stamp_quantity: Float? + attr_reader unit_amount: Float? + attr_reader unit_quantity: Float? + def self.new: (?amount: Float?, ?base: Float?, ?classification: String?, ?classification_code: String?, ?cst: String?, ?producer_cnpj: String?, ?rate: Float?, ?stamp_code: String?, ?stamp_quantity: Float?, ?unit_amount: Float?, ?unit_quantity: Float?) -> instance + def initialize: (?amount: Float?, ?base: Float?, ?classification: String?, ?classification_code: String?, ?cst: String?, ?producer_cnpj: String?, ?rate: Float?, ?stamp_code: String?, ?stamp_quantity: Float?, ?unit_amount: Float?, ?unit_quantity: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/issqntotal.rbs b/sig/nfe/generated/product_invoice_rtc_v1/issqntotal.rbs new file mode 100644 index 0000000..c58b767 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/issqntotal.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ISSQNTotal < Data + attr_reader base_rate_iss: Float? + attr_reader code_tax_regime: Float? + attr_reader deduction_reduction_bc: Float? + attr_reader discount_conditioning: Float? + attr_reader discount_unconditional: Float? + attr_reader provision_service: String? + attr_reader total_iss: Float? + attr_reader total_retention_iss: Float? + attr_reader total_service_not_taxed_icms: Float? + attr_reader value_other_retention: Float? + attr_reader value_service_cofins: Float? + attr_reader value_service_pis: Float? + def self.new: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> instance + def initialize: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/issqntotal_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/issqntotal_resource.rbs new file mode 100644 index 0000000..bff656a --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/issqntotal_resource.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ISSQNTotalResource < Data + attr_reader base_rate_iss: Float? + attr_reader code_tax_regime: Float? + attr_reader deduction_reduction_bc: Float? + attr_reader discount_conditioning: Float? + attr_reader discount_unconditional: Float? + attr_reader provision_service: String? + attr_reader total_iss: Float? + attr_reader total_retention_iss: Float? + attr_reader total_service_not_taxed_icms: Float? + attr_reader value_other_retention: Float? + attr_reader value_service_cofins: Float? + attr_reader value_service_pis: Float? + def self.new: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> instance + def initialize: (?base_rate_iss: Float?, ?code_tax_regime: Float?, ?deduction_reduction_bc: Float?, ?discount_conditioning: Float?, ?discount_unconditional: Float?, ?provision_service: String?, ?total_iss: Float?, ?total_retention_iss: Float?, ?total_service_not_taxed_icms: Float?, ?value_other_retention: Float?, ?value_service_cofins: Float?, ?value_service_pis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/issuer_from_request_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/issuer_from_request_resource.rbs new file mode 100644 index 0000000..d7d76b3 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/issuer_from_request_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IssuerFromRequestResource < Data + attr_reader st_state_tax_number: String? + def self.new: (?st_state_tax_number: String?) -> instance + def initialize: (?st_state_tax_number: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/issuer_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/issuer_resource.rbs new file mode 100644 index 0000000..d88e831 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/issuer_resource.rbs @@ -0,0 +1,33 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class IssuerResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader company_registry_number: Integer? + attr_reader economic_activities: Array[EconomicActivityResource]? + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader legal_nature: untyped + attr_reader municipal_tax_number: String? + attr_reader name: String? + attr_reader openning_date: String? + attr_reader regional_sttax_number: Integer? + attr_reader regional_tax_number: Integer? + attr_reader special_tax_regime: untyped + attr_reader st_state_tax_number: String? + attr_reader tax_regime: untyped + attr_reader trade_name: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?company_registry_number: Integer?, ?economic_activities: Array[EconomicActivityResource]?, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?legal_nature: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_sttax_number: Integer?, ?regional_tax_number: Integer?, ?special_tax_regime: untyped, ?st_state_tax_number: String?, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?company_registry_number: Integer?, ?economic_activities: Array[EconomicActivityResource]?, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?legal_nature: untyped, ?municipal_tax_number: String?, ?name: String?, ?openning_date: String?, ?regional_sttax_number: Integer?, ?regional_tax_number: Integer?, ?special_tax_regime: untyped, ?st_state_tax_number: String?, ?tax_regime: untyped, ?trade_name: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/istax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/istax_resource.rbs new file mode 100644 index 0000000..f08f8e6 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/istax_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ISTaxResource < Data + attr_reader amount: Float? + attr_reader basis: Float? + attr_reader classification_code: String? + attr_reader quantity: Float? + attr_reader rate: Float? + attr_reader situation_code: String? + attr_reader unit: String? + attr_reader unit_rate: Float? + def self.new: (?amount: Float?, ?basis: Float?, ?classification_code: String?, ?quantity: Float?, ?rate: Float?, ?situation_code: String?, ?unit: String?, ?unit_rate: Float?) -> instance + def initialize: (?amount: Float?, ?basis: Float?, ?classification_code: String?, ?quantity: Float?, ?rate: Float?, ?situation_code: String?, ?unit: String?, ?unit_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/istotals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/istotals_resource.rbs new file mode 100644 index 0000000..56c9044 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/istotals_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ISTotalsResource < Data + attr_reader amount: Float? + def self.new: (?amount: Float?) -> instance + def initialize: (?amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/legal_nature.rbs b/sig/nfe/generated/product_invoice_rtc_v1/legal_nature.rbs new file mode 100644 index 0000000..6f3f98a --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/legal_nature.rbs @@ -0,0 +1,51 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module LegalNature + EmpresaPublica: String + SociedadeEconomiaMista: String + SociedadeAnonimaAberta: String + SociedadeAnonimaFechada: String + SociedadeEmpresariaLimitada: String + SociedadeEmpresariaEmNomeColetivo: String + SociedadeEmpresariaEmComanditaSimples: String + SociedadeEmpresariaEmComanditaporAcoes: String + SociedadeemContaParticipacao: String + Empresario: String + Cooperativa: String + ConsorcioSociedades: String + GrupoSociedades: String + EmpresaDomiciliadaExterior: String + ClubeFundoInvestimento: String + SociedadeSimplesPura: String + SociedadeSimplesLimitada: String + SociedadeSimplesEmNomeColetivo: String + SociedadeSimplesEmComanditaSimples: String + EmpresaBinacional: String + ConsorcioEmpregadores: String + ConsorcioSimples: String + EireliNaturezaEmpresaria: String + EireliNaturezaSimples: String + ServicoNotarial: String + FundacaoPrivada: String + ServicoSocialAutonomo: String + CondominioEdilicio: String + ComissaoConciliacaoPrevia: String + EntidadeMediacaoArbitragem: String + PartidoPolitico: String + EntidadeSindical: String + EstabelecimentoBrasilFundacaoAssociacaoEstrangeiras: String + FundacaoAssociacaoDomiciliadaExterior: String + OrganizacaoReligiosa: String + ComunidadeIndigena: String + FundoPrivado: String + AssociacaoPrivada: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_cbstotals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_cbstotals_resource.rbs new file mode 100644 index 0000000..258f0dd --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_cbstotals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseCBSTotalsResource < Data + attr_reader amount: Float? + attr_reader previously_withheld_amount: Float? + attr_reader withheld_amount: Float? + def self.new: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> instance + def initialize: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_deferment_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_deferment_tax_resource.rbs new file mode 100644 index 0000000..a875558 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_deferment_tax_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseDefermentTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader cbs_rate: Float? + attr_reader ibs_amount: Float? + attr_reader ibs_rate: Float? + def self.new: (?cbs_amount: Float?, ?cbs_rate: Float?, ?ibs_amount: Float?, ?ibs_rate: Float?) -> instance + def initialize: (?cbs_amount: Float?, ?cbs_rate: Float?, ?ibs_amount: Float?, ?ibs_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_ibscbstax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_ibscbstax_resource.rbs new file mode 100644 index 0000000..317d9aa --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_ibscbstax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseIBSCBSTaxResource < Data + attr_reader cbs_amount: Float? + attr_reader deferment: MonophaseDefermentTaxResource + attr_reader ibs_amount: Float? + attr_reader previously_withheld: MonophasePreviouslyWithheldTaxResource + attr_reader standart: MonophaseStandardTaxResource + attr_reader withholding: MonophaseWithholdingTaxResource + def self.new: (?cbs_amount: Float?, ?deferment: MonophaseDefermentTaxResource, ?ibs_amount: Float?, ?previously_withheld: MonophasePreviouslyWithheldTaxResource, ?standart: MonophaseStandardTaxResource, ?withholding: MonophaseWithholdingTaxResource) -> instance + def initialize: (?cbs_amount: Float?, ?deferment: MonophaseDefermentTaxResource, ?ibs_amount: Float?, ?previously_withheld: MonophasePreviouslyWithheldTaxResource, ?standart: MonophaseStandardTaxResource, ?withholding: MonophaseWithholdingTaxResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_ibstotals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_ibstotals_resource.rbs new file mode 100644 index 0000000..bcea2aa --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_ibstotals_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseIBSTotalsResource < Data + attr_reader amount: Float? + attr_reader previously_withheld_amount: Float? + attr_reader withheld_amount: Float? + def self.new: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> instance + def initialize: (?amount: Float?, ?previously_withheld_amount: Float?, ?withheld_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource.rbs new file mode 100644 index 0000000..8f8cf5b --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_previously_withheld_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophasePreviouslyWithheldTaxResource < Data + attr_reader cbs_ad_rem_rate: Float? + attr_reader cbs_amount: Float? + attr_reader ibs_ad_rem_rate: Float? + attr_reader ibs_amount: Float? + attr_reader quantity_basis: Float? + def self.new: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> instance + def initialize: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_standard_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_standard_tax_resource.rbs new file mode 100644 index 0000000..508f241 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_standard_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseStandardTaxResource < Data + attr_reader cbs_ad_rem_rate: Float? + attr_reader cbs_amount: Float? + attr_reader ibs_ad_rem_rate: Float? + attr_reader ibs_amount: Float? + attr_reader quantity_basis: Float? + def self.new: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> instance + def initialize: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_totals_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_totals_resource.rbs new file mode 100644 index 0000000..73b2521 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_totals_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseTotalsResource < Data + attr_reader cbs: MonophaseCBSTotalsResource + attr_reader ibs: MonophaseIBSTotalsResource + def self.new: (?cbs: MonophaseCBSTotalsResource, ?ibs: MonophaseIBSTotalsResource) -> instance + def initialize: (?cbs: MonophaseCBSTotalsResource, ?ibs: MonophaseIBSTotalsResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/monophase_withholding_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/monophase_withholding_tax_resource.rbs new file mode 100644 index 0000000..195d880 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/monophase_withholding_tax_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class MonophaseWithholdingTaxResource < Data + attr_reader cbs_ad_rem_rate: Float? + attr_reader cbs_amount: Float? + attr_reader ibs_ad_rem_rate: Float? + attr_reader ibs_amount: Float? + attr_reader quantity_basis: Float? + def self.new: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> instance + def initialize: (?cbs_ad_rem_rate: Float?, ?cbs_amount: Float?, ?ibs_ad_rem_rate: Float?, ?ibs_amount: Float?, ?quantity_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/operation_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/operation_type.rbs new file mode 100644 index 0000000..314d980 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/operation_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module OperationType + Outgoing: String + Incoming: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/operational_presumed_credit_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/operational_presumed_credit_resource.rbs new file mode 100644 index 0000000..ed36d12 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/operational_presumed_credit_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class OperationalPresumedCreditResource < Data + attr_reader basis: Float? + attr_reader cbs: PresumedCreditDetailsResource + attr_reader classification_code: untyped + attr_reader ibs: PresumedCreditDetailsResource + def self.new: (?basis: Float?, ?cbs: PresumedCreditDetailsResource, ?classification_code: untyped, ?ibs: PresumedCreditDetailsResource) -> instance + def initialize: (?basis: Float?, ?cbs: PresumedCreditDetailsResource, ?classification_code: untyped, ?ibs: PresumedCreditDetailsResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/payment_detail_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/payment_detail_resource.rbs new file mode 100644 index 0000000..1bb9e2b --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/payment_detail_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PaymentDetailResource < Data + attr_reader amount: Float + attr_reader card: CardResource + attr_reader federal_tax_number_pag: String? + attr_reader method: untyped + attr_reader method_description: String? + attr_reader payment_date: String? + attr_reader payment_type: untyped + attr_reader state_pag: String? + def self.new: (amount: Float, ?card: CardResource, ?federal_tax_number_pag: String?, method: untyped, ?method_description: String?, ?payment_date: String?, ?payment_type: untyped, ?state_pag: String?) -> instance + def initialize: (amount: Float, ?card: CardResource, ?federal_tax_number_pag: String?, method: untyped, ?method_description: String?, ?payment_date: String?, ?payment_type: untyped, ?state_pag: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/payment_method.rbs b/sig/nfe/generated/product_invoice_rtc_v1/payment_method.rbs new file mode 100644 index 0000000..985c163 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/payment_method.rbs @@ -0,0 +1,33 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PaymentMethod + Cash: String + Cheque: String + CreditCard: String + DebitCard: String + StoreCredict: String + FoodVouchers: String + MealVouchers: String + GiftVouchers: String + FuelVouchers: String + MercantileDuplicate: String + BankBill: String + BankDeposit: String + InstantPayment: String + WireTransfer: String + Cashback: String + StaticInstantPayment: String + StoreCredit: String + ElectronicPaymentNotInformed: String + WithoutPayment: String + Others: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/payment_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/payment_resource.rbs new file mode 100644 index 0000000..1ed31c2 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/payment_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PaymentResource < Data + attr_reader pay_back: Float? + attr_reader payment_detail: Array[PaymentDetailResource] + def self.new: (?pay_back: Float?, payment_detail: Array[PaymentDetailResource]) -> instance + def initialize: (?pay_back: Float?, payment_detail: Array[PaymentDetailResource]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/payment_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/payment_type.rbs new file mode 100644 index 0000000..21a5ae8 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/payment_type.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PaymentType + InCash: String + Term: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/person_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/person_type.rbs new file mode 100644 index 0000000..66c3476 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/person_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PersonType + Undefined: String + NaturalPerson: String + LegalEntity: String + Company: String + Customer: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/pistax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/pistax_resource.rbs new file mode 100644 index 0000000..2d0ec38 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/pistax_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PISTaxResource < Data + attr_reader amount: Float? + attr_reader base_tax: Float? + attr_reader base_tax_product_quantity: Float? + attr_reader cst: String? + attr_reader product_rate: Float? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?base_tax: Float?, ?base_tax_product_quantity: Float?, ?cst: String?, ?product_rate: Float?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_classification_code.rbs b/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_classification_code.rbs new file mode 100644 index 0000000..e30d379 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_classification_code.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PresumedCreditClassificationCode + RuralProducerNonTaxpayer: String + TacPfTransportServiceNonTaxpayer: String + RecyclingFromIndividual: String + UsedMovableGoodsFromIndividualForResale: String + OptionalRegimeForCooperative: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_details_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_details_resource.rbs new file mode 100644 index 0000000..051b7f5 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_details_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PresumedCreditDetailsResource < Data + attr_reader amount: Float? + attr_reader rate: Float? + attr_reader suspensive_condition_amount: Float? + def self.new: (?amount: Float?, ?rate: Float?, ?suspensive_condition_amount: Float?) -> instance + def initialize: (?amount: Float?, ?rate: Float?, ?suspensive_condition_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_resource.rbs new file mode 100644 index 0000000..1d7953a --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/presumed_credit_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PresumedCreditResource < Data + attr_reader amount: Float? + attr_reader code: String? + attr_reader rate: Float? + def self.new: (?amount: Float?, ?code: String?, ?rate: Float?) -> instance + def initialize: (?amount: Float?, ?code: String?, ?rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/print_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/print_type.rbs new file mode 100644 index 0000000..8b9f261 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/print_type.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PrintType + None: String + NFeNormalPortrait: String + NFeNormalLandscape: String + NFeSimplified: String + DANFENFCE: String + DANFENFCEMSGELETRONICA: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/product_invoice_request.rbs b/sig/nfe/generated/product_invoice_rtc_v1/product_invoice_request.rbs new file mode 100644 index 0000000..fda1576 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/product_invoice_request.rbs @@ -0,0 +1,47 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ProductInvoiceRequest < Data + attr_reader additional_information: AdditionalInformationResource + attr_reader billing: BillingResource + attr_reader buyer: BuyerResource + attr_reader consumer_type: untyped + attr_reader consumption_city_code: Integer? + attr_reader contingency_justification: String? + attr_reader contingency_on: String? + attr_reader credit_type: untyped + attr_reader debit_type: untyped + attr_reader delivery: DeliveryInformationResource + attr_reader destination: untyped + attr_reader expected_delivery_on: String? + attr_reader export: ExportResource + attr_reader government_purchase: GovernmentPurchaseResource + attr_reader ibs_consumption_city_code: Integer? + attr_reader id: String? + attr_reader issuer_tax_substitute: IssuerFromRequestResource + attr_reader items: Array[InvoiceItemResource] + attr_reader number: Integer? + attr_reader operation_nature: String? + attr_reader operation_on: String? + attr_reader operation_type: untyped + attr_reader payment: Array[PaymentResource] + attr_reader presence_type: untyped + attr_reader print_type: untyped + attr_reader purchase_information: PurchaseInformationResource + attr_reader purpose_type: untyped + attr_reader serie: Integer? + attr_reader totals: Total + attr_reader transaction_intermediate: IntermediateResource + attr_reader transport: TransportInformationResource + attr_reader withdrawal: WithdrawalInformationResource + def self.new: (?additional_information: AdditionalInformationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?consumer_type: untyped, ?consumption_city_code: Integer?, ?contingency_justification: String?, ?contingency_on: String?, ?credit_type: untyped, ?debit_type: untyped, ?delivery: DeliveryInformationResource, ?destination: untyped, ?expected_delivery_on: String?, ?export: ExportResource, ?government_purchase: GovernmentPurchaseResource, ?ibs_consumption_city_code: Integer?, ?id: String?, ?issuer_tax_substitute: IssuerFromRequestResource, items: Array[InvoiceItemResource], ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, payment: Array[PaymentResource], ?presence_type: untyped, ?print_type: untyped, ?purchase_information: PurchaseInformationResource, ?purpose_type: untyped, ?serie: Integer?, ?totals: Total, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> instance + def initialize: (?additional_information: AdditionalInformationResource, ?billing: BillingResource, ?buyer: BuyerResource, ?consumer_type: untyped, ?consumption_city_code: Integer?, ?contingency_justification: String?, ?contingency_on: String?, ?credit_type: untyped, ?debit_type: untyped, ?delivery: DeliveryInformationResource, ?destination: untyped, ?expected_delivery_on: String?, ?export: ExportResource, ?government_purchase: GovernmentPurchaseResource, ?ibs_consumption_city_code: Integer?, ?id: String?, ?issuer_tax_substitute: IssuerFromRequestResource, items: Array[InvoiceItemResource], ?number: Integer?, ?operation_nature: String?, ?operation_on: String?, ?operation_type: untyped, payment: Array[PaymentResource], ?presence_type: untyped, ?print_type: untyped, ?purchase_information: PurchaseInformationResource, ?purpose_type: untyped, ?serie: Integer?, ?totals: Total, ?transaction_intermediate: IntermediateResource, ?transport: TransportInformationResource, ?withdrawal: WithdrawalInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/product_invoices_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/product_invoices_resource.rbs new file mode 100644 index 0000000..b39d2bb --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/product_invoices_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ProductInvoicesResource < Data + attr_reader has_more: bool + attr_reader product_invoices: Array[InvoiceWithoutEventsResource]? + def self.new: (?has_more: bool, ?product_invoices: Array[InvoiceWithoutEventsResource]?) -> instance + def initialize: (?has_more: bool, ?product_invoices: Array[InvoiceWithoutEventsResource]?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/pump_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/pump_resource.rbs new file mode 100644 index 0000000..34ff6a4 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/pump_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PumpResource < Data + attr_reader beginning_amount: Float? + attr_reader end_amount: Float? + attr_reader number: Integer? + attr_reader percentage_bio: Float? + attr_reader spout_number: Integer? + attr_reader tank_number: Integer? + def self.new: (?beginning_amount: Float?, ?end_amount: Float?, ?number: Integer?, ?percentage_bio: Float?, ?spout_number: Integer?, ?tank_number: Integer?) -> instance + def initialize: (?beginning_amount: Float?, ?end_amount: Float?, ?number: Integer?, ?percentage_bio: Float?, ?spout_number: Integer?, ?tank_number: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/purchase_information_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/purchase_information_resource.rbs new file mode 100644 index 0000000..b585372 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/purchase_information_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class PurchaseInformationResource < Data + attr_reader commitment_note: String? + attr_reader contract_number: String? + attr_reader purchase_order: String? + def self.new: (?commitment_note: String?, ?contract_number: String?, ?purchase_order: String?) -> instance + def initialize: (?commitment_note: String?, ?contract_number: String?, ?purchase_order: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/purpose_type.rbs b/sig/nfe/generated/product_invoice_rtc_v1/purpose_type.rbs new file mode 100644 index 0000000..3c1f12b --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/purpose_type.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module PurposeType + None: String + Normal: String + Complement: String + Adjustment: String + Devolution: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/queue_event_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/queue_event_resource.rbs new file mode 100644 index 0000000..7b13605 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/queue_event_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class QueueEventResource < Data + attr_reader reason: String? + def self.new: (?reason: String?) -> instance + def initialize: (?reason: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/reboque_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/reboque_resource.rbs new file mode 100644 index 0000000..d506ecb --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/reboque_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ReboqueResource < Data + attr_reader ferry: String? + attr_reader plate: String? + attr_reader rntc: String? + attr_reader uf: String? + attr_reader wagon: String? + def self.new: (?ferry: String?, ?plate: String?, ?rntc: String?, ?uf: String?, ?wagon: String?) -> instance + def initialize: (?ferry: String?, ?plate: String?, ?rntc: String?, ?uf: String?, ?wagon: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/receiver_state_tax_indicator.rbs b/sig/nfe/generated/product_invoice_rtc_v1/receiver_state_tax_indicator.rbs new file mode 100644 index 0000000..138cb6f --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/receiver_state_tax_indicator.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ReceiverStateTaxIndicator + None: String + TaxPayer: String + Exempt: String + NonTaxPayer: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/reduction_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/reduction_tax_resource.rbs new file mode 100644 index 0000000..8b52276 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/reduction_tax_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ReductionTaxResource < Data + attr_reader effective_rate: Float? + attr_reader rate_reduction: Float? + def self.new: (?effective_rate: Float?, ?rate_reduction: Float?) -> instance + def initialize: (?effective_rate: Float?, ?rate_reduction: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/referenced_dfe_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/referenced_dfe_resource.rbs new file mode 100644 index 0000000..52fec9d --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/referenced_dfe_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ReferencedDFeResource < Data + attr_reader access_key: String + attr_reader item_number: Integer? + def self.new: (access_key: String, ?item_number: Integer?) -> instance + def initialize: (access_key: String, ?item_number: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/referenced_process_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/referenced_process_resource.rbs new file mode 100644 index 0000000..9c22898 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/referenced_process_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ReferencedProcessResource < Data + attr_reader concession_act_type: Integer? + attr_reader identifier_concessory: String? + attr_reader identifier_origin: Integer? + def self.new: (?concession_act_type: Integer?, ?identifier_concessory: String?, ?identifier_origin: Integer?) -> instance + def initialize: (?concession_act_type: Integer?, ?identifier_concessory: String?, ?identifier_origin: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/regular_taxation_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/regular_taxation_resource.rbs new file mode 100644 index 0000000..4989a03 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/regular_taxation_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class RegularTaxationResource < Data + attr_reader amount: Float? + attr_reader cbs_amount: Float? + attr_reader cbs_effective_rate: Float? + attr_reader class_code: String? + attr_reader municipal_amount: Float? + attr_reader municipal_effective_rate: Float? + attr_reader situation_code: String? + attr_reader state_effective_rate: Float? + def self.new: (?amount: Float?, ?cbs_amount: Float?, ?cbs_effective_rate: Float?, ?class_code: String?, ?municipal_amount: Float?, ?municipal_effective_rate: Float?, ?situation_code: String?, ?state_effective_rate: Float?) -> instance + def initialize: (?amount: Float?, ?cbs_amount: Float?, ?cbs_effective_rate: Float?, ?class_code: String?, ?municipal_amount: Float?, ?municipal_effective_rate: Float?, ?situation_code: String?, ?state_effective_rate: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/request_cancellation_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/request_cancellation_resource.rbs new file mode 100644 index 0000000..30ba290 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/request_cancellation_resource.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class RequestCancellationResource < Data + attr_reader account_id: String? + attr_reader company_id: String? + attr_reader product_invoice_id: String? + attr_reader reason: String? + def self.new: (?account_id: String?, ?company_id: String?, ?product_invoice_id: String?, ?reason: String?) -> instance + def initialize: (?account_id: String?, ?company_id: String?, ?product_invoice_id: String?, ?reason: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/returned_tax_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/returned_tax_resource.rbs new file mode 100644 index 0000000..076b629 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/returned_tax_resource.rbs @@ -0,0 +1,16 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ReturnedTaxResource < Data + attr_reader amount: Float? + def self.new: (?amount: Float?) -> instance + def initialize: (?amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/shipping_modality.rbs b/sig/nfe/generated/product_invoice_rtc_v1/shipping_modality.rbs new file mode 100644 index 0000000..f2a0271 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/shipping_modality.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module ShippingModality + ByIssuer: String + ByReceiver: String + ByThirdParties: String + OwnBySender: String + OwnByBuyer: String + Free: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/special_tax_regime.rbs b/sig/nfe/generated/product_invoice_rtc_v1/special_tax_regime.rbs new file mode 100644 index 0000000..ae78aab --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/special_tax_regime.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module SpecialTaxRegime + Nenhum: String + MicroempresaMunicipal: String + Estimativa: String + SociedadeDeProfissionais: String + MicroempreendedorIndividual: String + MicroempresarioEmpresaPequenoPorte: String + Automatico: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/state_code.rbs b/sig/nfe/generated/product_invoice_rtc_v1/state_code.rbs new file mode 100644 index 0000000..65126bc --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/state_code.rbs @@ -0,0 +1,42 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module StateCode + NA: String + RO: String + AC: String + AM: String + RR: String + PA: String + AP: String + TO: String + MA: String + PI: String + CE: String + RN: String + PB: String + PE: String + AL: String + SE: String + BA: String + MG: String + ES: String + RJ: String + SP: String + PR: String + SC: String + RS: String + MS: String + MT: String + GO: String + DF: String + EX: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/state_tax_processing_authorizer.rbs b/sig/nfe/generated/product_invoice_rtc_v1/state_tax_processing_authorizer.rbs new file mode 100644 index 0000000..3168dd6 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/state_tax_processing_authorizer.rbs @@ -0,0 +1,15 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module StateTaxProcessingAuthorizer + Normal: String + EPEC: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/tax_coupon_information_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/tax_coupon_information_resource.rbs new file mode 100644 index 0000000..6390bb1 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/tax_coupon_information_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TaxCouponInformationResource < Data + attr_reader model_document_fiscal: String? + attr_reader order_count_operation: Integer? + attr_reader order_ecf: String? + def self.new: (?model_document_fiscal: String?, ?order_count_operation: Integer?, ?order_ecf: String?) -> instance + def initialize: (?model_document_fiscal: String?, ?order_count_operation: Integer?, ?order_ecf: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/tax_determination_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/tax_determination_resource.rbs new file mode 100644 index 0000000..737ec85 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/tax_determination_resource.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TaxDeterminationResource < Data + attr_reader acquisition_purpose: String? + attr_reader buyer_tax_profile: String? + attr_reader issuer_tax_profile: String? + attr_reader operation_code: Integer? + attr_reader origin: String? + def self.new: (?acquisition_purpose: String?, ?buyer_tax_profile: String?, ?issuer_tax_profile: String?, ?operation_code: Integer?, ?origin: String?) -> instance + def initialize: (?acquisition_purpose: String?, ?buyer_tax_profile: String?, ?issuer_tax_profile: String?, ?operation_code: Integer?, ?origin: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/tax_documents_reference_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/tax_documents_reference_resource.rbs new file mode 100644 index 0000000..f645527 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/tax_documents_reference_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TaxDocumentsReferenceResource < Data + attr_reader document_electronic_invoice: DocumentElectronicInvoiceResource + attr_reader document_invoice_reference: DocumentInvoiceReferenceResource + attr_reader tax_coupon_information: TaxCouponInformationResource + def self.new: (?document_electronic_invoice: DocumentElectronicInvoiceResource, ?document_invoice_reference: DocumentInvoiceReferenceResource, ?tax_coupon_information: TaxCouponInformationResource) -> instance + def initialize: (?document_electronic_invoice: DocumentElectronicInvoiceResource, ?document_invoice_reference: DocumentInvoiceReferenceResource, ?tax_coupon_information: TaxCouponInformationResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/tax_regime.rbs b/sig/nfe/generated/product_invoice_rtc_v1/tax_regime.rbs new file mode 100644 index 0000000..44d3c0b --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/tax_regime.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + module TaxRegime + None: String + LucroReal: String + LucroPresumido: String + SimplesNacional: String + SimplesNacionalExcessoSublimite: String + MicroempreendedorIndividual: String + Isento: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/taxpayer_comments_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/taxpayer_comments_resource.rbs new file mode 100644 index 0000000..e6789f4 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/taxpayer_comments_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TaxpayerCommentsResource < Data + attr_reader field: String? + attr_reader text: String? + def self.new: (?field: String?, ?text: String?) -> instance + def initialize: (?field: String?, ?text: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/total.rbs b/sig/nfe/generated/product_invoice_rtc_v1/total.rbs new file mode 100644 index 0000000..ff6311f --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/total.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class Total < Data + attr_reader ibs_cbs_totals: IBSCBSTotalsResource + attr_reader icms: ICMSTotal + attr_reader is_totals: ISTotalsResource + attr_reader issqn: ISSQNTotal + attr_reader total_invoice_amount: Float? + attr_reader withheld_taxes: TotalsWithholdings + def self.new: (?ibs_cbs_totals: IBSCBSTotalsResource, ?icms: ICMSTotal, ?is_totals: ISTotalsResource, ?issqn: ISSQNTotal, ?total_invoice_amount: Float?, ?withheld_taxes: TotalsWithholdings) -> instance + def initialize: (?ibs_cbs_totals: IBSCBSTotalsResource, ?icms: ICMSTotal, ?is_totals: ISTotalsResource, ?issqn: ISSQNTotal, ?total_invoice_amount: Float?, ?withheld_taxes: TotalsWithholdings) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/total_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/total_resource.rbs new file mode 100644 index 0000000..5460a68 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/total_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TotalResource < Data + attr_reader icms: ICMSTotalResource + attr_reader issqn: ISSQNTotalResource + def self.new: (?icms: ICMSTotalResource, ?issqn: ISSQNTotalResource) -> instance + def initialize: (?icms: ICMSTotalResource, ?issqn: ISSQNTotalResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/totals_withholdings.rbs b/sig/nfe/generated/product_invoice_rtc_v1/totals_withholdings.rbs new file mode 100644 index 0000000..17cf40d --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/totals_withholdings.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TotalsWithholdings < Data + attr_reader cofins_amount: Float? + attr_reader csll_amount: Float? + attr_reader irrf_amount: Float? + attr_reader irrf_basis: Float? + attr_reader pis_amount: Float? + attr_reader social_secutiry_amount: Float? + attr_reader social_secutiry_basis: Float? + def self.new: (?cofins_amount: Float?, ?csll_amount: Float?, ?irrf_amount: Float?, ?irrf_basis: Float?, ?pis_amount: Float?, ?social_secutiry_amount: Float?, ?social_secutiry_basis: Float?) -> instance + def initialize: (?cofins_amount: Float?, ?csll_amount: Float?, ?irrf_amount: Float?, ?irrf_basis: Float?, ?pis_amount: Float?, ?social_secutiry_amount: Float?, ?social_secutiry_basis: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/transport_group_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/transport_group_resource.rbs new file mode 100644 index 0000000..0c08634 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/transport_group_resource.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TransportGroupResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader transport_retention: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?transport_retention: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?transport_retention: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/transport_information_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/transport_information_resource.rbs new file mode 100644 index 0000000..0ffbff7 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/transport_information_resource.rbs @@ -0,0 +1,22 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TransportInformationResource < Data + attr_reader freight_modality: untyped + attr_reader reboque: ReboqueResource + attr_reader seal_number: String? + attr_reader transp_rate: TransportRateResource + attr_reader transport_group: TransportGroupResource + attr_reader transport_vehicle: TransportVehicleResource + attr_reader volume: VolumeResource + def self.new: (?freight_modality: untyped, ?reboque: ReboqueResource, ?seal_number: String?, ?transp_rate: TransportRateResource, ?transport_group: TransportGroupResource, ?transport_vehicle: TransportVehicleResource, ?volume: VolumeResource) -> instance + def initialize: (?freight_modality: untyped, ?reboque: ReboqueResource, ?seal_number: String?, ?transp_rate: TransportRateResource, ?transport_group: TransportGroupResource, ?transport_vehicle: TransportVehicleResource, ?volume: VolumeResource) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/transport_rate_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/transport_rate_resource.rbs new file mode 100644 index 0000000..1c7c5b9 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/transport_rate_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TransportRateResource < Data + attr_reader bc_retention_amount: Float? + attr_reader cfop: Integer? + attr_reader city_generator_fact_code: Integer? + attr_reader icms_retention_amount: Float? + attr_reader icms_retention_rate: Float? + attr_reader service_amount: Float? + def self.new: (?bc_retention_amount: Float?, ?cfop: Integer?, ?city_generator_fact_code: Integer?, ?icms_retention_amount: Float?, ?icms_retention_rate: Float?, ?service_amount: Float?) -> instance + def initialize: (?bc_retention_amount: Float?, ?cfop: Integer?, ?city_generator_fact_code: Integer?, ?icms_retention_amount: Float?, ?icms_retention_rate: Float?, ?service_amount: Float?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/transport_vehicle_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/transport_vehicle_resource.rbs new file mode 100644 index 0000000..653c640 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/transport_vehicle_resource.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class TransportVehicleResource < Data + attr_reader plate: String? + attr_reader rntc: String? + attr_reader state: String? + def self.new: (?plate: String?, ?rntc: String?, ?state: String?) -> instance + def initialize: (?plate: String?, ?rntc: String?, ?state: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/vehicle_detail_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/vehicle_detail_resource.rbs new file mode 100644 index 0000000..cef85ef --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/vehicle_detail_resource.rbs @@ -0,0 +1,39 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class VehicleDetailResource < Data + attr_reader brand_model_code: String? + attr_reader chassis: String? + attr_reader color_code: String? + attr_reader color_description: String? + attr_reader denatran_color_code: String? + attr_reader engine_displacement: String? + attr_reader engine_number: String? + attr_reader engine_power: String? + attr_reader fuel_type: String? + attr_reader gross_weight: String? + attr_reader manufacture_year: Integer? + attr_reader maximum_traction_capacity: String? + attr_reader model_year: Integer? + attr_reader net_weight: String? + attr_reader operation_type: Integer? + attr_reader paint_type: String? + attr_reader restriction_type: Integer? + attr_reader seating_capacity: Integer? + attr_reader serial_number: String? + attr_reader vehicle_condition: Integer? + attr_reader vehicle_species: Integer? + attr_reader vehicle_type: String? + attr_reader vin_condition: String? + attr_reader wheel_base: String? + def self.new: (?brand_model_code: String?, ?chassis: String?, ?color_code: String?, ?color_description: String?, ?denatran_color_code: String?, ?engine_displacement: String?, ?engine_number: String?, ?engine_power: String?, ?fuel_type: String?, ?gross_weight: String?, ?manufacture_year: Integer?, ?maximum_traction_capacity: String?, ?model_year: Integer?, ?net_weight: String?, ?operation_type: Integer?, ?paint_type: String?, ?restriction_type: Integer?, ?seating_capacity: Integer?, ?serial_number: String?, ?vehicle_condition: Integer?, ?vehicle_species: Integer?, ?vehicle_type: String?, ?vin_condition: String?, ?wheel_base: String?) -> instance + def initialize: (?brand_model_code: String?, ?chassis: String?, ?color_code: String?, ?color_description: String?, ?denatran_color_code: String?, ?engine_displacement: String?, ?engine_number: String?, ?engine_power: String?, ?fuel_type: String?, ?gross_weight: String?, ?manufacture_year: Integer?, ?maximum_traction_capacity: String?, ?model_year: Integer?, ?net_weight: String?, ?operation_type: Integer?, ?paint_type: String?, ?restriction_type: Integer?, ?seating_capacity: Integer?, ?serial_number: String?, ?vehicle_condition: Integer?, ?vehicle_species: Integer?, ?vehicle_type: String?, ?vin_condition: String?, ?wheel_base: String?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/volume_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/volume_resource.rbs new file mode 100644 index 0000000..d826bb8 --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/volume_resource.rbs @@ -0,0 +1,21 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class VolumeResource < Data + attr_reader brand: String? + attr_reader gross_weight: Float? + attr_reader net_weight: Float? + attr_reader species: String? + attr_reader volume_numeration: String? + attr_reader volume_quantity: Integer? + def self.new: (?brand: String?, ?gross_weight: Float?, ?net_weight: Float?, ?species: String?, ?volume_numeration: String?, ?volume_quantity: Integer?) -> instance + def initialize: (?brand: String?, ?gross_weight: Float?, ?net_weight: Float?, ?species: String?, ?volume_numeration: String?, ?volume_quantity: Integer?) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/withdrawal_information_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/withdrawal_information_resource.rbs new file mode 100644 index 0000000..187f11e --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/withdrawal_information_resource.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class WithdrawalInformationResource < Data + attr_reader account_id: String? + attr_reader address: AddressResource + attr_reader email: String? + attr_reader federal_tax_number: Integer? + attr_reader id: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader type: untyped + def self.new: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> instance + def initialize: (?account_id: String?, ?address: AddressResource, ?email: String?, ?federal_tax_number: Integer?, ?id: String?, ?name: String?, ?state_tax_number: String?, ?type: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_invoice_rtc_v1/zfm_presumed_credit_resource.rbs b/sig/nfe/generated/product_invoice_rtc_v1/zfm_presumed_credit_resource.rbs new file mode 100644 index 0000000..2045a2c --- /dev/null +++ b/sig/nfe/generated/product_invoice_rtc_v1/zfm_presumed_credit_resource.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-invoice-rtc-v1.yaml +# Hash: sha256:4327ad141eeace6219dc4267678c44a134ae1fdde93f7dd69cf4c9ae9418415a + +module Nfe + module Generated + module ProductInvoiceRtcV1 + class ZfmPresumedCreditResource < Data + attr_reader amount: Float? + attr_reader classification_code: untyped + def self.new: (?amount: Float?, ?classification_code: untyped) -> instance + def initialize: (?amount: Float?, ?classification_code: untyped) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/cofins_tax_group.rbs b/sig/nfe/generated/product_register_pt_br_v1/cofins_tax_group.rbs new file mode 100644 index 0000000..64c706f --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/cofins_tax_group.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class CofinsTaxGroup < Data + attr_reader cst: String + attr_reader p_cofins: String + def self.new: (?cst: String, ?p_cofins: String) -> instance + def initialize: (?cst: String, ?p_cofins: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/custom_tax_scenario.rbs b/sig/nfe/generated/product_register_pt_br_v1/custom_tax_scenario.rbs new file mode 100644 index 0000000..c8962db --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/custom_tax_scenario.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class CustomTaxScenario < Data + attr_reader operation_code: Integer + attr_reader inter_state: InterStateTaxGroup + attr_reader intra_state: IntraStateTaxGroup + attr_reader issuer: Array[Hash[String, untyped]] + attr_reader recipient: Array[Hash[String, untyped]] + def self.new: (operation_code: Integer, ?inter_state: InterStateTaxGroup, ?intra_state: IntraStateTaxGroup, ?issuer: Array[Hash[String, untyped]], ?recipient: Array[Hash[String, untyped]]) -> instance + def initialize: (operation_code: Integer, ?inter_state: InterStateTaxGroup, ?intra_state: IntraStateTaxGroup, ?issuer: Array[Hash[String, untyped]], ?recipient: Array[Hash[String, untyped]]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/icms_tax_group.rbs b/sig/nfe/generated/product_register_pt_br_v1/icms_tax_group.rbs new file mode 100644 index 0000000..335a1e3 --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/icms_tax_group.rbs @@ -0,0 +1,33 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class IcmsTaxGroup < Data + attr_reader cst: String + attr_reader mod_bc: String + attr_reader mod_bcst: String + attr_reader mot_des_icms: String + attr_reader mot_des_icmsst: String + attr_reader p_cred_sn: String + attr_reader p_dif: String + attr_reader p_fcp: String + attr_reader p_fcpdif: String + attr_reader p_fcpst: String + attr_reader p_fcpstret: String + attr_reader p_icms: String + attr_reader p_icmsefet: String + attr_reader p_icmsst: String + attr_reader p_mvast: String + attr_reader p_red_bc: String + attr_reader p_red_bcefet: String + attr_reader p_red_bcst: String + def self.new: (?cst: String, ?mod_bc: String, ?mod_bcst: String, ?mot_des_icms: String, ?mot_des_icmsst: String, ?p_cred_sn: String, ?p_dif: String, ?p_fcp: String, ?p_fcpdif: String, ?p_fcpst: String, ?p_fcpstret: String, ?p_icms: String, ?p_icmsefet: String, ?p_icmsst: String, ?p_mvast: String, ?p_red_bc: String, ?p_red_bcefet: String, ?p_red_bcst: String) -> instance + def initialize: (?cst: String, ?mod_bc: String, ?mod_bcst: String, ?mot_des_icms: String, ?mot_des_icmsst: String, ?p_cred_sn: String, ?p_dif: String, ?p_fcp: String, ?p_fcpdif: String, ?p_fcpst: String, ?p_fcpstret: String, ?p_icms: String, ?p_icmsefet: String, ?p_icmsst: String, ?p_mvast: String, ?p_red_bc: String, ?p_red_bcefet: String, ?p_red_bcst: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/inter_state_tax_group.rbs b/sig/nfe/generated/product_register_pt_br_v1/inter_state_tax_group.rbs new file mode 100644 index 0000000..da8f3d1 --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/inter_state_tax_group.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class InterStateTaxGroup < Data + attr_reader cfop: Float + attr_reader cofins: CofinsTaxGroup + attr_reader icms: IcmsTaxGroup + attr_reader pis: PisTaxGroup + def self.new: (?cfop: Float, ?cofins: CofinsTaxGroup, ?icms: IcmsTaxGroup, ?pis: PisTaxGroup) -> instance + def initialize: (?cfop: Float, ?cofins: CofinsTaxGroup, ?icms: IcmsTaxGroup, ?pis: PisTaxGroup) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/intra_state_tax_group.rbs b/sig/nfe/generated/product_register_pt_br_v1/intra_state_tax_group.rbs new file mode 100644 index 0000000..52d3311 --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/intra_state_tax_group.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class IntraStateTaxGroup < Data + attr_reader cfop: Float + attr_reader cofins: CofinsTaxGroup + attr_reader icms: IcmsTaxGroup + attr_reader pis: PisTaxGroup + def self.new: (cfop: Float, ?cofins: CofinsTaxGroup, ?icms: IcmsTaxGroup, ?pis: PisTaxGroup) -> instance + def initialize: (cfop: Float, ?cofins: CofinsTaxGroup, ?icms: IcmsTaxGroup, ?pis: PisTaxGroup) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/issuer_tax_profile_enum.rbs b/sig/nfe/generated/product_register_pt_br_v1/issuer_tax_profile_enum.rbs new file mode 100644 index 0000000..8722035 --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/issuer_tax_profile_enum.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + module IssuerTaxProfileEnum + None: String + Retail: String + Wholesale: String + WholesaleIndustry: String + Importer: String + Industry: String + Cooperative: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/pis_tax_group.rbs b/sig/nfe/generated/product_register_pt_br_v1/pis_tax_group.rbs new file mode 100644 index 0000000..f435fbc --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/pis_tax_group.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class PisTaxGroup < Data + attr_reader cst: String + attr_reader p_pis: String + def self.new: (?cst: String, ?p_pis: String) -> instance + def initialize: (?cst: String, ?p_pis: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/product.rbs b/sig/nfe/generated/product_register_pt_br_v1/product.rbs new file mode 100644 index 0000000..948dd92 --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/product.rbs @@ -0,0 +1,25 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class Product < Data + attr_reader collection_id: String + attr_reader custom_tax: Array[CustomTaxScenario] + attr_reader description: String + attr_reader gtin: String + attr_reader id: String + attr_reader origin: String + attr_reader sku: String + attr_reader tax: Hash[String, untyped] + attr_reader tax_gtin: String + attr_reader tenant_id: String + def self.new: (collection_id: String, custom_tax: Array[CustomTaxScenario], description: String, ?gtin: String, id: String, origin: String, sku: String, ?tax: Hash[String, untyped], ?tax_gtin: String, tenant_id: String) -> instance + def initialize: (collection_id: String, custom_tax: Array[CustomTaxScenario], description: String, ?gtin: String, id: String, origin: String, sku: String, ?tax: Hash[String, untyped], ?tax_gtin: String, tenant_id: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/product_input.rbs b/sig/nfe/generated/product_register_pt_br_v1/product_input.rbs new file mode 100644 index 0000000..001cf0b --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/product_input.rbs @@ -0,0 +1,24 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + class ProductInput < Data + attr_reader collection_id: String + attr_reader custom_tax: Array[CustomTaxScenario] + attr_reader description: String + attr_reader gtin: String + attr_reader origin: String + attr_reader sku: String + attr_reader tax: Hash[String, untyped] + attr_reader tax_gtin: String + attr_reader tenant_id: String + def self.new: (collection_id: String, custom_tax: Array[CustomTaxScenario], description: String, ?gtin: String, origin: String, sku: String, ?tax: Hash[String, untyped], ?tax_gtin: String, tenant_id: String) -> instance + def initialize: (collection_id: String, custom_tax: Array[CustomTaxScenario], description: String, ?gtin: String, origin: String, sku: String, ?tax: Hash[String, untyped], ?tax_gtin: String, tenant_id: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/recipient_tax_profile_enum.rbs b/sig/nfe/generated/product_register_pt_br_v1/recipient_tax_profile_enum.rbs new file mode 100644 index 0000000..d09d72f --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/recipient_tax_profile_enum.rbs @@ -0,0 +1,30 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + module RecipientTaxProfileEnum + None: String + Industry: String + FinalConsumerIcmsContributor: String + FinalConsumerNonIcmsContributor: String + GeneralWarehouse: String + ClosedDeposit: String + NaturalPerson: String + CommercialExporter: String + Importer: String + Coop: String + Wholesale: String + Retail: String + InterdependentCompany: String + RetailBranch: String + NonRetailBranch: String + WholesaleBranch: String + ClosedWarehouse: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/product_register_pt_br_v1/tax_regime_enum.rbs b/sig/nfe/generated/product_register_pt_br_v1/tax_regime_enum.rbs new file mode 100644 index 0000000..04c6a54 --- /dev/null +++ b/sig/nfe/generated/product_register_pt_br_v1/tax_regime_enum.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/product-register-pt-br-v1.yaml +# Hash: sha256:beba0a3fb4dc1bc157a5a4a28e55768cea0e7390b491bdd4bedee2ee2297ca64 + +module Nfe + module Generated + module ProductRegisterPtBrV1 + module TaxRegimeEnum + NationalSimple: String + NationalSimpleSublimitExceeded: String + RealProfit: String + PresumidProfile: String + ALL: Array[String] + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/activity_event.rbs b/sig/nfe/generated/service_invoice_rtc_v1/activity_event.rbs new file mode 100644 index 0000000..c63b2c6 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/activity_event.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ActivityEvent < Data + attr_reader code: String + attr_reader address: AddressDefinition + attr_reader begin_on: String + attr_reader end_on: String + attr_reader name: String + def self.new: (?code: String, ?address: AddressDefinition, ?begin_on: String, ?end_on: String, ?name: String) -> instance + def initialize: (?code: String, ?address: AddressDefinition, ?begin_on: String, ?end_on: String, ?name: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/address_definition.rbs b/sig/nfe/generated/service_invoice_rtc_v1/address_definition.rbs new file mode 100644 index 0000000..5dd8730 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/address_definition.rbs @@ -0,0 +1,23 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class AddressDefinition < Data + attr_reader additional_information: String + attr_reader city: Hash[String, untyped] + attr_reader country: String + attr_reader district: String + attr_reader number: String + attr_reader postal_code: String + attr_reader state: String + attr_reader street: String + def self.new: (?additional_information: String, ?city: Hash[String, untyped], ?country: String, ?district: String, ?number: String, ?postal_code: String, ?state: String, ?street: String) -> instance + def initialize: (?additional_information: String, ?city: Hash[String, untyped], ?country: String, ?district: String, ?number: String, ?postal_code: String, ?state: String, ?street: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/approximate_tax.rbs b/sig/nfe/generated/service_invoice_rtc_v1/approximate_tax.rbs new file mode 100644 index 0000000..b5e9235 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/approximate_tax.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ApproximateTax < Data + attr_reader source: String + attr_reader total_amount: Float + attr_reader total_rate: Float + attr_reader version: String + def self.new: (?source: String, ?total_amount: Float, ?total_rate: Float, ?version: String) -> instance + def initialize: (?source: String, ?total_amount: Float, ?total_rate: Float, ?version: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/approximate_totals.rbs b/sig/nfe/generated/service_invoice_rtc_v1/approximate_totals.rbs new file mode 100644 index 0000000..24982bd --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/approximate_totals.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ApproximateTotals < Data + attr_reader amount: Float + attr_reader federal: Hash[String, untyped] + attr_reader municipal: Hash[String, untyped] + attr_reader rate: Float + attr_reader state: Hash[String, untyped] + def self.new: (?amount: Float, ?federal: Hash[String, untyped], ?municipal: Hash[String, untyped], ?rate: Float, ?state: Hash[String, untyped]) -> instance + def initialize: (?amount: Float, ?federal: Hash[String, untyped], ?municipal: Hash[String, untyped], ?rate: Float, ?state: Hash[String, untyped]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/benefit.rbs b/sig/nfe/generated/service_invoice_rtc_v1/benefit.rbs new file mode 100644 index 0000000..a359c6b --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/benefit.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class Benefit < Data + attr_reader amount: Float + attr_reader id: String + attr_reader rate: Float + def self.new: (?amount: Float, id: String, ?rate: Float) -> instance + def initialize: (?amount: Float, id: String, ?rate: Float) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/construction.rbs b/sig/nfe/generated/service_invoice_rtc_v1/construction.rbs new file mode 100644 index 0000000..dbf41c0 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/construction.rbs @@ -0,0 +1,20 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class Construction < Data + attr_reader cib_code: String + attr_reader encapsulation_number: String + attr_reader property_fiscal_registration: String + attr_reader site_address: AddressDefinition + attr_reader work_id: Hash[String, untyped] + def self.new: (?cib_code: String, ?encapsulation_number: String, ?property_fiscal_registration: String, ?site_address: AddressDefinition, ?work_id: Hash[String, untyped]) -> instance + def initialize: (?cib_code: String, ?encapsulation_number: String, ?property_fiscal_registration: String, ?site_address: AddressDefinition, ?work_id: Hash[String, untyped]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/deduction.rbs b/sig/nfe/generated/service_invoice_rtc_v1/deduction.rbs new file mode 100644 index 0000000..6e8d801 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/deduction.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class Deduction < Data + attr_reader amount: Float + attr_reader documents: Array[DeductionDocument] + attr_reader rate: Float + def self.new: (?amount: Float, ?documents: Array[DeductionDocument], ?rate: Float) -> instance + def initialize: (?amount: Float, ?documents: Array[DeductionDocument], ?rate: Float) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/deduction_document.rbs b/sig/nfe/generated/service_invoice_rtc_v1/deduction_document.rbs new file mode 100644 index 0000000..3254d6d --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/deduction_document.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class DeductionDocument < Data + attr_reader deductible_total: Float + attr_reader deduction_type: String + attr_reader fiscal_document_number: String + attr_reader issue_date: String + attr_reader municipal_nfse: Hash[String, untyped] + attr_reader nfe_key: String + attr_reader nfse_key: String + attr_reader non_fiscal_document_number: String + attr_reader other_deduction_description: String + attr_reader supplier: PartyDefinition + attr_reader used_amount: Float + def self.new: (deductible_total: Float, deduction_type: String, ?fiscal_document_number: String, issue_date: String, ?municipal_nfse: Hash[String, untyped], ?nfe_key: String, ?nfse_key: String, ?non_fiscal_document_number: String, ?other_deduction_description: String, ?supplier: PartyDefinition, used_amount: Float) -> instance + def initialize: (deductible_total: Float, deduction_type: String, ?fiscal_document_number: String, issue_date: String, ?municipal_nfse: Hash[String, untyped], ?nfe_key: String, ?nfse_key: String, ?non_fiscal_document_number: String, ?other_deduction_description: String, ?supplier: PartyDefinition, used_amount: Float) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/foreign_trade.rbs b/sig/nfe/generated/service_invoice_rtc_v1/foreign_trade.rbs new file mode 100644 index 0000000..4420301 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/foreign_trade.rbs @@ -0,0 +1,25 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ForeignTrade < Data + attr_reader currency: String + attr_reader export_registration: String + attr_reader import_declaration: String + attr_reader mdic_delivery: bool + attr_reader relation_ship: String + attr_reader service_amount_in_currency: Float + attr_reader service_mode: String + attr_reader support_mechanism_provider: String + attr_reader support_mechanism_receiver: String + attr_reader temporary_goods: String + def self.new: (?currency: String, ?export_registration: String, ?import_declaration: String, ?mdic_delivery: bool, ?relation_ship: String, ?service_amount_in_currency: Float, ?service_mode: String, ?support_mechanism_provider: String, ?support_mechanism_receiver: String, ?temporary_goods: String) -> instance + def initialize: (?currency: String, ?export_registration: String, ?import_declaration: String, ?mdic_delivery: bool, ?relation_ship: String, ?service_amount_in_currency: Float, ?service_mode: String, ?support_mechanism_provider: String, ?support_mechanism_receiver: String, ?temporary_goods: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/ibs_cbs.rbs b/sig/nfe/generated/service_invoice_rtc_v1/ibs_cbs.rbs new file mode 100644 index 0000000..9c1656c --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/ibs_cbs.rbs @@ -0,0 +1,35 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class IbsCbs < Data + attr_reader basis: Float + attr_reader cbs: Hash[String, untyped] + attr_reader class_code: String + attr_reader credit_transfer: Hash[String, untyped] + attr_reader destination_indicator: String + attr_reader government_purchase: Hash[String, untyped] + attr_reader ibs: Hash[String, untyped] + attr_reader ibscbs_deduction_reduction_amount: Float + attr_reader is_donation: bool? + attr_reader leased_movable_assets: Array[Hash[String, untyped]] + attr_reader operation_indicator: String + attr_reader operation_type: String + attr_reader personal_use: untyped + attr_reader presumed_credits: Hash[String, untyped] + attr_reader purpose: String + attr_reader regular_taxation: Hash[String, untyped] + attr_reader reimbursed_resupplied_amount: Float + attr_reader related_docs: Hash[String, untyped] + attr_reader situation_code: String + attr_reader third_party_reimbursements: Hash[String, untyped] + def self.new: (?basis: Float, ?cbs: Hash[String, untyped], class_code: String, ?credit_transfer: Hash[String, untyped], ?destination_indicator: String, ?government_purchase: Hash[String, untyped], ?ibs: Hash[String, untyped], ?ibscbs_deduction_reduction_amount: Float, ?is_donation: bool?, ?leased_movable_assets: Array[Hash[String, untyped]], operation_indicator: String, ?operation_type: String, ?personal_use: untyped, ?presumed_credits: Hash[String, untyped], ?purpose: String, ?regular_taxation: Hash[String, untyped], ?reimbursed_resupplied_amount: Float, ?related_docs: Hash[String, untyped], ?situation_code: String, ?third_party_reimbursements: Hash[String, untyped]) -> instance + def initialize: (?basis: Float, ?cbs: Hash[String, untyped], class_code: String, ?credit_transfer: Hash[String, untyped], ?destination_indicator: String, ?government_purchase: Hash[String, untyped], ?ibs: Hash[String, untyped], ?ibscbs_deduction_reduction_amount: Float, ?is_donation: bool?, ?leased_movable_assets: Array[Hash[String, untyped]], operation_indicator: String, ?operation_type: String, ?personal_use: untyped, ?presumed_credits: Hash[String, untyped], ?purpose: String, ?regular_taxation: Hash[String, untyped], ?reimbursed_resupplied_amount: Float, ?related_docs: Hash[String, untyped], ?situation_code: String, ?third_party_reimbursements: Hash[String, untyped]) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/lease.rbs b/sig/nfe/generated/service_invoice_rtc_v1/lease.rbs new file mode 100644 index 0000000..0da83d3 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/lease.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class Lease < Data + attr_reader category: String + attr_reader object_type: String + attr_reader poles_count: Integer + attr_reader total_length: Float + def self.new: (?category: String, ?object_type: String, ?poles_count: Integer, ?total_length: Float) -> instance + def initialize: (?category: String, ?object_type: String, ?poles_count: Integer, ?total_length: Float) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/nfse_request.rbs b/sig/nfe/generated/service_invoice_rtc_v1/nfse_request.rbs new file mode 100644 index 0000000..93e3608 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/nfse_request.rbs @@ -0,0 +1,73 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class NFSeRequest < Data + attr_reader reference_substitution: ReferenceSubstitution + attr_reader accrual_on: String + attr_reader activity_event: ActivityEvent + attr_reader additional_information: String + attr_reader additional_information_group: Hash[String, untyped] + attr_reader approximate_tax: ApproximateTax + attr_reader approximate_totals: ApproximateTotals + attr_reader benefit: Benefit + attr_reader borrower: PartyDefinition + attr_reader city_service_code: String + attr_reader cnae_code: String + attr_reader cofins_amount: Float + attr_reader cofins_amount_withheld: Float + attr_reader cofins_rate: Float + attr_reader construction: Construction + attr_reader csll_amount: Float + attr_reader csll_amount_withheld: Float + attr_reader csll_rate: Float + attr_reader cst_pis_cofins: String + attr_reader deduction: Deduction + attr_reader deductions_amount: Float + attr_reader description: String + attr_reader discount_conditioned_amount: Float + attr_reader discount_unconditioned_amount: Float + attr_reader external_id: String + attr_reader federal_service_code: String + attr_reader foreign_trade: ForeignTrade + attr_reader ibs_cbs: IbsCbs + attr_reader immunity_type: String + attr_reader inss_amount_withheld: Float + attr_reader intermediary: PartyDefinition + attr_reader ipi_amount: Float + attr_reader ipi_rate: Float + attr_reader ir_amount_withheld: Float + attr_reader is_early_installment_payment: bool + attr_reader iss_amount_withheld: Float + attr_reader iss_rate: Float + attr_reader iss_tax_amount: Float + attr_reader issued_on: String + attr_reader lease: Lease + attr_reader location: AddressDefinition + attr_reader nbs_code: String + attr_reader ncm_code: String + attr_reader others_amount_withheld: Float + attr_reader paid_amount: Float + attr_reader pis_amount: Float + attr_reader pis_amount_withheld: Float + attr_reader pis_cofins_base_tax: Float + attr_reader pis_rate: Float + attr_reader real_estate: RealEstate + attr_reader recipient: PartyDefinition + attr_reader retention_type: String + attr_reader rps_number: Float + attr_reader rps_serial_number: String + attr_reader service_amount_details: ServiceAmountDefinitions + attr_reader services_amount: Float + attr_reader suspension: Suspension + attr_reader taxation_type: String + def self.new: (?reference_substitution: ReferenceSubstitution, ?accrual_on: String, ?activity_event: ActivityEvent, ?additional_information: String, ?additional_information_group: Hash[String, untyped], ?approximate_tax: ApproximateTax, ?approximate_totals: ApproximateTotals, ?benefit: Benefit, ?borrower: PartyDefinition, city_service_code: String, ?cnae_code: String, ?cofins_amount: Float, ?cofins_amount_withheld: Float, ?cofins_rate: Float, ?construction: Construction, ?csll_amount: Float, ?csll_amount_withheld: Float, ?csll_rate: Float, ?cst_pis_cofins: String, ?deduction: Deduction, ?deductions_amount: Float, description: String, ?discount_conditioned_amount: Float, ?discount_unconditioned_amount: Float, ?external_id: String, ?federal_service_code: String, ?foreign_trade: ForeignTrade, ?ibs_cbs: IbsCbs, ?immunity_type: String, ?inss_amount_withheld: Float, ?intermediary: PartyDefinition, ?ipi_amount: Float, ?ipi_rate: Float, ?ir_amount_withheld: Float, ?is_early_installment_payment: bool, ?iss_amount_withheld: Float, ?iss_rate: Float, ?iss_tax_amount: Float, ?issued_on: String, ?lease: Lease, ?location: AddressDefinition, nbs_code: String, ?ncm_code: String, ?others_amount_withheld: Float, ?paid_amount: Float, ?pis_amount: Float, ?pis_amount_withheld: Float, ?pis_cofins_base_tax: Float, ?pis_rate: Float, ?real_estate: RealEstate, ?recipient: PartyDefinition, ?retention_type: String, ?rps_number: Float, ?rps_serial_number: String, ?service_amount_details: ServiceAmountDefinitions, services_amount: Float, ?suspension: Suspension, ?taxation_type: String) -> instance + def initialize: (?reference_substitution: ReferenceSubstitution, ?accrual_on: String, ?activity_event: ActivityEvent, ?additional_information: String, ?additional_information_group: Hash[String, untyped], ?approximate_tax: ApproximateTax, ?approximate_totals: ApproximateTotals, ?benefit: Benefit, ?borrower: PartyDefinition, city_service_code: String, ?cnae_code: String, ?cofins_amount: Float, ?cofins_amount_withheld: Float, ?cofins_rate: Float, ?construction: Construction, ?csll_amount: Float, ?csll_amount_withheld: Float, ?csll_rate: Float, ?cst_pis_cofins: String, ?deduction: Deduction, ?deductions_amount: Float, description: String, ?discount_conditioned_amount: Float, ?discount_unconditioned_amount: Float, ?external_id: String, ?federal_service_code: String, ?foreign_trade: ForeignTrade, ?ibs_cbs: IbsCbs, ?immunity_type: String, ?inss_amount_withheld: Float, ?intermediary: PartyDefinition, ?ipi_amount: Float, ?ipi_rate: Float, ?ir_amount_withheld: Float, ?is_early_installment_payment: bool, ?iss_amount_withheld: Float, ?iss_rate: Float, ?iss_tax_amount: Float, ?issued_on: String, ?lease: Lease, ?location: AddressDefinition, nbs_code: String, ?ncm_code: String, ?others_amount_withheld: Float, ?paid_amount: Float, ?pis_amount: Float, ?pis_amount_withheld: Float, ?pis_cofins_base_tax: Float, ?pis_rate: Float, ?real_estate: RealEstate, ?recipient: PartyDefinition, ?retention_type: String, ?rps_number: Float, ?rps_serial_number: String, ?service_amount_details: ServiceAmountDefinitions, services_amount: Float, ?suspension: Suspension, ?taxation_type: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/party_definition.rbs b/sig/nfe/generated/service_invoice_rtc_v1/party_definition.rbs new file mode 100644 index 0000000..46466f3 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/party_definition.rbs @@ -0,0 +1,26 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class PartyDefinition < Data + attr_reader address: AddressDefinition + attr_reader caepf: String + attr_reader email: String + attr_reader federal_tax_number: Float + attr_reader municipal_tax_number: String + attr_reader name: String + attr_reader no_tax_id_reason: String + attr_reader phone_number: String + attr_reader state_tax_number: String + attr_reader tax_regime: String + attr_reader type: String + def self.new: (?address: AddressDefinition, ?caepf: String, ?email: String, ?federal_tax_number: Float, ?municipal_tax_number: String, ?name: String, ?no_tax_id_reason: String, ?phone_number: String, ?state_tax_number: String, ?tax_regime: String, ?type: String) -> instance + def initialize: (?address: AddressDefinition, ?caepf: String, ?email: String, ?federal_tax_number: Float, ?municipal_tax_number: String, ?name: String, ?no_tax_id_reason: String, ?phone_number: String, ?state_tax_number: String, ?tax_regime: String, ?type: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/real_estate.rbs b/sig/nfe/generated/service_invoice_rtc_v1/real_estate.rbs new file mode 100644 index 0000000..7d46dac --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/real_estate.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class RealEstate < Data + attr_reader cib_code: String + attr_reader property_fiscal_registration: String + attr_reader site_address: AddressDefinition + def self.new: (?cib_code: String, ?property_fiscal_registration: String, ?site_address: AddressDefinition) -> instance + def initialize: (?cib_code: String, ?property_fiscal_registration: String, ?site_address: AddressDefinition) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/reference_substitution.rbs b/sig/nfe/generated/service_invoice_rtc_v1/reference_substitution.rbs new file mode 100644 index 0000000..d1fb4b4 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/reference_substitution.rbs @@ -0,0 +1,18 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ReferenceSubstitution < Data + attr_reader id: String + attr_reader reason: String + attr_reader reason_text: String + def self.new: (?id: String, ?reason: String, ?reason_text: String) -> instance + def initialize: (?id: String, ?reason: String, ?reason_text: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/service_amount_definitions.rbs b/sig/nfe/generated/service_invoice_rtc_v1/service_amount_definitions.rbs new file mode 100644 index 0000000..9d6d916 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/service_amount_definitions.rbs @@ -0,0 +1,19 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ServiceAmountDefinitions < Data + attr_reader final_charged_amount: Float + attr_reader fine_amount: Float + attr_reader initial_charged_amount: Float + attr_reader interest_amount: Float + def self.new: (?final_charged_amount: Float, ?fine_amount: Float, ?initial_charged_amount: Float, ?interest_amount: Float) -> instance + def initialize: (?final_charged_amount: Float, ?fine_amount: Float, ?initial_charged_amount: Float, ?interest_amount: Float) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/suspension.rbs b/sig/nfe/generated/service_invoice_rtc_v1/suspension.rbs new file mode 100644 index 0000000..a5c2555 --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/suspension.rbs @@ -0,0 +1,17 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class Suspension < Data + attr_reader process_number: String + attr_reader reason: String + def self.new: (process_number: String, reason: String) -> instance + def initialize: (process_number: String, reason: String) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/generated/service_invoice_rtc_v1/third_party_reimbursement_document.rbs b/sig/nfe/generated/service_invoice_rtc_v1/third_party_reimbursement_document.rbs new file mode 100644 index 0000000..d0e6f0b --- /dev/null +++ b/sig/nfe/generated/service_invoice_rtc_v1/third_party_reimbursement_document.rbs @@ -0,0 +1,27 @@ +# AUTO-GENERATED — do not edit +# Source: openapi/service-invoice-rtc-v1.yaml +# Hash: sha256:5c3b751b63e6a0adabb185b974e141f1b06127934fa0bf05fc505676024db32b + +module Nfe + module Generated + module ServiceInvoiceRtcV1 + class ThirdPartyReimbursementDocument < Data + attr_reader accrual_on: String + attr_reader amount: Float + attr_reader cte_key: String + attr_reader issue_date: String + attr_reader nfe_key: String + attr_reader nfse_key: String + attr_reader other_doc: Hash[String, untyped] + attr_reader other_fiscal_doc: Hash[String, untyped] + attr_reader other_national_dfe: Hash[String, untyped] + attr_reader reimbursement_type: String + attr_reader reimbursement_type_text: String + attr_reader supplier: PartyDefinition + def self.new: (accrual_on: String, amount: Float, ?cte_key: String, issue_date: String, ?nfe_key: String, ?nfse_key: String, ?other_doc: Hash[String, untyped], ?other_fiscal_doc: Hash[String, untyped], ?other_national_dfe: Hash[String, untyped], reimbursement_type: String, ?reimbursement_type_text: String, ?supplier: PartyDefinition) -> instance + def initialize: (accrual_on: String, amount: Float, ?cte_key: String, issue_date: String, ?nfe_key: String, ?nfse_key: String, ?other_doc: Hash[String, untyped], ?other_fiscal_doc: Hash[String, untyped], ?other_national_dfe: Hash[String, untyped], reimbursement_type: String, ?reimbursement_type_text: String, ?supplier: PartyDefinition) -> void + def self.from_api: (Hash[String, untyped]? payload) -> instance? + end + end + end +end diff --git a/sig/nfe/http/net_http.rbs b/sig/nfe/http/net_http.rbs new file mode 100644 index 0000000..d997b59 --- /dev/null +++ b/sig/nfe/http/net_http.rbs @@ -0,0 +1,33 @@ +module Nfe + module Http + class NetHttp + KEEP_ALIVE_TIMEOUT: Integer + + @default_open_timeout: Integer + @default_read_timeout: Integer + @ca_file: String? + @pool: Hash[String, Array[untyped]] + @mutex: Thread::Mutex + + def initialize: (?default_open_timeout: Integer, ?default_read_timeout: Integer, ?ca_file: String?) -> void + + def call: (Nfe::Http::Request request) -> Nfe::Http::Response + + private + + def checkout: (String key, URI::Generic uri, Nfe::Http::Request request) -> untyped + def checkin: (String key, untyped http) -> void + def discard: (untyped http) -> void + def build_connection: (URI::Generic uri) -> untyped + def configure_tls: (untyped http, URI::Generic uri) -> void + def apply_timeouts: (untyped http, Nfe::Http::Request request) -> void + def origin_key: (URI::Generic uri) -> String + def build_net_request: (URI::Generic uri, Nfe::Http::Request request) -> untyped + def accept_encoding_set?: (Hash[untyped, untyped] headers) -> bool + def request_class: (untyped method) -> untyped + def build_response: (untyped net_response) -> Nfe::Http::Response + def normalize_headers: (untyped net_response) -> Hash[String, String] + def decompress: (String body, Hash[String, String] headers) -> [ String, Hash[String, String] ] + end + end +end diff --git a/sig/nfe/http/redactor.rbs b/sig/nfe/http/redactor.rbs new file mode 100644 index 0000000..06fd7d5 --- /dev/null +++ b/sig/nfe/http/redactor.rbs @@ -0,0 +1,12 @@ +module Nfe + module Http + module Redactor + REDACTED: String + SENSITIVE_NAMES: Array[String] + SENSITIVE_PATTERN: Regexp + + def self?.headers: (untyped hash) -> Hash[untyped, untyped] + def self?.sensitive?: (untyped key) -> bool + end + end +end diff --git a/sig/nfe/http/request.rbs b/sig/nfe/http/request.rbs new file mode 100644 index 0000000..d221f21 --- /dev/null +++ b/sig/nfe/http/request.rbs @@ -0,0 +1,43 @@ +module Nfe + module Http + class Request < Data + attr_reader method: String + attr_reader base_url: String + attr_reader path: String + attr_reader headers: Hash[String, untyped] + attr_reader query: Hash[untyped, untyped] + attr_reader body: String? + attr_reader open_timeout: Numeric? + attr_reader read_timeout: Numeric? + attr_reader idempotency_key: String? + + def self.new: ( + method: String, + base_url: String, + path: String, + ?headers: Hash[String, untyped], + ?query: Hash[untyped, untyped], + ?body: String?, + ?open_timeout: Numeric?, + ?read_timeout: Numeric?, + ?idempotency_key: String? + ) -> instance + + def initialize: ( + method: String, + base_url: String, + path: String, + ?headers: Hash[String, untyped], + ?query: Hash[untyped, untyped], + ?body: String?, + ?open_timeout: Numeric?, + ?read_timeout: Numeric?, + ?idempotency_key: String? + ) -> void + + def url: () -> String + + def idempotent?: () -> bool + end + end +end diff --git a/sig/nfe/http/response.rbs b/sig/nfe/http/response.rbs new file mode 100644 index 0000000..5610c71 --- /dev/null +++ b/sig/nfe/http/response.rbs @@ -0,0 +1,27 @@ +module Nfe + module Http + class Response < Data + attr_reader status: Integer + attr_reader headers: Hash[String, String] + attr_reader body: String? + + def self.new: ( + status: Integer, + ?headers: Hash[String, String], + ?body: String? + ) -> instance + + def initialize: ( + status: Integer, + ?headers: Hash[String, String], + ?body: String? + ) -> void + + def header: (String name) -> String? + + def success?: () -> bool + + def location: () -> String? + end + end +end diff --git a/sig/nfe/http/retry_policy.rbs b/sig/nfe/http/retry_policy.rbs new file mode 100644 index 0000000..15389e2 --- /dev/null +++ b/sig/nfe/http/retry_policy.rbs @@ -0,0 +1,18 @@ +module Nfe + module Http + class RetryPolicy < Data + attr_reader max_retries: Integer + attr_reader base_delay: Float + attr_reader max_delay: Float + attr_reader jitter: Float + + def self.new: (max_retries: Integer, base_delay: Float, max_delay: Float, jitter: Float) -> RetryPolicy + def initialize: (max_retries: Integer, base_delay: Float, max_delay: Float, jitter: Float) -> void + + def self.default: () -> RetryPolicy + def self.none: () -> RetryPolicy + + def delay_for: (Integer attempt) -> Float + end + end +end diff --git a/sig/nfe/http/retrying_transport.rbs b/sig/nfe/http/retrying_transport.rbs new file mode 100644 index 0000000..421e360 --- /dev/null +++ b/sig/nfe/http/retrying_transport.rbs @@ -0,0 +1,27 @@ +module Nfe + module Http + class RetryingTransport + @inner: untyped + @policy: RetryPolicy + @sleep_fn: ^(Float | Integer seconds) -> untyped + @logger: untyped + + def initialize: (inner: untyped, ?policy: RetryPolicy, ?sleep_fn: ^(Float | Integer) -> untyped, ?logger: untyped) -> void + + def call: (Nfe::Http::Request request) -> Nfe::Http::Response + + def retryable_status?: (Integer status) -> bool + + private + + def retry_again?: (Integer attempt, Nfe::Http::Request request) -> bool + def delay_for_response: (Integer attempt, Nfe::Http::Response response) -> Float + def parse_retry_after: (Nfe::Http::Response response) -> Integer? + def log_start: (Nfe::Http::Request request) -> void + def log_retry: (Nfe::Http::Request request, attempt: Integer, delay: (Float | Integer), ?status: Integer?, ?error: untyped) -> void + def log_final_error: (Nfe::Http::Request request, ?response: Nfe::Http::Response?, ?error: untyped) -> void + def truncate: (untyped body, ?Integer limit) -> String + def safe_log: () { () -> untyped } -> untyped + end + end +end diff --git a/sig/nfe/http/transport.rbs b/sig/nfe/http/transport.rbs new file mode 100644 index 0000000..452fb11 --- /dev/null +++ b/sig/nfe/http/transport.rbs @@ -0,0 +1,11 @@ +module Nfe + module Http + interface _Transport + def call: (Nfe::Http::Request request) -> Nfe::Http::Response + end + + module Transport : _Transport + def call: (Nfe::Http::Request request) -> Nfe::Http::Response + end + end +end diff --git a/sig/nfe/http/user_agent.rbs b/sig/nfe/http/user_agent.rbs new file mode 100644 index 0000000..3f57c26 --- /dev/null +++ b/sig/nfe/http/user_agent.rbs @@ -0,0 +1,7 @@ +module Nfe + module Http + module UserAgent + def self?.build: (?String? suffix) -> String + end + end +end diff --git a/sig/nfe/id_validator.rbs b/sig/nfe/id_validator.rbs new file mode 100644 index 0000000..1d40463 --- /dev/null +++ b/sig/nfe/id_validator.rbs @@ -0,0 +1,18 @@ +module Nfe + module IdValidator + UF: Array[String] + + def self?.company_id: (untyped value) -> untyped + def self?.invoice_id: (untyped value) -> untyped + def self?.state_tax_id: (untyped value) -> untyped + def self?.event_key: (untyped value) -> untyped + def self?.access_key: (untyped value) -> String + def self?.cnpj: (untyped value) -> String + def self?.cpf: (untyped value) -> String + def self?.cep: (untyped value) -> String + def self?.state: (untyped value) -> String + def self?.presence!: (untyped value, String name) -> untyped + def self?.digits_only: (untyped value) -> String + def self?.strip_separators: (untyped value) -> String + end +end diff --git a/sig/nfe/pagination.rbs b/sig/nfe/pagination.rbs new file mode 100644 index 0000000..5adf1a6 --- /dev/null +++ b/sig/nfe/pagination.rbs @@ -0,0 +1,31 @@ +module Nfe + class ListPage < Data + attr_reader page_index: untyped + attr_reader page_count: untyped + attr_reader starting_after: untyped + attr_reader ending_before: untyped + attr_reader total: untyped + + def self.new: (?page_index: untyped, ?page_count: untyped, ?starting_after: untyped, ?ending_before: untyped, ?total: untyped) -> instance + + def initialize: (?page_index: untyped, ?page_count: untyped, ?starting_after: untyped, ?ending_before: untyped, ?total: untyped) -> void + + def self.from_page: (?page_index: untyped, ?page_count: untyped, ?total: untyped) -> instance + + def self.from_cursor: (?starting_after: untyped, ?ending_before: untyped, ?total: untyped) -> instance + end + + class ListResponse < Data + include Enumerable[untyped] + + attr_reader data: untyped + attr_reader page: untyped + + def self.new: (?data: untyped, ?page: untyped) -> instance + + def initialize: (?data: untyped, ?page: untyped) -> void + + def each: () { (untyped) -> void } -> void + | () -> Enumerator[untyped, void] + end +end diff --git a/sig/nfe/request_options.rbs b/sig/nfe/request_options.rbs new file mode 100644 index 0000000..ceaf4d7 --- /dev/null +++ b/sig/nfe/request_options.rbs @@ -0,0 +1,11 @@ +module Nfe + class RequestOptions < Data + attr_reader api_key: String? + attr_reader base_url: String? + attr_reader timeout: Numeric? + + def self.new: (?api_key: String?, ?base_url: String?, ?timeout: Numeric?) -> instance + + def initialize: (?api_key: String?, ?base_url: String?, ?timeout: Numeric?) -> void + end +end diff --git a/sig/nfe/resources/abstract_resource.rbs b/sig/nfe/resources/abstract_resource.rbs new file mode 100644 index 0000000..b675771 --- /dev/null +++ b/sig/nfe/resources/abstract_resource.rbs @@ -0,0 +1,39 @@ +module Nfe + module Resources + class AbstractResource + @client: Nfe::Client + + def initialize: (Nfe::Client client) -> void + + attr_reader client: Nfe::Client + + def api_family: () -> Symbol + def api_version: () -> String + + def get: (String path, ?query: Hash[untyped, untyped], ?request_options: Nfe::RequestOptions?, ?headers: Hash[untyped, untyped]) -> Nfe::Http::Response + def post: (String path, ?body: untyped, ?query: Hash[untyped, untyped], ?request_options: Nfe::RequestOptions?, ?headers: Hash[untyped, untyped], ?idempotency_key: String?) -> Nfe::Http::Response + def put: (String path, ?body: untyped, ?query: Hash[untyped, untyped], ?request_options: Nfe::RequestOptions?, ?headers: Hash[untyped, untyped]) -> Nfe::Http::Response + def delete: (String path, ?query: Hash[untyped, untyped], ?request_options: Nfe::RequestOptions?, ?headers: Hash[untyped, untyped]) -> Nfe::Http::Response + + def full_path: (String path) -> String + def hydrate: (untyped klass, untyped payload) -> untyped + def download: (String path, ?query: Hash[untyped, untyped], ?request_options: Nfe::RequestOptions?, ?headers: Hash[untyped, untyped]) -> String + def hydrate_list: (untyped klass, untyped payload, wrapper_key: (String | Symbol)) -> Nfe::ListResponse + def handle_async_response: (Nfe::Http::Response response, issued_klass: untyped) -> (Nfe::Pending | Nfe::Issued) + + private + + def unwrap: (untyped payload, (String | Symbol) key) -> untyped + def upload_multipart: (String path, Hash[untyped, untyped] parts) -> Nfe::Http::Response + def build_multipart_body: (Hash[untyped, untyped] parts, String boundary) -> String + def multipart_part: (String name, untyped value) -> String + + def build_list_page: (untyped payload) -> Nfe::ListPage + def dig_key: (untyped payload, String camel_key, Symbol snake_key) -> untyped + def page_list_page: (untyped page_index, untyped page_count, untyped total) -> Nfe::ListPage + def cursor_list_page: (untyped payload, untyped total) -> Nfe::ListPage + def extract_invoice_id: (String location) -> String? + def parse_json: (String? body) -> untyped + end + end +end diff --git a/sig/nfe/resources/addresses.rbs b/sig/nfe/resources/addresses.rbs new file mode 100644 index 0000000..d51d53d --- /dev/null +++ b/sig/nfe/resources/addresses.rbs @@ -0,0 +1,12 @@ +module Nfe + module Resources + class Addresses < AbstractResource + def lookup_by_postal_code: (untyped postal_code) -> Nfe::AddressLookupResponse? + def search: (?filter: untyped) -> Nfe::AddressLookupResponse? + def lookup_by_term: (untyped term) -> Nfe::AddressLookupResponse? + + def api_family: () -> Symbol + def api_version: () -> String + end + end +end diff --git a/sig/nfe/resources/companies.rbs b/sig/nfe/resources/companies.rbs new file mode 100644 index 0000000..4b69547 --- /dev/null +++ b/sig/nfe/resources/companies.rbs @@ -0,0 +1,39 @@ +module Nfe + module Resources + class Companies < AbstractResource + ENVELOPE: String + + def api_family: () -> Symbol + + def create: (Hash[untyped, untyped] data) -> Nfe::Company? + def list: (?page_index: Integer, ?page_count: Integer) -> Nfe::ListResponse + def list_all: () -> Array[Nfe::Company] + def list_each: () -> Enumerator[Nfe::Company, void] + def retrieve: (String company_id) -> Nfe::Company? + def update: (String company_id, Hash[untyped, untyped] data) -> Nfe::Company? + def remove: (String company_id) -> { deleted: bool, id: String } + def find_by_tax_number: ((String | Integer) tax_number) -> Nfe::Company? + def find_by_name: (String name) -> Array[Nfe::Company] + def validate_certificate: (file: String, password: String) -> Nfe::CertificateInfo + def upload_certificate: (String company_id, file: String, password: String, ?filename: String?) -> { uploaded: bool, message: String? } + def replace_certificate: (String company_id, file: String, password: String, ?filename: String?) -> { uploaded: bool, message: String? } + def get_certificate_status: (String company_id) -> Nfe::CertificateStatus + def check_certificate_expiration: (String company_id, ?threshold_days: Integer) -> ({ expiring: bool, days_remaining: Integer, expires_on: String }?) + def get_companies_with_certificates: () -> Array[Nfe::Company] + def get_companies_with_expiring_certificates: (?threshold_days: Integer) -> Array[Nfe::Company] + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def resolve_page_index: (Hash[untyped, untyped] payload, Integer requested_index) -> Integer + def validate_company_data: (Hash[untyped, untyped] data) -> void + def valid_email?: (String value) -> bool + def normalize_tax_number: (untyped value) -> String + def read_certificate_bytes: (String file) -> String + def build_certificate_status: (Hash[untyped, untyped] details) -> Nfe::CertificateStatus + def certificate_status_or_nil: (String company_id) -> Nfe::CertificateStatus? + def expiring_or_nil: (String company_id, Integer threshold_days) -> untyped + end + end +end diff --git a/sig/nfe/resources/consumer_invoice_issued.rbs b/sig/nfe/resources/consumer_invoice_issued.rbs new file mode 100644 index 0000000..a59211d --- /dev/null +++ b/sig/nfe/resources/consumer_invoice_issued.rbs @@ -0,0 +1,16 @@ +module Nfe + module Resources + class ConsumerInvoiceIssued < Data + attr_reader resource: Nfe::ConsumerInvoice? + + def self.new: (resource: Nfe::ConsumerInvoice?) -> instance + | (Nfe::ConsumerInvoice? resource) -> instance + + def initialize: (resource: Nfe::ConsumerInvoice?) -> void + | (Nfe::ConsumerInvoice? resource) -> void + + def pending?: () -> bool + def issued?: () -> bool + end + end +end diff --git a/sig/nfe/resources/consumer_invoice_pending.rbs b/sig/nfe/resources/consumer_invoice_pending.rbs new file mode 100644 index 0000000..8a7bc07 --- /dev/null +++ b/sig/nfe/resources/consumer_invoice_pending.rbs @@ -0,0 +1,17 @@ +module Nfe + module Resources + class ConsumerInvoicePending < Data + attr_reader invoice_id: String? + attr_reader location: String? + + def self.new: (invoice_id: String?, location: String?) -> instance + | (String? invoice_id, String? location) -> instance + + def initialize: (invoice_id: String?, location: String?) -> void + | (String? invoice_id, String? location) -> void + + def pending?: () -> bool + def issued?: () -> bool + end + end +end diff --git a/sig/nfe/resources/consumer_invoice_query.rbs b/sig/nfe/resources/consumer_invoice_query.rbs new file mode 100644 index 0000000..e9cda96 --- /dev/null +++ b/sig/nfe/resources/consumer_invoice_query.rbs @@ -0,0 +1,11 @@ +module Nfe + module Resources + class ConsumerInvoiceQuery < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + def retrieve: (String access_key) -> Nfe::TaxCoupon? + def download_xml: (String access_key) -> String + end + end +end diff --git a/sig/nfe/resources/consumer_invoices.rbs b/sig/nfe/resources/consumer_invoices.rbs new file mode 100644 index 0000000..0ceacf3 --- /dev/null +++ b/sig/nfe/resources/consumer_invoices.rbs @@ -0,0 +1,33 @@ +module Nfe + module Resources + class ConsumerInvoices < AbstractResource + ENVELOPE: String + + def api_family: () -> Symbol + def api_version: () -> String + + def create: (company_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ConsumerInvoicePending | Nfe::Resources::ConsumerInvoiceIssued) + def create_with_state_tax: (company_id: String, state_tax_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ConsumerInvoicePending | Nfe::Resources::ConsumerInvoiceIssued) + def list: (company_id: String, environment: String, **untyped options) -> Nfe::ListResponse + def retrieve: (company_id: String, invoice_id: String) -> Nfe::ConsumerInvoice? + def cancel: (company_id: String, invoice_id: String) -> Nfe::ConsumerInvoice? + def list_items: (company_id: String, invoice_id: String) -> Array[untyped] + def list_events: (company_id: String, invoice_id: String) -> Array[untyped] + def download_pdf: (company_id: String, invoice_id: String) -> String + def download_xml: (company_id: String, invoice_id: String) -> String + def download_rejection_xml: (company_id: String, invoice_id: String) -> String + def disable_range: (company_id: String, data: Hash[untyped, untyped]) -> Hash[untyped, untyped] + + private + + def require_environment: (untyped environment) -> void + def validate_pair: (String company_id, String invoice_id) -> Array[String] + def discriminate: (Nfe::Http::Response response) -> (Nfe::Resources::ConsumerInvoicePending | Nfe::Resources::ConsumerInvoiceIssued) + def issued_result: (Nfe::Http::Response response) -> Nfe::Resources::ConsumerInvoiceIssued + def extract_invoice_id: (String location) -> String? + def unwrap_collection: (untyped payload, String key) -> Array[untyped] + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + end + end +end diff --git a/sig/nfe/resources/dto/addresses/address_lookup_response.rbs b/sig/nfe/resources/dto/addresses/address_lookup_response.rbs new file mode 100644 index 0000000..48382e3 --- /dev/null +++ b/sig/nfe/resources/dto/addresses/address_lookup_response.rbs @@ -0,0 +1,40 @@ +module Nfe + class Address < Data + class City < Data + attr_reader code: String? + attr_reader name: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::Address::City? + def self.new: (code: String?, name: String?) -> instance + def initialize: (code: String?, name: String?) -> void + end + + attr_reader street: String? + attr_reader street_suffix: String? + attr_reader number: String? + attr_reader number_min: String? + attr_reader number_max: String? + attr_reader additional_information: String? + attr_reader district: String? + attr_reader postal_code: String? + attr_reader city: Nfe::Address::City? + attr_reader state: String? + attr_reader country: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::Address? + + def self.new: (street: String?, street_suffix: String?, number: String?, number_min: String?, number_max: String?, additional_information: String?, district: String?, postal_code: String?, city: Nfe::Address::City?, state: String?, country: String?) -> instance + + def initialize: (street: String?, street_suffix: String?, number: String?, number_min: String?, number_max: String?, additional_information: String?, district: String?, postal_code: String?, city: Nfe::Address::City?, state: String?, country: String?) -> void + end + + class AddressLookupResponse < Data + attr_reader addresses: Array[Nfe::Address?] + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::AddressLookupResponse? + + def self.new: (addresses: Array[Nfe::Address?]) -> instance + + def initialize: (addresses: Array[Nfe::Address?]) -> void + end +end diff --git a/sig/nfe/resources/dto/company.rbs b/sig/nfe/resources/dto/company.rbs new file mode 100644 index 0000000..b6d13c8 --- /dev/null +++ b/sig/nfe/resources/dto/company.rbs @@ -0,0 +1,27 @@ +module Nfe + class Company < Data + attr_reader id: String? + attr_reader name: String? + attr_reader trade_name: String? + attr_reader federal_tax_number: String? + attr_reader email: String? + attr_reader status: untyped + attr_reader tax_regime: untyped + attr_reader municipal_tax_number: String? + attr_reader address: untyped + attr_reader state_taxes: untyped + attr_reader municipal_taxes: untyped + attr_reader environment: untyped + attr_reader account_id: String? + attr_reader created_on: String? + attr_reader modified_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::Company? + + def self.stringify: (untyped value) -> String? + + def self.new: (id: String?, name: String?, trade_name: String?, federal_tax_number: String?, email: String?, status: untyped, tax_regime: untyped, municipal_tax_number: String?, address: untyped, state_taxes: untyped, municipal_taxes: untyped, environment: untyped, account_id: String?, created_on: String?, modified_on: String?) -> instance + + def initialize: (id: String?, name: String?, trade_name: String?, federal_tax_number: String?, email: String?, status: untyped, tax_regime: untyped, municipal_tax_number: String?, address: untyped, state_taxes: untyped, municipal_taxes: untyped, environment: untyped, account_id: String?, created_on: String?, modified_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/consumer_invoice.rbs b/sig/nfe/resources/dto/consumer_invoice.rbs new file mode 100644 index 0000000..1078ddc --- /dev/null +++ b/sig/nfe/resources/dto/consumer_invoice.rbs @@ -0,0 +1,24 @@ +module Nfe + class ConsumerInvoice < Data + attr_reader id: String? + attr_reader status: untyped + attr_reader flow_status: String? + attr_reader flow_message: String? + attr_reader environment: String? + attr_reader access_key: String? + attr_reader number: untyped + attr_reader serie: untyped + attr_reader total_amount: untyped + attr_reader issued_on: String? + attr_reader created_on: String? + attr_reader modified_on: String? + attr_reader cancelled_on: String? + attr_reader raw: Hash[untyped, untyped]? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ConsumerInvoice? + + def self.new: (id: String?, status: untyped, flow_status: String?, flow_message: String?, environment: String?, access_key: String?, number: untyped, serie: untyped, total_amount: untyped, issued_on: String?, created_on: String?, modified_on: String?, cancelled_on: String?, raw: Hash[untyped, untyped]?) -> instance + + def initialize: (id: String?, status: untyped, flow_status: String?, flow_message: String?, environment: String?, access_key: String?, number: untyped, serie: untyped, total_amount: untyped, issued_on: String?, created_on: String?, modified_on: String?, cancelled_on: String?, raw: Hash[untyped, untyped]?) -> void + end +end diff --git a/sig/nfe/resources/dto/consumer_invoice_query/tax_coupon.rbs b/sig/nfe/resources/dto/consumer_invoice_query/tax_coupon.rbs new file mode 100644 index 0000000..883bcc4 --- /dev/null +++ b/sig/nfe/resources/dto/consumer_invoice_query/tax_coupon.rbs @@ -0,0 +1,117 @@ +module Nfe + class TaxCoupon < Data + class Issuer < Data + attr_reader federal_tax_number: untyped + attr_reader name: String? + attr_reader trade_name: String? + attr_reader state_tax_number: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Issuer? + def self.new: (federal_tax_number: untyped, name: String?, trade_name: String?, state_tax_number: untyped) -> instance + def initialize: (federal_tax_number: untyped, name: String?, trade_name: String?, state_tax_number: untyped) -> void + end + + class Buyer < Data + attr_reader federal_tax_number: untyped + attr_reader name: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Buyer? + def self.new: (federal_tax_number: untyped, name: String?) -> instance + def initialize: (federal_tax_number: untyped, name: String?) -> void + end + + class Total < Data + attr_reader total_amount: untyped + attr_reader coupon_amount: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Total? + def self.new: (total_amount: untyped, coupon_amount: untyped) -> instance + def initialize: (total_amount: untyped, coupon_amount: untyped) -> void + end + + class Delivery < Data + attr_reader address: Nfe::TaxCoupon::Address? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Delivery? + def self.new: (address: Nfe::TaxCoupon::Address?) -> instance + def initialize: (address: Nfe::TaxCoupon::Address?) -> void + end + + class Address < Data + attr_reader street: String? + attr_reader number: untyped + attr_reader district: String? + attr_reader postal_code: untyped + attr_reader city: untyped + attr_reader state: String? + attr_reader country: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Address? + def self.new: (street: String?, number: untyped, district: String?, postal_code: untyped, city: untyped, state: String?, country: String?) -> instance + def initialize: (street: String?, number: untyped, district: String?, postal_code: untyped, city: untyped, state: String?, country: String?) -> void + end + + class AdditionalInformation < Data + attr_reader taxpayer: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::AdditionalInformation? + def self.new: (taxpayer: untyped) -> instance + def initialize: (taxpayer: untyped) -> void + end + + class Item < Data + attr_reader code: untyped + attr_reader description: String? + attr_reader quantity: untyped + attr_reader unit_amount: untyped + attr_reader net_amount: untyped + attr_reader gross_amount: untyped + attr_reader cfop: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Item? + def self.new: (code: untyped, description: String?, quantity: untyped, unit_amount: untyped, net_amount: untyped, gross_amount: untyped, cfop: untyped) -> instance + def initialize: (code: untyped, description: String?, quantity: untyped, unit_amount: untyped, net_amount: untyped, gross_amount: untyped, cfop: untyped) -> void + end + + class PaymentDetail < Data + attr_reader method: untyped + attr_reader amount: untyped + attr_reader card: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::PaymentDetail? + def self.new: (method: untyped, amount: untyped, card: untyped) -> instance + def initialize: (method: untyped, amount: untyped, card: untyped) -> void + end + + class Payment < Data + attr_reader pay_back: untyped + attr_reader payment_details: Array[Nfe::TaxCoupon::PaymentDetail?] + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon::Payment? + def self.new: (pay_back: untyped, payment_details: Array[Nfe::TaxCoupon::PaymentDetail?]) -> instance + def initialize: (pay_back: untyped, payment_details: Array[Nfe::TaxCoupon::PaymentDetail?]) -> void + end + + attr_reader current_status: untyped + attr_reader number: untyped + attr_reader sat_serie: untyped + attr_reader software_version: String? + attr_reader software_federal_tax_number: untyped + attr_reader access_key: untyped + attr_reader cashier: untyped + attr_reader issued_on: String? + attr_reader created_on: String? + attr_reader xml_version: String? + attr_reader issuer: Nfe::TaxCoupon::Issuer? + attr_reader buyer: Nfe::TaxCoupon::Buyer? + attr_reader totals: Nfe::TaxCoupon::Total? + attr_reader delivery: Nfe::TaxCoupon::Delivery? + attr_reader additional_information: Nfe::TaxCoupon::AdditionalInformation? + attr_reader items: Array[Nfe::TaxCoupon::Item?] + attr_reader payment: Nfe::TaxCoupon::Payment? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCoupon? + def self.new: (current_status: untyped, number: untyped, sat_serie: untyped, software_version: String?, software_federal_tax_number: untyped, access_key: untyped, cashier: untyped, issued_on: String?, created_on: String?, xml_version: String?, issuer: Nfe::TaxCoupon::Issuer?, buyer: Nfe::TaxCoupon::Buyer?, totals: Nfe::TaxCoupon::Total?, delivery: Nfe::TaxCoupon::Delivery?, additional_information: Nfe::TaxCoupon::AdditionalInformation?, items: Array[Nfe::TaxCoupon::Item?], payment: Nfe::TaxCoupon::Payment?) -> instance + def initialize: (current_status: untyped, number: untyped, sat_serie: untyped, software_version: String?, software_federal_tax_number: untyped, access_key: untyped, cashier: untyped, issued_on: String?, created_on: String?, xml_version: String?, issuer: Nfe::TaxCoupon::Issuer?, buyer: Nfe::TaxCoupon::Buyer?, totals: Nfe::TaxCoupon::Total?, delivery: Nfe::TaxCoupon::Delivery?, additional_information: Nfe::TaxCoupon::AdditionalInformation?, items: Array[Nfe::TaxCoupon::Item?], payment: Nfe::TaxCoupon::Payment?) -> void + end +end diff --git a/sig/nfe/resources/dto/inbound_invoice_metadata.rbs b/sig/nfe/resources/dto/inbound_invoice_metadata.rbs new file mode 100644 index 0000000..4a08ad2 --- /dev/null +++ b/sig/nfe/resources/dto/inbound_invoice_metadata.rbs @@ -0,0 +1,21 @@ +module Nfe + class InboundInvoiceMetadata < Data + attr_reader access_key: String? + attr_reader nsu: untyped + attr_reader status: untyped + attr_reader name_sender: String? + attr_reader federal_tax_number_sender: String? + attr_reader total_invoice_amount: untyped + attr_reader issued_on: String? + attr_reader product_invoices: untyped + attr_reader details: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::InboundInvoiceMetadata? + + def self.stringify: (untyped value) -> String? + + def self.new: (access_key: String?, nsu: untyped, status: untyped, name_sender: String?, federal_tax_number_sender: String?, total_invoice_amount: untyped, issued_on: String?, product_invoices: untyped, details: untyped) -> instance + + def initialize: (access_key: String?, nsu: untyped, status: untyped, name_sender: String?, federal_tax_number_sender: String?, total_invoice_amount: untyped, issued_on: String?, product_invoices: untyped, details: untyped) -> void + end +end diff --git a/sig/nfe/resources/dto/inbound_settings.rbs b/sig/nfe/resources/dto/inbound_settings.rbs new file mode 100644 index 0000000..099bfaf --- /dev/null +++ b/sig/nfe/resources/dto/inbound_settings.rbs @@ -0,0 +1,20 @@ +module Nfe + class InboundSettings < Data + attr_reader id: String? + attr_reader status: untyped + attr_reader start_from_nsu: untyped + attr_reader start_from_date: String? + attr_reader environment_sefaz: String? + attr_reader automatic_manifesting: untyped + attr_reader webhook_version: untyped + attr_reader created_on: String? + attr_reader modified_on: String? + attr_reader details: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::InboundSettings? + + def self.new: (id: String?, status: untyped, start_from_nsu: untyped, start_from_date: String?, environment_sefaz: String?, automatic_manifesting: untyped, webhook_version: untyped, created_on: String?, modified_on: String?, details: untyped) -> instance + + def initialize: (id: String?, status: untyped, start_from_nsu: untyped, start_from_date: String?, environment_sefaz: String?, automatic_manifesting: untyped, webhook_version: untyped, created_on: String?, modified_on: String?, details: untyped) -> void + end +end diff --git a/sig/nfe/resources/dto/legal_entity_lookup/legal_entity_responses.rbs b/sig/nfe/resources/dto/legal_entity_lookup/legal_entity_responses.rbs new file mode 100644 index 0000000..e37b106 --- /dev/null +++ b/sig/nfe/resources/dto/legal_entity_lookup/legal_entity_responses.rbs @@ -0,0 +1,61 @@ +module Nfe + class LegalEntity < Data + attr_reader federal_tax_number: String? + attr_reader name: String? + attr_reader trade_name: String? + attr_reader status: untyped + attr_reader status_on: String? + attr_reader status_reason: String? + attr_reader legal_nature: untyped + attr_reader size: untyped + attr_reader opened_on: String? + attr_reader issued_on: String? + attr_reader special_status: String? + attr_reader special_status_on: String? + attr_reader responsable_entity: String? + attr_reader share_capital: untyped + attr_reader registration_unit: String? + attr_reader unit: untyped + attr_reader address: untyped + attr_reader phones: untyped + attr_reader email: String? + attr_reader economic_activities: untyped + attr_reader partners: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::LegalEntity? + + def self.new: (federal_tax_number: String?, name: String?, trade_name: String?, status: untyped, status_on: String?, status_reason: String?, legal_nature: untyped, size: untyped, opened_on: String?, issued_on: String?, special_status: String?, special_status_on: String?, responsable_entity: String?, share_capital: untyped, registration_unit: String?, unit: untyped, address: untyped, phones: untyped, email: String?, economic_activities: untyped, partners: untyped) -> instance + + def initialize: (federal_tax_number: String?, name: String?, trade_name: String?, status: untyped, status_on: String?, status_reason: String?, legal_nature: untyped, size: untyped, opened_on: String?, issued_on: String?, special_status: String?, special_status_on: String?, responsable_entity: String?, share_capital: untyped, registration_unit: String?, unit: untyped, address: untyped, phones: untyped, email: String?, economic_activities: untyped, partners: untyped) -> void + end + + class LegalEntityBasicInfoResponse < Data + attr_reader legal_entity: Nfe::LegalEntity? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::LegalEntityBasicInfoResponse? + + def self.new: (legal_entity: Nfe::LegalEntity?) -> instance + + def initialize: (legal_entity: Nfe::LegalEntity?) -> void + end + + class LegalEntityStateTaxResponse < Data + attr_reader legal_entity: Nfe::StateTaxLegalEntity? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::LegalEntityStateTaxResponse? + + def self.new: (legal_entity: Nfe::StateTaxLegalEntity?) -> instance + + def initialize: (legal_entity: Nfe::StateTaxLegalEntity?) -> void + end + + class LegalEntityStateTaxForInvoiceResponse < Data + attr_reader legal_entity: Nfe::StateTaxLegalEntity? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::LegalEntityStateTaxForInvoiceResponse? + + def self.new: (legal_entity: Nfe::StateTaxLegalEntity?) -> instance + + def initialize: (legal_entity: Nfe::StateTaxLegalEntity?) -> void + end +end diff --git a/sig/nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity.rbs b/sig/nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity.rbs new file mode 100644 index 0000000..d2fc9e0 --- /dev/null +++ b/sig/nfe/resources/dto/legal_entity_lookup/state_tax_legal_entity.rbs @@ -0,0 +1,71 @@ +module Nfe + class StateTaxLegalEntity < Data + class Address < Data + attr_reader street: String? + attr_reader number: String? + attr_reader district: String? + attr_reader postal_code: String? + attr_reader city: untyped + attr_reader state: String? + attr_reader country: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::StateTaxLegalEntity::Address? + def self.new: (street: String?, number: String?, district: String?, postal_code: String?, city: untyped, state: String?, country: String?) -> instance + def initialize: (street: String?, number: String?, district: String?, postal_code: String?, city: untyped, state: String?, country: String?) -> void + end + + class EconomicActivity < Data + attr_reader type: untyped + attr_reader code: String? + attr_reader description: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::StateTaxLegalEntity::EconomicActivity? + def self.new: (type: untyped, code: String?, description: String?) -> instance + def initialize: (type: untyped, code: String?, description: String?) -> void + end + + class FiscalDocumentInfo < Data + attr_reader status: untyped + attr_reader description: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::StateTaxLegalEntity::FiscalDocumentInfo? + def self.new: (status: untyped, description: String?) -> instance + def initialize: (status: untyped, description: String?) -> void + end + + class StateTax < Data + attr_reader status: untyped + attr_reader tax_number: String? + attr_reader status_on: String? + attr_reader opened_on: String? + attr_reader closed_on: String? + attr_reader additional_information: String? + attr_reader code: String? + attr_reader address: Nfe::StateTaxLegalEntity::Address? + attr_reader economic_activities: untyped + attr_reader nfe: Nfe::StateTaxLegalEntity::FiscalDocumentInfo? + attr_reader nfse: Nfe::StateTaxLegalEntity::FiscalDocumentInfo? + attr_reader cte: Nfe::StateTaxLegalEntity::FiscalDocumentInfo? + attr_reader nfce: Nfe::StateTaxLegalEntity::FiscalDocumentInfo? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::StateTaxLegalEntity::StateTax? + def self.new: (status: untyped, tax_number: String?, status_on: String?, opened_on: String?, closed_on: String?, additional_information: String?, code: String?, address: Nfe::StateTaxLegalEntity::Address?, economic_activities: untyped, nfe: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?, nfse: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?, cte: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?, nfce: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?) -> instance + def initialize: (status: untyped, tax_number: String?, status_on: String?, opened_on: String?, closed_on: String?, additional_information: String?, code: String?, address: Nfe::StateTaxLegalEntity::Address?, economic_activities: untyped, nfe: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?, nfse: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?, cte: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?, nfce: Nfe::StateTaxLegalEntity::FiscalDocumentInfo?) -> void + end + + attr_reader federal_tax_number: String? + attr_reader name: String? + attr_reader trade_name: String? + attr_reader tax_regime: untyped + attr_reader legal_nature: untyped + attr_reader fiscal_unit: String? + attr_reader created_unit: String? + attr_reader created_on: String? + attr_reader check_code: String? + attr_reader state_taxes: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::StateTaxLegalEntity? + def self.new: (federal_tax_number: String?, name: String?, trade_name: String?, tax_regime: untyped, legal_nature: untyped, fiscal_unit: String?, created_unit: String?, created_on: String?, check_code: String?, state_taxes: untyped) -> instance + def initialize: (federal_tax_number: String?, name: String?, trade_name: String?, tax_regime: untyped, legal_nature: untyped, fiscal_unit: String?, created_unit: String?, created_on: String?, check_code: String?, state_taxes: untyped) -> void + end +end diff --git a/sig/nfe/resources/dto/legal_person.rbs b/sig/nfe/resources/dto/legal_person.rbs new file mode 100644 index 0000000..35ebfdb --- /dev/null +++ b/sig/nfe/resources/dto/legal_person.rbs @@ -0,0 +1,18 @@ +module Nfe + class LegalPerson < Data + attr_reader id: String? + attr_reader name: String? + attr_reader trade_name: String? + attr_reader federal_tax_number: String? + attr_reader email: String? + attr_reader address: untyped + attr_reader created_on: String? + attr_reader modified_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::LegalPerson? + + def self.new: (id: String?, name: String?, trade_name: String?, federal_tax_number: String?, email: String?, address: untyped, created_on: String?, modified_on: String?) -> instance + + def initialize: (id: String?, name: String?, trade_name: String?, federal_tax_number: String?, email: String?, address: untyped, created_on: String?, modified_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/natural_person.rbs b/sig/nfe/resources/dto/natural_person.rbs new file mode 100644 index 0000000..5832247 --- /dev/null +++ b/sig/nfe/resources/dto/natural_person.rbs @@ -0,0 +1,17 @@ +module Nfe + class NaturalPerson < Data + attr_reader id: String? + attr_reader name: String? + attr_reader federal_tax_number: String? + attr_reader email: String? + attr_reader address: untyped + attr_reader created_on: String? + attr_reader modified_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::NaturalPerson? + + def self.new: (id: String?, name: String?, federal_tax_number: String?, email: String?, address: untyped, created_on: String?, modified_on: String?) -> instance + + def initialize: (id: String?, name: String?, federal_tax_number: String?, email: String?, address: untyped, created_on: String?, modified_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rbs b/sig/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rbs new file mode 100644 index 0000000..c022be6 --- /dev/null +++ b/sig/nfe/resources/dto/natural_person_lookup/natural_person_status_response.rbs @@ -0,0 +1,15 @@ +module Nfe + class NaturalPersonStatusResponse < Data + attr_reader name: String? + attr_reader federal_tax_number: String? + attr_reader birth_on: String? + attr_reader status: String? + attr_reader created_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::NaturalPersonStatusResponse? + + def self.new: (name: String?, federal_tax_number: String?, birth_on: String?, status: String?, created_on: String?) -> instance + + def initialize: (name: String?, federal_tax_number: String?, birth_on: String?, status: String?, created_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/nfe_file_resource.rbs b/sig/nfe/resources/dto/nfe_file_resource.rbs new file mode 100644 index 0000000..a6596e7 --- /dev/null +++ b/sig/nfe/resources/dto/nfe_file_resource.rbs @@ -0,0 +1,13 @@ +module Nfe + class NfeFileResource < Data + attr_reader uri: String? + attr_reader name: String? + attr_reader content_type: String? + attr_reader size: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::NfeFileResource? + + def self.new: (?uri: String?, ?name: String?, ?content_type: String?, ?size: untyped) -> instance + def initialize: (?uri: String?, ?name: String?, ?content_type: String?, ?size: untyped) -> void + end +end diff --git a/sig/nfe/resources/dto/product_invoice.rbs b/sig/nfe/resources/dto/product_invoice.rbs new file mode 100644 index 0000000..b08daeb --- /dev/null +++ b/sig/nfe/resources/dto/product_invoice.rbs @@ -0,0 +1,26 @@ +module Nfe + class ProductInvoice < Data + attr_reader id: String? + attr_reader flow_status: String? + attr_reader flow_message: String? + attr_reader status: untyped + attr_reader environment: untyped + attr_reader serie: untyped + attr_reader number: untyped + attr_reader operation_nature: untyped + attr_reader operation_type: untyped + attr_reader access_key: String? + attr_reader protocol: untyped + attr_reader buyer: untyped + attr_reader items: untyped + attr_reader totals: untyped + attr_reader issued_on: String? + attr_reader created_on: String? + attr_reader modified_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ProductInvoice? + + def self.new: (id: String?, flow_status: String?, flow_message: String?, status: untyped, environment: untyped, serie: untyped, number: untyped, operation_nature: untyped, operation_type: untyped, access_key: String?, protocol: untyped, buyer: untyped, items: untyped, totals: untyped, issued_on: String?, created_on: String?, modified_on: String?) -> instance + def initialize: (id: String?, flow_status: String?, flow_message: String?, status: untyped, environment: untyped, serie: untyped, number: untyped, operation_nature: untyped, operation_type: untyped, access_key: String?, protocol: untyped, buyer: untyped, items: untyped, totals: untyped, issued_on: String?, created_on: String?, modified_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/product_invoice_query/product_invoice_details.rbs b/sig/nfe/resources/dto/product_invoice_query/product_invoice_details.rbs new file mode 100644 index 0000000..d89aa4b --- /dev/null +++ b/sig/nfe/resources/dto/product_invoice_query/product_invoice_details.rbs @@ -0,0 +1,53 @@ +module Nfe + class ProductInvoiceDetails < Data + class Issuer < Data + attr_reader federal_tax_number: String? + attr_reader name: String? + attr_reader trade_name: String? + attr_reader state_tax_number: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ProductInvoiceDetails::Issuer? + def self.new: (federal_tax_number: String?, name: String?, trade_name: String?, state_tax_number: String?) -> instance + def initialize: (federal_tax_number: String?, name: String?, trade_name: String?, state_tax_number: String?) -> void + end + + class Buyer < Data + attr_reader federal_tax_number: String? + attr_reader name: String? + attr_reader state_tax_number: String? + attr_reader email: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ProductInvoiceDetails::Buyer? + def self.new: (federal_tax_number: String?, name: String?, state_tax_number: String?, email: String?) -> instance + def initialize: (federal_tax_number: String?, name: String?, state_tax_number: String?, email: String?) -> void + end + + class Totals < Data + attr_reader product_amount: untyped + attr_reader invoice_amount: untyped + attr_reader discount_amount: untyped + attr_reader icms_amount: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ProductInvoiceDetails::Totals? + def self.new: (product_amount: untyped, invoice_amount: untyped, discount_amount: untyped, icms_amount: untyped) -> instance + def initialize: (product_amount: untyped, invoice_amount: untyped, discount_amount: untyped, icms_amount: untyped) -> void + end + + attr_reader current_status: String? + attr_reader state_code: untyped + attr_reader check_code: String? + attr_reader operation_nature: String? + attr_reader serie: untyped + attr_reader number: untyped + attr_reader issued_on: String? + attr_reader operation_on: String? + attr_reader issuer: Nfe::ProductInvoiceDetails::Issuer? + attr_reader buyer: Nfe::ProductInvoiceDetails::Buyer? + attr_reader totals: Nfe::ProductInvoiceDetails::Totals? + attr_reader items: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ProductInvoiceDetails? + def self.new: (current_status: String?, state_code: untyped, check_code: String?, operation_nature: String?, serie: untyped, number: untyped, issued_on: String?, operation_on: String?, issuer: Nfe::ProductInvoiceDetails::Issuer?, buyer: Nfe::ProductInvoiceDetails::Buyer?, totals: Nfe::ProductInvoiceDetails::Totals?, items: untyped) -> instance + def initialize: (current_status: String?, state_code: untyped, check_code: String?, operation_nature: String?, serie: untyped, number: untyped, issued_on: String?, operation_on: String?, issuer: Nfe::ProductInvoiceDetails::Issuer?, buyer: Nfe::ProductInvoiceDetails::Buyer?, totals: Nfe::ProductInvoiceDetails::Totals?, items: untyped) -> void + end +end diff --git a/sig/nfe/resources/dto/product_invoice_query/product_invoice_events_response.rbs b/sig/nfe/resources/dto/product_invoice_query/product_invoice_events_response.rbs new file mode 100644 index 0000000..03b5790 --- /dev/null +++ b/sig/nfe/resources/dto/product_invoice_query/product_invoice_events_response.rbs @@ -0,0 +1,12 @@ +module Nfe + class ProductInvoiceEventsResponse < Data + attr_reader events: untyped + attr_reader created_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ProductInvoiceEventsResponse? + + def self.new: (events: untyped, created_on: String?) -> instance + + def initialize: (events: untyped, created_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/service_invoice.rbs b/sig/nfe/resources/dto/service_invoice.rbs new file mode 100644 index 0000000..8a626a8 --- /dev/null +++ b/sig/nfe/resources/dto/service_invoice.rbs @@ -0,0 +1,30 @@ +module Nfe + class ServiceInvoice < Data + attr_reader id: String? + attr_reader flow_status: String? + attr_reader flow_message: String? + attr_reader status: untyped + attr_reader environment: untyped + attr_reader rps_number: untyped + attr_reader rps_serial_number: untyped + attr_reader number: untyped + attr_reader check_code: String? + attr_reader issued_on: String? + attr_reader cancelled_on: String? + attr_reader amount_net: untyped + attr_reader services_amount: untyped + attr_reader borrower: untyped + attr_reader city_service_code: untyped + attr_reader federal_service_code: untyped + attr_reader description: String? + attr_reader pdf: untyped + attr_reader xml: untyped + attr_reader created_on: String? + attr_reader modified_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::ServiceInvoice? + + def self.new: (id: String?, flow_status: String?, flow_message: String?, status: untyped, environment: untyped, rps_number: untyped, rps_serial_number: untyped, number: untyped, check_code: String?, issued_on: String?, cancelled_on: String?, amount_net: untyped, services_amount: untyped, borrower: untyped, city_service_code: untyped, federal_service_code: untyped, description: String?, pdf: untyped, xml: untyped, created_on: String?, modified_on: String?) -> instance + def initialize: (id: String?, flow_status: String?, flow_message: String?, status: untyped, environment: untyped, rps_number: untyped, rps_serial_number: untyped, number: untyped, check_code: String?, issued_on: String?, cancelled_on: String?, amount_net: untyped, services_amount: untyped, borrower: untyped, city_service_code: untyped, federal_service_code: untyped, description: String?, pdf: untyped, xml: untyped, created_on: String?, modified_on: String?) -> void + end +end diff --git a/sig/nfe/resources/dto/state_taxes/nfe_state_tax.rbs b/sig/nfe/resources/dto/state_taxes/nfe_state_tax.rbs new file mode 100644 index 0000000..32702ff --- /dev/null +++ b/sig/nfe/resources/dto/state_taxes/nfe_state_tax.rbs @@ -0,0 +1,17 @@ +module Nfe + class NfeStateTax < Data + attr_reader id: String? + attr_reader tax_number: untyped + attr_reader serie: untyped + attr_reader number: untyped + attr_reader code: untyped + attr_reader environment_type: untyped + attr_reader type: untyped + attr_reader status: untyped + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::NfeStateTax? + + def self.new: (id: String?, tax_number: untyped, serie: untyped, number: untyped, code: untyped, environment_type: untyped, type: untyped, status: untyped) -> instance + def initialize: (id: String?, tax_number: untyped, serie: untyped, number: untyped, code: untyped, environment_type: untyped, type: untyped, status: untyped) -> void + end +end diff --git a/sig/nfe/resources/dto/tax_codes/tax_code_paginated_response.rbs b/sig/nfe/resources/dto/tax_codes/tax_code_paginated_response.rbs new file mode 100644 index 0000000..1b54192 --- /dev/null +++ b/sig/nfe/resources/dto/tax_codes/tax_code_paginated_response.rbs @@ -0,0 +1,23 @@ +module Nfe + class TaxCode < Data + attr_reader code: String? + attr_reader description: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCode? + + def self.new: (code: String?, description: String?) -> instance + def initialize: (code: String?, description: String?) -> void + end + + class TaxCodePaginatedResponse < Data + attr_reader current_page: untyped + attr_reader total_pages: untyped + attr_reader total_count: untyped + attr_reader items: Array[Nfe::TaxCode?] + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::TaxCodePaginatedResponse? + + def self.new: (current_page: untyped, total_pages: untyped, total_count: untyped, items: Array[Nfe::TaxCode?]) -> instance + def initialize: (current_page: untyped, total_pages: untyped, total_count: untyped, items: Array[Nfe::TaxCode?]) -> void + end +end diff --git a/sig/nfe/resources/dto/webhook.rbs b/sig/nfe/resources/dto/webhook.rbs new file mode 100644 index 0000000..1beb9e4 --- /dev/null +++ b/sig/nfe/resources/dto/webhook.rbs @@ -0,0 +1,18 @@ +module Nfe + class WebhookSubscription < Data + attr_reader id: String? + attr_reader url: String? + attr_reader events: Array[String]? + attr_reader secret: String? + attr_reader active: bool? + attr_reader status: untyped + attr_reader created_on: String? + attr_reader modified_on: String? + + def self.from_api: (Hash[untyped, untyped]? payload) -> Nfe::WebhookSubscription? + + def self.new: (id: String?, url: String?, events: Array[String]?, secret: String?, active: bool?, status: untyped, created_on: String?, modified_on: String?) -> instance + + def initialize: (id: String?, url: String?, events: Array[String]?, secret: String?, active: bool?, status: untyped, created_on: String?, modified_on: String?) -> void + end +end diff --git a/sig/nfe/resources/inbound_product_invoices.rbs b/sig/nfe/resources/inbound_product_invoices.rbs new file mode 100644 index 0000000..dcc91f7 --- /dev/null +++ b/sig/nfe/resources/inbound_product_invoices.rbs @@ -0,0 +1,36 @@ +module Nfe + module Resources + class InboundProductInvoices < AbstractResource + MANIFEST_AWARENESS: Integer + MANIFEST_CONFIRMATION: Integer + MANIFEST_NOT_PERFORMED: Integer + + def api_family: () -> Symbol + def api_version: () -> String + + def enable_auto_fetch: (company_id: String, ?start_from_nsu: untyped, ?start_from_date: String?, ?environment_sefaz: String?, ?automatic_manifesting: untyped, ?webhook_version: untyped) -> Nfe::InboundSettings? + def disable_auto_fetch: (company_id: String) -> Nfe::InboundSettings? + def get_settings: (company_id: String) -> Nfe::InboundSettings? + def get_details: (company_id: String, access_key: String) -> Nfe::InboundInvoiceMetadata? + def get_product_invoice_details: (company_id: String, access_key: String) -> Nfe::InboundInvoiceMetadata? + def get_event_details: (company_id: String, access_key: String, event_key: String) -> Nfe::InboundInvoiceMetadata? + def get_product_invoice_event_details: (company_id: String, access_key: String, event_key: String) -> Nfe::InboundInvoiceMetadata? + def get_xml: (company_id: String, access_key: String) -> String + def get_event_xml: (company_id: String, access_key: String, event_key: String) -> String + def get_pdf: (company_id: String, access_key: String) -> String + def get_json: (company_id: String, access_key: String) -> Nfe::InboundInvoiceMetadata? + def manifest: (company_id: String, access_key: String, ?tp_event: Integer) -> String + def reprocess_webhook: (company_id: String, access_key_or_nsu: untyped) -> Nfe::InboundInvoiceMetadata? + + private + + def company_and_key: (String company_id, String access_key) -> [ String, String ] + def company_key_event: (String company_id, String access_key, String event_key) -> [ String, String, String ] + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def xml_accept: () -> Hash[String, String] + def pdf_accept: () -> Hash[String, String] + def compact: (Hash[untyped, untyped] hash) -> Hash[untyped, untyped] + end + end +end diff --git a/sig/nfe/resources/legal_entity_lookup.rbs b/sig/nfe/resources/legal_entity_lookup.rbs new file mode 100644 index 0000000..44d47d9 --- /dev/null +++ b/sig/nfe/resources/legal_entity_lookup.rbs @@ -0,0 +1,13 @@ +module Nfe + module Resources + class LegalEntityLookup < AbstractResource + def get_basic_info: (untyped federal_tax_number, ?update_address: untyped, ?update_city_code: untyped) -> Nfe::LegalEntityBasicInfoResponse? + def get_state_tax_info: (untyped state, untyped federal_tax_number) -> Nfe::LegalEntityStateTaxResponse? + def get_state_tax_for_invoice: (untyped state, untyped federal_tax_number) -> Nfe::LegalEntityStateTaxForInvoiceResponse? + def get_suggested_state_tax_for_invoice: (untyped state, untyped federal_tax_number) -> Nfe::LegalEntityStateTaxForInvoiceResponse? + + def api_family: () -> Symbol + def api_version: () -> String + end + end +end diff --git a/sig/nfe/resources/legal_people.rbs b/sig/nfe/resources/legal_people.rbs new file mode 100644 index 0000000..aa5f889 --- /dev/null +++ b/sig/nfe/resources/legal_people.rbs @@ -0,0 +1,22 @@ +module Nfe + module Resources + class LegalPeople < AbstractResource + ENVELOPE: String + + def api_family: () -> Symbol + + def list: (String company_id) -> Nfe::ListResponse + def create: (String company_id, Hash[untyped, untyped] data) -> Nfe::LegalPerson? + def retrieve: (String company_id, String legal_person_id) -> Nfe::LegalPerson? + def update: (String company_id, String legal_person_id, Hash[untyped, untyped] data) -> Nfe::LegalPerson? + def delete: (String company_id, String legal_person_id) -> nil + def create_batch: (String company_id, Array[Hash[untyped, untyped]] list) -> Array[Nfe::LegalPerson?] + def find_by_tax_number: (String company_id, String federal_tax_number) -> Nfe::LegalPerson? + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + end + end +end diff --git a/sig/nfe/resources/natural_people.rbs b/sig/nfe/resources/natural_people.rbs new file mode 100644 index 0000000..e6b6dab --- /dev/null +++ b/sig/nfe/resources/natural_people.rbs @@ -0,0 +1,22 @@ +module Nfe + module Resources + class NaturalPeople < AbstractResource + ENVELOPE: String + + def api_family: () -> Symbol + + def list: (String company_id) -> Nfe::ListResponse + def create: (String company_id, Hash[untyped, untyped] data) -> Nfe::NaturalPerson? + def retrieve: (String company_id, String natural_person_id) -> Nfe::NaturalPerson? + def update: (String company_id, String natural_person_id, Hash[untyped, untyped] data) -> Nfe::NaturalPerson? + def delete: (String company_id, String natural_person_id) -> nil + def create_batch: (String company_id, Array[Hash[untyped, untyped]] list) -> Array[Nfe::NaturalPerson?] + def find_by_tax_number: (String company_id, String federal_tax_number) -> Nfe::NaturalPerson? + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + end + end +end diff --git a/sig/nfe/resources/natural_person_lookup.rbs b/sig/nfe/resources/natural_person_lookup.rbs new file mode 100644 index 0000000..aeebb3d --- /dev/null +++ b/sig/nfe/resources/natural_person_lookup.rbs @@ -0,0 +1,10 @@ +module Nfe + module Resources + class NaturalPersonLookup < AbstractResource + def get_status: (untyped federal_tax_number, untyped birth_date) -> Nfe::NaturalPersonStatusResponse? + + def api_family: () -> Symbol + def api_version: () -> String + end + end +end diff --git a/sig/nfe/resources/product_invoice_query.rbs b/sig/nfe/resources/product_invoice_query.rbs new file mode 100644 index 0000000..5816e6b --- /dev/null +++ b/sig/nfe/resources/product_invoice_query.rbs @@ -0,0 +1,13 @@ +module Nfe + module Resources + class ProductInvoiceQuery < AbstractResource + def retrieve: (untyped access_key) -> Nfe::ProductInvoiceDetails? + def download_pdf: (untyped access_key) -> String + def download_xml: (untyped access_key) -> String + def list_events: (untyped access_key) -> Nfe::ProductInvoiceEventsResponse? + + def api_family: () -> Symbol + def api_version: () -> String + end + end +end diff --git a/sig/nfe/resources/product_invoices.rbs b/sig/nfe/resources/product_invoices.rbs new file mode 100644 index 0000000..d8f8fa1 --- /dev/null +++ b/sig/nfe/resources/product_invoices.rbs @@ -0,0 +1,39 @@ +module Nfe + module Resources + class ProductInvoices < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + def create: (company_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ProductInvoicePending | Nfe::Resources::ProductInvoiceIssued) + def create_with_state_tax: (company_id: String, state_tax_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ProductInvoicePending | Nfe::Resources::ProductInvoiceIssued) + def list: (company_id: String, environment: String, **untyped options) -> Nfe::ListResponse + def retrieve: (company_id: String, invoice_id: String) -> Nfe::ProductInvoice? + def cancel: (company_id: String, invoice_id: String, ?reason: String?) -> Hash[untyped, untyped] + def list_items: (company_id: String, invoice_id: String, ?limit: Integer?, ?starting_after: String?) -> Nfe::ListResponse + def list_events: (company_id: String, invoice_id: String, ?limit: Integer?, ?starting_after: String?) -> Nfe::ListResponse + def download_pdf: (company_id: String, invoice_id: String, ?force: bool?) -> Nfe::NfeFileResource? + def download_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def download_rejection_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def download_epec_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def send_correction_letter: (company_id: String, invoice_id: String, reason: String) -> Hash[untyped, untyped] + def download_correction_letter_pdf: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def download_correction_letter_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def disable: (company_id: String, invoice_id: String, ?reason: String?) -> Hash[untyped, untyped] + def disable_range: (company_id: String, data: Hash[untyped, untyped]) -> Hash[untyped, untyped] + + private + + def base_path: (String company_id) -> String + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def require_environment: (untyped environment) -> void + def cursor_query: (Hash[Symbol, untyped] options) -> Hash[Symbol, untyped] + def validate_correction_reason: (untyped reason) -> void + def sub_list: (company_id: String, invoice_id: String, segment: String, limit: untyped, starting_after: untyped, wrapper_key: String) -> Nfe::ListResponse + def file_resource: (company_id: String, invoice_id: String, segment: String, ?query: Hash[untyped, untyped]) -> Nfe::NfeFileResource? + def discriminate: (Nfe::Http::Response response) -> (Nfe::Resources::ProductInvoicePending | Nfe::Resources::ProductInvoiceIssued) + def build_pending: (Nfe::Http::Response response) -> Nfe::Resources::ProductInvoicePending + def extract_invoice_id: (String? location) -> String? + end + end +end diff --git a/sig/nfe/resources/product_invoices_rtc.rbs b/sig/nfe/resources/product_invoices_rtc.rbs new file mode 100644 index 0000000..12cc9ee --- /dev/null +++ b/sig/nfe/resources/product_invoices_rtc.rbs @@ -0,0 +1,38 @@ +module Nfe + module Resources + class ProductInvoicesRtc < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + def create: (company_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ProductInvoiceRtcPending | Nfe::Resources::ProductInvoiceRtcIssued) + def create_with_state_tax: (company_id: String, state_tax_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ProductInvoiceRtcPending | Nfe::Resources::ProductInvoiceRtcIssued) + def list: (company_id: String, environment: String, ?starting_after: String?, ?ending_before: String?, ?limit: Integer?, ?q: String?) -> Nfe::ListResponse + def retrieve: (company_id: String, invoice_id: String) -> Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource? + def cancel: (company_id: String, invoice_id: String, ?reason: String?) -> Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource? + def list_items: (company_id: String, invoice_id: String) -> Nfe::Generated::ProductInvoiceRtcV1::InvoiceItemsResource? + def list_events: (company_id: String, invoice_id: String) -> Nfe::Generated::ProductInvoiceRtcV1::InvoiceEventsResource? + def download_pdf: (company_id: String, invoice_id: String, ?force: bool) -> Nfe::NfeFileResource? + def download_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def download_rejection_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def download_epec_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def send_correction_letter: (company_id: String, invoice_id: String, reason: String) -> Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource? + def download_correction_letter_pdf: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def download_correction_letter_xml: (company_id: String, invoice_id: String) -> Nfe::NfeFileResource? + def disable: (company_id: String, invoice_id: String, ?reason: String?) -> Nfe::Generated::ProductInvoiceRtcV1::DisablementResource? + def disable_range: (company_id: String, data: Hash[untyped, untyped]) -> Nfe::Generated::ProductInvoiceRtcV1::DisablementResource? + + private + + def base_path: (String company_id) -> String + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def require_environment: (untyped environment) -> void + def list_query: (starting_after: untyped, ending_before: untyped, limit: untyped, q: untyped) -> Hash[Symbol, untyped] + def validate_correction_reason: (untyped reason) -> void + def file_resource: (company_id: String, invoice_id: String, segment: String, ?query: Hash[untyped, untyped]) -> Nfe::NfeFileResource? + def discriminate: (Nfe::Http::Response response) -> (Nfe::Resources::ProductInvoiceRtcPending | Nfe::Resources::ProductInvoiceRtcIssued) + def build_pending: (Nfe::Http::Response response) -> Nfe::Resources::ProductInvoiceRtcPending + def extract_invoice_id: (String? location) -> String? + end + end +end diff --git a/sig/nfe/resources/responses/product_invoice_issued.rbs b/sig/nfe/resources/responses/product_invoice_issued.rbs new file mode 100644 index 0000000..d341c64 --- /dev/null +++ b/sig/nfe/resources/responses/product_invoice_issued.rbs @@ -0,0 +1,13 @@ +module Nfe + module Resources + class ProductInvoiceIssued < Data + attr_reader resource: untyped + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (resource: untyped) -> instance + def initialize: (resource: untyped) -> void + end + end +end diff --git a/sig/nfe/resources/responses/product_invoice_pending.rbs b/sig/nfe/resources/responses/product_invoice_pending.rbs new file mode 100644 index 0000000..94c83ec --- /dev/null +++ b/sig/nfe/resources/responses/product_invoice_pending.rbs @@ -0,0 +1,14 @@ +module Nfe + module Resources + class ProductInvoicePending < Data + attr_reader invoice_id: String + attr_reader location: String + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (invoice_id: String, location: String) -> instance + def initialize: (invoice_id: String, location: String) -> void + end + end +end diff --git a/sig/nfe/resources/responses/product_invoice_rtc_issued.rbs b/sig/nfe/resources/responses/product_invoice_rtc_issued.rbs new file mode 100644 index 0000000..44c290c --- /dev/null +++ b/sig/nfe/resources/responses/product_invoice_rtc_issued.rbs @@ -0,0 +1,13 @@ +module Nfe + module Resources + class ProductInvoiceRtcIssued < Data + attr_reader resource: untyped + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (resource: untyped) -> instance + def initialize: (resource: untyped) -> void + end + end +end diff --git a/sig/nfe/resources/responses/product_invoice_rtc_pending.rbs b/sig/nfe/resources/responses/product_invoice_rtc_pending.rbs new file mode 100644 index 0000000..762a695 --- /dev/null +++ b/sig/nfe/resources/responses/product_invoice_rtc_pending.rbs @@ -0,0 +1,14 @@ +module Nfe + module Resources + class ProductInvoiceRtcPending < Data + attr_reader invoice_id: String + attr_reader location: String + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (invoice_id: String, location: String) -> instance + def initialize: (invoice_id: String, location: String) -> void + end + end +end diff --git a/sig/nfe/resources/responses/service_invoice_issued.rbs b/sig/nfe/resources/responses/service_invoice_issued.rbs new file mode 100644 index 0000000..35b73e2 --- /dev/null +++ b/sig/nfe/resources/responses/service_invoice_issued.rbs @@ -0,0 +1,13 @@ +module Nfe + module Resources + class ServiceInvoiceIssued < Data + attr_reader resource: untyped + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (resource: untyped) -> instance + def initialize: (resource: untyped) -> void + end + end +end diff --git a/sig/nfe/resources/responses/service_invoice_pending.rbs b/sig/nfe/resources/responses/service_invoice_pending.rbs new file mode 100644 index 0000000..9ab2abc --- /dev/null +++ b/sig/nfe/resources/responses/service_invoice_pending.rbs @@ -0,0 +1,14 @@ +module Nfe + module Resources + class ServiceInvoicePending < Data + attr_reader invoice_id: String + attr_reader location: String + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (invoice_id: String, location: String) -> instance + def initialize: (invoice_id: String, location: String) -> void + end + end +end diff --git a/sig/nfe/resources/responses/service_invoice_rtc_issued.rbs b/sig/nfe/resources/responses/service_invoice_rtc_issued.rbs new file mode 100644 index 0000000..6eb17a3 --- /dev/null +++ b/sig/nfe/resources/responses/service_invoice_rtc_issued.rbs @@ -0,0 +1,13 @@ +module Nfe + module Resources + class ServiceInvoiceRtcIssued < Data + attr_reader resource: untyped + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (resource: untyped) -> instance + def initialize: (resource: untyped) -> void + end + end +end diff --git a/sig/nfe/resources/responses/service_invoice_rtc_pending.rbs b/sig/nfe/resources/responses/service_invoice_rtc_pending.rbs new file mode 100644 index 0000000..fe5b702 --- /dev/null +++ b/sig/nfe/resources/responses/service_invoice_rtc_pending.rbs @@ -0,0 +1,14 @@ +module Nfe + module Resources + class ServiceInvoiceRtcPending < Data + attr_reader invoice_id: String + attr_reader location: String + + def pending?: () -> bool + def issued?: () -> bool + + def self.new: (invoice_id: String, location: String) -> instance + def initialize: (invoice_id: String, location: String) -> void + end + end +end diff --git a/sig/nfe/resources/service_invoices.rbs b/sig/nfe/resources/service_invoices.rbs new file mode 100644 index 0000000..04419a1 --- /dev/null +++ b/sig/nfe/resources/service_invoices.rbs @@ -0,0 +1,41 @@ +module Nfe + module Resources + class ServiceInvoices < AbstractResource + class StatusResult < Data + attr_reader status: String + attr_reader invoice: Nfe::ServiceInvoice? + attr_reader complete: bool + attr_reader failed: bool + + def complete?: () -> bool + def failed?: () -> bool + + def self.new: (status: String, invoice: Nfe::ServiceInvoice?, complete: bool, failed: bool) -> instance + def initialize: (status: String, invoice: Nfe::ServiceInvoice?, complete: bool, failed: bool) -> void + end + + FAILED_STATUSES: Array[String] + + def api_family: () -> Symbol + + def create: (company_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ServiceInvoicePending | Nfe::Resources::ServiceInvoiceIssued) + def list: (company_id: String, **untyped options) -> Nfe::ListResponse + def retrieve: (company_id: String, invoice_id: String) -> Nfe::ServiceInvoice? + def cancel: (company_id: String, invoice_id: String) -> Nfe::ServiceInvoice? + def send_email: (company_id: String, invoice_id: String) -> { sent: untyped, message: untyped } + def download_pdf: (company_id: String, ?invoice_id: String?) -> String + def download_xml: (company_id: String, ?invoice_id: String?) -> String + def get_status: (company_id: String, invoice_id: String) -> Nfe::Resources::ServiceInvoices::StatusResult + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def list_query: (Hash[Symbol, untyped] options) -> Hash[Symbol, untyped] + def download_document: (company_id: String, invoice_id: String?, ext: String, accept: String) -> String + def discriminate: (Nfe::Http::Response response) -> (Nfe::Resources::ServiceInvoicePending | Nfe::Resources::ServiceInvoiceIssued) + def build_pending: (Nfe::Http::Response response) -> Nfe::Resources::ServiceInvoicePending + def extract_invoice_id: (String? location) -> String? + end + end +end diff --git a/sig/nfe/resources/service_invoices_rtc.rbs b/sig/nfe/resources/service_invoices_rtc.rbs new file mode 100644 index 0000000..87a4706 --- /dev/null +++ b/sig/nfe/resources/service_invoices_rtc.rbs @@ -0,0 +1,21 @@ +module Nfe + module Resources + class ServiceInvoicesRtc < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + def create: (company_id: String, data: Hash[untyped, untyped], ?idempotency_key: String?, ?request_options: Nfe::RequestOptions?) -> (Nfe::Resources::ServiceInvoiceRtcPending | Nfe::Resources::ServiceInvoiceRtcIssued) + def retrieve: (company_id: String, invoice_id: String) -> Nfe::ServiceInvoice? + def cancel: (company_id: String, invoice_id: String) -> Nfe::ServiceInvoice? + def download_cancellation_xml: (company_id: String, invoice_id: String) -> String + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def discriminate: (Nfe::Http::Response response) -> (Nfe::Resources::ServiceInvoiceRtcPending | Nfe::Resources::ServiceInvoiceRtcIssued) + def build_pending: (Nfe::Http::Response response) -> Nfe::Resources::ServiceInvoiceRtcPending + def extract_rtc_invoice_id: (String? location) -> String? + end + end +end diff --git a/sig/nfe/resources/state_taxes.rbs b/sig/nfe/resources/state_taxes.rbs new file mode 100644 index 0000000..15814bb --- /dev/null +++ b/sig/nfe/resources/state_taxes.rbs @@ -0,0 +1,22 @@ +module Nfe + module Resources + class StateTaxes < AbstractResource + ENVELOPE: String + LIST_ENVELOPE: String + + def api_family: () -> Symbol + def api_version: () -> String + + def list: (String company_id, ?starting_after: untyped, ?ending_before: untyped, ?limit: untyped) -> Nfe::ListResponse + def create: (String company_id, Hash[untyped, untyped] data) -> Nfe::NfeStateTax? + def retrieve: (String company_id, String state_tax_id) -> Nfe::NfeStateTax? + def update: (String company_id, String state_tax_id, Hash[untyped, untyped] data) -> Nfe::NfeStateTax? + def delete: (String company_id, String state_tax_id) -> nil + + private + + def base_path: (String company_id) -> String + def json_headers: () -> Hash[String, String] + end + end +end diff --git a/sig/nfe/resources/tax_calculation.rbs b/sig/nfe/resources/tax_calculation.rbs new file mode 100644 index 0000000..a478562 --- /dev/null +++ b/sig/nfe/resources/tax_calculation.rbs @@ -0,0 +1,18 @@ +module Nfe + module Resources + class TaxCalculation < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + # +request+ accepts a plain Hash; build it from + # Nfe::Generated::CalculoImpostosV1::CalculateRequest#to_h for type-safety. + def calculate: (String tenant_id, Hash[untyped, untyped] request) -> Nfe::Generated::CalculoImpostosV1::CalculateResponse? + + private + + def validate_calculate!: (String tenant_id, untyped request) -> void + def operation_type?: (Hash[untyped, untyped] request) -> bool + def items?: (Hash[untyped, untyped] request) -> bool + end + end +end diff --git a/sig/nfe/resources/tax_codes.rbs b/sig/nfe/resources/tax_codes.rbs new file mode 100644 index 0000000..7ab54b4 --- /dev/null +++ b/sig/nfe/resources/tax_codes.rbs @@ -0,0 +1,17 @@ +module Nfe + module Resources + class TaxCodes < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + def list_operation_codes: (?page_index: Integer?, ?page_count: Integer?) -> Nfe::TaxCodePaginatedResponse? + def list_acquisition_purposes: (?page_index: Integer?, ?page_count: Integer?) -> Nfe::TaxCodePaginatedResponse? + def list_issuer_tax_profiles: (?page_index: Integer?, ?page_count: Integer?) -> Nfe::TaxCodePaginatedResponse? + def list_recipient_tax_profiles: (?page_index: Integer?, ?page_count: Integer?) -> Nfe::TaxCodePaginatedResponse? + + private + + def list_tax_codes: (String path, Integer? page_index, Integer? page_count) -> Nfe::TaxCodePaginatedResponse? + end + end +end diff --git a/sig/nfe/resources/transportation_invoices.rbs b/sig/nfe/resources/transportation_invoices.rbs new file mode 100644 index 0000000..0d0f63b --- /dev/null +++ b/sig/nfe/resources/transportation_invoices.rbs @@ -0,0 +1,23 @@ +module Nfe + module Resources + class TransportationInvoices < AbstractResource + def api_family: () -> Symbol + def api_version: () -> String + + def enable: (company_id: String, ?start_from_nsu: untyped, ?start_from_date: String?) -> Nfe::InboundSettings? + def disable: (company_id: String) -> Nfe::InboundSettings? + def get_settings: (company_id: String) -> Nfe::InboundSettings? + def retrieve: (company_id: String, access_key: String) -> Nfe::InboundInvoiceMetadata? + def download_xml: (company_id: String, access_key: String) -> String + def get_event: (company_id: String, access_key: String, event_key: String) -> Nfe::InboundInvoiceMetadata? + def download_event_xml: (company_id: String, access_key: String, event_key: String) -> String + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def xml_accept: () -> Hash[String, String] + def compact: (Hash[untyped, untyped] hash) -> Hash[untyped, untyped] + end + end +end diff --git a/sig/nfe/resources/webhooks.rbs b/sig/nfe/resources/webhooks.rbs new file mode 100644 index 0000000..0acbd3c --- /dev/null +++ b/sig/nfe/resources/webhooks.rbs @@ -0,0 +1,24 @@ +module Nfe + module Resources + class Webhooks < AbstractResource + AVAILABLE_EVENTS: Array[String] + + def api_family: () -> Symbol + + def list: (String company_id) -> Nfe::ListResponse + def create: (String company_id, Hash[untyped, untyped] data) -> Nfe::WebhookSubscription? + def retrieve: (String company_id, String webhook_id) -> Nfe::WebhookSubscription? + def update: (String company_id, String webhook_id, Hash[untyped, untyped] data) -> Nfe::WebhookSubscription? + def delete: (String company_id, String webhook_id) -> nil + def test: (String company_id, String webhook_id) -> { success: bool, message: String? } + def get_available_events: () -> Array[String] + def verify_signature: (payload: String, signature: (String | Array[String])?, secret: String?) -> bool + + private + + def json_headers: () -> Hash[String, String] + def json_body: (untyped data) -> String + def webhook_items: (untyped payload) -> Array[untyped] + end + end +end diff --git a/sig/nfe/results.rbs b/sig/nfe/results.rbs new file mode 100644 index 0000000..ae11879 --- /dev/null +++ b/sig/nfe/results.rbs @@ -0,0 +1,22 @@ +module Nfe + class Pending < Data + attr_reader invoice_id: untyped + attr_reader location: untyped + + def self.new: (untyped invoice_id, untyped location) -> instance + | (invoice_id: untyped, location: untyped) -> instance + + def initialize: (untyped invoice_id, untyped location) -> void + | (invoice_id: untyped, location: untyped) -> void + end + + class Issued < Data + attr_reader resource: untyped + + def self.new: (untyped resource) -> instance + | (resource: untyped) -> instance + + def initialize: (untyped resource) -> void + | (resource: untyped) -> void + end +end diff --git a/sig/nfe/version.rbs b/sig/nfe/version.rbs new file mode 100644 index 0000000..3da0acc --- /dev/null +++ b/sig/nfe/version.rbs @@ -0,0 +1,3 @@ +module Nfe + VERSION: String +end diff --git a/sig/nfe/webhook.rbs b/sig/nfe/webhook.rbs new file mode 100644 index 0000000..f56e14c --- /dev/null +++ b/sig/nfe/webhook.rbs @@ -0,0 +1,20 @@ +module Nfe + module Webhook + SIGNATURE_PREFIX: String + HEX_RE: Regexp + + def self?.verify_signature: (payload: String, signature: (String | Array[String])?, secret: String?) -> bool + + def self?.construct_event: (payload: String, signature: (String | Array[String])?, secret: String?) -> Nfe::WebhookEvent + + def self?.parse_payload: (untyped payload) -> Hash[untyped, untyped] + + def self?.build_event: (Hash[untyped, untyped] decoded) -> Nfe::WebhookEvent + + def self?.envelope_data: (Hash[untyped, untyped] decoded) -> Hash[untyped, untyped] + + def self?.first_string: (Hash[untyped, untyped] hash, *String keys) -> String? + + def self?.nullable_string: (untyped value) -> String? + end +end diff --git a/sig/nfe/webhook_event.rbs b/sig/nfe/webhook_event.rbs new file mode 100644 index 0000000..3c1d41c --- /dev/null +++ b/sig/nfe/webhook_event.rbs @@ -0,0 +1,13 @@ +module Nfe + class WebhookEvent < Data + attr_reader type: String? + attr_reader data: Hash[untyped, untyped] + attr_reader id: String? + attr_reader created_at: String? + + def self.new: (type: String?, data: Hash[untyped, untyped], ?id: String?, ?created_at: String?) -> instance + | (String? type, Hash[untyped, untyped] data, ?String? id, ?String? created_at) -> instance + + def initialize: (type: String?, data: Hash[untyped, untyped], ?id: String?, ?created_at: String?) -> void + end +end diff --git a/skills/nfeio-ruby-sdk/SKILL.md b/skills/nfeio-ruby-sdk/SKILL.md new file mode 100644 index 0000000..497346e --- /dev/null +++ b/skills/nfeio-ruby-sdk/SKILL.md @@ -0,0 +1,301 @@ +--- +name: nfeio-ruby-sdk +description: >- + Use ao escrever ou revisar Ruby que integra a NFE.io via o gem oficial "nfe-io" + (require "nfe", Nfe::Client). Acione quando o código mencionar Nfe::Client, + NFE.io, emissão/consulta de nota fiscal eletrônica (NFS-e / NF-e / NFC-e / CT-e), + consulta de CNPJ / CPF / CEP (legal entity, natural person, address lookup), + verificação de assinatura de webhook (X-Hub-Signature), carta de correção (CC-e), + inutilização, certificado digital A1, ou cálculo de impostos. Cobre os 17 + recursos canônicos + 2 addons RTC (Reforma Tributária — IBS/CBS/IS). Ruby 3.2+, + zero dependências de runtime (stdlib only). +--- + +# NFE.io Ruby SDK (gem `nfe-io`, v1.0) + +SDK oficial da NFE.io para Ruby. Cliente estilo Stripe, **thread-safe**, **zero +dependências de runtime** (só stdlib: `net/http`, `json`, `openssl`, `uri`, +`securerandom`, `time`, `zlib`, `cgi`, `date`, `base64`). Ruby **3.2+**. + +> Use os nomes EXATOS deste documento. A v1 NÃO é compatível com a 0.3.x (que +> tinha `Nfe.api_key` global e `Nfe::ServiceInvoice.company_id(...).create`). + +## Gem & require + +```ruby +# Gemfile +gem "nfe-io", "~> 1.0" +``` + +```ruby +require "nfe" # carrega tudo sob o namespace Nfe:: +``` + +O gem publica `sig/**/*.rbs` — consumidores podem rodar `steep check` contra os +tipos. + +## Quickstart + +```ruby +client = Nfe::Client.new(api_key: "sua-chave") # produção, defaults sãos +client.service_invoices # acessor lazy + memoizado +``` + +Assinatura completa do construtor de `Nfe::Client.new` (kwargs): + +```ruby +Nfe::Client.new( + api_key: nil, # fallback ENV NFE_API_KEY (argumento explícito vence) + data_api_key: nil, # fallback ENV NFE_DATA_API_KEY + configuration: nil, # quando passado, IGNORA os demais kwargs abaixo + environment: :production, # SÍMBOLO :production | :development — reservado p/ uso futuro (sem efeito hoje) + timeout: 30, # read timeout (s) + max_retries: 3, # tentativas após a 1ª + logger: nil, + user_agent_suffix: nil +) +``` + +> **Atenção:** o construtor de `Client` NÃO aceita +> `open_timeout:`, `base_url_overrides:`, `ca_file:`, `ca_path:` nem `proxy:` +> diretamente. Esses campos vivem em `Nfe::Configuration`. Para usá-los, construa +> a configuração e injete via `configuration:`: + +```ruby +config = Nfe::Configuration.new( + api_key: ENV.fetch("NFE_API_KEY"), + open_timeout: 10, + base_url_overrides: { main: "https://mock.local" }, # escape hatch p/ testes/proxy + ca_file: "/etc/ssl/custom-ca.pem", # SÓ adiciona CA; não há como desabilitar verificação TLS + proxy: "http://proxy:3128" +) +client = Nfe::Client.new(configuration: config) +``` + +`environment:` (`:production`/`:development`) é um **símbolo reservado para uso +futuro**: hoje é validado mas não altera endpoints/chaves. A separação +produção/teste (homologação) é definida na conta em https://app.nfe.io. + +## Sandbox vs Produção + +- Não há host de sandbox separado. Produção/teste é definido na **conta** + (https://app.nfe.io), **não** pela chave; o `environment:` Símbolo do `Client` + está reservado para uso futuro. +- Para os recursos de **product/consumer invoices**, `list` exige um parâmetro + `environment:` **String separado** (`"Production"` ou `"Test"`) — distinto do + `environment:` Símbolo do `Client`. Eles coexistem e significam coisas diferentes. + +```ruby +client.product_invoices.list(company_id: id, environment: "Test") # String! +``` + +## Mapa de recursos + +19 acessores snake_case = 17 canônicos + 2 addons RTC. Roteamento de host é +**automático** por recurso (você nunca monta URL). + +| Acessor | Host | Escopo | Operações principais | +|---|---|---|---| +| `service_invoices` | api.nfe.io `/v1` | NFS-e (emissão) | create, list, retrieve, cancel, send_email, download_pdf/xml, get_status | +| `product_invoices` | api.nfse.io `/v2` | NF-e (mod 55) | create, create_with_state_tax, list*, retrieve, cancel, list_items/events, send_correction_letter, disable, disable_range, download_* | +| `consumer_invoices` | api.nfse.io `/v2` | NFC-e (emissão) | create, create_with_state_tax, list, retrieve, cancel, list_items/events, disable_range, download_pdf/xml/rejection_xml | +| `transportation_invoices` | api.nfse.io `/v2` | CT-e inbound | enable, disable, get_settings, retrieve, get_event, download_xml/event_xml | +| `inbound_product_invoices` | api.nfse.io `/v2` | NF-e recebida | enable_auto_fetch, disable_auto_fetch, get_settings, get_details, get_product_invoice_details, manifest, reprocess_webhook, get_xml/pdf/json | +| `product_invoice_query` | nfe.api.nfe.io | NF-e (consulta por chave) | retrieve, download_pdf, download_xml, list_events | +| `consumer_invoice_query` | nfe.api.nfe.io `/v1` | cupom NFC-e (consulta) | retrieve, download_xml | +| `companies` | api.nfe.io `/v1` | empresas + certificado A1 | create, list, retrieve, update, **remove**, find_by_*, upload_certificate, get_certificate_status | +| `legal_people` | api.nfe.io `/v1` | PJ (tomadores) | list, create, retrieve, update, delete, create_batch, find_by_tax_number | +| `natural_people` | api.nfe.io `/v1` | PF (tomadores) | list, create, retrieve, update, delete, create_batch, find_by_tax_number | +| `webhooks` | api.nfe.io `/v1` | assinaturas de webhook | list, create, retrieve, update, delete, test, get_available_events | +| `addresses` | address.api.nfe.io `/v2` | consulta de CEP | lookup_by_postal_code, search, lookup_by_term | +| `legal_entity_lookup` | legalentity.api.nfe.io | consulta CNPJ | get_basic_info, get_state_tax_info, get_state_tax_for_invoice, get_suggested_state_tax_for_invoice | +| `natural_person_lookup` | naturalperson.api.nfe.io | consulta CPF | get_status(cpf, birth_date) | +| `tax_calculation` | api.nfse.io | motor de impostos | calculate(tenant_id, request) | +| `tax_codes` | api.nfse.io | tabelas CT-e | list_operation_codes, list_acquisition_purposes, list_issuer/recipient_tax_profiles | +| `state_taxes` | api.nfse.io `/v2` | Inscrição Estadual | list, create, retrieve, update, delete | +| `service_invoices_rtc` | api.nfe.io `/v1` | NFS-e RTC (IBS/CBS) | create, retrieve, cancel, download_cancellation_xml | +| `product_invoices_rtc` | api.nfse.io `/v2` | NF-e/NFC-e RTC (IBSCBS) | create, create_with_state_tax, list*, retrieve, cancel, list_items/events, send_correction_letter, disable, disable_range, download_* | + +`*` = `list` exige `environment:` String. Famílias **DATA** (`addresses`, +`legal_entity`, `natural_person`, `nfe_query`) usam `data_api_key` (fallback +`api_key`). O host `api.nfse.io` (família `:cte`) usa `api_key` e **NÃO** é +família de dados — divergência deliberada do SDK Node. + +> **Convenção de argumentos (mista, intencional):** recursos de emissão usam +> kwargs (`create(company_id:, data:)`); `companies`, `legal_people`, +> `natural_people`, `state_taxes`, `webhooks` e os lookups usam **posicionais** +> (`companies.create(data)`, `companies.retrieve(company_id)`, +> `legal_entity_lookup.get_basic_info(cnpj)`). Sempre confira a assinatura. + +## Contrato 202 (Pending / Issued) + +Emissão é tipicamente **assíncrona**. `create` retorna um resultado +**discriminado**: + +- **`*Pending`** (HTTP 202): `#invoice_id`, `#location`; `pending? => true`, `issued? => false`. +- **`*Issued`** (HTTP 201/200): `#resource` (DTO hidratado); `issued? => true`, `pending? => false`. + +Não existe `create_and_wait`/`create_batch` para notas em v1.0. Faça polling: + +```ruby +result = client.service_invoices.create(company_id: id, data: payload) + +case result +in Nfe::Resources::ServiceInvoicePending => p + loop do + inv = client.service_invoices.retrieve(company_id: id, invoice_id: p.invoice_id) + break inv if Nfe::FlowStatus.terminal?(inv.flow_status) + sleep 2 + end +in Nfe::Resources::ServiceInvoiceIssued => i + i.resource +end +``` + +`Nfe::FlowStatus::TERMINAL = %w[Issued IssueFailed Cancelled CancelFailed]`. + +> Atalho só em `service_invoices`: `get_status(company_id:, invoice_id:)` retorna +> um `StatusResult` com `#complete?` e `#failed?` (deriva de `retrieve`, sem HTTP +> extra). Veja `references/service-invoices-and-polling.md`. + +## Tratamento de erros + +Toda exceção deriva de `Nfe::Error` (rescue único pega tudo). Cada erro carrega +`#status_code`, `#request_id`, `#error_code`, `#response_body`, `#response_headers` +e um `#to_h` seguro para log (sem body/headers). + +| Classe | HTTP | Notas | +|---|---|---| +| `Nfe::AuthenticationError` | 401 | chave ausente/inválida | +| `Nfe::AuthorizationError` | 403 | chave sem permissão | +| `Nfe::InvalidRequestError` | 400/422 | payload inválido (+ validações client-side) | +| `Nfe::NotFoundError` | 404 | recurso inexistente | +| `Nfe::ConflictError` | 409 | conflito de estado | +| `Nfe::RateLimitError` | 429 | tem `#retry_after` | +| `Nfe::ServerError` | 5xx | falha no servidor | +| `Nfe::ApiConnectionError` | — | falha de rede (DNS/conexão/TLS) | +| `Nfe::TimeoutError` | — | subclasse de `ApiConnectionError` | +| `Nfe::SignatureVerificationError` | — | assinatura de webhook inválida | +| `Nfe::ConfigurationError` | — | mal-configurado (antes de qualquer HTTP) | +| `Nfe::InvoiceProcessingError` | — | 202 sem `Location` utilizável | + +> Nomes que **NÃO existem**: `ConnectionError`, `ValidationError`, +> `PollingTimeoutError`. Use os da tabela. + +```ruby +begin + client.service_invoices.create(company_id: id, data: payload) +rescue Nfe::RateLimitError => e + sleep(e.retry_after || 5); retry +rescue Nfe::InvalidRequestError => e + logger.warn(e.to_h) # seguro para log +rescue Nfe::Error => e # rede a partir das classes específicas + raise +end +``` + +## Paginação + +`Nfe::ListResponse` inclui `Enumerable` (delega `each` a `#data`) e expõe `#data` ++ `#page`. `Nfe::ListPage` traz `#page_index`/`#page_count` (page-style) OU +`#starting_after`/`#ending_before` (cursor-style), além de `#total`. + +```ruby +client.service_invoices.list(company_id: id).each { |inv| ... } # já é Enumerable +``` + +- **page-style**: `service_invoices.list`, `companies.list`, `tax_codes.*`. +- **cursor-style**: `product_invoices.list`, `consumer_invoices.list`, `state_taxes.list`. +- `product_invoices.list` e `product_invoices_rtc.list` **exigem** `environment:` + String (`"Production"`/`"Test"`), senão levantam `InvalidRequestError`. + +## Downloads + +Por padrão, os `download_*` retornam **bytes binários** (`String` ASCII-8BIT) → +grave com `File.binwrite`: + +```ruby +File.binwrite("nota.pdf", client.service_invoices.download_pdf(company_id: id, invoice_id: iid)) +``` + +Retornam bytes: `service_invoices`, `consumer_invoices`, `transportation_invoices`, +`inbound_product_invoices`, `product_invoice_query`, `consumer_invoice_query`. + +> **EXCEÇÃO:** `product_invoices` e `product_invoices_rtc` retornam um +> `Nfe::NfeFileResource` (objeto de valor `{ uri, name, content_type, size }`), +> **NÃO** bytes — o host responde com um envelope JSON `{ uri }`. + +```ruby +file = client.product_invoices.download_pdf(company_id: id, invoice_id: iid) +file.uri # baixe você mesmo a partir desta URI +``` + +## Webhooks + +Verificação é estática, sem `Client` e sem rede: + +```ruby +raw = request.body.read # bytes BRUTOS, antes do parse JSON +sig = request.get_header("HTTP_X_HUB_SIGNATURE") # header X-Hub-Signature + +if Nfe::Webhook.verify_signature(payload: raw, signature: sig, secret: ENV.fetch("NFE_WEBHOOK_SECRET")) + event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: ENV.fetch("NFE_WEBHOOK_SECRET")) + # event => Nfe::WebhookEvent(type:, data:, id:, created_at:) +end +``` + +- **HMAC-SHA1** sobre os **bytes brutos** da request; header `X-Hub-Signature` + (prefixo `sha1=`), comparação case-insensitive e **timing-safe**. +- `verify_signature` **nunca levanta** (retorna `false` em qualquer entrada + inválida). `construct_event` levanta `SignatureVerificationError` se a + assinatura/JSON falhar. +- Nunca re-serialize o objeto parseado (`payload.to_json`) — ordem de chaves + difere dos bytes assinados. +- **Validade ≠ frescor:** a NFE.io não envia timestamp/nonce anti-replay. Uma + assinatura válida prova autenticidade, não frescor → handlers DEVEM ser + **idempotentes** e **deduplicar** por `event.id` / id da nota. +- Esquema legado `X-NFe-Signature` / SHA-256 / Base64 **não** é suportado (e está + errado em docs antigas). + +## Pitfalls idiomáticos + +- `companies` apaga com `#remove(company_id)` (retorna `{ deleted:, id: }`), **não** + `#delete`. Já `legal_people`/`natural_people`/`state_taxes`/`webhooks` usam `#delete`. +- Recursos de emissão usam **keyword args**; entidades/lookups usam **posicionais** + (ver nota no Mapa de recursos). +- Objetos de valor são `Data.define` **imutáveis** (Pending/Issued, ServiceInvoice, + NfeFileResource, WebhookEvent, ListResponse, ListPage…). +- **Chaves de acesso = 44 dígitos**; separadores são removidos automaticamente. +- **Carta de correção (CC-e)**: `reason` deve ter **15..1000 caracteres** (validado + client-side antes do HTTP). CC-e existe só para NF-e/CT-e — NFC-e não tem. +- `idempotency_key:` nas emissões vira header `Idempotency-Key`. O SDK **não** + re-tenta emissões automaticamente; reenviar com a MESMA chave após timeout deixa + o servidor deduplicar. +- `request_options: Nfe::RequestOptions.new(api_key:, base_url:, timeout:)` faz + override por chamada (multi-tenant) sem mutar o `Client`. + +## Árvore de decisão ("Quero…") + +- **Emitir NFS-e** → `service_invoices.create(company_id:, data:)` → polling. +- **Emitir NF-e** → `product_invoices.create(company_id:, data:)` (202 → webhook). +- **Emitir NFC-e** → `consumer_invoices.create(company_id:, data:)`. +- **Emitir nota com IBS/CBS/IS (Reforma)** → `service_invoices_rtc` / + `product_invoices_rtc` → `references/rtc-emission.md`. +- **Cancelar / carta de correção / inutilizar** → métodos do recurso de emissão → + `references/product-invoices-and-taxes.md`. +- **Consultar nota de terceiro por chave de 44 dígitos** → `product_invoice_query` / + `consumer_invoice_query`, ou inbound (`transportation_invoices` / + `inbound_product_invoices`). +- **Consultar CNPJ / CPF / CEP** → `legal_entity_lookup` / `natural_person_lookup` / + `addresses` → `references/data-services-and-lookups.md`. +- **Calcular impostos** → `tax_calculation.calculate(tenant_id, request)`. +- **Verificar webhook** → `Nfe::Webhook.verify_signature(...)`. +- **Tratar erros / retry / multi-tenant** → `references/error-handling-and-patterns.md`. + +## Referências + +- `references/service-invoices-and-polling.md` — NFS-e ponta a ponta + polling/get_status. +- `references/product-invoices-and-taxes.md` — NF-e/NFC-e, CC-e, inutilização, state_taxes, tax_codes, tax_calculation. +- `references/data-services-and-lookups.md` — addresses, legal/natural lookup, query por chave, certificados, companies/people. +- `references/error-handling-and-patterns.md` — hierarquia de erros, retries, idempotência, request_options, webhooks. +- `references/rtc-emission.md` — emissão RTC (IBS/CBS/IS) de serviço e produto. diff --git a/skills/nfeio-ruby-sdk/references/data-services-and-lookups.md b/skills/nfeio-ruby-sdk/references/data-services-and-lookups.md new file mode 100644 index 0000000..360d29d --- /dev/null +++ b/skills/nfeio-ruby-sdk/references/data-services-and-lookups.md @@ -0,0 +1,128 @@ +# Consultas (CEP/CNPJ/CPF), cupom NFC-e, empresas, pessoas e certificados + +## Famílias de dados e a chave + +`addresses`, `legal_entity_lookup`, `natural_person_lookup` e os recursos +`*_query` pertencem às famílias **DATA** (`addresses`, `legal-entity`, +`natural-person`, `nfe-query`). Elas usam `data_api_key` e, na ausência dele, +caem em `api_key`. Configure ambas as chaves quando consumir dados: + +```ruby +client = Nfe::Client.new( + api_key: ENV.fetch("NFE_API_KEY"), + data_api_key: ENV.fetch("NFE_DATA_API_KEY") # ou deixe cair no api_key +) +``` + +> Lembrete: `api.nfse.io` (`:cte`) NÃO é família de dados; usa `api_key`. + +## `addresses` — consulta de CEP (posicional) + +Host `address.api.nfe.io/v2`. Todas retornam `Nfe::AddressLookupResponse`. + +```ruby +client.addresses.lookup_by_postal_code("01310-100") # CEP normalizado p/ 8 dígitos +client.addresses.lookup_by_term("Avenida Paulista") +client.addresses.search(filter: "...") # OData $filter opaco +``` + +CEP que não vira 8 dígitos → `Nfe::InvalidRequestError`. Termo vazio idem. + +## `legal_entity_lookup` — consulta CNPJ (posicional) + +Host `legalentity.api.nfe.io`. CNPJ aceito em qualquer formato (normalizado p/ +14 caracteres; UF case-insensitive). + +```ruby +client.legal_entity_lookup.get_basic_info(cnpj, update_address: nil, update_city_code: nil) + # => Nfe::LegalEntityBasicInfoResponse +client.legal_entity_lookup.get_state_tax_info(state, cnpj) # => Nfe::LegalEntityStateTaxResponse +client.legal_entity_lookup.get_state_tax_for_invoice(state, cnpj) # => ...ForInvoiceResponse +client.legal_entity_lookup.get_suggested_state_tax_for_invoice(state, cnpj) +``` + +CNPJ ≠ 14 ou UF inválida → `Nfe::InvalidRequestError`. + +## `natural_person_lookup` — consulta CPF (posicional) + +Host `naturalperson.api.nfe.io`. CPF normalizado p/ 11 dígitos; a data de +nascimento é normalizada p/ `YYYY-MM-DD` (aceita `String`/`Date`/`Time`). + +```ruby +client.natural_person_lookup.get_status("123.456.789-00", "1990-05-20") + # => Nfe::NaturalPersonStatusResponse +client.natural_person_lookup.get_status(cpf, Date.new(1990, 5, 20)) # Date também serve +``` + +## `consumer_invoice_query` — cupom NFC-e por chave (posicional) + +Host `nfe.api.nfe.io/v1`. DISTINTO de `consumer_invoices` (emissão). + +```ruby +client.consumer_invoice_query.retrieve(access_key) # => Nfe::TaxCoupon +File.binwrite("cupom.xml", client.consumer_invoice_query.download_xml(access_key)) # bytes +``` + +(`product_invoice_query` está em `references/product-invoices-and-taxes.md`.) + +## `companies` — empresas + certificado A1 (posicional) + +Host `api.nfe.io/v1`. CRUD com **argumentos posicionais**; apaga com `remove`. + +```ruby +company = client.companies.create({ name: "Acme", federalTaxNumber: "12345678000199" }) +client.companies.retrieve(company.id) # => Nfe::Company +client.companies.update(company.id, { email: "fiscal@acme.com" }) +client.companies.remove(company.id) # => { deleted: true, id: ... } (NÃO #delete) +client.companies.list(page_index: 0, page_count: 100) # page-style (0-based aqui) +client.companies.list_all # auto-pagina (helper, não otimizado) +client.companies.find_by_tax_number("12345678000199") # client-side +client.companies.find_by_name("acme") +``` + +`create`/`update` validam client-side: `federalTaxNumber` deve ter 11 (CPF) ou +14 (CNPJ) dígitos e `email` formato válido — senão `Nfe::InvalidRequestError` +(sem coerção a Integer, sem dígito verificador). + +### Certificado digital (PKCS#12 .pfx/.p12) + +```ruby +# valida localmente, sem HTTP: +info = client.companies.validate_certificate(file: "/path/cert.pfx", password: "senha") + +# upload (pré-valida local, depois multipart): +client.companies.upload_certificate(company.id, file: "/path/cert.pfx", password: "senha") +client.companies.replace_certificate(company.id, file: bytes, password: "senha") # alias + +status = client.companies.get_certificate_status(company.id) # => Nfe::CertificateStatus +status.has_certificate; status.expires_on; status.days_until_expiration; status.expiring_soon + +client.companies.check_certificate_expiration(company.id, threshold_days: 30) # => Hash | nil +client.companies.get_companies_with_certificates +client.companies.get_companies_with_expiring_certificates(threshold_days: 30) +``` + +`file:` aceita um **path** OU os **bytes crus** do .pfx/.p12. Senha/bytes ficam +só em memória. Formato não suportado / senha errada → `Nfe::InvalidRequestError`. + +## `legal_people` / `natural_people` — tomadores (posicional, escopo por empresa) + +Host `api.nfe.io/v1`, sob `/companies/{id}/legalpeople` (PJ) e `/naturalpeople` +(PF). `list` retorna `Nfe::ListResponse` sem paginação (parity Node). + +```ruby +client.legal_people.list(company_id) # => Nfe::ListResponse +client.legal_people.create(company_id, data) # => Nfe::LegalPerson +client.legal_people.retrieve(company_id, legal_person_id) +client.legal_people.update(company_id, legal_person_id, data) +client.legal_people.delete(company_id, legal_person_id) # => nil +client.legal_people.create_batch(company_id, [data1, data2]) # sequencial, em ordem +client.legal_people.find_by_tax_number(company_id, "12345678000199") + +client.natural_people.create(company_id, data) # => Nfe::NaturalPerson +client.natural_people.find_by_tax_number(company_id, "12345678900") # normaliza p/ 11 dígitos +``` + +Objetos de valor (`Nfe::Company`, `Nfe::LegalPerson`, `Nfe::NaturalPerson`, +`Nfe::CertificateStatus`, etc.) são `Data.define` imutáveis com membros +snake_case hidratados de payloads camelCase. diff --git a/skills/nfeio-ruby-sdk/references/error-handling-and-patterns.md b/skills/nfeio-ruby-sdk/references/error-handling-and-patterns.md new file mode 100644 index 0000000..42619f5 --- /dev/null +++ b/skills/nfeio-ruby-sdk/references/error-handling-and-patterns.md @@ -0,0 +1,139 @@ +# Erros, retries, idempotência, multi-tenant e webhooks + +## Hierarquia de erros + +Toda exceção do SDK deriva de `Nfe::Error`. Um `rescue Nfe::Error` pega tudo. + +``` +Nfe::Error +├─ Nfe::AuthenticationError # 401 +├─ Nfe::AuthorizationError # 403 +├─ Nfe::InvalidRequestError # 400/422 (+ validações client-side) +├─ Nfe::NotFoundError # 404 +├─ Nfe::ConflictError # 409 +├─ Nfe::RateLimitError # 429 (#retry_after) +├─ Nfe::ServerError # 5xx +├─ Nfe::ApiConnectionError # falha de rede +│ └─ Nfe::TimeoutError # timeout (subclasse!) +├─ Nfe::SignatureVerificationError # webhook +├─ Nfe::ConfigurationError # mal-configurado (antes do HTTP) +└─ Nfe::InvoiceProcessingError # 202 sem Location utilizável +``` + +> NÃO existem `ConnectionError`, `ValidationError`, `PollingTimeoutError`. +> `TimeoutError < ApiConnectionError`, então `rescue Nfe::ApiConnectionError` +> também captura timeouts. + +Cada erro de resposta carrega: `#status_code`, `#request_id`, `#error_code`, +`#response_body`, `#response_headers`. Use `#to_h` para logar com segurança — +ele **omite** body e headers (que podem ter chave de API / senha / PII). + +```ruby +begin + client.product_invoices.create(company_id: id, data: payload) +rescue Nfe::AuthenticationError, Nfe::AuthorizationError => e + logger.error(e.to_h); raise # chave errada/sem permissão — não re-tentar +rescue Nfe::RateLimitError => e + sleep(e.retry_after || 5); retry +rescue Nfe::InvalidRequestError => e + logger.warn(e.to_h) # payload inválido — corrija, não re-tente +rescue Nfe::TimeoutError => e + retry_with_same_idempotency_key # ver abaixo +rescue Nfe::Error => e + report(e.to_h); raise +end +``` + +## Retries + +O SDK já re-tenta no transporte (`max_retries`, padrão 3, com backoff + +jitter) para falhas transitórias. Configure no construtor: + +```ruby +Nfe::Client.new(api_key: key, max_retries: 5, timeout: 30) +``` + +> Emissões de nota não são re-tentadas cegamente — use `idempotency_key` para +> reenviar com segurança. + +## Idempotência + +`idempotency_key:` (nas emissões) vira o header `Idempotency-Key`. Como o SDK +**não** re-tenta emissões automaticamente, reenviar com a **mesma** chave após um +timeout deixa o servidor deduplicar (não emite duas notas). + +```ruby +key = SecureRandom.uuid +begin + client.service_invoices.create(company_id: id, data: payload, idempotency_key: key) +rescue Nfe::TimeoutError + client.service_invoices.create(company_id: id, data: payload, idempotency_key: key) # mesma chave +end +``` + +## Multi-tenant (`request_options`) + +`Nfe::RequestOptions` faz override **por chamada** sem mutar (nem reconstruir) o +`Client`. Campos nil caem na resolução normal por família. + +```ruby +opts = Nfe::RequestOptions.new(api_key: tenant_api_key) # ou base_url:, timeout: +client.service_invoices.create(company_id: id, data: payload, request_options: opts) +``` + +Útil para um único `Client` compartilhado (thread-safe) atendendo vários tenants +com chaves distintas. + +## TLS + +`ca_file`/`ca_path` (em `Nfe::Configuration`) só **adicionam** uma CA ao trust +store. Não há API para desabilitar verificação de peer (sem `VERIFY_NONE`, sem +`insecure_ssl`). O `insecureSsl` da API é propriedade do *alvo de entrega de +webhook* no servidor, não do TLS de saída do SDK. + +## Webhooks — verificação e handler idempotente + +```ruby +require "nfe" + +def handle_webhook(request) # ex.: Rack/Rails + raw = request.body.read # bytes BRUTOS (antes de parsear) + sig = request.get_header("HTTP_X_HUB_SIGNATURE") # header X-Hub-Signature + secret = ENV.fetch("NFE_WEBHOOK_SECRET") + + unless Nfe::Webhook.verify_signature(payload: raw, signature: sig, secret: secret) + return [401, {}, ["assinatura inválida"]] + end + + event = Nfe::Webhook.construct_event(payload: raw, signature: sig, secret: secret) + # event => Nfe::WebhookEvent(type:, data:, id:, created_at:) + + return [200, {}, ["duplicado"]] if already_processed?(event.id) # DEDUPE obrigatório + process!(event) + mark_processed(event.id) + [200, {}, ["ok"]] +end +``` + +Pontos-chave: + +- **HMAC-SHA1** sobre os **bytes brutos**; header `X-Hub-Signature` (`sha1=`), + comparação timing-safe e case-insensitive. +- `verify_signature` **nunca levanta** (retorna `false` p/ entrada inválida, + algoritmo errado `sha256=`, tamanho/hex errado, secret vazio). + `construct_event` levanta `Nfe::SignatureVerificationError` se assinatura/JSON + falhar. +- Nunca re-serialize o objeto (`payload.to_json`) — bytes diferem dos assinados. +- **Validade ≠ frescor:** não há timestamp/nonce anti-replay. Assinatura válida + prova autenticidade, **não** frescor → handler DEVE ser **idempotente** e + **deduplicar** por `event.id` (ou id da nota). +- Eventos disponíveis (`client.webhooks.get_available_events`): `invoice.issued`, + `invoice.cancelled`, `invoice.failed`, `invoice.processing`, `company.created`, + `company.updated`, `company.deleted`. +- Esquema legado `X-NFe-Signature`/SHA-256/Base64 **não** é suportado. + +## Concorrência + +Um `Nfe::Client` é seguro para compartilhar entre threads (Puma/Sidekiq): os +acessores de recurso e transportes são memoizados sob `Mutex`. Crie um por +processo e reutilize. diff --git a/skills/nfeio-ruby-sdk/references/product-invoices-and-taxes.md b/skills/nfeio-ruby-sdk/references/product-invoices-and-taxes.md new file mode 100644 index 0000000..5558de1 --- /dev/null +++ b/skills/nfeio-ruby-sdk/references/product-invoices-and-taxes.md @@ -0,0 +1,162 @@ +# NF-e, NFC-e, CT-e inbound, state_taxes, tax_codes e tax_calculation + +Recursos da família `:cte` (host `api.nfse.io`, paths com `/v2`) + a consulta +`product_invoice_query` (host `nfe.api.nfe.io`). A família `:cte` usa `api_key` +(NÃO é família de dados). Recursos de emissão usam **keyword args**. + +## `product_invoices` — NF-e (mod 55) + +```ruby +client.product_invoices.create(company_id:, data:, idempotency_key: nil, request_options: nil) +client.product_invoices.create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) +client.product_invoices.list(company_id:, environment:, **options) # environment OBRIGATÓRIO +client.product_invoices.retrieve(company_id:, invoice_id:) # => Nfe::ProductInvoice +client.product_invoices.cancel(company_id:, invoice_id:, reason: nil)# => Hash (async) +client.product_invoices.list_items(company_id:, invoice_id:, limit: nil, starting_after: nil) +client.product_invoices.list_events(company_id:, invoice_id:, limit: nil, starting_after: nil) +client.product_invoices.send_correction_letter(company_id:, invoice_id:, reason:) # reason 15..1000 +client.product_invoices.disable(company_id:, invoice_id:, reason: nil) +client.product_invoices.disable_range(company_id:, data:) +# downloads => Nfe::NfeFileResource (URI, NÃO bytes): +client.product_invoices.download_pdf(company_id:, invoice_id:, force: nil) +client.product_invoices.download_xml(company_id:, invoice_id:) +client.product_invoices.download_rejection_xml(company_id:, invoice_id:) +client.product_invoices.download_epec_xml(company_id:, invoice_id:) +client.product_invoices.download_correction_letter_pdf(company_id:, invoice_id:) +client.product_invoices.download_correction_letter_xml(company_id:, invoice_id:) +``` + +`create`/`create_with_state_tax` retornam `ProductInvoicePending` (202, comum — +conclusão chega por **webhook**) ou `ProductInvoiceIssued` (201). Faça polling +com `retrieve` + `Nfe::FlowStatus.terminal?`, ou trate o webhook `invoice.issued`. + +```ruby +res = client.product_invoices.create(company_id: id, data: nfe_payload) +res.invoice_id if res.pending? # 202 — acompanhe via webhook/polling +``` + +`list` (cursor-style) **exige** `environment:` String (`"Production"`/`"Test"`), +senão levanta `Nfe::InvalidRequestError`. Options: `starting_after`, +`ending_before`, `limit`, `q`. + +```ruby +page = client.product_invoices.list(company_id: id, environment: "Production", limit: 50) +page.each { |nfe| ... } # ListResponse é Enumerable +page.page.starting_after # cursor +``` + +### Downloads de NF-e retornam URI (não bytes) + +```ruby +file = client.product_invoices.download_pdf(company_id: id, invoice_id: iid) +file.uri # baixe a partir desta URI +file.content_type # "application/pdf", quando informado +``` + +### Carta de correção (CC-e) + +`reason` deve ter **15 a 1000 caracteres** (sem acentos), validado client-side +ANTES de qualquer HTTP — fora do range levanta `Nfe::InvalidRequestError`. + +```ruby +client.product_invoices.send_correction_letter( + company_id: id, invoice_id: iid, + reason: "Correcao do endereco de entrega do destinatario" # >= 15 chars +) +``` + +### Inutilização + +```ruby +client.product_invoices.disable(company_id: id, invoice_id: iid, reason: "Erro de digitacao") +client.product_invoices.disable_range(company_id: id, data: { + environment: "Production", serie: 1, state: "SP", + beginNumber: 100, lastNumber: 110, reason: "Salto de numeracao" # camelCase no Hash +}) +``` + +## `consumer_invoices` — NFC-e + +Emissão NFC-e (parity-plus: o SDK Node não tem). Mesma forma de `create`/`list`/ +`retrieve`/`cancel`/`list_items`/`list_events`/`disable_range`, MAS: + +- **downloads retornam BYTES** (`download_pdf`, `download_xml`, + `download_rejection_xml`), diferente de `product_invoices`. +- **NÃO** existem `send_correction_letter` (CC-e não se aplica a NFC-e), + `download_epec_xml`, nem `disable` por nota — só `disable_range` (inutilização + coletiva). Chamar os ausentes → `NoMethodError`. + +```ruby +File.binwrite("nfce.pdf", client.consumer_invoices.download_pdf(company_id: id, invoice_id: iid)) +``` + +## CT-e e NF-e recebidas (inbound) + +`transportation_invoices` (CT-e) e `inbound_product_invoices` (NF-e de +fornecedor) NÃO são emissão — gerenciam a busca automática via Distribuição DFe +e leem documentos por **chave de acesso de 44 dígitos**. Não têm contrato 202. + +```ruby +client.transportation_invoices.enable(company_id: id) # liga auto-fetch +cte = client.transportation_invoices.retrieve(company_id: id, access_key: "3524...7890") +File.binwrite("cte.xml", client.transportation_invoices.download_xml(company_id: id, access_key: key)) + +client.inbound_product_invoices.enable_auto_fetch(company_id: id, webhook_version: "2") +det = client.inbound_product_invoices.get_product_invoice_details(company_id: id, access_key: key) +client.inbound_product_invoices.manifest(company_id: id, access_key: key) # tp_event padrão = Ciência (210210) +``` + +Constantes de manifesto: `MANIFEST_AWARENESS` (210210, padrão), +`MANIFEST_CONFIRMATION` (210220), `MANIFEST_NOT_PERFORMED` (210240). +Downloads inbound (`download_xml`, `get_xml`, `get_pdf`, `download_event_xml`) +retornam **bytes**. + +## `product_invoice_query` — consulta NF-e por chave + +Host `nfe.api.nfe.io` (família de dados `nfe_query`, usa `data_api_key`). +Argumento **posicional** (a chave de acesso): + +```ruby +client.product_invoice_query.retrieve(access_key) # => Nfe::ProductInvoiceDetails +client.product_invoice_query.list_events(access_key) # => Nfe::ProductInvoiceEventsResponse +File.binwrite("nfe.pdf", client.product_invoice_query.download_pdf(access_key)) # bytes +File.binwrite("nfe.xml", client.product_invoice_query.download_xml(access_key)) # bytes +``` + +## `state_taxes` — Inscrição Estadual (CRUD, posicional) + +```ruby +client.state_taxes.list(company_id, starting_after: nil, ending_before: nil, limit: nil) # cursor +client.state_taxes.create(company_id, { code: "SP", taxNumber: "1234567890" }) +client.state_taxes.retrieve(company_id, state_tax_id) +client.state_taxes.update(company_id, state_tax_id, data) +client.state_taxes.delete(company_id, state_tax_id) # => nil +``` + +O `state_tax_id` retornado alimenta `product_invoices.create_with_state_tax`. + +## `tax_codes` — tabelas de referência CT-e (page-style) + +Retornam `Nfe::TaxCodePaginatedResponse` (page-style 1-based, NÃO `ListResponse`): + +```ruby +client.tax_codes.list_operation_codes(page_index: 1, page_count: 50) +client.tax_codes.list_acquisition_purposes +client.tax_codes.list_issuer_tax_profiles +client.tax_codes.list_recipient_tax_profiles +``` + +## `tax_calculation` — motor de impostos (posicional) + +```ruby +resp = client.tax_calculation.calculate(tenant_id, { + operationType: "...", # operation_type ou operationType (obrigatório) + items: [ { ... } ] # Array não vazio (obrigatório) +}) +# => Nfe::Generated::CalculoImpostosV1::CalculateResponse +``` + +Validação client-side: `tenant_id` não vazio + `request` Hash com +`operation_type`/`operationType` e `items` Array não vazio; senão +`Nfe::InvalidRequestError` (sem HTTP). Para type-safety, monte o `request` a +partir de `Nfe::Generated::CalculoImpostosV1::CalculateRequest#to_h`. diff --git a/skills/nfeio-ruby-sdk/references/rtc-emission.md b/skills/nfeio-ruby-sdk/references/rtc-emission.md new file mode 100644 index 0000000..c59287f --- /dev/null +++ b/skills/nfeio-ruby-sdk/references/rtc-emission.md @@ -0,0 +1,133 @@ +# Emissão RTC — Reforma Tributária do Consumo (IBS / CBS / IS) + +Dois addons "parity-plus" (além dos 17 recursos canônicos compartilhados com os +SDKs PHP/Node): `service_invoices_rtc` (NFS-e) e `product_invoices_rtc` +(NF-e mod 55 / NFC-e mod 65). Use-os quando precisar dos campos da Reforma +(IBS/CBS/IS) e/ou dos DTOs RTC hidratados na resposta. + +## Princípio central: layout selecionado pelo PAYLOAD + +Os recursos RTC compartilham **os mesmos endpoints** dos clássicos. **Não há** +header nem query param discriminador. A API escolhe o layout RTC pela +**presença de um grupo no payload**: + +- **NFS-e RTC** (`service_invoices_rtc`): presença do grupo **`ibsCbs`** no topo + do `data`. Ausente → cai no layout NFS-e clássico. +- **NF-e/NFC-e RTC** (`product_invoices_rtc`): presença do grupo + **`IBSCBS`** por item (`items[].tax.IBSCBS`). NF-e (55) vs NFC-e (65) também é + inferido pela forma do payload. + +`data` é sempre um `Hash` com chaves **camelCase** (JSON cru). Os DTOs gerados +(`Nfe::Generated::ServiceInvoiceRtcV1::*`, `Nfe::Generated::ProductInvoiceRtcV1::*`) +documentam a **forma** esperada, mas **não** são aceitos como entrada: eles só +deserializam (`from_api`) e não têm re-serializador camelCase — passar o objeto +emitiria chaves erradas. + +## `service_invoices_rtc` — NFS-e RTC (host api.nfe.io `/v1`) + +```ruby +client.service_invoices_rtc.create(company_id:, data:, idempotency_key: nil, request_options: nil) + # => ServiceInvoiceRtcPending (202) | ServiceInvoiceRtcIssued (201; resource => Nfe::ServiceInvoice) +client.service_invoices_rtc.retrieve(company_id:, invoice_id:) # => Nfe::ServiceInvoice +client.service_invoices_rtc.cancel(company_id:, invoice_id:) # => Nfe::ServiceInvoice +client.service_invoices_rtc.download_cancellation_xml(company_id:, invoice_id:) # => bytes (ADN, após Cancelled) +``` + +Exemplo (o grupo `ibsCbs` é o que ativa o RTC): + +```ruby +result = client.service_invoices_rtc.create( + company_id: id, + data: { + borrower: { type: "LegalEntity", name: "Cliente Ltda", federalTaxNumber: "12345678000199" }, + servicesAmount: 100.0, + ibsCbs: { + cbs: { /* ... */ }, + ibs: { /* ... */ } + } + }, + idempotency_key: SecureRandom.uuid +) + +invoice = + if result.issued? + result.resource # Nfe::ServiceInvoice + else + poll_until_terminal(client.service_invoices_rtc, id, result.invoice_id) + end +``` + +`download_cancellation_xml` é exclusivo do RTC de serviço: retorna **bytes** do +XML de cancelamento (ADN), disponível só após o estado `Cancelled`; indisponível +→ `Nfe::NotFoundError`. + +## `product_invoices_rtc` — NF-e/NFC-e RTC (host api.nfse.io `/v2`) + +Mesma superfície do `product_invoices` clássico, mas hidrata os DTOs RTC: + +```ruby +client.product_invoices_rtc.create(company_id:, data:, idempotency_key: nil, request_options: nil) +client.product_invoices_rtc.create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) +client.product_invoices_rtc.list(company_id:, environment:, starting_after: nil, ending_before: nil, limit: nil, q: nil) +client.product_invoices_rtc.retrieve(company_id:, invoice_id:) # => Generated::ProductInvoiceRtcV1::InvoiceResource +client.product_invoices_rtc.cancel(company_id:, invoice_id:, reason: nil) +client.product_invoices_rtc.list_items(company_id:, invoice_id:) +client.product_invoices_rtc.list_events(company_id:, invoice_id:) +client.product_invoices_rtc.send_correction_letter(company_id:, invoice_id:, reason:) # reason 15..1000 +client.product_invoices_rtc.disable(company_id:, invoice_id:, reason: nil) +client.product_invoices_rtc.disable_range(company_id:, data:) +# downloads => Nfe::NfeFileResource (URI, NÃO bytes): +client.product_invoices_rtc.download_pdf(company_id:, invoice_id:, force: false) +client.product_invoices_rtc.download_xml(company_id:, invoice_id:) +client.product_invoices_rtc.download_rejection_xml(company_id:, invoice_id:) +client.product_invoices_rtc.download_epec_xml(company_id:, invoice_id:) +client.product_invoices_rtc.download_correction_letter_pdf(company_id:, invoice_id:) +client.product_invoices_rtc.download_correction_letter_xml(company_id:, invoice_id:) +``` + +Diferenças de hidratação vs o recurso clássico: + +- `retrieve`/`list`/`*Issued.resource` → `Generated::ProductInvoiceRtcV1::InvoiceResource`. +- `cancel`/`send_correction_letter` → `...::RequestCancellationResource`. +- `disable`/`disable_range` → `...::DisablementResource`. +- `list_items`/`list_events` → `...::InvoiceItemsResource` / `...::InvoiceEventsResource`. + +Exemplo (o grupo `IBSCBS` por item ativa o RTC): + +```ruby +result = client.product_invoices_rtc.create( + company_id: id, + data: { + buyer: { /* ... */ }, + items: [ + { code: "001", description: "Produto", quantity: 1, unitAmount: 50.0, + tax: { IBSCBS: { /* ... */ } } } # presença de IBSCBS => layout RTC + ] + } +) +result.pending? ? result.invoice_id : result.resource +``` + +`list` (cursor-style) **exige** `environment:` String (`"Production"`/`"Test"`). +Downloads retornam `Nfe::NfeFileResource` (`.uri`), igual ao clássico. + +## Polling RTC + +Idêntico ao fluxo padrão — `*Pending`/`*Issued` com `pending?`/`issued?`, e +`Nfe::FlowStatus.terminal?` decide quando parar: + +```ruby +def poll_until_terminal(resource, company_id, invoice_id, interval: 2, max: 30) + max.times do + inv = resource.retrieve(company_id: company_id, invoice_id: invoice_id) + status = inv.respond_to?(:flow_status) ? inv.flow_status : inv&.flowStatus + return inv if Nfe::FlowStatus.terminal?(status) + sleep interval + end + raise "RTC #{invoice_id} não concluiu a tempo" +end +``` + +Para NF-e (mod 55) a conclusão normalmente chega por **webhook** — combine +`invoice.issued`/`invoice.failed` com o polling acima como fallback. CC-e segue a +regra de **15..1000 caracteres**, validada client-side. diff --git a/skills/nfeio-ruby-sdk/references/service-invoices-and-polling.md b/skills/nfeio-ruby-sdk/references/service-invoices-and-polling.md new file mode 100644 index 0000000..f9f750f --- /dev/null +++ b/skills/nfeio-ruby-sdk/references/service-invoices-and-polling.md @@ -0,0 +1,125 @@ +# NFS-e (`service_invoices`) e polling + +Recurso canônico de emissão da plataforma. Host `api.nfe.io` `/v1`, família +`:main`, chave `api_key`. Todos os métodos usam **keyword args**. + +## Assinaturas + +```ruby +client.service_invoices.create(company_id:, data:, idempotency_key: nil, request_options: nil) + # => Nfe::Resources::ServiceInvoicePending | Nfe::Resources::ServiceInvoiceIssued +client.service_invoices.list(company_id:, **options) # => Nfe::ListResponse (page-style) +client.service_invoices.retrieve(company_id:, invoice_id:) # => Nfe::ServiceInvoice +client.service_invoices.cancel(company_id:, invoice_id:) # => Nfe::ServiceInvoice (síncrono) +client.service_invoices.send_email(company_id:, invoice_id:) # => { sent:, message: } +client.service_invoices.download_pdf(company_id:, invoice_id: nil) # => String (bytes); nil => ZIP da empresa +client.service_invoices.download_xml(company_id:, invoice_id: nil) # => String (bytes); nil => ZIP da empresa +client.service_invoices.get_status(company_id:, invoice_id:) # => StatusResult +``` + +`list` aceita (snake_case, mapeados p/ camelCase): `page_index`, `page_count`, +`issued_begin`, `issued_end`, `created_begin`, `created_end`, `has_totals`. + +`data` é um `Hash` com chaves **camelCase** (serializado como JSON cru). Campos +do DTO de leitura `Nfe::ServiceInvoice`: `id`, `flow_status`, `flow_message`, +`status`, `environment`, `rps_number`, `number`, `check_code`, `issued_on`, +`cancelled_on`, `amount_net`, `services_amount`, `borrower`, `city_service_code`, +`federal_service_code`, `description`, `pdf`, `xml`, `created_on`, `modified_on`. + +## Emitir + esperar (polling manual) + +Não há `create_and_wait` em v1.0. Padrão recomendado: + +```ruby +result = client.service_invoices.create( + company_id: company_id, + data: { + cityServiceCode: "2690", + description: "Consultoria", + servicesAmount: 1500.0, + borrower: { + type: "LegalEntity", + name: "Cliente Ltda", + federalTaxNumber: "12345678000199", + email: "fiscal@cliente.com" + } + }, + idempotency_key: SecureRandom.uuid # opcional, mas recomendado +) + +invoice = + if result.issued? # 201/200 — materializou na hora + result.resource + else # 202 — entrou na fila + poll(client, company_id, result.invoice_id) + end + +def poll(client, company_id, invoice_id, max_attempts: 30, interval: 2) + max_attempts.times do + inv = client.service_invoices.retrieve(company_id: company_id, invoice_id: invoice_id) + return inv if Nfe::FlowStatus.terminal?(inv.flow_status) + sleep interval + end + raise "NFS-e #{invoice_id} não concluiu a tempo" +end +``` + +## `get_status` (atalho exclusivo de `service_invoices`) + +Deriva o status de um `retrieve` (sem HTTP extra) e devolve um `StatusResult` +com predicados de conveniência: + +```ruby +st = client.service_invoices.get_status(company_id: id, invoice_id: iid) +st.status # => "Issued" (String do flow_status; "WaitingSend" se ausente) +st.invoice # => Nfe::ServiceInvoice +st.complete? # => Nfe::FlowStatus.terminal?(status) +st.failed? # => status in %w[IssueFailed CancelFailed] +``` + +Loop equivalente baseado em `get_status`: + +```ruby +loop do + st = client.service_invoices.get_status(company_id: id, invoice_id: iid) + break if st.complete? + sleep 2 +end +``` + +## Flow status + +`Nfe::FlowStatus` (module_function `terminal?`): + +- **TERMINAL** (para o polling): `Issued`, `IssueFailed`, `Cancelled`, `CancelFailed`. +- **NON_TERMINAL** (continua): `PullFromCityHall`, `WaitingCalculateTaxes`, + `WaitingDefineRpsNumber`, `WaitingSend`, `WaitingSendCancel`, `WaitingReturn`, + `WaitingDownload`. + +```ruby +Nfe::FlowStatus.terminal?(invoice.flow_status) # => Boolean +``` + +## Download + +`download_pdf`/`download_xml` retornam **bytes** (`ASCII-8BIT`). Passe +`invoice_id: nil` (ou omita) para baixar o **ZIP** consolidado da empresa. + +```ruby +File.binwrite("nfse-#{iid}.pdf", client.service_invoices.download_pdf(company_id: id, invoice_id: iid)) +File.binwrite("nfse-empresa.zip", client.service_invoices.download_pdf(company_id: id)) # ZIP +``` + +## Discriminação por pattern matching + +```ruby +case client.service_invoices.create(company_id: id, data: payload) +in Nfe::Resources::ServiceInvoicePending(invoice_id:, location:) + enqueue_poll(invoice_id) +in Nfe::Resources::ServiceInvoiceIssued(resource:) + persist(resource) +end +``` + +`*Pending` (`invoice_id`, `location`) e `*Issued` (`resource`) são +`Data.define` imutáveis com `pending?`/`issued?`. diff --git a/spec/fixtures/openapi/minimal.yaml b/spec/fixtures/openapi/minimal.yaml new file mode 100644 index 0000000..4de71a3 --- /dev/null +++ b/spec/fixtures/openapi/minimal.yaml @@ -0,0 +1,64 @@ +openapi: "3.0.3" +info: + title: Minimal Fixture API + version: "1.0.0" +paths: {} +components: + schemas: + Borrower: + type: object + required: + - name + properties: + name: + type: string + description: Legal name of the borrower. + federalTaxNumber: + type: integer + email: + type: string + nullable: true + address: + $ref: "#/components/schemas/Address" + documents: + type: array + items: + $ref: "#/components/schemas/Document" + externalId: + oneOf: + - type: integer + - type: string + Address: + type: object + required: + - city + properties: + city: + type: string + postalCode: + type: string + nullable: true + Document: + type: object + required: + - kind + properties: + kind: + type: string + number: + type: string + InvoiceStatus: + type: string + enum: + - Issued + - Cancelled + - WaitingCalculateTaxes + Priority: + type: integer + enum: + - 1 + - 2 + - 3 + FreeForm: + type: object + additionalProperties: true diff --git a/spec/generator/check_mode_spec.rb b/spec/generator/check_mode_spec.rb new file mode 100644 index 0000000..5cdbe03 --- /dev/null +++ b/spec/generator/check_mode_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "tmpdir" +require "fileutils" +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/generator" +require_relative "../../scripts/generator/check_mode" + +RSpec.describe Nfe::Build::CheckMode do + let(:openapi_dir) { File.expand_path("../fixtures/openapi", __dir__) } + let(:generator) do + Nfe::Build::Generator.new(openapi_dir: openapi_dir, name_mapper: Nfe::Build::NameMapper) + end + + def with_generated_trees + Dir.mktmpdir do |root| + lib_root = File.join(root, "lib") + sig_root = File.join(root, "sig") + generator.write_to(lib_root: lib_root, sig_root: sig_root) + yield(lib_root, sig_root) + end + end + + it "reports ok with no drift after a fresh write" do + with_generated_trees do |lib_root, sig_root| + result = described_class.diff(generator: generator, lib_root: lib_root, sig_root: sig_root) + + expect(result).to include(ok: true, added: [], removed: [], changed: []) + end + end + + it "detects a changed file" do + with_generated_trees do |lib_root, sig_root| + target = Dir.glob(File.join(lib_root, "nfe/generated/minimal/*.rb")).first + File.write(target, "# hand-edited drift\n", mode: "a") + + result = described_class.diff(generator: generator, lib_root: lib_root, sig_root: sig_root) + + expect(result[:ok]).to be(false) + expect(result[:changed]).not_to be_empty + end + end + + it "detects a missing file as added" do + with_generated_trees do |lib_root, sig_root| + target = Dir.glob(File.join(lib_root, "nfe/generated/minimal/*.rb")).first + FileUtils.rm(target) + + result = described_class.diff(generator: generator, lib_root: lib_root, sig_root: sig_root) + + expect(result[:ok]).to be(false) + expect(result[:added]).not_to be_empty + end + end + + it "detects an extra checked-in file as removed" do + with_generated_trees do |lib_root, sig_root| + stale = File.join(lib_root, "nfe/generated/minimal/stale_dto.rb") + File.write(stale, "# frozen_string_literal: true\n") + + result = described_class.diff(generator: generator, lib_root: lib_root, sig_root: sig_root) + + expect(result[:ok]).to be(false) + expect(result[:removed]).not_to be_empty + end + end +end diff --git a/spec/generator/enum_compiler_spec.rb b/spec/generator/enum_compiler_spec.rb new file mode 100644 index 0000000..fb198e6 --- /dev/null +++ b/spec/generator/enum_compiler_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/enum_compiler" + +RSpec.describe Nfe::Build::EnumCompiler do + subject(:compiler) { described_class.new(name_mapper: Nfe::Build::NameMapper) } + + def compile(name, schema) + compiler.compile( + name, schema, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + end + + describe "#compile string-backed enum" do + let(:schema) { { "type" => "string", "enum" => %w[Issued Cancelled] } } + + it "produces an :enum model backed by string" do + model = compile("InvoiceStatus", schema) + + expect(model).to include(kind: :enum, const: "InvoiceStatus", backing: :string) + end + + it "maps each value to a constant entry preserving the value" do + entries = compile("InvoiceStatus", schema).fetch(:entries) + + expect(entries).to include( + a_hash_including(const_name: "Issued", value: "Issued"), + a_hash_including(const_name: "Cancelled", value: "Cancelled") + ) + end + end + + describe "#compile integer-backed enum" do + let(:schema) { { "type" => "integer", "enum" => [1, 2, 3] } } + + it "produces an :enum model backed by integer" do + model = compile("Priority", schema) + + expect(model).to include(kind: :enum, backing: :integer) + expect(model.fetch(:entries).map { |e| e[:value] }).to eq([1, 2, 3]) + end + end + + describe "#compile non-enum schema" do + it "returns nil when the schema has no enum key" do + schema = { "type" => "object", "properties" => {} } + + expect(compile("Borrower", schema)).to be_nil + end + end + + describe "#compile constant collision" do + let(:schema) { { "type" => "string", "enum" => ["a-b", "a.b"] } } + + it "resolves colliding constant names deterministically" do + names = compile("Collide", schema).fetch(:entries).map { |e| e[:const_name] } + + expect(names.uniq.length).to eq(names.length) + end + end +end diff --git a/spec/generator/from_api_spec.rb b/spec/generator/from_api_spec.rb new file mode 100644 index 0000000..1122f8f --- /dev/null +++ b/spec/generator/from_api_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/type_mapper" +require_relative "../../scripts/generator/schema_compiler" +require_relative "../../scripts/generator/ruby_emitter" + +RSpec.describe Nfe::Build::RubyEmitter, ".emit" do + # Exercises the generated `from_api` hydration on the emitted Data classes. + let(:schemas) do + { + "Borrower" => { + "type" => "object", + "required" => ["name"], + "properties" => { + "name" => { "type" => "string" }, + "federalTaxNumber" => { "type" => "integer" }, + "address" => { "$ref" => "#/components/schemas/Address" }, + "documents" => { + "type" => "array", + "items" => { "$ref" => "#/components/schemas/Document" } + } + } + }, + "Address" => { + "type" => "object", + "properties" => { "city" => { "type" => "string" } } + }, + "Document" => { + "type" => "object", + "properties" => { "kind" => { "type" => "string" } } + } + } + end + + # Eval all DTOs into one anonymous module so $ref hydration resolves the + # sibling constants (Address.from_api, Document.from_api). + let(:namespace_module) do + type_mapper = Nfe::Build::TypeMapper.new(schema_names: schemas.keys) + compiler = Nfe::Build::SchemaCompiler.new( + name_mapper: Nfe::Build::NameMapper, type_mapper: type_mapper + ) + mod = Module.new + schemas.each do |name, schema| + model = compiler.compile( + name, schema, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + mod.module_eval(described_class.emit(model), "(generated #{name})", 1) + end + mod.const_get(:Nfe).const_get(:Generated).const_get(:MinimalV1) + end + + let(:borrower) { namespace_module.const_get(:Borrower) } + + it "returns nil for a nil payload" do + expect(borrower.from_api(nil)).to be_nil + end + + it "maps camelCase keys to snake_case members" do + instance = borrower.from_api("name" => "Acme", "federalTaxNumber" => 123) + + expect(instance.name).to eq("Acme") + expect(instance.federal_tax_number).to eq(123) + end + + it "drops unknown keys without raising" do + instance = borrower.from_api("name" => "Acme", "surpriseField" => "x") + + expect(instance.name).to eq("Acme") + end + + it "tolerates missing keys, leaving them nil" do + instance = borrower.from_api("name" => "Acme") + + expect(instance.federal_tax_number).to be_nil + end + + it "hydrates a nested $ref object into its DTO" do + instance = borrower.from_api("name" => "Acme", "address" => { "city" => "Sao Paulo" }) + + expect(instance.address).to be_a(namespace_module.const_get(:Address)) + expect(instance.address.city).to eq("Sao Paulo") + end + + it "hydrates an array of $ref element-by-element" do + instance = borrower.from_api( + "name" => "Acme", + "documents" => [{ "kind" => "RG" }, { "kind" => "CPF" }] + ) + + expect(instance.documents).to all(be_a(namespace_module.const_get(:Document))) + expect(instance.documents.map(&:kind)).to eq(%w[RG CPF]) + end +end diff --git a/spec/generator/generator_spec.rb b/spec/generator/generator_spec.rb new file mode 100644 index 0000000..5c719f0 --- /dev/null +++ b/spec/generator/generator_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require "tmpdir" +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/generator" + +RSpec.describe Nfe::Build::Generator do + subject(:generator) do + described_class.new(openapi_dir: openapi_dir, name_mapper: Nfe::Build::NameMapper) + end + + let(:openapi_dir) { File.expand_path("../fixtures/openapi", __dir__) } + + describe "#generate" do + subject(:output) { generator.generate } + + it "returns both .rb and .rbs entries keyed by relative path" do + rb = output.keys.select { |k| k.end_with?(".rb") } + rbs = output.keys.select { |k| k.end_with?(".rbs") } + + expect(rb).not_to be_empty + expect(rbs).not_to be_empty + end + + it "writes value objects under lib/nfe/generated and signatures under sig/nfe/generated" do + expect(output.keys).to include( + a_string_matching(%r{\Alib/nfe/generated/minimal/}), + a_string_matching(%r{\Asig/nfe/generated/minimal/}) + ) + end + + it "includes the require_relative loader and the generated marker" do + expect(output).to have_key("lib/nfe/generated.rb") + expect(output).to have_key("lib/nfe/generated/generated_marker.rb") + end + + it "records the spec hash in the marker" do + expect(output.fetch("lib/nfe/generated/generated_marker.rb")).to include("sha256:") + end + + it "is deterministic — generating twice yields byte-identical output" do + expect(generator.generate).to eq(output) + end + end + + describe "#write_to" do + it "writes both trees and returns the list of written paths" do + Dir.mktmpdir do |root| + lib_root = File.join(root, "lib") + sig_root = File.join(root, "sig") + + written = generator.write_to(lib_root: lib_root, sig_root: sig_root) + + expect(written).not_to be_empty + expect(written).to include(a_string_matching(%r{lib/nfe/generated/minimal/})) + expect(written).to include(a_string_matching(%r{sig/nfe/generated/minimal/})) + expect(written).to all(satisfy { |path| File.exist?(path) }) + end + end + end +end diff --git a/spec/generator/name_mapper_spec.rb b/spec/generator/name_mapper_spec.rb new file mode 100644 index 0000000..08f60ab --- /dev/null +++ b/spec/generator/name_mapper_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/name_mapper" + +RSpec.describe Nfe::Build::NameMapper do + describe ".namespace_from_spec" do + it "converts kebab/dot names to PascalCase and preserves version suffix" do + expect(described_class.namespace_from_spec("service-invoice-rtc-v1.yaml")) + .to eq("ServiceInvoiceRtcV1") + end + + it "produces distinct namespaces for versioned and unversioned families" do + expect(described_class.namespace_from_spec("consulta-cnpj.yaml")).to eq("ConsultaCnpj") + expect(described_class.namespace_from_spec("consulta-cnpj-v3.yaml")).to eq("ConsultaCnpjV3") + end + + it "handles a .json extension" do + expect(described_class.namespace_from_spec("contribuintes-v2.json")).to eq("ContribuintesV2") + end + end + + describe ".module_path_from_spec" do + it "snake_cases the basename without extension" do + expect(described_class.module_path_from_spec("service-invoice-rtc-v1.yaml")) + .to eq("service_invoice_rtc_v1") + end + end + + describe ".class_name" do + it "keeps a valid constant unchanged" do + expect(described_class.class_name("NFSeRequest")).to eq("NFSeRequest") + end + + it "replaces invalid characters with underscore" do + expect(described_class.class_name("Foo.Bar-Baz")).to eq("Foo_Bar_Baz") + end + + it "capitalises a camelCase schema name into a constant" do + expect(described_class.class_name("thirdPartyReimbursementDocument")) + .to eq("ThirdPartyReimbursementDocument") + end + + it "yields a valid constant when the name starts with a digit" do + result = described_class.class_name("3DSecure") + expect(result).to eq("N3DSecure") + expect(result).to match(/\A[A-Z]/) + end + end + + describe ".file_snake" do + it "snake_cases a constant for use as a filename" do + expect(described_class.file_snake("NFSeRequest")).to eq("nfse_request") + end + end + + describe ".attr_name" do + it "converts camelCase to snake_case" do + expect(described_class.attr_name("federalTaxNumber")).to eq("federal_tax_number") + end + + it "converts PascalCase to snake_case" do + expect(described_class.attr_name("CityName")).to eq("city_name") + end + + it "prefixes an underscore when it starts with a digit" do + expect(described_class.attr_name("3rdParty")).to start_with("_") + end + + it "suffixes reserved words with an underscore" do + expect(described_class.attr_name("class")).to eq("class_") + expect(described_class.attr_name("end")).to eq("end_") + end + end +end diff --git a/spec/generator/rbs_emitter_spec.rb b/spec/generator/rbs_emitter_spec.rb new file mode 100644 index 0000000..a6ea8ff --- /dev/null +++ b/spec/generator/rbs_emitter_spec.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/type_mapper" +require_relative "../../scripts/generator/schema_compiler" +require_relative "../../scripts/generator/enum_compiler" +require_relative "../../scripts/generator/rbs_emitter" + +RSpec.describe Nfe::Build::RbsEmitter do + let(:type_mapper) { Nfe::Build::TypeMapper.new(schema_names: %w[Borrower Address]) } + let(:schema_compiler) do + Nfe::Build::SchemaCompiler.new(name_mapper: Nfe::Build::NameMapper, type_mapper: type_mapper) + end + let(:enum_compiler) { Nfe::Build::EnumCompiler.new(name_mapper: Nfe::Build::NameMapper) } + + let(:object_schema) do + { + "type" => "object", + "required" => ["name"], + "properties" => { + "name" => { "type" => "string" }, + "federalTaxNumber" => { "type" => "integer" }, + "email" => { "type" => "string", "nullable" => true } + } + } + end + + def data_model(name, schema) + schema_compiler.compile( + name, schema, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + end + + def rbs_parses?(source) + require "rbs" + RBS::Parser.parse_signature(source) + true + rescue LoadError + :skip + end + + describe ".emit data model" do + subject(:source) { described_class.emit(data_model("Borrower", object_schema)) } + + it "carries the AUTO-GENERATED comment banner with source and hash" do + expect(source).to include("# AUTO-GENERATED") + expect(source).to include("# Source: openapi/minimal.yaml") + expect(source).to include("# Hash: sha256:abc") + end + + it "declares the class under the generated namespace" do + expect(source).to include("module Nfe") + expect(source).to include("module Generated") + expect(source).to include("module MinimalV1") + expect(source).to include("class Borrower < Data") + end + + it "mirrors the .rb members as typed attr_readers" do + expect(source).to include("attr_reader name: String") + expect(source).to include("attr_reader federal_tax_number: Integer") + end + + it "types an optional/nullable property as nullable" do + expect(source).to include("email: String?") + end + + it "declares the from_api signature" do + expect(source).to include("def self.from_api:") + expect(source).to include("instance") + end + + it "is valid RBS syntax when the rbs gem is available" do + result = rbs_parses?(source) + skip "rbs gem not available" if result == :skip + + expect(result).to be(true) + end + end + + describe ".emit enum model" do + subject(:source) do + model = enum_compiler.compile( + "InvoiceStatus", { "type" => "string", "enum" => %w[Issued Cancelled] }, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + described_class.emit(model) + end + + it "declares the enum constants and ALL" do + expect(source).to include("Issued") + expect(source).to include("Cancelled") + expect(source).to include("ALL") + end + + it "is valid RBS syntax when the rbs gem is available" do + result = rbs_parses?(source) + skip "rbs gem not available" if result == :skip + + expect(result).to be(true) + end + end +end diff --git a/spec/generator/ruby_emitter_spec.rb b/spec/generator/ruby_emitter_spec.rb new file mode 100644 index 0000000..4cdbf5d --- /dev/null +++ b/spec/generator/ruby_emitter_spec.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/type_mapper" +require_relative "../../scripts/generator/schema_compiler" +require_relative "../../scripts/generator/enum_compiler" +require_relative "../../scripts/generator/ruby_emitter" + +RSpec.describe Nfe::Build::RubyEmitter do + let(:type_mapper) { Nfe::Build::TypeMapper.new(schema_names: %w[Borrower Address]) } + let(:schema_compiler) do + Nfe::Build::SchemaCompiler.new(name_mapper: Nfe::Build::NameMapper, type_mapper: type_mapper) + end + let(:enum_compiler) { Nfe::Build::EnumCompiler.new(name_mapper: Nfe::Build::NameMapper) } + let(:object_schema) do + { + "type" => "object", + "required" => ["name"], + "properties" => { + "name" => { "type" => "string" }, + "federalTaxNumber" => { "type" => "integer" } + } + } + end + + def data_model(name, schema) + schema_compiler.compile( + name, schema, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + end + + def eval_in_anon_module(source) + mod = Module.new + mod.module_eval(source, "(generated)", 1) + mod + end + + describe ".emit data model" do + subject(:source) { described_class.emit(data_model("Borrower", object_schema)) } + + it "puts the frozen_string_literal magic comment on line 1" do + expect(source.lines.first.chomp).to eq("# frozen_string_literal: true") + end + + it "carries the AUTO-GENERATED banner with source and hash" do + expect(source).to include("# AUTO-GENERATED") + expect(source).to include("# Source: openapi/minimal.yaml") + expect(source).to include("# Hash: sha256:abc") + end + + it "declares a Data.define with the snake_case members" do + expect(source).to include("Data.define(") + expect(source).to include(":name") + expect(source).to include(":federal_tax_number") + end + + it "emits a from_api class method" do + expect(source).to include("def self.from_api") + end + + it "records the original camelCase name for traceability" do + expect(source).to include("federalTaxNumber") + end + + it "evals into a loadable constant under Nfe::Generated" do + mod = eval_in_anon_module(source) + const = mod.const_get(:Nfe).const_get(:Generated).const_get(:MinimalV1).const_get(:Borrower) + + expect(const.members).to contain_exactly(:name, :federal_tax_number) + end + end + + describe ".emit enum model" do + subject(:source) do + model = enum_compiler.compile( + "InvoiceStatus", { "type" => "string", "enum" => %w[Issued Cancelled] }, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + described_class.emit(model) + end + + it "emits frozen constants and an ALL array" do + expect(source).to include("Issued = \"Issued\"") + expect(source).to include("Cancelled = \"Cancelled\"") + expect(source).to include("ALL = [") + end + + it "evals into a module exposing the enum constants" do + mod = eval_in_anon_module(source) + enum = mod.const_get(:Nfe).const_get(:Generated).const_get(:MinimalV1).const_get(:InvoiceStatus) + + expect(enum::ALL).to contain_exactly("Issued", "Cancelled") + end + end + + describe ".emit alias model" do + subject(:source) do + model = schema_compiler.compile( + "FreeForm", { "type" => "object", "additionalProperties" => true }, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + described_class.emit(model) + end + + it "emits a thin Hash assignment and loads" do + expect(source.lines.first.chomp).to eq("# frozen_string_literal: true") + mod = eval_in_anon_module(source) + const = mod.const_get(:Nfe).const_get(:Generated).const_get(:MinimalV1).const_get(:FreeForm) + + expect(const).to eq(Hash) + end + end +end diff --git a/spec/generator/schema_compiler_spec.rb b/spec/generator/schema_compiler_spec.rb new file mode 100644 index 0000000..590ffe0 --- /dev/null +++ b/spec/generator/schema_compiler_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/name_mapper" +require_relative "../../scripts/generator/type_mapper" +require_relative "../../scripts/generator/schema_compiler" + +RSpec.describe Nfe::Build::SchemaCompiler do + subject(:compiler) do + described_class.new(name_mapper: Nfe::Build::NameMapper, type_mapper: type_mapper) + end + + let(:type_mapper) { Nfe::Build::TypeMapper.new(schema_names: %w[Borrower Address]) } + + def compile(name, schema) + compiler.compile( + name, schema, + namespace: "MinimalV1", module_path: "minimal_v1", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + end + + describe "#compile object schema" do + let(:schema) do + { + "type" => "object", + "required" => ["name"], + "properties" => { + "name" => { "type" => "string" }, + "federalTaxNumber" => { "type" => "integer" } + } + } + end + + it "produces a :data model carrying namespace and naming metadata" do + model = compile("Borrower", schema) + + expect(model).to include( + kind: :data, namespace: "MinimalV1", const: "Borrower", + module_path: "minimal_v1", file_snake: "borrower", + source_spec: "openapi/minimal.yaml", spec_hash: "sha256:abc" + ) + end + + it "orders attributes by name for deterministic output" do + names = compile("Borrower", schema).fetch(:attributes).map { |a| a[:ruby_name] } + + expect(names).to eq(%w[federal_tax_number name]) + end + + it "maps camelCase properties to snake_case ruby names and keeps the original" do + attr = compile("Borrower", schema).fetch(:attributes) + .find { |a| a[:original_name] == "federalTaxNumber" } + + expect(attr[:ruby_name]).to eq("federal_tax_number") + end + + it "marks required properties required and others optional" do + attrs = compile("Borrower", schema).fetch(:attributes).to_h do |a| + [a[:ruby_name], a[:required]] + end + + expect(attrs).to eq("name" => true, "federal_tax_number" => false) + end + end + + describe "#compile allOf composition" do + let(:schema) do + { + "allOf" => [ + { "type" => "object", "properties" => { "a" => { "type" => "string" } } }, + { "type" => "object", "properties" => { "b" => { "type" => "integer" } } } + ] + } + end + + it "shallow-merges member properties into one data model" do + names = compile("Merged", schema).fetch(:attributes).map { |a| a[:ruby_name] } + + expect(names).to contain_exactly("a", "b") + end + end + + describe "#compile reserved-word property" do + let(:schema) do + { "type" => "object", "properties" => { "class" => { "type" => "string" } } } + end + + it "renames a reserved-word property to a valid ruby identifier" do + ruby_name = compile("Reserved", schema).fetch(:attributes).first[:ruby_name] + + expect(ruby_name).to eq("class_") + end + end + + describe "#compile free-form object" do + let(:schema) { { "type" => "object", "additionalProperties" => true } } + + it "falls back to an :alias model of Hash[String, untyped]" do + model = compile("FreeForm", schema) + + expect(model).to include(kind: :alias, rbs_type: "Hash[String, untyped]") + end + end +end diff --git a/spec/generator/spec_loader_spec.rb b/spec/generator/spec_loader_spec.rb new file mode 100644 index 0000000..a82a839 --- /dev/null +++ b/spec/generator/spec_loader_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require "tempfile" +require_relative "../../scripts/generator/spec_loader" + +RSpec.describe Nfe::Build::SpecLoader do + let(:fixture) { File.expand_path("../fixtures/openapi/minimal.yaml", __dir__) } + + def write_temp(contents, ext: ".yaml") + file = Tempfile.new(["spec_loader", ext]) + file.write(contents) + file.flush + file.path + end + + describe "#schemas" do + it "returns the components.schemas map keyed by schema name" do + loader = described_class.new(fixture) + + expect(loader.schemas.keys).to include("Borrower", "Address", "InvoiceStatus") + end + + it "exposes each schema as a Hash fragment" do + loader = described_class.new(fixture) + + expect(loader.schemas.fetch("Borrower")).to include("type" => "object") + end + + it "returns an empty hash when components.schemas is absent" do + path = write_temp("openapi: \"3.0.0\"\ninfo:\n title: Empty\n") + + expect(described_class.new(path).schemas).to eq({}) + end + end + + describe "#path and #basename" do + it "exposes the file path and basename" do + loader = described_class.new(fixture) + + expect(loader.path).to eq(fixture) + expect(loader.basename).to eq("minimal.yaml") + end + end + + describe "#hash" do + it "is the sha256 of the raw bytes, prefixed sha256:" do + loader = described_class.new(fixture) + raw = File.binread(fixture) + expected = "sha256:#{Digest::SHA256.hexdigest(raw)}" + + expect(loader.hash).to eq(expected) + end + + it "is stable across repeated reads of the same file" do + first = described_class.new(fixture).hash + second = described_class.new(fixture).hash + + expect(first).to eq(second) + end + end + + describe "JSON support" do + it "parses a JSON document through Psych" do + json = "{\"openapi\":\"3.0.0\",\"components\":{\"schemas\":{\"Foo\":{\"type\":\"object\"}}}}" + path = write_temp(json, ext: ".json") + + expect(described_class.new(path).schemas.keys).to eq(["Foo"]) + end + end + + describe "validation failures" do + it "raises Nfe::Build::Error when the file cannot be parsed" do + path = write_temp("key: value\n bad: : indentation\n:::") + + expect { described_class.new(path) }.to raise_error(Nfe::Build::Error) + end + + it "raises Nfe::Build::Error when the parsed root is not a Hash" do + path = write_temp("- just\n- a\n- list\n") + + expect { described_class.new(path) }.to raise_error(Nfe::Build::Error) + end + + it "raises Nfe::Build::Error when neither openapi nor swagger key is present" do + path = write_temp("info:\n title: No version key\n") + + expect { described_class.new(path) }.to raise_error(Nfe::Build::Error) + end + + it "accepts a swagger document" do + path = write_temp("swagger: \"2.0\"\ninfo:\n title: Legacy\n") + + expect { described_class.new(path) }.not_to raise_error + end + end +end diff --git a/spec/generator/type_mapper_spec.rb b/spec/generator/type_mapper_spec.rb new file mode 100644 index 0000000..2f9e9a2 --- /dev/null +++ b/spec/generator/type_mapper_spec.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +require_relative "../../scripts/generator/type_mapper" + +RSpec.describe Nfe::Build::TypeMapper do + subject(:mapper) { described_class.new(schema_names: %w[Address Document]) } + + describe "#rbs_type primitives" do + it "maps the primitive scalar types" do + expect(mapper.rbs_type("type" => "string")).to eq("String") + expect(mapper.rbs_type("type" => "integer")).to eq("Integer") + expect(mapper.rbs_type("type" => "number")).to eq("Float") + expect(mapper.rbs_type("type" => "boolean")).to eq("bool") + end + + it "maps a free-form object to Hash[String, untyped]" do + expect(mapper.rbs_type("type" => "object")).to eq("Hash[String, untyped]") + end + + it "treats date and date-time formats as String" do + expect(mapper.rbs_type("type" => "string", "format" => "date-time")).to eq("String") + expect(mapper.rbs_type("type" => "string", "format" => "date")).to eq("String") + end + end + + describe "#rbs_type refs" do + it "resolves a known local $ref to its class name" do + expect(mapper.rbs_type("$ref" => "#/components/schemas/Address")).to eq("Address") + end + + it "falls back to untyped for an unknown local $ref" do + expect(mapper.rbs_type("$ref" => "#/components/schemas/Unknown")).to eq("untyped") + end + + it "falls back to untyped for a cross-file $ref" do + expect(mapper.rbs_type("$ref" => "other.yaml#/components/schemas/Address")).to eq("untyped") + end + end + + describe "#rbs_type arrays" do + it "maps an array of a primitive item type" do + expect(mapper.rbs_type("type" => "array", "items" => { "type" => "string" })) + .to eq("Array[String]") + end + + it "maps an array of a $ref item type" do + expect(mapper.rbs_type("type" => "array", "items" => { "$ref" => "#/components/schemas/Document" })) + .to eq("Array[Document]") + end + + it "maps an array without items to Array[untyped]" do + expect(mapper.rbs_type("type" => "array")).to eq("Array[untyped]") + end + end + + describe "#rbs_type nullable" do + it "suffixes a nullable type with ?" do + expect(mapper.rbs_type("type" => "string", "nullable" => true)).to eq("String?") + end + end + + describe "#rbs_type oneOf" do + it "maps a oneOf of primitives to an RBS union" do + fragment = { "oneOf" => [{ "type" => "integer" }, { "type" => "string" }] } + + expect(mapper.rbs_type(fragment)).to eq("Integer | String") + end + + it "maps a oneOf of objects to untyped" do + fragment = { "oneOf" => [ + { "$ref" => "#/components/schemas/Address" }, + { "$ref" => "#/components/schemas/Document" } + ] } + + expect(mapper.rbs_type(fragment)).to eq("untyped") + end + end + + describe "#ref_target" do + it "returns the class name for a known local $ref" do + expect(mapper.ref_target("$ref" => "#/components/schemas/Address")).to eq("Address") + end + + it "returns nil for a non-ref fragment" do + expect(mapper.ref_target("type" => "string")).to be_nil + end + end + + describe "#array_ref_target" do + it "returns the item class name for an array of a known $ref" do + fragment = { "type" => "array", "items" => { "$ref" => "#/components/schemas/Document" } } + + expect(mapper.array_ref_target(fragment)).to eq("Document") + end + + it "returns nil for an array of primitives" do + fragment = { "type" => "array", "items" => { "type" => "string" } } + + expect(mapper.array_ref_target(fragment)).to be_nil + end + end +end diff --git a/spec/nfe/api_resource_spec.rb b/spec/nfe/api_resource_spec.rb deleted file mode 100644 index dcc0f4f..0000000 --- a/spec/nfe/api_resource_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -require_relative '../rspec_helper' - -describe Nfe::ApiResource do - before(:each) do - Nfe.api_key('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - end - - it 'call Nfe API' do - url = "/v1/companies" - method = :get - - response = Nfe::Company.api_request(url, method) - expect(response['companies'].class).to eq(Array) - end - - it 'should throw error' do - url = "/v1/companies" - method = :post - - params = {exp_month: 5, - exp_year: 2017, - cvc: '021', - name: 'Doctor Who' - } - - expect{ Nfe::Company.api_request(url, method, params) }.to raise_error Nfe::NfeError - - end - - it 'should create NfeError with error message and http code' do - http_code = 400 - json_message = {error: {type: '', message: 'Error Message'}} - http_message = '' - message = 'Error Message' - nfe_error = Nfe::NfeError.new(http_code, json_message, http_message, message) - expect(nfe_error.http_status).to eq(http_code) - expect(nfe_error.json_message).to eq(json_message) - expect(nfe_error.http_message).to eq(http_message) - expect(nfe_error.message).to eq(message) - end -end \ No newline at end of file diff --git a/spec/nfe/certificate_spec.rb b/spec/nfe/certificate_spec.rb new file mode 100644 index 0000000..30ec0dd --- /dev/null +++ b/spec/nfe/certificate_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require "openssl" +require "time" + +RSpec.describe Nfe::CertificateValidator do + # Build a self-signed cert + PKCS#12 in-memory so the spec needs no fixture + # file on disk. + def build_pfx(password:, not_after: Time.now + (365 * 24 * 60 * 60)) + key = OpenSSL::PKey::RSA.new(2048) + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 4242 + name = OpenSSL::X509::Name.parse("/CN=Acme Test/O=NFE.io Spec") + cert.subject = name + cert.issuer = name + cert.public_key = key.public_key + cert.not_before = Time.now - 60 + cert.not_after = not_after + cert.sign(key, OpenSSL::Digest.new("SHA256")) + OpenSSL::PKCS12.create(password, "spec-cert", key, cert).to_der + end + + describe ".supported_format?" do + it "is true for .pfx, .p12 and uppercase variants" do + %w[cert.pfx cert.p12 CERT.PFX a.b.P12].each do |name| + expect(described_class.supported_format?(name)).to be(true) + end + end + + it "is false for unsupported extensions and nil" do + ["cert.pem", "cert.txt", "noext", "", nil].each do |name| + expect(described_class.supported_format?(name)).to be(false) + end + end + end + + describe ".validate" do + let(:password) { "pfx-pass-123" } + let(:expiry) { Time.now + (200 * 24 * 60 * 60) } + let(:der) { build_pfx(password: password, not_after: expiry) } + + it "extracts real metadata with the correct password" do + info = described_class.validate(der, password) + expect(info).to be_a(Nfe::CertificateInfo) + expect(info.subject).to include("Acme Test") + expect(info.issuer).to include("Acme Test") + expect(info.serial_number).to eq("4242") + expect(info.not_after).to be_within(60).of(expiry) + expect(info.not_before).to be_a(Time) + end + + it "raises InvalidRequestError on a wrong password" do + expect { described_class.validate(der, "wrong-password") } + .to raise_error(Nfe::InvalidRequestError, /Certificado ou senha inválidos/) + end + + it "raises InvalidRequestError on non-DER bytes" do + expect { described_class.validate("not a certificate at all", password) } + .to raise_error(Nfe::InvalidRequestError, /Certificado ou senha inválidos/) + end + + it "never leaks the password into the raised error" do + described_class.validate(der, "leak-check-secret") + rescue Nfe::InvalidRequestError => e + expect(e.message).not_to include("leak-check-secret") + end + end + + describe ".days_until_expiration" do + it "counts whole days for a future expiry" do + future = Time.now + (10 * 24 * 60 * 60) + 3600 + expect(described_class.days_until_expiration(future)).to eq(10) + end + + it "is negative once expired" do + past = Time.now - (5 * 24 * 60 * 60) + expect(described_class.days_until_expiration(past)).to be < 0 + end + + it "accepts an ISO-8601 string" do + future = (Time.now + (3 * 24 * 60 * 60) + 7200).utc.iso8601 + expect(described_class.days_until_expiration(future)).to eq(3) + end + end + + describe ".expiring_soon?" do + it "is true within the default 30-day threshold" do + soon = Time.now + (10 * 24 * 60 * 60) + 3600 + expect(described_class.expiring_soon?(soon)).to be(true) + end + + it "is false beyond the threshold" do + later = Time.now + (200 * 24 * 60 * 60) + expect(described_class.expiring_soon?(later)).to be(false) + end + + it "is false once already expired (negative days)" do + past = Time.now - (1 * 24 * 60 * 60) + expect(described_class.expiring_soon?(past)).to be(false) + end + + it "honours a custom threshold" do + in_50_days = Time.now + (50 * 24 * 60 * 60) + 3600 + expect(described_class.expiring_soon?(in_50_days, 60)).to be(true) + expect(described_class.expiring_soon?(in_50_days, 30)).to be(false) + end + end +end diff --git a/spec/nfe/client_request_options_spec.rb b/spec/nfe/client_request_options_spec.rb new file mode 100644 index 0000000..293948c --- /dev/null +++ b/spec/nfe/client_request_options_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Behavior of per-call Nfe::RequestOptions threaded through Nfe::Client#request +# (the value object itself is covered in request_options_spec.rb). +RSpec.describe "Nfe::Client per-call request options" do # rubocop:disable RSpec/DescribeClass + subject(:client) { Nfe::Client.new(api_key: "client-key") } + + def with_fake_transport(target) + fake = FakeTransport.new([Nfe::Http::Response.new(status: 200, body: "{}")]) + allow(target).to receive(:build_transport).and_return(fake) + fake + end + + it "overrides the family-resolved api_key for a single call" do + fake = with_fake_transport(client) + options = Nfe::RequestOptions.new(api_key: "tenant-key") + + client.request(:get, family: :main, path: "/v1/companies", request_options: options) + + expect(fake.requests.last.headers["X-NFE-APIKEY"]).to eq("tenant-key") + end + + it "falls back to family resolution for nil fields" do + fake = with_fake_transport(client) + options = Nfe::RequestOptions.new(api_key: nil, base_url: nil, timeout: 90) + + client.request(:get, family: :main, path: "/v1/companies", request_options: options) + + sent = fake.requests.last + expect(sent.headers["X-NFE-APIKEY"]).to eq("client-key") + expect(sent.base_url).to eq("https://api.nfe.io") + expect(sent.read_timeout).to eq(90) + end + + it "lets two tenants share one client with distinct per-call keys" do + fake = with_fake_transport(client) + + client.request(:get, family: :main, path: "/v1/companies", + request_options: Nfe::RequestOptions.new(api_key: "tenant-a")) + client.request(:get, family: :main, path: "/v1/companies", + request_options: Nfe::RequestOptions.new(api_key: "tenant-b")) + + keys = fake.requests.map { |r| r.headers["X-NFE-APIKEY"] } + expect(keys).to eq(%w[tenant-a tenant-b]) + end +end diff --git a/spec/nfe/client_spec.rb b/spec/nfe/client_spec.rb new file mode 100644 index 0000000..14b009c --- /dev/null +++ b/spec/nfe/client_spec.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Client do + subject(:client) { described_class.new(api_key: "key") } + + # Inject a request-capturing fake transport in place of the real Net::HTTP + # stack, so #request can be exercised without network. + def with_fake_transport(target, response: Nfe::Http::Response.new(status: 200, body: "{}")) + fake = FakeTransport.new([response]) + allow(target).to receive(:build_transport).and_return(fake) + fake + end + + describe "construction" do + it "instantiates with an API key and exposes its configuration" do + expect(client).to be_a(described_class) + expect(client.configuration).to be_a(Nfe::Configuration) + expect(client.configuration.api_key).to eq("key") + end + + it "accepts an injected configuration and ignores convenience args" do + configuration = Nfe::Configuration.new(api_key: "k", timeout: 120) + built = described_class.new(configuration: configuration, timeout: 5) + expect(built.configuration).to be(configuration) + expect(built.configuration.timeout).to eq(120) + end + end + + describe "resource accessors" do + it "declares nineteen resource accessors (17 canonical + 2 RTC addons)" do + expect(described_class::RESOURCES.size).to eq(19) + end + + it "returns the right resource class for each accessor" do + described_class::RESOURCES.each do |name, klass| + expect(client.public_send(name)).to be_a(klass) + end + end + + it "memoizes each accessor (same instance on repeat reads)" do + first = client.companies + expect(client.companies).to be(first) + end + end + + describe "two-key model" do + it "serves a data-family resource with only a data_api_key" do + data_client = described_class.new(data_api_key: "data") + fake = with_fake_transport(data_client) + + data_client.request(:get, family: :addresses, path: "/addresses/01310100") + + expect(fake.requests.last.headers["X-NFE-APIKEY"]).to eq("data") + end + + it "raises ConfigurationError when a main-family request has no main key" do + data_client = described_class.new(data_api_key: "data") + with_fake_transport(data_client) + + expect { data_client.request(:get, family: :main, path: "/v1/companies") } + .to raise_error(Nfe::ConfigurationError) + end + end + + describe "#request" do + it "applies host, key, User-Agent and Accept headers" do + fake = with_fake_transport(client) + client.request(:get, family: :main, path: "/v1/companies") + + sent = fake.requests.last + expect(sent.base_url).to eq("https://api.nfe.io") + expect(sent.path).to eq("/v1/companies") + expect(sent.headers["X-NFE-APIKEY"]).to eq("key") + expect(sent.headers["Accept"]).to eq("application/json") + expect(sent.headers["User-Agent"]).to include(Nfe::VERSION) + end + + it "includes the configured user_agent_suffix in the User-Agent" do + suffixed = described_class.new(api_key: "key", user_agent_suffix: "my-app/2.1") + fake = with_fake_transport(suffixed) + suffixed.request(:get, family: :main, path: "/v1/companies") + + ua = fake.requests.last.headers["User-Agent"] + expect(ua).to include(Nfe::VERSION) + expect(ua).to include("my-app/2.1") + end + + it "raises a typed error on a non-2xx response" do + with_fake_transport(client, response: Nfe::Http::Response.new(status: 404, body: "{}")) + expect { client.request(:get, family: :main, path: "/v1/missing") } + .to raise_error(Nfe::NotFoundError) + end + + it "treats 202 as success and returns the response" do + with_fake_transport(client, response: Nfe::Http::Response.new(status: 202)) + response = client.request(:post, family: :main, path: "/v1/companies/x/invoices") + expect(response.status).to eq(202) + end + end + + describe "thread safety" do + it "returns one shared instance to concurrent first readers" do + shared = described_class.new(api_key: "key") + results = Queue.new + + threads = Array.new(16) do + Thread.new { results << shared.companies } + end + threads.each(&:join) + + instances = [] + instances << results.pop until results.empty? + expect(instances.uniq.size).to eq(1) + end + end +end diff --git a/spec/nfe/company_spec.rb b/spec/nfe/company_spec.rb deleted file mode 100644 index 861bbbd..0000000 --- a/spec/nfe/company_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require_relative '../rspec_helper' - -describe Nfe::Company do - before(:each) do - Nfe.api_key('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - end - - let(:company_params) { - company_params = { id: "55df4dc6b6cd9007e4f13ee8", federaltaxnumber: "25953366000106", name: "Empresa de Teste"} - } - - it 'should create a Company' do - company_params = {name: 'MyCompany', - federaltaxnumber: 54458287000127, - email: 'empresa@teste.com.br', - openningdate: '21/02/2005', - taxregime: 'LucroReal', - legalnature: 'EmpresaPublica', - municipaltaxnumber: 2} - response = {"companies"=>{"id"=>"55e0a00c41c23f0a584b398a", "name"=>"MyCompany", "federalTaxNumber"=>82388034000160, - "email"=>"empresa@teste.com.br", "taxRegime"=>"LucroReal", "legalNature"=>"EmpresaPublica", - "economicActivities"=>[], "municipalTaxNumber"=>2, "rpsSerialNumber"=>"IO", "rpsNumber"=>0, - "environment"=>"Development", "fiscalStatus"=>"Pending", "certificate"=>{"status"=>"Pending"}, - "createdOn"=>"2015-09-03T19:43:05.3772349+00:00", "modifiedOn"=>"2015-09-03T19:43:05.3772349+00:00"}} - allow(Nfe::Company).to receive(:api_request).and_return(response) - company = Nfe::Company.create(company_params) - - expect(company.name).to eq('MyCompany') - expect(company.email).to eq('empresa@teste.com.br') - end - - it 'should list all active companies' do - company_list = Nfe::Company.list_all - expect(company_list.object).to eq('list') - expect(company_list.data.size).to be >= 1 - end - - it 'should retrieve a company by id' do - company = Nfe::Company.retrieve(company_params[:id]) - expect(company.id).to eq(company_params[:id]) - expect(company.name).to eq(company_params[:name]) - end - - it 'should retrieve a company by federalTaxNumber' do - company = Nfe::Company.retrieve(company_params[:federaltaxnumber]) - expect(company.name).to eq("Company Name") - end - - it 'should delete a company' do - skip "Recurso não está sendo deletado na API" - company_params = {name: 'Company Teste', - federaltaxnumber: 32657522000157, - email: 'empresa@teste.com.br', - openningdate: '21/02/2005', - taxregime: 'LucroReal', - legalnature: 'EmpresaPublica', - municipaltaxnumber: 2} - response = {"companies"=>{"id"=>"55e9a4cf440c3b0b84ceace6", "name"=>"Company Teste", "federalTaxNumber"=>32657522000157, - "email"=>"empresa@teste.com.br", "taxRegime"=>"LucroReal", "legalNature"=>"EmpresaPublica", - "economicActivities"=>[], "municipalTaxNumber"=>2, "rpsSerialNumber"=>"IO", "rpsNumber"=>0, - "environment"=>"Development", "fiscalStatus"=>"Pending", "certificate"=>{"status"=>"Pending"}, - "createdOn"=>"2015-09-03T19:43:05.3772349+00:00", "modifiedOn"=>"2015-09-03T19:43:05.3772349+00:00"}} - allow(Nfe::Company).to receive(:api_request).and_return(response) - company = Nfe::Company.create(company_params) - deleted_company = company.delete('55e9a4cf440c3b0b84ceace6') - expect(deleted_company).to eq('teste') - end - - it 'should update a company' do - skip "Recurso retorna 0 para atributos (taxRegime e legalNature)" - company = Nfe::Company.retrieve(company_params[:id]) - company.name = "New Company Name" - company.save - company_updated = Nfe::Company.retrieve(company_params[:id]) - expect(company.name).to eq(company_updated.name) - expect(company.name).to eq("New Company Name") - expect(company_updated.name).to eq("New Company Name") - end - - it 'should set digital certificate to a company' do - skip "To be implemented" - end - -end diff --git a/spec/nfe/configuration_spec.rb b/spec/nfe/configuration_spec.rb new file mode 100644 index 0000000..96b17e7 --- /dev/null +++ b/spec/nfe/configuration_spec.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Configuration do + subject(:config) { described_class.new(api_key: "key") } + + # Keep the suite deterministic regardless of the developer's shell: by + # default neither env key is present unless a specific example sets it. + before do + allow(ENV).to receive(:[]).and_call_original + allow(ENV).to receive(:[]).with("NFE_API_KEY").and_return(nil) + allow(ENV).to receive(:[]).with("NFE_DATA_API_KEY").and_return(nil) + end + + describe "defaults" do + it "applies sensible defaults" do + expect(config.environment).to eq(:production) + expect(config.timeout).to eq(described_class::DEFAULT_TIMEOUT) + expect(config.timeout).to be > 0 + expect(config.open_timeout).to be > 0 + expect(config.max_retries).to be >= 0 + expect(config.ca_file).to be_nil + expect(config.ca_path).to be_nil + expect(config.proxy).to be_nil + expect(config.base_url_overrides).to eq({}) + end + end + + describe "validation" do + it "rejects an empty api_key when no data_api_key or env key is present" do + expect { described_class.new(api_key: "") } + .to raise_error(Nfe::ConfigurationError) + end + + it "rejects when no key is provided at all" do + expect { described_class.new } + .to raise_error(Nfe::ConfigurationError) + end + + it "rejects an invalid environment" do + expect { described_class.new(api_key: "k", environment: :sandbox) } + .to raise_error(Nfe::ConfigurationError, /environment/) + end + + it "rejects a non-positive timeout" do + expect { described_class.new(api_key: "k", timeout: 0) } + .to raise_error(Nfe::ConfigurationError, /timeout/) + end + + it "rejects a negative max_retries" do + expect { described_class.new(api_key: "k", max_retries: -1) } + .to raise_error(Nfe::ConfigurationError, /max_retries/) + end + + it "constructs with only a data_api_key" do + cfg = described_class.new(data_api_key: "d") + expect(cfg.data_api_key).to eq("d") + expect(cfg.api_key).to be_nil + end + end + + describe "#base_url_for" do + it "maps each product family to its canonical host" do + expect(config.base_url_for(:main)).to eq("https://api.nfe.io") + expect(config.base_url_for(:addresses)).to eq("https://address.api.nfe.io/v2") + expect(config.base_url_for(:nfe_query)).to eq("https://nfe.api.nfe.io") + expect(config.base_url_for(:legal_entity)).to eq("https://legalentity.api.nfe.io") + expect(config.base_url_for(:natural_person)).to eq("https://naturalperson.api.nfe.io") + expect(config.base_url_for(:cte)).to eq("https://api.nfse.io") + end + + it "resolves main-family aliases to the main host" do + %i[companies service_invoices legal_people natural_people webhooks].each do |alias_family| + expect(config.base_url_for(alias_family)).to eq("https://api.nfe.io") + end + end + + it "resolves cte-family aliases to the cte host" do + %i[transportation transportation_invoices inbound_product inbound_product_invoices + product_invoices consumer_invoices tax_calculation tax_codes state_taxes].each do |alias_family| + expect(config.base_url_for(alias_family)).to eq("https://api.nfse.io") + end + end + + it "resolves query aliases to the nfe-query host" do + expect(config.base_url_for(:product_invoice_query)).to eq("https://nfe.api.nfe.io") + expect(config.base_url_for(:consumer_invoice_query)).to eq("https://nfe.api.nfe.io") + end + + it "falls back to the main host for an unknown family" do + expect(config.base_url_for(:something_unknown)).to eq("https://api.nfe.io") + end + + it "honors a per-family override" do + overridden = described_class.new(api_key: "k", base_url_overrides: { cte: "https://staging.example" }) + expect(overridden.base_url_for(:cte)).to eq("https://staging.example") + end + end + + describe "#api_key_for" do + it "uses the data key for data families when present" do + cfg = described_class.new(api_key: "main", data_api_key: "data") + expect(cfg.api_key_for(:addresses)).to eq("data") + expect(cfg.api_key_for(:legal_entity)).to eq("data") + expect(cfg.api_key_for(:natural_person)).to eq("data") + expect(cfg.api_key_for(:nfe_query)).to eq("data") + end + + it "falls back to the main key for data families when no data key is set" do + cfg = described_class.new(api_key: "main") + expect(cfg.api_key_for(:nfe_query)).to eq("main") + end + + it "always uses the main key for main families even with a data key set" do + cfg = described_class.new(api_key: "main", data_api_key: "data") + expect(cfg.api_key_for(:main)).to eq("main") + expect(cfg.api_key_for(:companies)).to eq("main") + end + + it "raises when no key resolves for the accessed family" do + cfg = described_class.new(data_api_key: "data") + expect { cfg.api_key_for(:companies) } + .to raise_error(Nfe::ConfigurationError) + end + end + + describe "environment-variable fallback" do + around do |example| + saved = ENV.values_at("NFE_API_KEY", "NFE_DATA_API_KEY") + ENV.delete("NFE_API_KEY") + ENV.delete("NFE_DATA_API_KEY") + example.run + ensure + ENV["NFE_API_KEY"], ENV["NFE_DATA_API_KEY"] = saved + end + + it "adopts NFE_API_KEY when no explicit api_key is given" do + ENV["NFE_API_KEY"] = "from-env" + expect(described_class.new.api_key).to eq("from-env") + end + + it "adopts NFE_DATA_API_KEY when no explicit data_api_key is given" do + ENV["NFE_DATA_API_KEY"] = "data-env" + expect(described_class.new(api_key: "main").data_api_key).to eq("data-env") + end + + it "lets an explicit argument win over the environment value" do + ENV["NFE_API_KEY"] = "from-env" + expect(described_class.new(api_key: "explicit").api_key).to eq("explicit") + end + end + + describe "TLS trust surface" do + it "honors a custom CA bundle without exposing a way to disable verification" do + cfg = described_class.new(api_key: "k", ca_file: "/path/to/corporate-ca.pem") + expect(cfg.ca_file).to eq("/path/to/corporate-ca.pem") + expect(cfg).not_to respond_to(:insecure_ssl) + expect(cfg).not_to respond_to(:verify_none) + expect(cfg).not_to respond_to(:verify_mode) + end + end +end diff --git a/spec/nfe/date_normalizer_spec.rb b/spec/nfe/date_normalizer_spec.rb new file mode 100644 index 0000000..19a5f7b --- /dev/null +++ b/spec/nfe/date_normalizer_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require "date" + +RSpec.describe Nfe::DateNormalizer do + describe ".to_iso_date" do + it "passes a well-formed ISO date string through unchanged" do + expect(described_class.to_iso_date("2026-01-15")).to eq("2026-01-15") + end + + it "formats a Date as YYYY-MM-DD" do + expect(described_class.to_iso_date(Date.new(1990, 1, 15))).to eq("1990-01-15") + end + + it "formats a Time, discarding the time component" do + expect(described_class.to_iso_date(Time.new(2026, 6, 24, 13, 45, 0))).to eq("2026-06-24") + end + + it "formats a DateTime, discarding the time component" do + expect(described_class.to_iso_date(DateTime.new(2026, 6, 24, 13, 45, 0))).to eq("2026-06-24") + end + + it "raises on a non-ISO format such as DD/MM/YYYY" do + expect { described_class.to_iso_date("15/01/1990") } + .to raise_error(Nfe::InvalidRequestError, /YYYY-MM-DD/) + end + + it "raises on an out-of-range ISO date" do + expect { described_class.to_iso_date("2026-13-45") } + .to raise_error(Nfe::InvalidRequestError, /intervalo|inválida/) + end + + it "raises on an unexpected type" do + expect { described_class.to_iso_date(20_260_115) } + .to raise_error(Nfe::InvalidRequestError, /tipo/) + end + end +end diff --git a/spec/nfe/error_factory_spec.rb b/spec/nfe/error_factory_spec.rb new file mode 100644 index 0000000..d42b08f --- /dev/null +++ b/spec/nfe/error_factory_spec.rb @@ -0,0 +1,197 @@ +# frozen_string_literal: true + +# Minimal stand-in for Nfe::Http::Response, keeping this spec self-contained. +# Mirrors its contract: lowercase header keys and case-insensitive #header. +StubResponse = Struct.new(:status, :headers, :body) do + def header(name) + headers[name.downcase] + end +end + +RSpec.describe Nfe::ErrorFactory do + def response(status, body: nil, headers: {}) + StubResponse.new(status, headers, body) + end + + describe ".from_response status mapping" do + { + 400 => Nfe::InvalidRequestError, + 401 => Nfe::AuthenticationError, + 403 => Nfe::AuthorizationError, + 404 => Nfe::NotFoundError, + 409 => Nfe::ConflictError, + 422 => Nfe::InvalidRequestError, + 429 => Nfe::RateLimitError, + 500 => Nfe::ServerError, + 502 => Nfe::ServerError, + 599 => Nfe::ServerError + }.each do |status, klass| + it "maps HTTP #{status} to #{klass}" do + error = described_class.from_response(response(status)) + + expect(error).to be_a(klass) + expect(error.status_code).to eq(status) + end + end + + it "falls back to InvalidRequestError for an unmapped 4xx (e.g. 418)" do + expect(described_class.from_response(response(418))).to be_a(Nfe::InvalidRequestError) + end + + it "falls back to ServerError for an unmapped >= 500" do + expect(described_class.from_response(response(600))).to be_a(Nfe::ServerError) + end + end + + describe ".from_response body extraction" do + it "extracts message, error_code, and request_id" do + body = '{"message":"CNPJ inválido","code":"INVALID_CNPJ"}' + error = described_class.from_response( + response(422, body: body, headers: { "x-request-id" => "req_123" }) + ) + + expect(error.message).to eq("CNPJ inválido") + expect(error.error_code).to eq("INVALID_CNPJ") + expect(error.request_id).to eq("req_123") + end + + it "falls back to x-correlation-id for the request id" do + error = described_class.from_response( + response(500, headers: { "x-correlation-id" => "corr_9" }) + ) + + expect(error.request_id).to eq("corr_9") + end + + it "reads the message from alternate keys (error/detail/details)" do + expect(described_class.from_response(response(400, body: '{"error":"e1"}')).message).to eq("e1") + expect(described_class.from_response(response(400, body: '{"detail":"d1"}')).message).to eq("d1") + expect(described_class.from_response(response(400, body: '{"details":"d2"}')).message).to eq("d2") + end + + it "reads the message from a string errors field" do + expect(described_class.from_response(response(400, body: '{"errors":"oops"}')).message).to eq("oops") + end + + it "reads the message from an array errors field" do + expect(described_class.from_response(response(400, body: '{"errors":["first","second"]}')).message) + .to eq("first") + end + + it "reads the message from an array of error objects" do + body = '{"errors":[{"message":"nested"}]}' + expect(described_class.from_response(response(400, body: body)).message).to eq("nested") + end + + it "coerces an integer error code to a string" do + expect(described_class.from_response(response(400, body: '{"code":42}')).error_code).to eq("42") + end + + it "uses a default message when the body has none" do + expect(described_class.from_response(response(503)).message).to eq("API request failed with HTTP 503") + end + + it "preserves the raw body and headers on the error" do + headers = { "x-request-id" => "r1", "content-type" => "application/json" } + error = described_class.from_response(response(404, body: '{"message":"x"}', headers: headers)) + + expect(error.response_body).to eq('{"message":"x"}') + expect(error.response_headers).to eq(headers) + end + end + + describe ".from_response resilience" do + it "does not crash on a non-JSON body and still returns the right class" do + error = described_class.from_response(response(500, body: "oops")) + + expect(error).to be_a(Nfe::ServerError) + expect(error.message).to eq("API request failed with HTTP 500") + end + + it "tolerates an empty body" do + expect { described_class.from_response(response(400, body: "")) }.not_to raise_error + end + + it "tolerates a JSON array (non-Hash) body" do + error = described_class.from_response(response(400, body: "[1,2,3]")) + expect(error.message).to eq("API request failed with HTTP 400") + end + end + + describe ".from_response rate limiting" do + it "populates retry_after from the Retry-After header" do + error = described_class.from_response(response(429, headers: { "retry-after" => "30" })) + + expect(error).to be_a(Nfe::RateLimitError) + expect(error.retry_after).to eq(30) + end + + it "leaves retry_after nil when the header is absent or non-numeric" do + expect(described_class.from_response(response(429)).retry_after).to be_nil + expect(described_class.from_response(response(429, headers: { "retry-after" => "soon" })).retry_after) + .to be_nil + end + end + + describe ".from_response message hardening" do + it "caps an oversized message and appends an ellipsis" do + long = "a" * 1000 + error = described_class.from_response(response(400, body: { message: long }.to_json)) + + expect(error.message.length).to eq(described_class::MAX_MESSAGE_LENGTH + 3) + expect(error.message).to end_with("...") + end + + it "scrubs control characters from the message" do + raw = "line1\e[31mred\u0000end" + error = described_class.from_response(response(400, body: { message: raw }.to_json)) + + expect(error.message).not_to match(/[\x00-\x1f\x7f]/) + expect(error.message).to include("line1") + expect(error.message).to include("end") + end + + it "drops a message that is only control characters and uses the default" do + raw = "\u0000\u0001\u0002" + error = described_class.from_response(response(400, body: { message: raw }.to_json)) + + expect(error.message).to eq("API request failed with HTTP 400") + end + end + + describe ".from_network_error" do + it "maps Net::OpenTimeout to TimeoutError" do + error = described_class.from_network_error(Net::OpenTimeout.new("open timed out")) + + expect(error).to be_a(Nfe::TimeoutError) + expect(error.cause).to be_a(Net::OpenTimeout) + end + + it "maps Net::ReadTimeout to TimeoutError" do + expect(described_class.from_network_error(Net::ReadTimeout.new)).to be_a(Nfe::TimeoutError) + end + + it "maps Timeout::Error to TimeoutError" do + expect(described_class.from_network_error(Timeout::Error.new("t"))).to be_a(Nfe::TimeoutError) + end + + it "maps a connection refused to ApiConnectionError (not a timeout)" do + error = described_class.from_network_error(Errno::ECONNREFUSED.new) + + expect(error).to be_a(Nfe::ApiConnectionError) + expect(error).not_to be_a(Nfe::TimeoutError) + end + + it "maps SocketError to ApiConnectionError preserving the cause" do + original = SocketError.new("getaddrinfo failed") + error = described_class.from_network_error(original) + + expect(error).to be_a(Nfe::ApiConnectionError) + expect(error.cause).to eq(original) + end + + it "maps an OpenSSL TLS error to ApiConnectionError" do + expect(described_class.from_network_error(OpenSSL::SSL::SSLError.new("tls"))).to be_a(Nfe::ApiConnectionError) + end + end +end diff --git a/spec/nfe/errors_spec.rb b/spec/nfe/errors_spec.rb new file mode 100644 index 0000000..3a6ae13 --- /dev/null +++ b/spec/nfe/errors_spec.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Error do + describe "#initialize" do + it "defaults all response context to nil/empty" do + error = described_class.new("boom") + + expect(error.message).to eq("boom") + expect(error.status_code).to be_nil + expect(error.request_id).to be_nil + expect(error.error_code).to be_nil + expect(error.response_body).to be_nil + expect(error.response_headers).to eq({}) + end + + it "carries the full response context" do + error = described_class.new( + "bad", + status_code: 422, + request_id: "req_1", + error_code: "INVALID", + response_body: '{"message":"bad"}', + response_headers: { "x-nfe-apikey" => "secret" } + ) + + expect(error.status_code).to eq(422) + expect(error.request_id).to eq("req_1") + expect(error.error_code).to eq("INVALID") + expect(error.response_body).to eq('{"message":"bad"}') + expect(error.response_headers).to eq("x-nfe-apikey" => "secret") + end + + it "tolerates a nil response_headers" do + expect(described_class.new("x", response_headers: nil).response_headers).to eq({}) + end + end + + describe "#to_h" do + subject(:hash) do + described_class.new( + "CNPJ inválido", + status_code: 422, + request_id: "req_1", + error_code: "INVALID_CNPJ", + response_body: '{"apikey":"super-secret"}', + response_headers: { "x-nfe-apikey" => "super-secret" } + ).to_h + end + + it "exposes the logging-safe fields" do + expect(hash).to eq( + type: "Nfe::Error", + message: "CNPJ inválido", + status_code: 422, + request_id: "req_1", + error_code: "INVALID_CNPJ" + ) + end + + it "never includes raw headers or body that could carry secrets" do + expect(hash).not_to have_key(:response_headers) + expect(hash).not_to have_key(:response_body) + expect(hash.values.join(" ")).not_to include("super-secret") + end + end + + describe "the error hierarchy" do + it "roots every concrete error at Nfe::Error" do + [ + Nfe::AuthenticationError, Nfe::AuthorizationError, Nfe::InvalidRequestError, + Nfe::NotFoundError, Nfe::ConflictError, Nfe::RateLimitError, + Nfe::ServerError, Nfe::ApiConnectionError, Nfe::TimeoutError, + Nfe::SignatureVerificationError, Nfe::ConfigurationError, + Nfe::InvoiceProcessingError + ].each do |klass| + expect(klass.ancestors).to include(described_class) + end + end + + it "makes TimeoutError a kind of ApiConnectionError" do + expect(Nfe::TimeoutError.new).to be_a(Nfe::ApiConnectionError) + expect(Nfe::TimeoutError.ancestors).to include(Nfe::ApiConnectionError) + end + end + + describe Nfe::RateLimitError do + it "exposes retry_after alongside the base attributes" do + error = described_class.new("slow down", retry_after: 30, status_code: 429, request_id: "req_9") + + expect(error.retry_after).to eq(30) + expect(error.status_code).to eq(429) + expect(error.request_id).to eq("req_9") + end + + it "defaults retry_after to nil" do + expect(described_class.new("slow down").retry_after).to be_nil + end + end + + describe Nfe::ConfigurationError do + it "is a kind of Nfe::Error" do + expect(described_class.new("api_key ausente")).to be_a(Nfe::Error) + end + + it "carries the base response context like any other error" do + error = described_class.new("environment inválido", status_code: nil, error_code: "CONFIG") + + expect(error.message).to eq("environment inválido") + expect(error.error_code).to eq("CONFIG") + end + end + + describe Nfe::InvoiceProcessingError do + it "is a kind of Nfe::Error" do + expect(described_class.new("202 sem Location")).to be_a(Nfe::Error) + end + + it "carries a logging-safe to_h" do + expect(described_class.new("sem Location").to_h).to include( + type: "Nfe::InvoiceProcessingError", + message: "sem Location" + ) + end + end +end diff --git a/spec/nfe/flow_status_spec.rb b/spec/nfe/flow_status_spec.rb new file mode 100644 index 0000000..e258097 --- /dev/null +++ b/spec/nfe/flow_status_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::FlowStatus do + describe ".terminal?" do + it "is true for settled states" do + %w[Issued IssueFailed Cancelled CancelFailed].each do |status| + expect(described_class.terminal?(status)).to be(true) + end + end + + it "is false for in-progress states" do + %w[PullFromCityHall WaitingCalculateTaxes WaitingSend WaitingReturn].each do |status| + expect(described_class.terminal?(status)).to be(false) + end + end + + it "coerces non-string input before matching" do + expect(described_class.terminal?(:Issued)).to be(true) + expect(described_class.terminal?(nil)).to be(false) + end + end + + it "exposes every status through ALL" do + expect(described_class::ALL).to match_array(described_class::TERMINAL + described_class::NON_TERMINAL) + end +end diff --git a/spec/nfe/http/net_http_spec.rb b/spec/nfe/http/net_http_spec.rb new file mode 100644 index 0000000..2a8a641 --- /dev/null +++ b/spec/nfe/http/net_http_spec.rb @@ -0,0 +1,207 @@ +# frozen_string_literal: true + +require "socket" +require "zlib" +require "stringio" + +# Minimal canned HTTP/1.1 server backed by stdlib TCPServer (no webrick, no gems). +# Serves a single response per accepted connection, optionally delaying the write +# to exercise read timeouts, then records the raw request it received. +class CannedHttpServer + attr_reader :port + + def initialize(response:, delay: 0) + @response = response + @delay = delay + @server = TCPServer.new("127.0.0.1", 0) + @port = @server.addr[1] + @requests = Queue.new + @thread = Thread.new { serve_loop } + end + + def last_request + @requests.pop + end + + def base_url + "http://127.0.0.1:#{@port}" + end + + def shutdown + @thread.kill + @server.close + rescue IOError + # already closed + end + + private + + def serve_loop + loop do + client = @server.accept + raw = read_request(client) + @requests << raw + sleep(@delay) if @delay.positive? + client.write(@response) + client.close + rescue IOError, Errno::ECONNRESET + next + end + end + + def read_request(client) + request_line = client.gets.to_s + headers = +"" + while (line = client.gets) && line != "\r\n" + headers << line + end + request_line + headers + end +end + +RSpec.describe Nfe::Http::NetHttp do + subject(:transport) { described_class.new } + + def gzip(string) + io = StringIO.new + gz = Zlib::GzipWriter.new(io) + gz.write(string) + gz.close + io.string + end + + def http_response(status_line:, headers: {}, body: "") + head = ["HTTP/1.1 #{status_line}"] + headers.each { |k, v| head << "#{k}: #{v}" } + head << "Content-Length: #{body.bytesize}" unless headers.keys.map(&:downcase).include?("content-length") + head << "Connection: close" + "#{head.join("\r\n")}\r\n\r\n#{body}" + end + + def request_for(server, method: "GET", path: "/v1/ping", body: nil, headers: {}) + Nfe::Http::Request.new( + method: method, base_url: server.base_url, path: path, headers: headers, body: body + ) + end + + it "performs a basic GET returning 200 and a JSON body" do + server = CannedHttpServer.new( + response: http_response(status_line: "200 OK", headers: { "Content-Type" => "application/json" }, + body: '{"ok":true}') + ) + response = transport.call(request_for(server)) + + expect(response.status).to eq(200) + expect(response.body).to eq('{"ok":true}') + expect(response.header("content-type")).to eq("application/json") + ensure + server.shutdown + end + + it "sends POST bodies and the configured headers to the wire" do + server = CannedHttpServer.new(response: http_response(status_line: "201 Created")) + transport.call(request_for(server, method: "POST", body: '{"a":1}', + headers: { "X-NFE-APIKEY" => "k123" })) + + raw = server.last_request + expect(raw).to include("POST /v1/ping") + expect(raw.downcase).to include("x-nfe-apikey: k123") + ensure + server.shutdown + end + + it "lowercases response header names" do + server = CannedHttpServer.new( + response: http_response(status_line: "200 OK", headers: { "X-Request-Id" => "req_9" }) + ) + response = transport.call(request_for(server)) + + expect(response.headers).to have_key("x-request-id") + expect(response.header("X-Request-Id")).to eq("req_9") + ensure + server.shutdown + end + + it "decompresses a gzip body and drops content-encoding/content-length" do + body = gzip('{"big":"payload"}') + server = CannedHttpServer.new( + response: http_response(status_line: "200 OK", + headers: { "Content-Encoding" => "gzip" }, body: body) + ) + response = transport.call(request_for(server)) + + expect(response.body).to eq('{"big":"payload"}') + expect(response.header("content-encoding")).to be_nil + expect(response.header("content-length")).to be_nil + ensure + server.shutdown + end + + it "defaults Accept-Encoding to gzip when the caller does not set it" do + server = CannedHttpServer.new(response: http_response(status_line: "200 OK")) + transport.call(request_for(server)) + + expect(server.last_request.downcase).to include("accept-encoding: gzip") + ensure + server.shutdown + end + + it "preserves a 202 and its Location header without following it" do + server = CannedHttpServer.new( + response: http_response(status_line: "202 Accepted", + headers: { "Location" => "/v1/companies/1/serviceinvoices/9" }) + ) + response = transport.call(request_for(server, method: "POST", body: "{}")) + + expect(response.status).to eq(202) + expect(response.location).to eq("/v1/companies/1/serviceinvoices/9") + ensure + server.shutdown + end + + it "raises Nfe::TimeoutError when the read times out" do + server = CannedHttpServer.new(response: http_response(status_line: "200 OK"), delay: 1) + request = Nfe::Http::Request.new( + method: "GET", base_url: server.base_url, path: "/slow", read_timeout: 0.2 + ) + + expect { transport.call(request) }.to raise_error(Nfe::TimeoutError) + ensure + server.shutdown + end + + it "raises Nfe::ApiConnectionError when the connection is refused" do + closed = TCPServer.new("127.0.0.1", 0) + port = closed.addr[1] + closed.close + request = Nfe::Http::Request.new(method: "GET", base_url: "http://127.0.0.1:#{port}", path: "/") + + expect { transport.call(request) }.to raise_error(Nfe::ApiConnectionError) + end + + it "reuses a single pooled connection for the same origin" do + server = CannedHttpServer.new(response: http_response(status_line: "200 OK")) + transport.call(request_for(server)) + pool = transport.instance_variable_get(:@pool) + + expect(pool.keys).to eq(["127.0.0.1:#{server.port}"]) + expect(pool.values.first.size).to eq(1) + ensure + server.shutdown + end + + it "enforces TLS VERIFY_PEER for https origins without a real handshake" do + uri = URI.parse("https://api.nfse.io/v2/ping") + http = transport.send(:build_connection, uri) + + expect(http.use_ssl?).to be(true) + expect(http.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER) + end + + it "applies an optional ca_file to the https connection" do + transport = described_class.new(ca_file: "/etc/ssl/custom.pem") + http = transport.send(:build_connection, URI.parse("https://api.nfse.io")) + + expect(http.ca_file).to eq("/etc/ssl/custom.pem") + end +end diff --git a/spec/nfe/http/redactor_spec.rb b/spec/nfe/http/redactor_spec.rb new file mode 100644 index 0000000..c3b32a2 --- /dev/null +++ b/spec/nfe/http/redactor_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Http::Redactor do + describe ".headers" do + it "redacts the canonical sensitive headers regardless of casing" do + input = { + "X-NFE-APIKEY" => "sk_live_secret", + "Authorization" => "Bearer abc", + "Idempotency-Key" => "9f1c" + } + + result = described_class.headers(input) + + expect(result.values).to all(eq("[REDACTED]")) + end + + it "redacts any header matching secret/apikey/token" do + input = { + "X-Client-Secret" => "shh", + "App-Token" => "t0ken", + "Some-Apikey-Header" => "k" + } + + expect(described_class.headers(input).values).to all(eq("[REDACTED]")) + end + + it "leaves benign headers untouched" do + input = { "Content-Type" => "application/json", "Accept" => "application/json" } + + expect(described_class.headers(input)).to eq(input) + end + + it "does not mutate the input hash" do + input = { "Authorization" => "Bearer abc" } + + described_class.headers(input) + + expect(input["Authorization"]).to eq("Bearer abc") + end + + it "returns a new hash with mixed sensitive and benign keys" do + input = { "Authorization" => "Bearer abc", "Accept" => "application/json" } + + result = described_class.headers(input) + + expect(result).to eq("Authorization" => "[REDACTED]", "Accept" => "application/json") + end + end + + describe ".sensitive?" do + it "matches by exact name and by pattern, case-insensitively" do + expect(described_class.sensitive?("authorization")).to be(true) + expect(described_class.sensitive?(:"X-NFE-APIKEY")).to be(true) + expect(described_class.sensitive?("My-Secret")).to be(true) + expect(described_class.sensitive?("Content-Type")).to be(false) + end + end +end diff --git a/spec/nfe/http/request_spec.rb b/spec/nfe/http/request_spec.rb new file mode 100644 index 0000000..7a3c99e --- /dev/null +++ b/spec/nfe/http/request_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Http::Request do + def build(**overrides) + described_class.new( + method: "GET", + base_url: "https://api.nfse.io", + path: "/v2/companies/abc/productinvoices", + **overrides + ) + end + + describe "defaults" do + it "defaults the optional members" do + request = build + + expect(request.headers).to eq({}) + expect(request.query).to eq({}) + expect(request.body).to be_nil + expect(request.open_timeout).to be_nil + expect(request.read_timeout).to be_nil + expect(request.idempotency_key).to be_nil + end + end + + describe "#url" do + it "composes base_url + path with no query" do + expect(build.url).to eq("https://api.nfse.io/v2/companies/abc/productinvoices") + end + + it "strips a trailing slash from base_url" do + request = build(base_url: "https://api.nfse.io/") + + expect(request.url).to eq("https://api.nfse.io/v2/companies/abc/productinvoices") + end + + it "appends the URL-encoded query with a leading ?" do + request = build(query: { environment: "Production", limit: 50 }) + + expect(request.url).to eq( + "https://api.nfse.io/v2/companies/abc/productinvoices?environment=Production&limit=50" + ) + end + + it "emits array query values as repeated keys" do + request = build(query: { status: %w[Issued Cancelled] }) + + expect(request.url).to eq( + "https://api.nfse.io/v2/companies/abc/productinvoices?status=Issued&status=Cancelled" + ) + end + + it "uses & when the path already contains a ?" do + request = build(path: "/v2/companies?expand=tax", query: { limit: 10 }) + + expect(request.url).to eq("https://api.nfse.io/v2/companies?expand=tax&limit=10") + end + + it "omits the query string when query is empty" do + expect(build(query: {}).url).not_to include("?") + end + end + + describe "#idempotent?" do + %w[GET HEAD PUT DELETE get head put delete].each do |verb| + it "is true for #{verb}" do + expect(build(method: verb).idempotent?).to be(true) + end + end + + it "is false for POST without an idempotency_key" do + expect(build(method: "POST").idempotent?).to be(false) + end + + it "is true for POST carrying an idempotency_key" do + expect(build(method: "POST", idempotency_key: "9f1c").idempotent?).to be(true) + end + end +end diff --git a/spec/nfe/http/response_spec.rb b/spec/nfe/http/response_spec.rb new file mode 100644 index 0000000..4555907 --- /dev/null +++ b/spec/nfe/http/response_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Http::Response do + describe "defaults" do + it "defaults headers and body" do + response = described_class.new(status: 204) + + expect(response.headers).to eq({}) + expect(response.body).to be_nil + end + end + + describe "#header" do + let(:response) do + described_class.new(status: 200, headers: { "content-type" => "application/json" }) + end + + it "looks up headers case-insensitively" do + expect(response.header("Content-Type")).to eq("application/json") + expect(response.header("content-type")).to eq("application/json") + expect(response.header("CONTENT-TYPE")).to eq("application/json") + end + + it "returns nil for an absent header" do + expect(response.header("X-Missing")).to be_nil + end + end + + describe "#success?" do + it "is true for 2xx" do + [200, 201, 204, 299].each do |status| + expect(described_class.new(status: status).success?).to be(true) + end + end + + it "is false for 3xx and 4xx" do + [301, 302, 400, 404, 500].each do |status| + expect(described_class.new(status: status).success?).to be(false) + end + end + end + + describe "#location" do + it "returns the Location header regardless of casing" do + response = described_class.new(status: 202, headers: { "location" => "/v1/invoices/123" }) + + expect(response.location).to eq("/v1/invoices/123") + expect(response.header("Location")).to eq("/v1/invoices/123") + end + + it "returns nil when no Location header is present" do + expect(described_class.new(status: 200).location).to be_nil + end + end + + describe "binary body" do + it "preserves raw bytes without transcoding" do + bytes = "%PDF-1.4\x00\xFF\xFE".dup.force_encoding(Encoding::ASCII_8BIT) + response = described_class.new(status: 200, body: bytes) + + expect(response.body.encoding).to eq(Encoding::ASCII_8BIT) + expect(response.body.bytes).to eq(bytes.bytes) + end + end +end diff --git a/spec/nfe/http/retry_policy_spec.rb b/spec/nfe/http/retry_policy_spec.rb new file mode 100644 index 0000000..472bd5b --- /dev/null +++ b/spec/nfe/http/retry_policy_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Http::RetryPolicy do + describe ".default" do + subject(:policy) { described_class.default } + + it "uses the recommended settings" do + expect(policy.max_retries).to eq(3) + expect(policy.base_delay).to eq(1.0) + expect(policy.max_delay).to eq(30.0) + expect(policy.jitter).to eq(0.3) + end + end + + describe ".none" do + subject(:policy) { described_class.none } + + it "disables retries with zero delay" do + expect(policy.max_retries).to eq(0) + expect(policy.delay_for(1)).to eq(0.0) + end + end + + describe "#delay_for" do + it "caps the delay at max_delay even for large attempts" do + policy = described_class.new(max_retries: 10, base_delay: 1.0, max_delay: 5.0, jitter: 0.0) + + 100.times do + expect(policy.delay_for(20)).to be <= 5.0 + end + end + + it "keeps jittered values within [base*(1-j), base*(1+j)]" do + policy = described_class.new(max_retries: 3, base_delay: 2.0, max_delay: 100.0, jitter: 0.3) + base = 2.0 * (2**(2 - 1)) # attempt 2 => 4.0 + + 500.times do + delay = policy.delay_for(2) + expect(delay).to be >= (base * 0.7) - 1e-9 + expect(delay).to be <= (base * 1.3) + 1e-9 + end + end + + it "grows exponentially with the attempt index" do + policy = described_class.new(max_retries: 5, base_delay: 1.0, max_delay: 1000.0, jitter: 0.0) + + expect(policy.delay_for(1)).to be_within(1e-9).of(1.0) + expect(policy.delay_for(2)).to be_within(1e-9).of(2.0) + expect(policy.delay_for(3)).to be_within(1e-9).of(4.0) + end + + it "clamps jittered values to max_delay" do + policy = described_class.new(max_retries: 5, base_delay: 30.0, max_delay: 30.0, jitter: 0.3) + + 200.times do + expect(policy.delay_for(3)).to be <= 30.0 + end + end + end +end diff --git a/spec/nfe/http/retrying_transport_spec.rb b/spec/nfe/http/retrying_transport_spec.rb new file mode 100644 index 0000000..85e9b3e --- /dev/null +++ b/spec/nfe/http/retrying_transport_spec.rb @@ -0,0 +1,219 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Http::RetryingTransport do + # Capture every requested sleep duration instead of really sleeping. + let(:slept) { [] } + let(:sleep_fn) { ->(seconds) { slept << seconds } } + let(:fake) { FakeTransport.new } + + def get_request(idempotency_key: nil) + Nfe::Http::Request.new( + method: "GET", + base_url: "https://api.nfse.io", + path: "/v2/companies/abc/productinvoices", + headers: { "X-NFE-APIKEY" => "secret-key", "Accept" => "application/json" }, + idempotency_key: idempotency_key + ) + end + + def post_request(idempotency_key: nil) + Nfe::Http::Request.new( + method: "POST", + base_url: "https://api.nfse.io", + path: "/v2/companies/abc/productinvoices", + headers: { "X-NFE-APIKEY" => "secret-key" }, + body: "{}", + idempotency_key: idempotency_key + ) + end + + def response(status, headers: {}, body: nil) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def transport(policy: Nfe::Http::RetryPolicy.default, logger: nil) + described_class.new(inner: fake, policy: policy, sleep_fn: sleep_fn, logger: logger) + end + + describe "#retryable_status?" do + subject(:decorator) { transport } + + it "treats 429 and 5xx as retryable, others as not" do + expect(decorator.retryable_status?(429)).to be(true) + expect(decorator.retryable_status?(500)).to be(true) + expect(decorator.retryable_status?(599)).to be(true) + expect(decorator.retryable_status?(400)).to be(false) + expect(decorator.retryable_status?(200)).to be(false) + end + end + + it "transparently returns 200 after 503 -> 503 -> 200 on a GET" do + fake.enqueue(response(503)).enqueue(response(503)).enqueue(response(200, body: "ok")) + + result = transport.call(get_request) + + expect(result.status).to eq(200) + expect(fake.call_count).to eq(3) + expect(slept.length).to eq(2) + end + + it "does not retry a 400 client error" do + fake.enqueue(response(400)) + + result = transport.call(get_request) + + expect(result.status).to eq(400) + expect(fake.call_count).to eq(1) + expect(slept).to be_empty + end + + it "returns the last 503 once retries are exhausted" do + fake.enqueue(response(503)) + + result = transport.call(get_request) + + expect(result.status).to eq(503) + # default policy: 1 initial + 3 retries = 4 attempts + expect(fake.call_count).to eq(4) + expect(slept.length).to eq(3) + end + + it "honors an integer Retry-After header (waits >= 5s)" do + fake.enqueue(response(429, headers: { "retry-after" => "5" })).enqueue(response(200)) + + transport.call(get_request) + + expect(slept.first).to be >= 5 + end + + it "clamps Retry-After to max_delay" do + policy = Nfe::Http::RetryPolicy.new(max_retries: 2, base_delay: 1.0, max_delay: 3.0, jitter: 0.0) + fake.enqueue(response(429, headers: { "retry-after" => "999" })).enqueue(response(200)) + + transport(policy: policy).call(get_request) + + expect(slept.first).to eq(3.0) + end + + it "does not retry a POST without an idempotency key" do + fake.enqueue(response(503)) + + result = transport.call(post_request) + + expect(result.status).to eq(503) + expect(fake.call_count).to eq(1) + expect(slept).to be_empty + end + + it "retries a POST that carries an idempotency key" do + fake.enqueue(response(503)).enqueue(response(201)) + + result = transport.call(post_request(idempotency_key: "9f1c-key")) + + expect(result.status).to eq(201) + expect(fake.call_count).to eq(2) + end + + it "retries a network error then propagates it after exhaustion" do + fake.enqueue(Nfe::ApiConnectionError.new("boom")) + + expect { transport.call(get_request) }.to raise_error(Nfe::ApiConnectionError) + expect(fake.call_count).to eq(4) + expect(slept.length).to eq(3) + end + + it "retries a timeout (subclass of ApiConnectionError) then succeeds" do + fake.enqueue(Nfe::TimeoutError.new("slow")).enqueue(response(200)) + + result = transport.call(get_request) + + expect(result.status).to eq(200) + expect(fake.call_count).to eq(2) + end + + it "does not retry a network error on a non-idempotent POST" do + fake.enqueue(Nfe::ApiConnectionError.new("boom")) + + expect { transport.call(post_request) }.to raise_error(Nfe::ApiConnectionError) + expect(fake.call_count).to eq(1) + expect(slept).to be_empty + end + + it "makes exactly one attempt under RetryPolicy.none" do + fake.enqueue(response(503)) + + result = transport(policy: Nfe::Http::RetryPolicy.none).call(get_request) + + expect(result.status).to eq(503) + expect(fake.call_count).to eq(1) + end + + describe "logging" do + # Duck-typed logger: any object responding to info/warn/error. Using a + # plain double keeps the SDK free of a Logger runtime dependency. + let(:logger) { double("DuckLogger", info: nil, warn: nil, error: nil) } + + it "warns on each retry and errors on final failure with redacted headers" do + fake.enqueue(response(503)) + + transport(logger: logger).call(get_request) + + expect(logger).to have_received(:warn).exactly(3).times + expect(logger).to have_received(:error).once + end + + it "redacts the API key and never logs the body in the start info line" do + captured = [] + allow(logger).to receive(:info) { |line| captured << line } + fake.enqueue(response(200, body: "sensitive-body-12345678901")) + + transport(logger: logger).call(get_request) + + line = captured.join("\n") + expect(line).to include("[REDACTED]") + expect(line).not_to include("secret-key") + expect(line).not_to include("sensitive-body") + end + + it "logs error on a network failure without raising from logging" do + fake.enqueue(Nfe::ApiConnectionError.new("boom")) + + expect { transport(logger: logger).call(get_request) }.to raise_error(Nfe::ApiConnectionError) + expect(logger).to have_received(:error).once + end + + it "never lets a raising logger break the request" do + allow(logger).to receive(:warn).and_raise(StandardError, "logger down") + allow(logger).to receive(:error).and_raise(StandardError, "logger down") + fake.enqueue(response(503)).enqueue(response(200)) + + result = transport(logger: logger).call(get_request) + + expect(result.status).to eq(200) + end + + it "does not log when no logger is configured" do + fake.enqueue(response(503)).enqueue(response(200)) + + expect { transport.call(get_request) }.not_to raise_error + end + end + + describe "per-call isolation" do + it "does not let one call's outcome affect a concurrent call" do + fake_a = FakeTransport.new.enqueue(response(503)).enqueue(response(200)) + fake_b = FakeTransport.new.enqueue(response(200)) + + decorator_a = described_class.new(inner: fake_a, sleep_fn: sleep_fn) + decorator_b = described_class.new(inner: fake_b, sleep_fn: sleep_fn) + + result_b = decorator_b.call(get_request) + result_a = decorator_a.call(get_request) + + expect(result_b.status).to eq(200) + expect(fake_b.call_count).to eq(1) + expect(result_a.status).to eq(200) + expect(fake_a.call_count).to eq(2) + end + end +end diff --git a/spec/nfe/http/user_agent_spec.rb b/spec/nfe/http/user_agent_spec.rb new file mode 100644 index 0000000..044f70a --- /dev/null +++ b/spec/nfe/http/user_agent_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Http::UserAgent do + describe ".build" do + it "uses the canonical format with version, ruby version and platform" do + expect(described_class.build).to eq( + "NFE.io Ruby Client v#{Nfe::VERSION} ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM})" + ) + end + + it "matches the documented shape" do + expect(described_class.build).to match( + %r{\ANFE\.io Ruby Client v\S+ ruby/\S+ \(.+\)\z} + ) + end + + it "appends a non-empty suffix after a single space" do + expect(described_class.build("MyApp/2.0")).to eq( + "NFE.io Ruby Client v#{Nfe::VERSION} ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}) MyApp/2.0" + ) + end + + it "ignores a nil or empty suffix" do + expect(described_class.build(nil)).to eq(described_class.build) + expect(described_class.build("")).to eq(described_class.build) + end + end +end diff --git a/spec/nfe/id_validator_spec.rb b/spec/nfe/id_validator_spec.rb new file mode 100644 index 0000000..d632f2d --- /dev/null +++ b/spec/nfe/id_validator_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::IdValidator do + describe ".company_id" do + it "returns the value when present" do + expect(described_class.company_id("co-1")).to eq("co-1") + end + + it "raises Nfe::InvalidRequestError on an empty value, naming the argument" do + expect { described_class.company_id("") } + .to raise_error(Nfe::InvalidRequestError, /company_id/) + end + + it "raises on a whitespace-only value" do + expect { described_class.company_id(" ") }.to raise_error(Nfe::InvalidRequestError) + end + end + + describe ".invoice_id" do + it "returns the value when present and raises when empty" do + expect(described_class.invoice_id("inv-9")).to eq("inv-9") + expect { described_class.invoice_id("") }.to raise_error(Nfe::InvalidRequestError, /invoice_id/) + end + end + + describe ".state_tax_id" do + it "returns the value when present and raises when empty" do + expect(described_class.state_tax_id("st-1")).to eq("st-1") + expect { described_class.state_tax_id(nil) }.to raise_error(Nfe::InvalidRequestError, /state_tax_id/) + end + end + + describe ".event_key" do + it "returns the value when present and raises when empty" do + expect(described_class.event_key("ev-1")).to eq("ev-1") + expect { described_class.event_key("") }.to raise_error(Nfe::InvalidRequestError, /event_key/) + end + end + + describe ".access_key" do + it "normalizes formatted input to 44 digits" do + raw = "35261234567890123456789012345678901234567890" # 44 digits + spaced = raw.chars.each_slice(4).map(&:join).join(" ") + + result = described_class.access_key(spaced) + + expect(result).to eq(raw) + expect(result.length).to eq(44) + end + + it "raises on a value of the wrong length" do + expect { described_class.access_key("123") }.to raise_error(Nfe::InvalidRequestError, /44/) + end + end + + describe ".cnpj" do + it "normalizes formatted input and returns a String, never an Integer" do + result = described_class.cnpj("12.345.678/0001-90") + + expect(result).to eq("12345678000190") + expect(result).to be_a(String) + end + + it "preserves alphanumeric CNPJ (v3) without coercing to Integer" do + result = described_class.cnpj("12ABC34501DE35") + + expect(result).to eq("12ABC34501DE35") + expect(result).to be_a(String) + end + + it "raises on the wrong length" do + expect { described_class.cnpj("123") }.to raise_error(Nfe::InvalidRequestError, /CNPJ/) + end + + it "raises on an empty value" do + expect { described_class.cnpj("") }.to raise_error(Nfe::InvalidRequestError, /CNPJ/) + end + end + + describe ".cpf" do + it "normalizes formatted input to 11 digits" do + expect(described_class.cpf("123.456.789-09")).to eq("12345678909") + end + + it "normalizes hyphen-and-dot formatted input to 11 digits" do + expect(described_class.cpf("123.456.789-01")).to eq("12345678901") + end + + it "raises on the wrong length" do + expect { described_class.cpf("123") }.to raise_error(Nfe::InvalidRequestError, /CPF/) + end + + it "raises on an empty value" do + expect { described_class.cpf("") }.to raise_error(Nfe::InvalidRequestError, /CPF/) + end + end + + describe ".cep" do + it "normalizes a hyphenated CEP to 8 digits" do + expect(described_class.cep("01310-100")).to eq("01310100") + end + + it "accepts an already-digits-only CEP" do + expect(described_class.cep("01310100")).to eq("01310100") + end + + it "raises on the wrong length" do + expect { described_class.cep("123") }.to raise_error(Nfe::InvalidRequestError, /CEP/) + end + + it "raises on an empty value" do + expect { described_class.cep("") }.to raise_error(Nfe::InvalidRequestError, /CEP/) + end + end + + describe ".state" do + it "uppercases and validates a UF" do + expect(described_class.state("sp")).to eq("SP") + end + + it "accepts the special EX and NA codes" do + expect(described_class.state("ex")).to eq("EX") + expect(described_class.state("na")).to eq("NA") + end + + it "raises on an invalid UF" do + expect { described_class.state("ZZ") }.to raise_error(Nfe::InvalidRequestError, /state/) + end + end +end diff --git a/spec/nfe/legal_people_spec.rb b/spec/nfe/legal_people_spec.rb deleted file mode 100644 index 51ab423..0000000 --- a/spec/nfe/legal_people_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require_relative '../rspec_helper' - -describe Nfe::LegalPeople do - before(:each) do - Nfe.api_key('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - Nfe::LegalPeople.company_id("55df4dc6b6cd9007e4f13ee8") - end - - it 'should list all LegalPeople' do - natural_peoples_list = Nfe::LegalPeople.list_all - expect(natural_peoples_list.object).to eq('list') - expect(natural_peoples_list.data.size).to be >= 0 - end - - it 'should retrieve a LegalPeople' do - customer_params = {borrower: { federalTaxNumber: '69919334000160', name: 'Empresa Teste', email: 'ricardo.nezz@mailinator.com', - postalCode: '21231110', street: 'Rua Do Cliente', number: '1310', additionalInformation: 'AP 202', - district: 'Centro', city_code: 4204202, city_name: 'Chapecó', city_state: 'SC' }} - - service_params = { cityServiceCode: '0107', description: 'Manutenção e suporte técnico.', servicesAmount: 0.15 } - - Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") - nfe = Nfe::ServiceInvoice.create(customer_params.merge(service_params)) - - natural_people = Nfe::LegalPeople.retrieve("55ef27f8440c3b0b84cebc2d") - expect(natural_people.id).to eq("55ef27f8440c3b0b84cebc2d") - expect(natural_people.name).to eq("Nome da Empresa") - end -end diff --git a/spec/nfe/natural_people_spec.rb b/spec/nfe/natural_people_spec.rb deleted file mode 100644 index e21999b..0000000 --- a/spec/nfe/natural_people_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative '../rspec_helper' - -describe Nfe::NaturalPeople do - before(:each) do - Nfe.api_key('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - Nfe::NaturalPeople.company_id("55e8a2c9440c3b0b84ceaa12") - end - - it 'should list all NaturalPeople' do - natural_peoples_list = Nfe::NaturalPeople.list_all - expect(natural_peoples_list.object).to eq('list') - expect(natural_peoples_list.data.size).to be >= 1 - end - - it 'should retrieve a NaturalPeople' do - natural_people = Nfe::NaturalPeople.retrieve("55eeebf8440c3b0b84ceb1a8") - expect(natural_people.id).to eq("55eeebf8440c3b0b84ceb1a8") - expect(natural_people.name).to eq("Ricardo Caldeira") - end -end diff --git a/spec/nfe/nfe_spec.rb b/spec/nfe/nfe_spec.rb deleted file mode 100644 index 66060c8..0000000 --- a/spec/nfe/nfe_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative '../rspec_helper' - -describe Nfe do - it 'has a version number' do - expect(Nfe::VERSION).not_to be nil - end - - it 'should set api key' do - Nfe.api_key('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - expect(Nfe.access_keys).to eq('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - end - - it 'should get empty access keys' do - Nfe.api_key('') - expect(Nfe.access_keys).to eq("") - end - - describe Nfe::NfeObject do - it 'should convert to hash' do - params_2 = {a: 1, b: 'b'} - params = {a: 'a', b: 'b', c: 1, d: Nfe::NfeObject.create_from(params_2), e:[a: 'a', b: 1, c: Nfe::NfeObject.create_from(params_2)]} - obj = Nfe::NfeObject.create_from(params) - expect(obj.to_hash).to eq(params.merge({d: params_2, e: [a: 'a', b: 1, c: params_2]})) - end - - it 'should convert to json' do - params_2 = {a: 1, b: 'b'} - params = {a: 'a', b: 'b', c: 1, d: Nfe::NfeObject.create_from(params_2), e:[a: 'a', b: 1, c: Nfe::NfeObject.create_from(params_2)]} - obj = Nfe::NfeObject.create_from(params) - expect(obj.to_json).to eq(params.to_json) - end - - it 'should convert to string' do - params_2 = {a: 1, b: 'b'} - params = {a: 'a', b: 'b', c: 1, d: Nfe::NfeObject.create_from(params_2), e:[a: 'a', b: 1, c: Nfe::NfeObject.create_from(params_2)]} - obj = Nfe::NfeObject.create_from(params) - expect(obj.to_s).to eq(params.to_json.to_s) - end - end -end diff --git a/spec/nfe/pagination_spec.rb b/spec/nfe/pagination_spec.rb new file mode 100644 index 0000000..8d06701 --- /dev/null +++ b/spec/nfe/pagination_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::ListPage do + describe ".from_page" do + subject(:page) { described_class.from_page(page_index: 0, page_count: 5, total: 42) } + + it "fills the page-style fields" do + expect(page.page_index).to eq(0) + expect(page.page_count).to eq(5) + expect(page.total).to eq(42) + end + + it "leaves the cursor fields nil" do + expect(page.starting_after).to be_nil + expect(page.ending_before).to be_nil + end + end + + describe ".from_cursor" do + subject(:page) { described_class.from_cursor(starting_after: "a", ending_before: "z", total: 7) } + + it "fills the cursor-style fields" do + expect(page.starting_after).to eq("a") + expect(page.ending_before).to eq("z") + expect(page.total).to eq(7) + end + + it "leaves page_index/page_count nil" do + expect(page.page_index).to be_nil + expect(page.page_count).to be_nil + end + end + + it "defaults every field to nil" do + page = described_class.new + + expect([page.page_index, page.page_count, page.starting_after, page.ending_before, page.total]).to all(be_nil) + end + + describe Nfe::ListResponse do + it "carries data intact alongside a page-style page" do + response = described_class.new(data: %w[a b c], page: Nfe::ListPage.from_page(page_index: 0, page_count: 1)) + + expect(response.data).to eq(%w[a b c]) + expect(response.page.page_index).to eq(0) + end + + it "carries data intact alongside a cursor-style page" do + response = described_class.new(data: [1, 2], page: Nfe::ListPage.from_cursor(starting_after: "x")) + + expect(response.data).to eq([1, 2]) + expect(response.page.starting_after).to eq("x") + expect(response.page.page_index).to be_nil + end + + it "defaults data to an empty array and page to nil" do + response = described_class.new + + expect(response.data).to eq([]) + expect(response.page).to be_nil + end + end +end diff --git a/spec/nfe/request_options_spec.rb b/spec/nfe/request_options_spec.rb new file mode 100644 index 0000000..f1fc973 --- /dev/null +++ b/spec/nfe/request_options_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::RequestOptions do + it "defaults every field to nil" do + options = described_class.new + + expect(options.api_key).to be_nil + expect(options.base_url).to be_nil + expect(options.timeout).to be_nil + end + + it "carries the supplied per-call overrides" do + options = described_class.new(api_key: "tenant-key", base_url: "https://staging.example", timeout: 90) + + expect(options.api_key).to eq("tenant-key") + expect(options.base_url).to eq("https://staging.example") + expect(options.timeout).to eq(90) + end + + it "allows overriding only a subset of fields" do + options = described_class.new(timeout: 90) + + expect(options.timeout).to eq(90) + expect(options.api_key).to be_nil + expect(options.base_url).to be_nil + end + + it "is frozen and compares by value" do + a = described_class.new(api_key: "k") + b = described_class.new(api_key: "k") + + expect(a).to be_frozen + expect(a).to eq(b) + end +end diff --git a/spec/nfe/resources/abstract_resource_spec.rb b/spec/nfe/resources/abstract_resource_spec.rb new file mode 100644 index 0000000..4f6d063 --- /dev/null +++ b/spec/nfe/resources/abstract_resource_spec.rb @@ -0,0 +1,166 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Resources::AbstractResource do + # A minimal client double that records the request kwargs and returns a canned + # response, so the AbstractResource helpers can be exercised without network. + subject(:resource) { cte_resource_class.new(client) } + + let(:recorded) { [] } + let(:canned_response) { Nfe::Http::Response.new(status: 200, body: "{}") } + + let(:client) do + recorder = recorded + response = canned_response + Class.new do + define_method(:request) do |method, **kwargs| + recorder << kwargs.merge(method: method) + response + end + end.new + end + + # DTO test double exposing the generated +from_api+ factory contract. + let(:dto_klass) do + Class.new do + attr_reader :payload + + def initialize(payload) + @payload = payload + end + + def self.from_api(payload) + new(payload) + end + end + end + + # Concrete subclass for the :cte family, version "v1". + let(:cte_resource_class) do + Class.new(described_class) do + def api_family = :cte + public :get, :post, :put, :delete, :full_path, :download, + :hydrate, :hydrate_list, :handle_async_response + end + end + + # Concrete subclass for the addresses family, empty version. + let(:versionless_resource_class) do + Class.new(described_class) do + def api_family = :addresses + def api_version = "" + public :full_path + end + end + + describe "#full_path" do + it "prefixes the api_version" do + expect(resource.full_path("/companies/x")).to eq("/v1/companies/x") + end + + it "returns the path unchanged when the version is empty" do + versionless = versionless_resource_class.new(client) + expect(versionless.full_path("/addresses/01310100")).to eq("/addresses/01310100") + end + end + + describe "HTTP verb helpers" do + it "routes #get through the client for the resource family" do + resource.get("/x", query: { a: 1 }) + expect(recorded.last).to include(method: :get, family: :cte, + path: "/v1/x", query: { a: 1 }) + end + + it "routes #post with a body and idempotency key" do + resource.post("/x", body: "payload", idempotency_key: "k-1") + expect(recorded.last).to include(method: :post, family: :cte, + path: "/v1/x", body: "payload", + idempotency_key: "k-1") + end + + it "routes #put and #delete" do + resource.put("/x", body: "b") + resource.delete("/x") + expect(recorded.map { |r| r[:method] }).to include(:put, :delete) + end + + it "threads request_options through to the client" do + options = Nfe::RequestOptions.new(api_key: "tenant") + resource.get("/x", request_options: options) + expect(recorded.last[:request_options]).to be(options) + end + end + + describe "#hydrate" do + it "delegates to the DTO factory and returns an instance" do + result = resource.hydrate(dto_klass, { "id" => 1 }) + expect(result).to be_a(dto_klass) + expect(result.payload).to eq({ "id" => 1 }) + end + end + + describe "#download" do + let(:canned_response) do + Nfe::Http::Response.new(status: 200, body: "%PDF-1.4 binary".dup) + end + + it "returns the body as binary-safe ASCII-8BIT bytes" do + bytes = resource.download("/x/pdf") + expect(bytes.encoding).to eq(Encoding::ASCII_8BIT) + expect(bytes[0, 4]).to eq("%PDF") + end + end + + describe "#hydrate_list" do + it "builds a page-style ListResponse" do + payload = { "data" => [{ "id" => 1 }, { "id" => 2 }], + "pageIndex" => 1, "pageCount" => 5, "totalResults" => 42 } + result = resource.hydrate_list(dto_klass, payload, wrapper_key: "data") + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:payload)).to eq([{ "id" => 1 }, { "id" => 2 }]) + expect(result.page.page_index).to eq(1) + expect(result.page.page_count).to eq(5) + expect(result.page.total).to eq(42) + expect(result.page.starting_after).to be_nil + end + + it "builds a cursor-style ListResponse" do + payload = { "data" => [{ "id" => 1 }], + "startingAfter" => "cur-a", "endingBefore" => "cur-b" } + result = resource.hydrate_list(dto_klass, payload, wrapper_key: "data") + + expect(result.page.starting_after).to eq("cur-a") + expect(result.page.ending_before).to eq("cur-b") + expect(result.page.page_index).to be_nil + end + end + + describe "#handle_async_response" do + it "returns Pending for a 202 with a Location header" do + response = Nfe::Http::Response.new( + status: 202, + headers: { "location" => "/v1/companies/x/serviceinvoices/abc-123" } + ) + result = resource.handle_async_response(response, issued_klass: dto_klass) + + expect(result).to be_a(Nfe::Pending) + expect(result.invoice_id).to eq("abc-123") + expect(result.location).to eq("/v1/companies/x/serviceinvoices/abc-123") + end + + it "raises InvoiceProcessingError for a 202 without a Location" do + response = Nfe::Http::Response.new(status: 202) + expect { resource.handle_async_response(response, issued_klass: dto_klass) } + .to raise_error(Nfe::InvoiceProcessingError, /Location/) + end + + it "returns Issued with a hydrated DTO for a 201" do + response = Nfe::Http::Response.new(status: 201, body: '{"id":"x"}') + result = resource.handle_async_response(response, issued_klass: dto_klass) + + expect(result).to be_a(Nfe::Issued) + expect(result.resource).to be_a(dto_klass) + expect(result.resource.payload).to eq({ "id" => "x" }) + end + end +end diff --git a/spec/nfe/resources/addresses_spec.rb b/spec/nfe/resources/addresses_spec.rb new file mode 100644 index 0000000..56910c0 --- /dev/null +++ b/spec/nfe/resources/addresses_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::Addresses do + subject(:addresses) { client.addresses } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "#lookup_by_postal_code" do + # Real API shape (confirmado contra address.api.nfe.io/v2): a consulta por + # CEP retorna UM endereço sob a chave SINGULAR "address" — o array + # "addresses" do openapi/consulta-endereco.yaml não bate com este endpoint. + # O DTO normaliza ambos os formatos (ver AddressLookupResponse abaixo). + let(:address_item) do + { "street" => "Paulista", "streetSuffix" => "Avenida", "number" => "1000", + "numberMin" => "0001", "numberMax" => "1999", "district" => "Bela Vista", + "additionalInformation" => "lado par", "postalCode" => "01310100", + "city" => { "code" => "3550308", "name" => "São Paulo" }, + "state" => "SP", "country" => "BR" } + end + let(:payload) { { "address" => address_item } } + + before { transport.enqueue(response(body: payload.to_json)) } + + it "routes to the address data host with the /v2 prefix already embedded" do + addresses.lookup_by_postal_code("01310-100") + + expect(last_request.url).to start_with("https://address.api.nfe.io/v2") + expect(last_request.method).to eq("GET") + end + + it "normalizes the CEP into the request path" do + addresses.lookup_by_postal_code("01310-100") + + expect(last_request.url).to include("/addresses/01310100") + end + + it "hydrates the addresses array into an AddressLookupResponse" do + result = addresses.lookup_by_postal_code("01310-100") + + expect(result).to be_a(Nfe::AddressLookupResponse) + expect(result.addresses.first).to be_a(Nfe::Address) + expect(result.addresses.first.street).to eq("Paulista") + expect(result.addresses.first.postal_code).to eq("01310100") + end + + it "maps the real district/numberMin/numberMax keys onto their members" do + address = addresses.lookup_by_postal_code("01310-100").addresses.first + + expect(address.district).to eq("Bela Vista") + expect(address.number_min).to eq("0001") + expect(address.number_max).to eq("1999") + expect(address.street_suffix).to eq("Avenida") + end + + it "hydrates the nested city object into Address::City with code and name" do + city = addresses.lookup_by_postal_code("01310-100").addresses.first.city + + expect(city).to be_a(Nfe::Address::City) + expect(city.code).to eq("3550308") + expect(city.name).to eq("São Paulo") + end + + it "rejects a wrong-length CEP before issuing any HTTP request" do + expect { addresses.lookup_by_postal_code("123") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#search" do + before { transport.enqueue(response(body: { "addresses" => [] }.to_json)) } + + it "forwards a present filter as $filter" do + addresses.search(filter: "city eq 'SP'") + + expect(last_request.url).to include("%24filter=").or include("$filter=") + expect(last_request.url).to start_with("https://address.api.nfe.io/v2/addresses") + end + + it "omits the query entirely when no filter is given" do + addresses.search + + expect(last_request.url).not_to include("filter") + end + end + + describe "#lookup_by_term" do + before { transport.enqueue(response(body: { "addresses" => [] }.to_json)) } + + it "URL-encodes the term into the path" do + addresses.lookup_by_term("Avenida Paulista") + + expect(last_request.url).to include("/addresses/Avenida") + expect(last_request.url).to include("+").or include("%20") + end + + it "rejects an empty/whitespace term before issuing any HTTP request" do + expect { addresses.lookup_by_term(" ") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe Nfe::AddressLookupResponse do + it "normalizes the singular { address: {...} } shape (postal-code lookup)" do + result = described_class.from_api("address" => { "street" => "Paulista" }) + expect(result.addresses.map(&:street)).to eq(["Paulista"]) + end + + it "accepts the list { addresses: [...] } shape (search/term)" do + result = described_class.from_api("addresses" => [{ "street" => "A" }, { "street" => "B" }]) + expect(result.addresses.map(&:street)).to eq(%w[A B]) + end + + it "returns an empty list when neither key is present" do + expect(described_class.from_api({}).addresses).to eq([]) + end + end +end diff --git a/spec/nfe/resources/companies_spec.rb b/spec/nfe/resources/companies_spec.rb new file mode 100644 index 0000000..6d08b1d --- /dev/null +++ b/spec/nfe/resources/companies_spec.rb @@ -0,0 +1,286 @@ +# frozen_string_literal: true + +require "openssl" +require "json" + +RSpec.describe Nfe::Resources::Companies do + subject(:companies) { client.companies } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + # A real self-signed PKCS#12, generated in-memory (no temp file on disk). + let(:pfx) do + key = OpenSSL::PKey::RSA.new(2048) + name = OpenSSL::X509::Name.parse("/CN=Acme Test/O=NFE") + cert = OpenSSL::X509::Certificate.new + cert.version = 2 + cert.serial = 4242 + cert.subject = name + cert.issuer = name + cert.public_key = key.public_key + cert.not_before = Time.now - 86_400 + cert.not_after = Time.now + (40 * 86_400) + cert.sign(key, OpenSSL::Digest.new("SHA256")) + OpenSSL::PKCS12.create("secret", "acme", key, cert).to_der + end + + # Route every request through a request-capturing fake transport. + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "#create" do + before { transport.enqueue(json(body: { "companies" => { "id" => "abc", "name" => "Acme" } }.to_json)) } + + it "POSTs to the main host and returns a hydrated Company" do + company = companies.create(name: "Acme", federalTaxNumber: "12345678000199") + + expect(company).to be_a(Nfe::Company) + expect(company.id).to eq("abc") + expect(last_request.method).to eq("POST") + expect(last_request.url).to start_with("https://api.nfe.io/v1/companies") + expect(last_request.headers["Content-Type"]).to eq("application/json") + end + + it "rejects a wrong-length tax number before issuing HTTP" do + expect { companies.create(name: "X", federalTaxNumber: "123") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "accepts a 14-char alphanumeric CNPJ without numeric coercion" do + companies.create(name: "X", federalTaxNumber: "12ABC678000199") + sent = JSON.parse(last_request.body) + expect(sent["federalTaxNumber"]).to eq("12ABC678000199") + end + + it "rejects a malformed e-mail before HTTP" do + expect { companies.create(name: "X", email: "not-an-email") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#list" do + before do + transport.enqueue(json(body: { "companies" => [{ "id" => "a" }, { "id" => "b" }], "page" => 1 }.to_json)) + end + + it "converts the API 1-based page to a 0-based page_index" do + result = companies.list(page_index: 0, page_count: 20) + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:id)).to eq(%w[a b]) + expect(result.page.page_index).to eq(0) + expect(result.page.page_count).to eq(20) + # page_index 0 (0-based) é enviado como pageIndex=1 (1-based, exigido pela API) + expect(last_request.url).to include("pageIndex=1").and include("pageCount=20") + end + end + + describe "#list_all" do + it "auto-paginates until a short page is returned" do + full = (1..100).map { |i| { "id" => "c#{i}" } } + transport.enqueue(json(body: { "companies" => full, "page" => 1 }.to_json)) + transport.enqueue(json(body: { "companies" => [{ "id" => "tail" }], "page" => 2 }.to_json)) + + all = companies.list_all + + expect(all.length).to eq(101) + expect(all.last.id).to eq("tail") + expect(transport.requests.length).to eq(2) + end + end + + describe "#list_each" do + it "returns an Enumerator yielding companies on demand" do + transport.enqueue(json(body: { "companies" => [{ "id" => "a" }], "page" => 1 }.to_json)) + enum = companies.list_each + + expect(enum).to be_a(Enumerator) + expect(enum.first.id).to eq("a") + end + end + + describe "#retrieve" do + it "unwraps the companies envelope" do + transport.enqueue(json(body: { "companies" => { "id" => "abc" } }.to_json)) + expect(companies.retrieve("abc").id).to eq("abc") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/abc") + end + + it "raises NotFoundError on 404" do + transport.enqueue(json(status: 404, body: "{}")) + expect { companies.retrieve("missing") }.to raise_error(Nfe::NotFoundError) + end + + it "rejects an empty company_id without HTTP" do + expect { companies.retrieve(" ") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#update" do + it "PUTs and unwraps" do + transport.enqueue(json(body: { "companies" => { "id" => "abc", "name" => "New" } }.to_json)) + company = companies.update("abc", name: "New") + expect(company.name).to eq("New") + expect(last_request.method).to eq("PUT") + end + end + + describe "#remove" do + it "returns a deletion confirmation" do + transport.enqueue(json(status: 200, body: "")) + expect(companies.remove("abc")).to eq({ deleted: true, id: "abc" }) + expect(last_request.method).to eq("DELETE") + end + end + + describe "#find_by_tax_number" do + it "finds by normalised federal tax number" do + transport.enqueue(json(body: { + "companies" => [{ "id" => "a", "federalTaxNumber" => "12345678000199" }], "page" => 1 + }.to_json)) + found = companies.find_by_tax_number("12.345.678/0001-99") + expect(found.id).to eq("a") + end + + it "returns nil when not found" do + transport.enqueue(json(body: { "companies" => [], "page" => 1 }.to_json)) + expect(companies.find_by_tax_number("12345678000199")).to be_nil + end + end + + describe "#find_by_name" do + it "matches case-insensitively" do + transport.enqueue(json(body: { + "companies" => [{ "id" => "a", "name" => "Acme Corp" }, { "id" => "b", "name" => "Other" }], + "page" => 1 + }.to_json)) + expect(companies.find_by_name("acme").map(&:id)).to eq(["a"]) + end + + it "raises on an empty name" do + expect { companies.find_by_name(" ") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#validate_certificate" do + it "extracts real metadata with the correct password (no HTTP)" do + info = companies.validate_certificate(file: pfx, password: "secret") + expect(info).to be_a(Nfe::CertificateInfo) + expect(info.subject).to include("Acme Test") + expect(info.not_after).to be > Time.now + expect(transport.requests).to be_empty + end + + it "raises InvalidRequestError on a wrong password" do + expect { companies.validate_certificate(file: pfx, password: "wrong") } + .to raise_error(Nfe::InvalidRequestError) + end + end + + describe "#upload_certificate" do + before { transport.enqueue(json(body: { "message" => "ok" }.to_json)) } + + it "POSTs a multipart body carrying file and password" do + result = companies.upload_certificate("abc", file: pfx, password: "secret", filename: "cert.pfx") + + expect(result).to eq({ uploaded: true, message: "ok" }) + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/abc/certificate") + content_type = last_request.headers["Content-Type"] + expect(content_type).to start_with("multipart/form-data; boundary=") + body = last_request.body + expect(body).to include('name="file"').and include('name="password"') + expect(body).to include("secret") + end + + it "rejects an unsupported extension before HTTP" do + expect { companies.upload_certificate("abc", file: pfx, password: "secret", filename: "cert.pem") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "fails fast on a wrong password before HTTP" do + expect { companies.upload_certificate("abc", file: pfx, password: "wrong", filename: "cert.pfx") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#replace_certificate" do + it "behaves like upload_certificate" do + transport.enqueue(json(body: "{}")) + expect(companies.replace_certificate("abc", file: pfx, + password: "secret")).to eq({ uploaded: true, message: nil }) + end + end + + describe "#get_certificate_status" do + it "computes days_until_expiration and expiring_soon from expires_on" do + expires = (Time.now + (10 * 86_400)).iso8601 + transport.enqueue(json(body: { "hasCertificate" => true, "expiresOn" => expires, "isValid" => true }.to_json)) + + status = companies.get_certificate_status("abc") + + expect(status).to be_a(Nfe::CertificateStatus) + expect(status.has_certificate).to be(true) + expect(status.days_until_expiration).to be_between(8, 10) + expect(status.expiring_soon).to be(true) + end + + it "leaves computed fields nil when there is no certificate" do + transport.enqueue(json(body: { "hasCertificate" => false }.to_json)) + status = companies.get_certificate_status("abc") + expect(status.days_until_expiration).to be_nil + expect(status.expiring_soon).to be_nil + end + end + + describe "#check_certificate_expiration" do + it "returns a warning within the threshold" do + expires = (Time.now + (10 * 86_400)).iso8601 + transport.enqueue(json(body: { "hasCertificate" => true, "expiresOn" => expires, "isValid" => true }.to_json)) + + warning = companies.check_certificate_expiration("abc", threshold_days: 30) + expect(warning[:expiring]).to be(true) + expect(warning[:days_remaining]).to be_between(8, 10) + end + + it "returns nil outside the threshold" do + expires = (Time.now + (200 * 86_400)).iso8601 + transport.enqueue(json(body: { "hasCertificate" => true, "expiresOn" => expires }.to_json)) + expect(companies.check_certificate_expiration("abc", threshold_days: 30)).to be_nil + end + end + + describe "#get_companies_with_expiring_certificates" do + it "lists companies, skips lookup failures, and keeps the expiring ones" do + expires = (Time.now + (10 * 86_400)).iso8601 + transport.enqueue(json(body: { + "companies" => [{ "id" => "ok" }, { "id" => "boom" }], "page" => 1 + }.to_json)) + transport.enqueue(json(body: { "hasCertificate" => true, "expiresOn" => expires }.to_json)) # status for "ok" + transport.enqueue(json(status: 500, body: "{}")) # status for "boom" -> skipped + + result = companies.get_companies_with_expiring_certificates(threshold_days: 30) + expect(result.map(&:id)).to eq(["ok"]) + end + end + + describe "main-host routing" do + it "targets https://api.nfe.io/v1 for every call" do + transport.enqueue(json(body: { "companies" => [], "page" => 1 }.to_json)) + companies.list + expect(last_request.url).to start_with("https://api.nfe.io/v1/companies") + end + end +end diff --git a/spec/nfe/resources/consumer_invoice_query_spec.rb b/spec/nfe/resources/consumer_invoice_query_spec.rb new file mode 100644 index 0000000..903dc82 --- /dev/null +++ b/spec/nfe/resources/consumer_invoice_query_spec.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::ConsumerInvoiceQuery do + subject(:consumer_invoice_query) { client.consumer_invoice_query } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + # Canonical 44-digit NFC-e access key, and the same key supplied with + # formatting separators to prove IdValidator normalizes it back to 44 digits. + let(:normalized_key) { "3" * 44 } + let(:formatted_key) { "3333 3333.3333/3333-3333 3333 3333 3333 3333 3333 3333" } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "routing" do + it "declares the :nfe_query api_family with an empty version" do + expect(consumer_invoice_query.send(:api_family)).to eq(:nfe_query) + expect(consumer_invoice_query.send(:api_version)).to eq("") + end + end + + describe "#retrieve" do + # Realistic CFe-SAT coupon body using the REAL camelCase keys and enum + # values from the TaxCouponResource schema (totals{totalAmount,couponAmount}, + # payment{payBack,paymentDetails:[{method,amount}]}, items:[{netAmount, + # grossAmount}], delivery{address}). A mismapped DTO leaves these members nil + # and fails the hydration assertions below. + let(:payload) do + { + "currentStatus" => "Authorized", + "number" => 10, + "satSerie" => "900001234", + "accessKey" => normalized_key, + "issuer" => { "federalTaxNumber" => 12_345_678_000_199, "name" => "Loja XPTO", + "tradeName" => "XPTO", "stateTaxNumber" => 123_456_789 }, + "buyer" => { "federalTaxNumber" => 11_122_233_396, "name" => "Consumidor" }, + "totals" => { "totalAmount" => 4.9, "couponAmount" => 49.9 }, + "delivery" => { "address" => { "street" => "Rua A", "number" => "100", + "district" => "Centro", "postalCode" => 1_310_100 } }, + "additionalInformation" => { "taxpayer" => "Obrigado pela preferência" }, + "items" => [{ "code" => 1, "description" => "Café", "cfop" => 5102, + "netAmount" => 49.9, "grossAmount" => 49.9 }], + "payment" => { "payBack" => 0.1, + "paymentDetails" => [{ "method" => "Cash", "amount" => 50.0 }] } + } + end + + before { transport.enqueue(response(body: payload.to_json)) } + + it "hits the nfe.api.nfe.io v1 coupon path with the normalized 44-digit key" do + consumer_invoice_query.retrieve(formatted_key) + + expect(last_request.method).to eq("GET") + expect(last_request.url).to start_with("https://nfe.api.nfe.io") + expect(last_request.url).to end_with("/v1/consumerinvoices/coupon/#{normalized_key}") + end + + it "hydrates the TaxCoupon scalars and issuer/buyer" do + coupon = consumer_invoice_query.retrieve(formatted_key) + + expect(coupon).to be_a(Nfe::TaxCoupon) + expect(coupon.current_status).to eq("Authorized") + expect(coupon.access_key).to eq(normalized_key) + expect(coupon.issuer).to be_a(Nfe::TaxCoupon::Issuer) + expect(coupon.issuer.name).to eq("Loja XPTO") + expect(coupon.issuer.federal_tax_number).to eq("12345678000199") + expect(coupon.buyer.federal_tax_number).to eq("11122233396") + end + + it "hydrates totals, items, payment and delivery with the real keys" do + coupon = consumer_invoice_query.retrieve(formatted_key) + + expect(coupon.totals.total_amount).to eq(4.9) + expect(coupon.totals.coupon_amount).to eq(49.9) + expect(coupon.items.first).to be_a(Nfe::TaxCoupon::Item) + expect(coupon.items.first.net_amount).to eq(49.9) + expect(coupon.items.first.gross_amount).to eq(49.9) + expect(coupon.payment.pay_back).to eq(0.1) + expect(coupon.payment.payment_details.first.method).to eq("Cash") + expect(coupon.payment.payment_details.first.amount).to eq(50.0) + expect(coupon.delivery.address.district).to eq("Centro") + end + + it "rejects an access key that is not 44 digits before any HTTP request" do + transport_with_no_calls = FakeTransport.new + allow(client).to receive(:build_transport).and_return(transport_with_no_calls) + + expect { consumer_invoice_query.retrieve("123") }.to raise_error(Nfe::InvalidRequestError) + expect(transport_with_no_calls.requests).to be_empty + end + end + + describe "#download_xml" do + before { transport.enqueue(response(body: "...".b)) } + + it "uses the .xml suffix, an XML Accept header, and returns binary bytes" do + bytes = consumer_invoice_query.download_xml(formatted_key) + + expect(bytes).to be_a(String) + expect(bytes.encoding).to eq(Encoding::ASCII_8BIT) + expect(bytes).to start_with("") + expect(last_request.headers["Accept"]).to eq("application/xml") + expect(last_request.url).to end_with("/v1/consumerinvoices/coupon/#{normalized_key}.xml") + expect(last_request.url).to start_with("https://nfe.api.nfe.io") + end + end +end diff --git a/spec/nfe/resources/consumer_invoice_response_spec.rb b/spec/nfe/resources/consumer_invoice_response_spec.rb new file mode 100644 index 0000000..28cab82 --- /dev/null +++ b/spec/nfe/resources/consumer_invoice_response_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +RSpec.describe "NFC-e discriminated response value objects" do # rubocop:disable RSpec/DescribeClass + describe Nfe::Resources::ConsumerInvoicePending do + subject(:pending) { described_class.new(invoice_id: "nfc-1", location: "/v2/.../nfc-1") } + + it "discriminates as pending" do + expect(pending).to be_pending + expect(pending).not_to be_issued + end + + it "exposes invoice_id and location" do + expect(pending.invoice_id).to eq("nfc-1") + expect(pending.location).to eq("/v2/.../nfc-1") + end + + it "matches via Data pattern matching" do + result = pending + matched = + case result + in Nfe::Resources::ConsumerInvoicePending then :pending # rubocop:disable RSpec/DescribedClass + in Nfe::Resources::ConsumerInvoiceIssued then :issued + end + expect(matched).to eq(:pending) + end + + it "is an immutable value object" do + expect(pending).to be_frozen + end + end + + describe Nfe::Resources::ConsumerInvoiceIssued do + subject(:issued) { described_class.new(resource: invoice) } + + let(:invoice) { Nfe::ConsumerInvoice.from_api("id" => "nfc-2") } + + it "discriminates as issued" do + expect(issued).to be_issued + expect(issued).not_to be_pending + end + + it "exposes the hydrated resource" do + expect(issued.resource).to be(invoice) + expect(issued.resource.id).to eq("nfc-2") + end + + it "matches via Data pattern matching" do + matched = + case issued + in Nfe::Resources::ConsumerInvoicePending then :pending + in Nfe::Resources::ConsumerInvoiceIssued then :issued # rubocop:disable RSpec/DescribedClass + end + expect(matched).to eq(:issued) + end + end +end diff --git a/spec/nfe/resources/consumer_invoices_spec.rb b/spec/nfe/resources/consumer_invoices_spec.rb new file mode 100644 index 0000000..4aa6469 --- /dev/null +++ b/spec/nfe/resources/consumer_invoices_spec.rb @@ -0,0 +1,278 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::ConsumerInvoices do + subject(:consumer_invoices) { client.consumer_invoices } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "routing" do + it "targets the api.nfse.io /v2 host for every call" do + transport.enqueue(response(body: { "consumerInvoices" => [] }.to_json)) + consumer_invoices.list(company_id: "co", environment: "Test") + expect(last_request.url).to start_with("https://api.nfse.io/v2/companies/co/consumerinvoices") + end + + it "declares the :cte api_family" do + expect(consumer_invoices.send(:api_family)).to eq(:cte) + end + end + + describe "#create" do + context "when the API enqueues the NFC-e (HTTP 202)" do + before do + transport.enqueue(response( + status: 202, + headers: { "location" => "/v2/companies/co/consumerinvoices/nfc-77" } + )) + end + + it "returns a ConsumerInvoicePending discriminating as pending" do + result = consumer_invoices.create(company_id: "co", data: { totalAmount: 10 }) + + expect(result).to be_a(Nfe::Resources::ConsumerInvoicePending) + expect(result).to be_pending + expect(result).not_to be_issued + expect(result.invoice_id).to eq("nfc-77") + expect(result.location).to eq("/v2/companies/co/consumerinvoices/nfc-77") + end + + it "POSTs a JSON body with the proper Content-Type" do + consumer_invoices.create(company_id: "co", data: { totalAmount: 10 }) + + expect(last_request.method).to eq("POST") + expect(last_request.headers["Content-Type"]).to eq("application/json") + expect(JSON.parse(last_request.body)).to eq({ "totalAmount" => 10 }) + end + + it "forwards idempotency_key on the request" do + consumer_invoices.create(company_id: "co", data: {}, idempotency_key: "order-42") + expect(last_request.idempotency_key).to eq("order-42") + end + + it "threads per-call request_options without mutating the client" do + consumer_invoices.create( + company_id: "co", data: {}, + request_options: Nfe::RequestOptions.new(api_key: "tenant-key") + ) + expect(last_request.headers["X-NFE-APIKEY"]).to eq("tenant-key") + end + end + + context "when the API materializes the NFC-e (HTTP 201)" do + before do + transport.enqueue(response( + status: 201, + body: { "id" => "nfc-1", "flowStatus" => "Issued", "accessKey" => "k" }.to_json + )) + end + + it "returns a ConsumerInvoiceIssued wrapping a hydrated model" do + result = consumer_invoices.create(company_id: "co", data: {}) + + expect(result).to be_a(Nfe::Resources::ConsumerInvoiceIssued) + expect(result).to be_issued + expect(result).not_to be_pending + expect(result.resource).to be_a(Nfe::ConsumerInvoice) + expect(result.resource.id).to eq("nfc-1") + expect(result.resource.flow_status).to eq("Issued") + end + end + + context "when 202 arrives without a Location header" do + before { transport.enqueue(response(status: 202)) } + + it "raises InvoiceProcessingError" do + expect { consumer_invoices.create(company_id: "co", data: {}) } + .to raise_error(Nfe::InvoiceProcessingError) + end + end + + it "rejects an empty company_id before any HTTP request" do + expect { consumer_invoices.create(company_id: " ", data: {}) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#create_with_state_tax" do + before do + transport.enqueue(response( + status: 202, + headers: { "location" => "/v2/companies/co/consumerinvoices/nfc-9" } + )) + end + + it "routes to the state-tax-scoped path and returns a Pending" do + result = consumer_invoices.create_with_state_tax( + company_id: "co", state_tax_id: "st-1", data: {}, idempotency_key: "k1" + ) + + expect(result).to be_a(Nfe::Resources::ConsumerInvoicePending) + expect(last_request.url) + .to start_with("https://api.nfse.io/v2/companies/co/statetaxes/st-1/consumerinvoices") + expect(last_request.idempotency_key).to eq("k1") + end + + it "validates the state_tax_id before HTTP" do + expect { consumer_invoices.create_with_state_tax(company_id: "co", state_tax_id: "", data: {}) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#list" do + before do + transport.enqueue(response(body: { + "consumerInvoices" => [{ "id" => "a" }, { "id" => "b" }], + "startingAfter" => "a", "endingBefore" => "b" + }.to_json)) + end + + it "returns a cursor-style ListResponse of hydrated models" do + result = consumer_invoices.list(company_id: "co", environment: "Test", limit: 50, starting_after: "x") + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:id)).to eq(%w[a b]) + expect(result.data.first).to be_a(Nfe::ConsumerInvoice) + expect(result.page.starting_after).to eq("a") + expect(result.page.page_index).to be_nil + expect(last_request.url).to include("limit=50").and include("starting_after=x").and include("environment=Test") + end + + it "iterates via Enumerable" do + result = consumer_invoices.list(company_id: "co", environment: "Test") + expect(result.map(&:id)).to eq(%w[a b]) + end + + it "exige environment não-vazio antes de qualquer HTTP" do + expect { consumer_invoices.list(company_id: "co", environment: " ") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#retrieve" do + it "hydrates a ConsumerInvoice" do + transport.enqueue(response(body: { "id" => "nfc-1", "status" => "Issued" }.to_json)) + invoice = consumer_invoices.retrieve(company_id: "co", invoice_id: "nfc-1") + + expect(invoice).to be_a(Nfe::ConsumerInvoice) + expect(invoice.id).to eq("nfc-1") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co/consumerinvoices/nfc-1") + end + + it "rejects an empty invoice_id before HTTP" do + expect { consumer_invoices.retrieve(company_id: "co", invoice_id: " ") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#cancel" do + it "DELETEs synchronously and returns the updated model" do + transport.enqueue(response(body: { "id" => "nfc-1", "status" => "Cancelled" }.to_json)) + invoice = consumer_invoices.cancel(company_id: "co", invoice_id: "nfc-1") + + expect(invoice.status).to eq("Cancelled") + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co/consumerinvoices/nfc-1") + end + end + + describe "#list_items" do + it "returns the unwrapped items array" do + transport.enqueue(response(body: { "items" => [{ "code" => "x" }] }.to_json)) + items = consumer_invoices.list_items(company_id: "co", invoice_id: "nfc-1") + + expect(items).to eq([{ "code" => "x" }]) + expect(last_request.url).to end_with("/consumerinvoices/nfc-1/items") + end + + it "tolerates a bare array body" do + transport.enqueue(response(body: [{ "code" => "y" }].to_json)) + expect(consumer_invoices.list_items(company_id: "co", invoice_id: "nfc-1")) + .to eq([{ "code" => "y" }]) + end + end + + describe "#list_events" do + it "returns the unwrapped events array" do + transport.enqueue(response(body: { "events" => [{ "type" => "Cancel" }] }.to_json)) + events = consumer_invoices.list_events(company_id: "co", invoice_id: "nfc-1") + + expect(events).to eq([{ "type" => "Cancel" }]) + expect(last_request.url).to end_with("/consumerinvoices/nfc-1/events") + end + end + + describe "byte downloads" do + it "#download_pdf returns ASCII-8BIT PDF bytes with an Accept header" do + transport.enqueue(response(body: "%PDF-1.4 binary".b)) + bytes = consumer_invoices.download_pdf(company_id: "co", invoice_id: "nfc-1") + + expect(bytes.encoding).to eq(Encoding::ASCII_8BIT) + expect(bytes[0, 4]).to eq("%PDF") + expect(last_request.headers["Accept"]).to eq("application/pdf") + expect(last_request.url).to end_with("/consumerinvoices/nfc-1/pdf") + end + + it "#download_xml returns ASCII-8BIT XML bytes" do + transport.enqueue(response(body: "".b)) + bytes = consumer_invoices.download_xml(company_id: "co", invoice_id: "nfc-1") + + expect(bytes.encoding).to eq(Encoding::ASCII_8BIT) + expect(bytes[0]).to eq("<") + expect(last_request.headers["Accept"]).to eq("application/xml") + end + + it "#download_rejection_xml hits the rejection path and returns bytes" do + transport.enqueue(response(body: "".b)) + bytes = consumer_invoices.download_rejection_xml(company_id: "co", invoice_id: "nfc-1") + + expect(bytes.encoding).to eq(Encoding::ASCII_8BIT) + expect(last_request.url).to end_with("/consumerinvoices/nfc-1/xml/rejection") + end + end + + describe "#disable_range" do + it "POSTs the collective inutilization payload" do + transport.enqueue(response(body: { "status" => "Done" }.to_json)) + result = consumer_invoices.disable_range( + company_id: "co", + data: { environment: "Production", serie: 1, state: "SP", begin_number: 1, last_number: 10 } + ) + + expect(result).to eq({ "status" => "Done" }) + expect(last_request.method).to eq("POST") + expect(last_request.url).to end_with("/consumerinvoices/disablement") + expect(last_request.headers["Content-Type"]).to eq("application/json") + end + end + + describe "methods absent by fiscal law" do + it "does not define send_correction_letter (CC-e is NF-e only)" do + expect { consumer_invoices.send_correction_letter }.to raise_error(NoMethodError) + end + + it "does not define download_epec_xml (no EPEC for NFC-e)" do + expect { consumer_invoices.download_epec_xml }.to raise_error(NoMethodError) + end + + it "does not define a per-invoice disable (only disable_range)" do + expect { consumer_invoices.disable }.to raise_error(NoMethodError) + end + end +end diff --git a/spec/nfe/resources/dto/company_spec.rb b/spec/nfe/resources/dto/company_spec.rb new file mode 100644 index 0000000..862c26f --- /dev/null +++ b/spec/nfe/resources/dto/company_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Company do + describe ".from_api" do + it "maps camelCase keys onto snake_case members" do + company = described_class.from_api( + "id" => "co_1", + "name" => "Acme Ltda", + "tradeName" => "Acme", + "federalTaxNumber" => "12345678000199", + "email" => "fiscal@acme.com", + "municipalTaxNumber" => "987", + "createdOn" => "2026-01-01T00:00:00Z", + "modifiedOn" => "2026-02-01T00:00:00Z" + ) + + expect(company.id).to eq("co_1") + expect(company.name).to eq("Acme Ltda") + expect(company.trade_name).to eq("Acme") + expect(company.federal_tax_number).to eq("12345678000199") + expect(company.email).to eq("fiscal@acme.com") + expect(company.municipal_tax_number).to eq("987") + expect(company.created_on).to eq("2026-01-01T00:00:00Z") + expect(company.modified_on).to eq("2026-02-01T00:00:00Z") + end + + it "keeps a numeric federalTaxNumber as a String without coercion" do + company = described_class.from_api("name" => "X", "federalTaxNumber" => 12_345_678_000_199) + expect(company.federal_tax_number).to eq("12345678000199") + expect(company.federal_tax_number).to be_a(String) + end + + it "drops unknown keys and tolerates missing fields" do + company = described_class.from_api("id" => "co_2", "unknownKey" => "ignored") + expect(company.id).to eq("co_2") + expect(company.name).to be_nil + expect(company.federal_tax_number).to be_nil + expect(company).not_to respond_to(:unknown_key) + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + + it "produces an immutable value object" do + company = described_class.from_api("id" => "co_3") + expect(company).to be_frozen + end + end +end diff --git a/spec/nfe/resources/dto/consumer_invoice_spec.rb b/spec/nfe/resources/dto/consumer_invoice_spec.rb new file mode 100644 index 0000000..58ed035 --- /dev/null +++ b/spec/nfe/resources/dto/consumer_invoice_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::ConsumerInvoice do + describe ".from_api" do + let(:payload) do + { + "id" => "nfc_1", + "status" => "Issued", + "flowStatus" => "Issued", + "flowMessage" => "Autorizada", + "environment" => "Production", + "accessKey" => "3524011234567800019059000000001234567890", + "number" => 12, + "serie" => 1, + "totalAmount" => 99.9, + "issuedOn" => "2026-01-01T00:00:00Z", + "createdOn" => "2026-01-01T00:00:00Z", + "modifiedOn" => "2026-01-02T00:00:00Z", + "cancelledOn" => nil + } + end + + it "maps camelCase keys onto snake_case members" do + invoice = described_class.from_api(payload) + + expect(invoice.id).to eq("nfc_1") + expect(invoice.flow_status).to eq("Issued") + expect(invoice.flow_message).to eq("Autorizada") + expect(invoice.environment).to eq("Production") + expect(invoice.access_key).to eq("3524011234567800019059000000001234567890") + expect(invoice.number).to eq(12) + expect(invoice.serie).to eq(1) + expect(invoice.total_amount).to eq(99.9) + expect(invoice.issued_on).to eq("2026-01-01T00:00:00Z") + expect(invoice.modified_on).to eq("2026-01-02T00:00:00Z") + end + + it "preserves the raw payload for forward compatibility" do + payload = { "id" => "nfc_2", "newApiField" => "kept" } + invoice = described_class.from_api(payload) + + expect(invoice.raw).to eq(payload) + expect(invoice).not_to respond_to(:new_api_field) + end + + it "tolerates missing fields" do + invoice = described_class.from_api("id" => "nfc_3") + expect(invoice.id).to eq("nfc_3") + expect(invoice.flow_status).to be_nil + expect(invoice.total_amount).to be_nil + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + + it "produces an immutable value object" do + expect(described_class.from_api("id" => "nfc_4")).to be_frozen + end + end +end diff --git a/spec/nfe/resources/dto/legal_person_spec.rb b/spec/nfe/resources/dto/legal_person_spec.rb new file mode 100644 index 0000000..17b94b1 --- /dev/null +++ b/spec/nfe/resources/dto/legal_person_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::LegalPerson do + describe ".from_api" do + it "maps camelCase keys onto snake_case members" do + person = described_class.from_api( + "id" => "lp_1", + "name" => "Fornecedor SA", + "tradeName" => "Fornecedor", + "federalTaxNumber" => "11222333000181", + "email" => "contato@fornecedor.com", + "createdOn" => "2026-01-01T00:00:00Z" + ) + + expect(person.id).to eq("lp_1") + expect(person.name).to eq("Fornecedor SA") + expect(person.trade_name).to eq("Fornecedor") + expect(person.federal_tax_number).to eq("11222333000181") + expect(person.email).to eq("contato@fornecedor.com") + expect(person.created_on).to eq("2026-01-01T00:00:00Z") + end + + it "keeps the CNPJ as a String even when numeric" do + person = described_class.from_api("federalTaxNumber" => 11_222_333_000_181) + expect(person.federal_tax_number).to eq("11222333000181") + end + + it "drops unknown keys and tolerates missing fields" do + person = described_class.from_api("id" => "lp_2", "weird" => 1) + expect(person.id).to eq("lp_2") + expect(person.name).to be_nil + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + end +end diff --git a/spec/nfe/resources/dto/natural_person_spec.rb b/spec/nfe/resources/dto/natural_person_spec.rb new file mode 100644 index 0000000..a75d740 --- /dev/null +++ b/spec/nfe/resources/dto/natural_person_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::NaturalPerson do + describe ".from_api" do + it "maps camelCase keys onto snake_case members" do + person = described_class.from_api( + "id" => "np_1", + "name" => "João da Silva", + "federalTaxNumber" => "12345678901", + "email" => "joao@example.com", + "modifiedOn" => "2026-03-01T00:00:00Z" + ) + + expect(person.id).to eq("np_1") + expect(person.name).to eq("João da Silva") + expect(person.federal_tax_number).to eq("12345678901") + expect(person.email).to eq("joao@example.com") + expect(person.modified_on).to eq("2026-03-01T00:00:00Z") + end + + it "keeps the CPF as a String even when numeric" do + person = described_class.from_api("federalTaxNumber" => 12_345_678_901) + expect(person.federal_tax_number).to eq("12345678901") + end + + it "drops unknown keys and tolerates missing fields" do + person = described_class.from_api("id" => "np_2", "extra" => true) + expect(person.id).to eq("np_2") + expect(person.name).to be_nil + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + end +end diff --git a/spec/nfe/resources/dto/nfe_file_resource_spec.rb b/spec/nfe/resources/dto/nfe_file_resource_spec.rb new file mode 100644 index 0000000..af5a4f7 --- /dev/null +++ b/spec/nfe/resources/dto/nfe_file_resource_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::NfeFileResource do + describe ".from_api" do + it "maps the uri and metadata fields" do + file = described_class.from_api( + "uri" => "https://files.nfse.io/abc.pdf", + "name" => "abc.pdf", + "contentType" => "application/pdf", + "size" => 1024 + ) + + expect(file.uri).to eq("https://files.nfse.io/abc.pdf") + expect(file.name).to eq("abc.pdf") + expect(file.content_type).to eq("application/pdf") + expect(file.size).to eq(1024) + end + + it "falls back to the url key when uri is absent" do + file = described_class.from_api("url" => "https://files.nfse.io/x.xml") + expect(file.uri).to eq("https://files.nfse.io/x.xml") + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + end +end diff --git a/spec/nfe/resources/dto/product_invoice_spec.rb b/spec/nfe/resources/dto/product_invoice_spec.rb new file mode 100644 index 0000000..37d9da3 --- /dev/null +++ b/spec/nfe/resources/dto/product_invoice_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::ProductInvoice do + describe ".from_api" do + let(:payload) do + { + "id" => "pi_1", + "flowStatus" => "Issued", + "flowMessage" => "ok", + "status" => "Authorized", + "environment" => "Production", + "serie" => 1, + "number" => 200, + "operationNature" => "Venda", + "operationType" => "Outgoing", + "accessKey" => "0" * 44, + "protocol" => "PROTO", + "items" => [{ "code" => "P1" }], + "totals" => { "amount" => 100 }, + "issuedOn" => "2026-01-01T00:00:00Z" + } + end + + it "maps camelCase keys onto snake_case members" do + invoice = described_class.from_api(payload) + + expect(invoice.id).to eq("pi_1") + expect(invoice.flow_status).to eq("Issued") + expect(invoice.operation_nature).to eq("Venda") + expect(invoice.operation_type).to eq("Outgoing") + expect(invoice.access_key).to eq("0" * 44) + expect(invoice.items).to eq([{ "code" => "P1" }]) + end + + it "drops unknown keys and tolerates missing fields" do + invoice = described_class.from_api("id" => "pi_2", "weird" => 1) + expect(invoice.id).to eq("pi_2") + expect(invoice.flow_status).to be_nil + expect(invoice).not_to respond_to(:weird) + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + end +end diff --git a/spec/nfe/resources/dto/service_invoice_spec.rb b/spec/nfe/resources/dto/service_invoice_spec.rb new file mode 100644 index 0000000..4a3034a --- /dev/null +++ b/spec/nfe/resources/dto/service_invoice_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::ServiceInvoice do + describe ".from_api" do + let(:payload) do + { + "id" => "si_1", + "flowStatus" => "Issued", + "flowMessage" => "ok", + "status" => "Done", + "environment" => "Production", + "rpsNumber" => 42, + "rpsSerialNumber" => "A1", + "number" => 100, + "checkCode" => "ABC123", + "issuedOn" => "2026-01-01T00:00:00Z", + "servicesAmount" => 1000.0, + "cityServiceCode" => "01234", + "description" => "Serviço X", + "createdOn" => "2026-01-01T00:00:00Z", + "modifiedOn" => "2026-01-02T00:00:00Z" + } + end + + it "maps camelCase keys onto snake_case members" do + invoice = described_class.from_api(payload) + + expect(invoice.id).to eq("si_1") + expect(invoice.flow_status).to eq("Issued") + expect(invoice.flow_message).to eq("ok") + expect(invoice.rps_number).to eq(42) + expect(invoice.rps_serial_number).to eq("A1") + expect(invoice.check_code).to eq("ABC123") + expect(invoice.city_service_code).to eq("01234") + expect(invoice.modified_on).to eq("2026-01-02T00:00:00Z") + end + + it "drops unknown keys and tolerates missing fields" do + invoice = described_class.from_api("id" => "si_2", "unknownKey" => "ignored") + expect(invoice.id).to eq("si_2") + expect(invoice.flow_status).to be_nil + expect(invoice).not_to respond_to(:unknown_key) + end + + it "returns nil for a nil payload and is immutable" do + expect(described_class.from_api(nil)).to be_nil + expect(described_class.from_api("id" => "x")).to be_frozen + end + end +end diff --git a/spec/nfe/resources/dto/webhook_spec.rb b/spec/nfe/resources/dto/webhook_spec.rb new file mode 100644 index 0000000..d2bccc9 --- /dev/null +++ b/spec/nfe/resources/dto/webhook_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::WebhookSubscription do + describe ".from_api" do + it "maps camelCase keys onto snake_case members" do + hook = described_class.from_api( + "id" => "wh_1", + "url" => "https://example.com/hook", + "events" => ["invoice.issued"], + "secret" => "s3cr3t", + "active" => true, + "status" => "Active", + "createdOn" => "2026-01-01T00:00:00Z", + "modifiedOn" => "2026-02-01T00:00:00Z" + ) + + expect(hook.id).to eq("wh_1") + expect(hook.url).to eq("https://example.com/hook") + expect(hook.events).to eq(["invoice.issued"]) + expect(hook.secret).to eq("s3cr3t") + expect(hook.active).to be(true) + expect(hook.status).to eq("Active") + expect(hook.created_on).to eq("2026-01-01T00:00:00Z") + expect(hook.modified_on).to eq("2026-02-01T00:00:00Z") + end + + it "drops unknown keys and tolerates missing fields" do + hook = described_class.from_api("id" => "wh_2", "mystery" => 1) + expect(hook.id).to eq("wh_2") + expect(hook.url).to be_nil + expect(hook.events).to be_nil + end + + it "returns nil for a nil payload" do + expect(described_class.from_api(nil)).to be_nil + end + + it "produces an immutable value object" do + expect(described_class.from_api("id" => "wh_3")).to be_frozen + end + end +end diff --git a/spec/nfe/resources/inbound_product_invoices_spec.rb b/spec/nfe/resources/inbound_product_invoices_spec.rb new file mode 100644 index 0000000..a07ae79 --- /dev/null +++ b/spec/nfe/resources/inbound_product_invoices_spec.rb @@ -0,0 +1,201 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::InboundProductInvoices do + subject(:resource) { client.inbound_product_invoices } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "data-key") } + let(:transport) { FakeTransport.new } + let(:access_key) { "5" * 44 } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "#enable_auto_fetch" do + before { transport.enqueue(json(body: { "status" => "Active" }.to_json)) } + + it "POSTs to api.nfse.io and returns hydrated settings" do + settings = resource.enable_auto_fetch( + company_id: "co-1", start_from_nsu: "99", environment_sefaz: "Production", webhook_version: "2" + ) + + expect(settings).to be_a(Nfe::InboundSettings) + expect(last_request.method).to eq("POST") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoices") + body = JSON.parse(last_request.body) + expect(body).to eq( + { "startFromNsu" => "99", "environmentSEFAZ" => "Production", "webhookVersion" => "2" } + ) + end + + it "rejects an empty company_id without HTTP" do + expect { resource.enable_auto_fetch(company_id: "") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#disable_auto_fetch" do + it "DELETEs the productinvoices settings" do + transport.enqueue(json(body: { "status" => "Disabled" }.to_json)) + resource.disable_auto_fetch(company_id: "co-1") + + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoices") + end + end + + describe "#get_settings" do + it "GETs the productinvoices settings" do + transport.enqueue(json(body: { "status" => "Active" }.to_json)) + resource.get_settings(company_id: "co-1") + + expect(last_request.method).to eq("GET") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoices") + end + end + + describe "detail endpoints" do + it "#get_details uses the webhook-v1 path" do + transport.enqueue(json(body: { "accessKey" => access_key }.to_json)) + doc = resource.get_details(company_id: "co-1", access_key: access_key) + + expect(doc).to be_a(Nfe::InboundInvoiceMetadata) + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}") + end + + it "#get_product_invoice_details uses the webhook-v2 path" do + transport.enqueue(json(body: { "accessKey" => access_key, "productInvoices" => [{ "id" => "p1" }] }.to_json)) + doc = resource.get_product_invoice_details(company_id: "co-1", access_key: access_key) + + expect(doc.product_invoices).to eq([{ "id" => "p1" }]) + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoice/#{access_key}") + end + + it "normalises a formatted access key" do + transport.enqueue(json(body: "{}")) + resource.get_details(company_id: "co-1", access_key: access_key.scan(/.{4}/).join(".")) + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}") + end + end + + describe "event endpoints" do + it "#get_event_details uses the v1 events path" do + transport.enqueue(json(body: "{}")) + resource.get_event_details(company_id: "co-1", access_key: access_key, event_key: "ev-1") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/events/ev-1") + end + + it "#get_product_invoice_event_details uses the v2 events path" do + transport.enqueue(json(body: "{}")) + resource.get_product_invoice_event_details(company_id: "co-1", access_key: access_key, event_key: "ev-1") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoice/#{access_key}/events/ev-1") + end + + it "rejects an empty event_key without HTTP" do + expect { resource.get_event_details(company_id: "co-1", access_key: access_key, event_key: " ") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "downloads" do + it "#get_xml returns binary XML bytes" do + transport.enqueue(json(body: "")) + xml = resource.get_xml(company_id: "co-1", access_key: access_key) + + expect(xml).to start_with("<") + expect(xml.encoding).to eq(Encoding::ASCII_8BIT) + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/xml") + expect(last_request.headers["Accept"]).to eq("application/xml") + end + + it "#get_event_xml returns binary event XML bytes" do + transport.enqueue(json(body: "")) + resource.get_event_xml(company_id: "co-1", access_key: access_key, event_key: "ev-1") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/events/ev-1/xml") + end + + it "#get_pdf returns binary PDF bytes with a PDF Accept header" do + transport.enqueue(json(body: "%PDF-1.7 bytes")) + pdf = resource.get_pdf(company_id: "co-1", access_key: access_key) + + expect(pdf[0, 4]).to eq("%PDF") + expect(pdf.encoding).to eq(Encoding::ASCII_8BIT) + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/pdf") + expect(last_request.headers["Accept"]).to eq("application/pdf") + end + end + + describe "#get_json" do + it "GETs the structured JSON and hydrates it" do + transport.enqueue(json(body: { "nameSender" => "Fornecedor" }.to_json)) + doc = resource.get_json(company_id: "co-1", access_key: access_key) + + expect(doc).to be_a(Nfe::InboundInvoiceMetadata) + expect(doc.name_sender).to eq("Fornecedor") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoice/#{access_key}/json") + end + end + + describe "#manifest" do + it "defaults tpEvent to 210210 (awareness)" do + transport.enqueue(json(body: "ok")) + result = resource.manifest(company_id: "co-1", access_key: access_key) + + expect(result).to eq("ok") + expect(last_request.method).to eq("POST") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/manifest?tpEvent=210210") + end + + it "forwards an explicit tpEvent" do + transport.enqueue(json(body: "ok")) + resource.manifest(company_id: "co-1", access_key: access_key, + tp_event: described_class::MANIFEST_CONFIRMATION) + expect(last_request.url).to include("tpEvent=210220") + end + + it "exposes symbolic manifest constants" do + expect(described_class::MANIFEST_AWARENESS).to eq(210_210) + expect(described_class::MANIFEST_CONFIRMATION).to eq(210_220) + expect(described_class::MANIFEST_NOT_PERFORMED).to eq(210_240) + end + end + + describe "#reprocess_webhook" do + it "accepts a 44-digit access key" do + transport.enqueue(json(body: "{}")) + resource.reprocess_webhook(company_id: "co-1", access_key_or_nsu: access_key) + expect(last_request.method).to eq("POST") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoice/#{access_key}/processwebhook") + end + + it "accepts a numeric NSU without rejecting it as an invalid key" do + transport.enqueue(json(body: "{}")) + expect { resource.reprocess_webhook(company_id: "co-1", access_key_or_nsu: 12_345) } + .not_to raise_error + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/productinvoice/12345/processwebhook") + end + + it "rejects an empty identifier without HTTP" do + expect { resource.reprocess_webhook(company_id: "co-1", access_key_or_nsu: "") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end +end diff --git a/spec/nfe/resources/invoice_response_spec.rb b/spec/nfe/resources/invoice_response_spec.rb new file mode 100644 index 0000000..73e6af5 --- /dev/null +++ b/spec/nfe/resources/invoice_response_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +RSpec.describe "invoice discriminated response value objects" do # rubocop:disable RSpec/DescribeClass + describe Nfe::Resources::ServiceInvoicePending do + subject(:pending) { described_class.new(invoice_id: "inv_1", location: "/v1/.../inv_1") } + + it "answers pending? true and issued? false" do + expect(pending.pending?).to be(true) + expect(pending.issued?).to be(false) + end + + it "exposes invoice_id and location" do + expect(pending.invoice_id).to eq("inv_1") + expect(pending.location).to eq("/v1/.../inv_1") + end + + it "is immutable and pattern-matches by type" do + branch = + case pending + in Nfe::Resources::ServiceInvoicePending then :pending # rubocop:disable RSpec/DescribedClass + else :other + end + expect(branch).to eq(:pending) + expect(pending).to be_frozen + end + end + + describe Nfe::Resources::ServiceInvoiceIssued do + subject(:issued) { described_class.new(resource: :invoice) } + + it "answers issued? true and pending? false" do + expect(issued.issued?).to be(true) + expect(issued.pending?).to be(false) + end + + it "exposes the hydrated resource" do + expect(issued.resource).to eq(:invoice) + end + end + + describe Nfe::Resources::ProductInvoicePending do + subject(:pending) { described_class.new(invoice_id: "p_1", location: "loc") } + + it "answers pending? true and issued? false" do + expect(pending.pending?).to be(true) + expect(pending.issued?).to be(false) + end + end + + describe Nfe::Resources::ProductInvoiceIssued do + subject(:issued) { described_class.new(resource: :p) } + + it "answers issued? true and pending? false" do + expect(issued.issued?).to be(true) + expect(issued.pending?).to be(false) + end + end +end diff --git a/spec/nfe/resources/legal_entity_lookup_spec.rb b/spec/nfe/resources/legal_entity_lookup_spec.rb new file mode 100644 index 0000000..972c33e --- /dev/null +++ b/spec/nfe/resources/legal_entity_lookup_spec.rb @@ -0,0 +1,146 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::LegalEntityLookup do + subject(:lookup) { client.legal_entity_lookup } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "#get_basic_info" do + let(:payload) do + { "legalEntity" => { "federalTaxNumber" => "12345678000190", "name" => "Acme S/A", + "tradeName" => "Acme", "status" => "Active", "statusOn" => "2020-01-15T00:00:00Z", + "size" => "EPP", "openedOn" => "2001-06-30T00:00:00Z", "email" => "fiscal@acme.com" } } + end + + before { transport.enqueue(response(body: payload.to_json)) } + + it "routes to the legal-entity host and normalizes the CNPJ into the path" do + lookup.get_basic_info("12.345.678/0001-90") + + expect(last_request.url).to start_with("https://legalentity.api.nfe.io") + expect(last_request.url).to include("/v2/legalentities/basicInfo/12345678000190") + end + + it "hydrates a LegalEntityBasicInfoResponse with a nested LegalEntity" do + result = lookup.get_basic_info("12.345.678/0001-90") + + expect(result).to be_a(Nfe::LegalEntityBasicInfoResponse) + expect(result.legal_entity).to be_a(Nfe::LegalEntity) + expect(result.legal_entity.federal_tax_number).to eq("12345678000190") + expect(result.legal_entity.name).to eq("Acme S/A") + end + + it "maps statusOn/size/openedOn/email onto the real snake_case members" do + legal_entity = lookup.get_basic_info("12.345.678/0001-90").legal_entity + + expect(legal_entity.status_on).to eq("2020-01-15T00:00:00Z") + expect(legal_entity.size).to eq("EPP") + expect(legal_entity.opened_on).to eq("2001-06-30T00:00:00Z") + expect(legal_entity.email).to eq("fiscal@acme.com") + end + + it "forwards update_address and update_city_code as query params" do + lookup.get_basic_info("12.345.678/0001-90", update_address: true, update_city_code: false) + + expect(last_request.url).to include("updateAddress=true") + expect(last_request.url).to include("updateCityCode=false") + end + + it "omits opts that are nil" do + lookup.get_basic_info("12.345.678/0001-90") + + expect(last_request.url).not_to include("updateAddress") + expect(last_request.url).not_to include("updateCityCode") + end + + it "rejects a wrong-length CNPJ before issuing any HTTP request" do + expect { lookup.get_basic_info("123") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#get_state_tax_info" do + let(:payload) do + { "legalEntity" => { "federalTaxNumber" => "12345678000190", "taxRegime" => "Normal", + "fiscalUnit" => "SP", "createdOn" => "2023-03-01T00:00:00Z", "checkCode" => "AB12", + "stateTaxes" => [{ "status" => "Abled", "taxNumber" => "111222333444", + "statusOn" => "2010-05-01T00:00:00Z", + "openedOn" => "2001-06-30T00:00:00Z", + "code" => "SP", "address" => { "district" => "Centro", "state" => "SP" }, + "nfe" => { "status" => "Abled" } }] } } + end + + before { transport.enqueue(response(body: payload.to_json)) } + + it "upcases the UF and normalizes the CNPJ into the path" do + lookup.get_state_tax_info("sp", "12.345.678/0001-90") + + expect(last_request.url) + .to include("/v2/legalentities/stateTaxInfo/SP/12345678000190") + end + + it "hydrates a LegalEntityStateTaxResponse with the state-tax legalEntity" do + result = lookup.get_state_tax_info("sp", "12.345.678/0001-90") + + expect(result).to be_a(Nfe::LegalEntityStateTaxResponse) + expect(result.legal_entity).to be_a(Nfe::StateTaxLegalEntity) + expect(result.legal_entity.tax_regime).to eq("Normal") + expect(result.legal_entity.fiscal_unit).to eq("SP") + expect(result.legal_entity.check_code).to eq("AB12") + end + + it "hydrates the nested stateTaxes registrations" do + state_taxes = lookup.get_state_tax_info("sp", "12.345.678/0001-90").legal_entity.state_taxes + + expect(state_taxes.first).to be_a(Nfe::StateTaxLegalEntity::StateTax) + expect(state_taxes.first.tax_number).to eq("111222333444") + expect(state_taxes.first.status_on).to eq("2010-05-01T00:00:00Z") + expect(state_taxes.first.code).to eq("SP") + expect(state_taxes.first.address.district).to eq("Centro") + expect(state_taxes.first.nfe.status).to eq("Abled") + end + + it "rejects an invalid UF before issuing any HTTP request" do + expect { lookup.get_state_tax_info("XX", "12.345.678/0001-90") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#get_state_tax_for_invoice" do + before { transport.enqueue(response(body: { "legalEntity" => { "taxRegime" => "Normal" } }.to_json)) } + + it "routes to the stateTaxForInvoice path and hydrates the for-invoice response" do + result = lookup.get_state_tax_for_invoice("sp", "12.345.678/0001-90") + + expect(last_request.url) + .to include("/v2/legalentities/stateTaxForInvoice/SP/12345678000190") + expect(result).to be_a(Nfe::LegalEntityStateTaxForInvoiceResponse) + expect(result.legal_entity).to be_a(Nfe::StateTaxLegalEntity) + end + end + + describe "#get_suggested_state_tax_for_invoice" do + before { transport.enqueue(response(body: { "legalEntity" => { "taxRegime" => "Normal" } }.to_json)) } + + it "routes to the stateTaxSuggestedForInvoice path and hydrates the for-invoice response" do + result = lookup.get_suggested_state_tax_for_invoice("sp", "12.345.678/0001-90") + + expect(last_request.url) + .to include("/v2/legalentities/stateTaxSuggestedForInvoice/SP/12345678000190") + expect(result).to be_a(Nfe::LegalEntityStateTaxForInvoiceResponse) + expect(result.legal_entity).to be_a(Nfe::StateTaxLegalEntity) + end + end +end diff --git a/spec/nfe/resources/legal_people_spec.rb b/spec/nfe/resources/legal_people_spec.rb new file mode 100644 index 0000000..7d9b13a --- /dev/null +++ b/spec/nfe/resources/legal_people_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::LegalPeople do + subject(:legal_people) { client.legal_people } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}") + Nfe::Http::Response.new(status: status, body: body) + end + + def last_request + transport.requests.last + end + + describe "#list" do + it "unwraps the legalPeople envelope" do + transport.enqueue(json(body: { "legalPeople" => [{ "id" => "lp1" }, { "id" => "lp2" }] }.to_json)) + + result = legal_people.list("co-1") + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:id)).to eq(%w[lp1 lp2]) + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co-1/legalpeople") + end + + it "rejects an empty company_id without HTTP" do + expect { legal_people.list("") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#create" do + it "POSTs and unwraps a single legal person" do + transport.enqueue(json(body: { "legalPeople" => { "id" => "lp1", "name" => "Empresa" } }.to_json)) + + person = legal_people.create("co-1", name: "Empresa", federalTaxNumber: "12345678000199") + + expect(person).to be_a(Nfe::LegalPerson) + expect(person.id).to eq("lp1") + expect(last_request.method).to eq("POST") + end + end + + describe "#retrieve / #update / #delete" do + it "retrieves by id" do + transport.enqueue(json(body: { "legalPeople" => { "id" => "lp1" } }.to_json)) + expect(legal_people.retrieve("co-1", "lp1").id).to eq("lp1") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co-1/legalpeople/lp1") + end + + it "updates by id" do + transport.enqueue(json(body: { "legalPeople" => { "id" => "lp1", "name" => "X" } }.to_json)) + expect(legal_people.update("co-1", "lp1", name: "X").name).to eq("X") + expect(last_request.method).to eq("PUT") + end + + it "deletes and returns nil" do + transport.enqueue(json(status: 200, body: "")) + expect(legal_people.delete("co-1", "lp1")).to be_nil + expect(last_request.method).to eq("DELETE") + end + + it "rejects an empty legal_person_id without HTTP" do + expect { legal_people.retrieve("co-1", "") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#create_batch" do + it "creates sequentially in order" do + transport.enqueue(json(body: { "legalPeople" => { "id" => "lp1" } }.to_json)) + transport.enqueue(json(body: { "legalPeople" => { "id" => "lp2" } }.to_json)) + + created = legal_people.create_batch("co-1", [{ name: "A" }, { name: "B" }]) + + expect(created.map(&:id)).to eq(%w[lp1 lp2]) + expect(transport.requests.length).to eq(2) + end + end + + describe "#find_by_tax_number" do + it "matches by normalised CNPJ" do + transport.enqueue(json(body: { + "legalPeople" => [{ "id" => "lp1", "federalTaxNumber" => "12345678000199" }] + }.to_json)) + + found = legal_people.find_by_tax_number("co-1", "12.345.678/0001-99") + expect(found.id).to eq("lp1") + end + end +end diff --git a/spec/nfe/resources/natural_people_spec.rb b/spec/nfe/resources/natural_people_spec.rb new file mode 100644 index 0000000..5437e88 --- /dev/null +++ b/spec/nfe/resources/natural_people_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::NaturalPeople do + subject(:natural_people) { client.natural_people } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}") + Nfe::Http::Response.new(status: status, body: body) + end + + def last_request + transport.requests.last + end + + describe "#list" do + it "unwraps the naturalPeople envelope and routes to naturalpeople" do + transport.enqueue(json(body: { "naturalPeople" => [{ "id" => "np1" }] }.to_json)) + + result = natural_people.list("co-1") + + expect(result.data.map(&:id)).to eq(%w[np1]) + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co-1/naturalpeople") + end + + it "rejects an empty company_id without HTTP" do + expect { natural_people.list("") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#create" do + it "POSTs and unwraps a single natural person" do + transport.enqueue(json(body: { "naturalPeople" => { "id" => "np1", "name" => "João" } }.to_json)) + + person = natural_people.create("co-1", name: "João", federalTaxNumber: "12345678901") + + expect(person).to be_a(Nfe::NaturalPerson) + expect(person.id).to eq("np1") + end + end + + describe "#delete" do + it "deletes and returns nil" do + transport.enqueue(json(status: 200, body: "")) + expect(natural_people.delete("co-1", "np1")).to be_nil + expect(last_request.method).to eq("DELETE") + end + end + + describe "#create_batch" do + it "creates sequentially in order" do + transport.enqueue(json(body: { "naturalPeople" => { "id" => "np1" } }.to_json)) + transport.enqueue(json(body: { "naturalPeople" => { "id" => "np2" } }.to_json)) + + created = natural_people.create_batch("co-1", [{ name: "A" }, { name: "B" }]) + + expect(created.map(&:id)).to eq(%w[np1 np2]) + expect(transport.requests.length).to eq(2) + end + end + + describe "#find_by_tax_number" do + it "normalises a formatted CPF to 11 digits before matching" do + transport.enqueue(json(body: { + "naturalPeople" => [{ "id" => "np1", "federalTaxNumber" => "12345678901" }] + }.to_json)) + + found = natural_people.find_by_tax_number("co-1", "123.456.789-01") + expect(found.id).to eq("np1") + end + end +end diff --git a/spec/nfe/resources/natural_person_lookup_spec.rb b/spec/nfe/resources/natural_person_lookup_spec.rb new file mode 100644 index 0000000..cd46eb2 --- /dev/null +++ b/spec/nfe/resources/natural_person_lookup_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require "json" +require "date" + +RSpec.describe Nfe::Resources::NaturalPersonLookup do + subject(:natural_person_lookup) { client.natural_person_lookup } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "#get_status" do + it "targets the naturalperson data host" do + transport.enqueue(response(body: { "name" => "Fulano" }.to_json)) + natural_person_lookup.get_status("123.456.789-01", "1990-01-15") + expect(last_request.url).to start_with("https://naturalperson.api.nfe.io") + end + + it "normalizes the CPF to digits-only in the path" do + transport.enqueue(response(body: "{}")) + natural_person_lookup.get_status("123.456.789-01", "1990-01-15") + expect(last_request.url).to include("/v1/naturalperson/status/12345678901/1990-01-15") + end + + it "produces the same path for an ISO String and a Date birth_date" do + transport.enqueue(response(body: "{}")) + natural_person_lookup.get_status("12345678901", "1990-01-15") + string_url = last_request.url + + natural_person_lookup.get_status("12345678901", Date.new(1990, 1, 15)) + date_url = last_request.url + + expect(date_url).to eq(string_url) + end + + it "hydrates the status response" do + transport.enqueue(response(body: { + "name" => "Fulano de Tal", + "federalTaxNumber" => "12345678901", + "birthOn" => "1990-01-15", + "status" => "Regular", + "createdOn" => "2026-01-01T00:00:00Z" + }.to_json)) + + result = natural_person_lookup.get_status("12345678901", "1990-01-15") + + expect(result).to be_a(Nfe::NaturalPersonStatusResponse) + expect(result.name).to eq("Fulano de Tal") + expect(result.federal_tax_number).to eq("12345678901") + expect(result.status).to eq("Regular") + end + + it "rejects a non-ISO birth_date before HTTP" do + expect { natural_person_lookup.get_status("12345678901", "15/01/1990") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects an out-of-range birth_date before HTTP" do + expect { natural_person_lookup.get_status("12345678901", "2026-13-45") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects an invalid CPF before HTTP" do + expect { natural_person_lookup.get_status("123", "1990-01-15") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end +end diff --git a/spec/nfe/resources/product_invoice_query_spec.rb b/spec/nfe/resources/product_invoice_query_spec.rb new file mode 100644 index 0000000..eaa1628 --- /dev/null +++ b/spec/nfe/resources/product_invoice_query_spec.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::ProductInvoiceQuery do + subject(:product_invoice_query) { client.product_invoice_query } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + let(:access_key) { "1" * 44 } + + # Real GET /v2/productinvoices/{accessKey} response shape: the status field is + # "currentStatus" (lowercase enum), there is NO top-level "accessKey", and the + # totals live under the nested "icms" group. + let(:payload) do + { + "currentStatus" => "authorized", + "stateCode" => 35, + "checkCode" => 12_345_678, + "serie" => 1, + "number" => 42, + "issuedOn" => "2026-01-01T00:00:00Z", + "issuer" => { + "federalTaxNumber" => 11_222_333_000_181, + "name" => "Emitente LTDA", + "tradeName" => "Emitente", + "stateTaxNumber" => "123456789" + }, + "buyer" => { "federalTaxNumber" => 98_765_432_000_199, "name" => "Destinatario SA" }, + "totals" => { "icms" => { "productAmount" => 150.0, "invoiceAmount" => 150.0 } } + } + end + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "#retrieve" do + it "targets the nfe query host" do + transport.enqueue(response(body: { "accessKey" => access_key }.to_json)) + product_invoice_query.retrieve(access_key) + expect(last_request.url).to start_with("https://nfe.api.nfe.io") + end + + it "normalizes an access key with spaces and dots to 44 digits in the path" do + # 44 ones interleaved with spaces and dots; the resource strips them all. + spaced = ("1" * 44).chars.each_slice(4).map(&:join).join(" .") + transport.enqueue(response(body: "{}")) + product_invoice_query.retrieve(spaced) + expect(last_request.url).to include("/v2/productinvoices/#{access_key}") + end + + it "hydrates the invoice details with the real top-level keys" do + transport.enqueue(response(body: payload.to_json)) + + result = product_invoice_query.retrieve(access_key) + + expect(result).to be_a(Nfe::ProductInvoiceDetails) + expect(result.current_status).to eq("authorized") + expect(result.number).to eq(42) + expect(result.serie).to eq(1) + expect(result.issued_on).to eq("2026-01-01T00:00:00Z") + expect(result.state_code).to eq(35) + end + + it "hydrates the nested issuer, buyer and totals" do + transport.enqueue(response(body: payload.to_json)) + + result = product_invoice_query.retrieve(access_key) + + expect(result.issuer.name).to eq("Emitente LTDA") + expect(result.issuer.federal_tax_number).to eq("11222333000181") + expect(result.buyer.name).to eq("Destinatario SA") + expect(result.totals.invoice_amount).to eq(150.0) + end + + it "rejects a malformed access key before HTTP" do + expect { product_invoice_query.retrieve("123") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#download_pdf" do + it "sends Accept application/pdf and returns the bytes" do + transport.enqueue(response(body: "%PDF-1.4 binary")) + bytes = product_invoice_query.download_pdf(access_key) + + expect(bytes).to start_with("%PDF") + expect(last_request.headers["Accept"]).to eq("application/pdf") + expect(last_request.url).to end_with("/v2/productinvoices/#{access_key}.pdf") + end + end + + describe "#download_xml" do + it "sends Accept application/xml and uses the .xml suffix" do + transport.enqueue(response(body: "")) + bytes = product_invoice_query.download_xml(access_key) + + expect(bytes).to start_with(" [{ "type" => "Cancellation" }], + "createdOn" => "2026-01-01T00:00:00Z" + }.to_json)) + + result = product_invoice_query.list_events(access_key) + + expect(result).to be_a(Nfe::ProductInvoiceEventsResponse) + expect(result.events.length).to eq(1) + expect(last_request.url).to include("/v2/productinvoices/events/#{access_key}") + end + end +end diff --git a/spec/nfe/resources/product_invoices_rtc_spec.rb b/spec/nfe/resources/product_invoices_rtc_spec.rb new file mode 100644 index 0000000..33fdcb6 --- /dev/null +++ b/spec/nfe/resources/product_invoices_rtc_spec.rb @@ -0,0 +1,294 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/product_invoices_rtc" + +RSpec.describe Nfe::Resources::ProductInvoicesRtc do + # The +product_invoices_rtc+ client accessor is wired by the orchestrator + # after this slice, so the resource is instantiated directly here. + subject(:resource) { described_class.new(client) } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + # An RTC product payload: the item-level +tax.IBSCBS+ group is what selects + # the RTC layout on the shared +/productinvoices+ endpoint (no discriminator + # header/param). NF-e (mod 55) vs NFC-e (mod 65) follows the payload shape. + let(:rtc_payload) do + { + "buyer" => { "name" => "ACME Ltda", "federalTaxNumber" => "11222333000181" }, + "operationNature" => "Venda", + "serie" => 1, + "items" => [ + { + "code" => "P-1", + "description" => "Produto RTC", + "ncm" => "85171231", + "quantity" => 1, + "unitAmount" => 100.0, + "totalAmount" => 100.0, + "tax" => { + "IBSCBS" => { + "situationCode" => "000", + "classCode" => "000001", + "calculationMode" => "OfficialService" + } + } + } + ] + } + end + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "host routing" do + it "targets https://api.nfse.io/v2 (distinct from the main host)" do + transport.enqueue(response(status: 201, body: { "id" => "pi_1" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload) + expect(last_request.url).to start_with("https://api.nfse.io/v2/companies/co_1/productinvoices") + end + end + + describe "#create" do + it "returns a ProductInvoiceRtcPending on 202, parsing invoice_id from Location" do + location = "/v2/companies/co_1/productinvoices/pi-rtc-async-1" + transport.enqueue(response(status: 202, headers: { "location" => location }, body: "")) + + result = resource.create(company_id: "co_1", data: rtc_payload) + + expect(result).to be_a(Nfe::Resources::ProductInvoiceRtcPending) + expect(result.pending?).to be(true) + expect(result.issued?).to be(false) + expect(result.invoice_id).to eq("pi-rtc-async-1") + expect(result.location).to eq(location) + expect(last_request.method).to eq("POST") + expect(last_request.headers["Content-Type"]).to eq("application/json") + end + + it "returns a ProductInvoiceRtcIssued on 201, hydrating an InvoiceResource" do + transport.enqueue(response(status: 201, body: { "id" => "pi_rtc_1", "status" => "Issued" }.to_json)) + + result = resource.create(company_id: "co_1", data: rtc_payload) + + expect(result).to be_a(Nfe::Resources::ProductInvoiceRtcIssued) + expect(result.issued?).to be(true) + expect(result.resource).to be_a(Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource) + expect(result.resource.id).to eq("pi_rtc_1") + end + + it "raises InvoiceProcessingError on a 202 with no Location header" do + transport.enqueue(response(status: 202, body: "")) + expect { resource.create(company_id: "co_1", data: rtc_payload) } + .to raise_error(Nfe::InvoiceProcessingError) + end + + it "serializes the camelCase payload, carrying items[].tax.IBSCBS" do + transport.enqueue(response(status: 201, body: { "id" => "pi_1" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload) + + body = JSON.parse(last_request.body) + ibscbs = body.dig("items", 0, "tax", "IBSCBS") + expect(ibscbs["situationCode"]).to eq("000") + expect(ibscbs["classCode"]).to eq("000001") + end + + it "forwards idempotency_key and per-call request_options" do + transport.enqueue(response(status: 201, body: { "id" => "pi_1" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload, idempotency_key: "k-1", + request_options: Nfe::RequestOptions.new(api_key: "tenant")) + expect(last_request.idempotency_key).to eq("k-1") + expect(last_request.headers["X-NFE-APIKEY"]).to eq("tenant") + end + + it "rejects an empty company_id before any HTTP call" do + expect { resource.create(company_id: " ", data: rtc_payload) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#create_with_state_tax" do + it "routes through the statetaxes path" do + transport.enqueue(response(status: 202, headers: { + "location" => "/v2/companies/co_1/productinvoices/pi_2" + }, body: "")) + resource.create_with_state_tax(company_id: "co_1", state_tax_id: "st_1", data: rtc_payload) + expect(last_request.url).to include("/companies/co_1/statetaxes/st_1/productinvoices") + end + + it "rejects an empty state_tax_id before any HTTP call" do + expect { resource.create_with_state_tax(company_id: "co_1", state_tax_id: " ", data: rtc_payload) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#retrieve" do + it "GETs the invoice and hydrates an InvoiceResource" do + transport.enqueue(response(body: { "id" => "pi_1", "number" => 42 }.to_json)) + result = resource.retrieve(company_id: "co_1", invoice_id: "pi_1") + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource) + expect(result.id).to eq("pi_1") + expect(last_request.url).to end_with("/productinvoices/pi_1") + end + + it "raises NotFoundError on 404" do + transport.enqueue(response(status: 404, body: "{}")) + expect { resource.retrieve(company_id: "co_1", invoice_id: "missing") } + .to raise_error(Nfe::NotFoundError) + end + end + + describe "#list" do + it "returns a cursor-style ListResponse and sends environment" do + transport.enqueue(response(body: { + "productInvoices" => [{ "id" => "a" }], "startingAfter" => "a" + }.to_json)) + + result = resource.list(company_id: "co_1", environment: "Production", limit: 50) + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.first).to be_a(Nfe::Generated::ProductInvoiceRtcV1::InvoiceResource) + expect(result.data.map(&:id)).to eq(["a"]) + expect(result.page.starting_after).to eq("a") + expect(result.page.page_index).to be_nil + expect(last_request.url).to include("environment=Production").and include("limit=50") + end + + it "rejects a missing environment before any HTTP call" do + expect { resource.list(company_id: "co_1", environment: nil) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#cancel" do + it "DELETEs with the reason in the query and hydrates a RequestCancellationResource" do + transport.enqueue(response(body: { "reason" => "Erro", "productInvoiceId" => "pi_1" }.to_json)) + result = resource.cancel(company_id: "co_1", invoice_id: "pi_1", reason: "Erro") + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to include("reason=Erro") + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource) + expect(result.product_invoice_id).to eq("pi_1") + end + end + + describe "#list_items and #list_events" do + it "lists items and hydrates an InvoiceItemsResource" do + transport.enqueue(response(body: { "id" => "pi_1", "items" => [{ "code" => "it_1" }] }.to_json)) + result = resource.list_items(company_id: "co_1", invoice_id: "pi_1") + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::InvoiceItemsResource) + expect(last_request.url).to end_with("/productinvoices/pi_1/items") + end + + it "lists events and hydrates an InvoiceEventsResource" do + transport.enqueue(response(body: { "id" => "pi_1", "events" => [{ "id" => "ev_1" }] }.to_json)) + result = resource.list_events(company_id: "co_1", invoice_id: "pi_1") + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::InvoiceEventsResource) + expect(last_request.url).to end_with("/productinvoices/pi_1/events") + end + end + + describe "downloads return a file URI (NfeFileResource)" do + it "download_pdf returns a NfeFileResource and forwards force" do + transport.enqueue(response(body: { "uri" => "https://files/abc.pdf" }.to_json)) + file = resource.download_pdf(company_id: "co_1", invoice_id: "pi_1", force: true) + expect(file).to be_a(Nfe::NfeFileResource) + expect(file.uri).to eq("https://files/abc.pdf") + expect(last_request.url).to include("/pdf").and include("force=true") + end + + it "download_xml/rejection/epec hit the right paths and return URIs" do + transport.enqueue(response(body: { "uri" => "https://files/xml" }.to_json)) + expect(resource.download_xml(company_id: "co_1", invoice_id: "pi_1")).to be_a(Nfe::NfeFileResource) + expect(last_request.url).to end_with("/pi_1/xml") + + transport.enqueue(response(body: { "uri" => "https://files/rej" }.to_json)) + resource.download_rejection_xml(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to end_with("/pi_1/xml-rejection") + + transport.enqueue(response(body: { "uri" => "https://files/epec" }.to_json)) + resource.download_epec_xml(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to end_with("/pi_1/xml-epec") + end + end + + describe "#send_correction_letter" do + it "PUTs the reason when length is in range and hydrates the resource" do + transport.enqueue(response(body: { "reason" => "Correção", "productInvoiceId" => "pi_1" }.to_json)) + result = resource.send_correction_letter(company_id: "co_1", invoice_id: "pi_1", + reason: "Correção válida com tamanho suficiente") + expect(last_request.method).to eq("PUT") + expect(last_request.url).to end_with("/pi_1/correctionletter") + expect(JSON.parse(last_request.body)["reason"]).to start_with("Correção") + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::RequestCancellationResource) + end + + it "rejects a too-short reason before any HTTP call" do + expect { resource.send_correction_letter(company_id: "co_1", invoice_id: "pi_1", reason: "curto") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects a too-long reason before any HTTP call" do + expect { resource.send_correction_letter(company_id: "co_1", invoice_id: "pi_1", reason: "a" * 1001) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "correction letter downloads" do + it "return NfeFileResource URIs" do + transport.enqueue(response(body: { "uri" => "https://files/cc.pdf" }.to_json)) + file = resource.download_correction_letter_pdf(company_id: "co_1", invoice_id: "pi_1") + expect(file).to be_a(Nfe::NfeFileResource) + expect(last_request.url).to end_with("/correctionletter/pdf") + + transport.enqueue(response(body: { "uri" => "https://files/cc.xml" }.to_json)) + resource.download_correction_letter_xml(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to end_with("/correctionletter/xml") + end + end + + describe "#disable and #disable_range" do + it "POSTs disablement for a single invoice with the reason in query" do + transport.enqueue(response(body: { "reason" => "Erro", "serie" => 1 }.to_json)) + result = resource.disable(company_id: "co_1", invoice_id: "pi_1", reason: "Erro") + expect(last_request.method).to eq("POST") + expect(last_request.url).to include("/pi_1/disablement").and include("reason=Erro") + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::DisablementResource) + end + + it "POSTs a range disablement with the body" do + transport.enqueue(response(body: { "serie" => 1, "beginNumber" => 10, "lastNumber" => 20 }.to_json)) + data = { "environment" => "Production", "serie" => 1, "state" => "SP", + "beginNumber" => 10, "lastNumber" => 20 } + result = resource.disable_range(company_id: "co_1", data: data) + expect(last_request.url).to end_with("/productinvoices/disablement") + expect(JSON.parse(last_request.body)["serie"]).to eq(1) + expect(result).to be_a(Nfe::Generated::ProductInvoiceRtcV1::DisablementResource) + expect(result.begin_number).to eq(10) + end + end + + describe "fail-fast id validation" do + it "rejects an empty invoice_id on retrieve before any HTTP call" do + expect { resource.retrieve(company_id: "co_1", invoice_id: " ") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects an empty company_id on download_pdf before any HTTP call" do + expect { resource.download_pdf(company_id: " ", invoice_id: "pi_1") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end +end diff --git a/spec/nfe/resources/product_invoices_spec.rb b/spec/nfe/resources/product_invoices_spec.rb new file mode 100644 index 0000000..a0ce7d6 --- /dev/null +++ b/spec/nfe/resources/product_invoices_spec.rb @@ -0,0 +1,193 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::ProductInvoices do + subject(:invoices) { client.product_invoices } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "host routing" do + it "targets https://api.nfse.io/v2 (distinct from the main host)" do + transport.enqueue(json(status: 201, body: { "id" => "pi_1" }.to_json)) + invoices.create(company_id: "co_1", data: {}) + expect(last_request.url).to start_with("https://api.nfse.io/v2/companies/co_1/productinvoices") + end + end + + describe "#create" do + it "returns a ProductInvoicePending on 202" do + location = "/v2/companies/co_1/productinvoices/pi-async-1" + transport.enqueue(json(status: 202, headers: { "location" => location }, body: "")) + + result = invoices.create(company_id: "co_1", data: {}) + + expect(result).to be_a(Nfe::Resources::ProductInvoicePending) + expect(result.invoice_id).to eq("pi-async-1") + expect(last_request.method).to eq("POST") + end + + it "returns a ProductInvoiceIssued on 201" do + transport.enqueue(json(status: 201, body: { "id" => "pi_1", "flowStatus" => "Issued" }.to_json)) + result = invoices.create(company_id: "co_1", data: {}) + expect(result).to be_a(Nfe::Resources::ProductInvoiceIssued) + expect(result.resource.id).to eq("pi_1") + end + + it "forwards idempotency_key and per-call request_options" do + transport.enqueue(json(status: 201, body: { "id" => "pi_1" }.to_json)) + invoices.create(company_id: "co_1", data: {}, idempotency_key: "k-1", + request_options: Nfe::RequestOptions.new(api_key: "tenant")) + expect(last_request.idempotency_key).to eq("k-1") + expect(last_request.headers["X-NFE-APIKEY"]).to eq("tenant") + end + end + + describe "#create_with_state_tax" do + it "routes through the statetaxes path and validates state_tax_id" do + transport.enqueue(json(status: 202, headers: { + "location" => "/v2/companies/co_1/productinvoices/pi_2" + }, body: "")) + invoices.create_with_state_tax(company_id: "co_1", state_tax_id: "st_1", data: {}) + expect(last_request.url).to include("/companies/co_1/statetaxes/st_1/productinvoices") + end + + it "rejects an empty state_tax_id before HTTP" do + expect { invoices.create_with_state_tax(company_id: "co_1", state_tax_id: " ", data: {}) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#list" do + it "returns a cursor-style ListResponse and sends environment" do + transport.enqueue(json(body: { + "productInvoices" => [{ "id" => "a" }], "startingAfter" => "a" + }.to_json)) + + result = invoices.list(company_id: "co_1", environment: "Production", limit: 50) + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:id)).to eq(["a"]) + expect(result.page.starting_after).to eq("a") + expect(result.page.page_index).to be_nil + expect(last_request.url).to include("environment=Production").and include("limit=50") + end + + it "rejects a missing environment before HTTP" do + expect { invoices.list(company_id: "co_1", environment: nil) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#cancel" do + it "DELETEs with the reason in the query and returns the resource" do + transport.enqueue(json(body: { "id" => "cancel_1" }.to_json)) + result = invoices.cancel(company_id: "co_1", invoice_id: "pi_1", reason: "Erro") + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to include("reason=Erro") + expect(result["id"]).to eq("cancel_1") + end + end + + describe "#list_items and #list_events" do + it "lists items via the cursor sub-path" do + transport.enqueue(json(body: { "items" => [{ "id" => "it_1" }] }.to_json)) + result = invoices.list_items(company_id: "co_1", invoice_id: "pi_1", limit: 10) + expect(result).to be_a(Nfe::ListResponse) + expect(last_request.url).to include("/productinvoices/pi_1/items").and include("limit=10") + end + + it "lists events via the cursor sub-path" do + transport.enqueue(json(body: { "events" => [{ "id" => "ev_1" }] }.to_json)) + invoices.list_events(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to include("/productinvoices/pi_1/events") + end + end + + describe "downloads return a file URI (NfeFileResource)" do + it "download_pdf returns a NfeFileResource and forwards force" do + transport.enqueue(json(body: { "uri" => "https://files/abc.pdf" }.to_json)) + file = invoices.download_pdf(company_id: "co_1", invoice_id: "pi_1", force: true) + expect(file).to be_a(Nfe::NfeFileResource) + expect(file.uri).to eq("https://files/abc.pdf") + expect(last_request.url).to include("/pdf").and include("force=true") + end + + it "download_xml/rejection/epec hit the right paths and return URIs" do + %w[xml xml-rejection xml-epec].each do |segment| + transport.enqueue(json(body: { "uri" => "https://files/#{segment}" }.to_json)) + end + expect(invoices.download_xml(company_id: "co_1", invoice_id: "pi_1")).to be_a(Nfe::NfeFileResource) + expect(last_request.url).to end_with("/pi_1/xml") + invoices.download_rejection_xml(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to end_with("/pi_1/xml-rejection") + invoices.download_epec_xml(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to end_with("/pi_1/xml-epec") + end + end + + describe "#send_correction_letter" do + it "PUTs the reason when length is in range" do + transport.enqueue(json(body: { "id" => "cc_1" }.to_json)) + invoices.send_correction_letter(company_id: "co_1", invoice_id: "pi_1", + reason: "Correção válida com tamanho suficiente") + expect(last_request.method).to eq("PUT") + expect(last_request.url).to end_with("/pi_1/correctionletter") + expect(JSON.parse(last_request.body)["reason"]).to start_with("Correção") + end + + it "rejects a too-short reason before HTTP" do + expect { invoices.send_correction_letter(company_id: "co_1", invoice_id: "pi_1", reason: "curto") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects a too-long reason before HTTP" do + expect { invoices.send_correction_letter(company_id: "co_1", invoice_id: "pi_1", reason: "a" * 1001) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "correction letter downloads" do + it "return NfeFileResource URIs" do + transport.enqueue(json(body: { "uri" => "https://files/cc.pdf" }.to_json)) + file = invoices.download_correction_letter_pdf(company_id: "co_1", invoice_id: "pi_1") + expect(file).to be_a(Nfe::NfeFileResource) + expect(last_request.url).to end_with("/correctionletter/pdf") + transport.enqueue(json(body: { "uri" => "https://files/cc.xml" }.to_json)) + invoices.download_correction_letter_xml(company_id: "co_1", invoice_id: "pi_1") + expect(last_request.url).to end_with("/correctionletter/xml") + end + end + + describe "#disable and #disable_range" do + it "POSTs disablement for a single invoice with the reason in query" do + transport.enqueue(json(body: { "id" => "dis_1" }.to_json)) + invoices.disable(company_id: "co_1", invoice_id: "pi_1", reason: "Erro") + expect(last_request.method).to eq("POST") + expect(last_request.url).to include("/pi_1/disablement").and include("reason=Erro") + end + + it "POSTs a range disablement with the body" do + transport.enqueue(json(body: { "id" => "dis_2" }.to_json)) + data = { environment: "Production", serie: 1, state: "SP", begin_number: 10, last_number: 20 } + invoices.disable_range(company_id: "co_1", data: data) + expect(last_request.url).to end_with("/productinvoices/disablement") + expect(JSON.parse(last_request.body)["serie"]).to eq(1) + end + end +end diff --git a/spec/nfe/resources/registry_spec.rb b/spec/nfe/resources/registry_spec.rb new file mode 100644 index 0000000..62f9323 --- /dev/null +++ b/spec/nfe/resources/registry_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +RSpec.describe "resource registry" do # rubocop:disable RSpec/DescribeClass + subject(:client) { Nfe::Client.new(api_key: "main", data_api_key: "data") } + + # accessor => [resource class, expected host via base_url_for] + def expected + { + service_invoices: [Nfe::Resources::ServiceInvoices, "https://api.nfe.io"], + companies: [Nfe::Resources::Companies, "https://api.nfe.io"], + legal_people: [Nfe::Resources::LegalPeople, "https://api.nfe.io"], + natural_people: [Nfe::Resources::NaturalPeople, "https://api.nfe.io"], + webhooks: [Nfe::Resources::Webhooks, "https://api.nfe.io"], + product_invoices: [Nfe::Resources::ProductInvoices, "https://api.nfse.io"], + consumer_invoices: [Nfe::Resources::ConsumerInvoices, "https://api.nfse.io"], + transportation_invoices: [Nfe::Resources::TransportationInvoices, "https://api.nfse.io"], + inbound_product_invoices: [Nfe::Resources::InboundProductInvoices, "https://api.nfse.io"], + tax_calculation: [Nfe::Resources::TaxCalculation, "https://api.nfse.io"], + tax_codes: [Nfe::Resources::TaxCodes, "https://api.nfse.io"], + state_taxes: [Nfe::Resources::StateTaxes, "https://api.nfse.io"], + product_invoice_query: [Nfe::Resources::ProductInvoiceQuery, "https://nfe.api.nfe.io"], + consumer_invoice_query: [Nfe::Resources::ConsumerInvoiceQuery, "https://nfe.api.nfe.io"], + addresses: [Nfe::Resources::Addresses, "https://address.api.nfe.io/v2"], + legal_entity_lookup: [Nfe::Resources::LegalEntityLookup, "https://legalentity.api.nfe.io"], + natural_person_lookup: [Nfe::Resources::NaturalPersonLookup, "https://naturalperson.api.nfe.io"] + } + end + + it "maps exactly seventeen accessors across six distinct hosts" do + expect(expected.size).to eq(17) + expect(expected.values.map(&:last).uniq.size).to eq(6) + end + + it "returns the right class for each accessor" do + expected.each_key do |accessor| + klass = expected.fetch(accessor).first + expect(client.public_send(accessor)).to be_a(klass) + end + end + + it "resolves each declared family to its canonical host" do + expected.each_key do |accessor| + host = expected.fetch(accessor).last + family = client.public_send(accessor).send(:api_family) + expect(client.configuration.base_url_for(family)).to eq(host) + end + end + + it "exposes the lookup resources as functional (non-stub) instances" do + expect(client.addresses).to respond_to(:lookup_by_postal_code, :search, :lookup_by_term) + expect(client.legal_entity_lookup).to respond_to(:get_basic_info, :get_state_tax_info) + expect(client.natural_person_lookup).to respond_to(:get_status) + expect(client.product_invoice_query).to respond_to(:retrieve, :download_pdf, :download_xml) + expect(client.consumer_invoice_query).to respond_to(:retrieve, :download_xml) + expect(client.tax_calculation).to respond_to(:calculate) + expect(client.tax_codes).to respond_to(:list_operation_codes, :list_acquisition_purposes) + expect(client.state_taxes).to respond_to(:list, :create, :retrieve, :update, :delete) + end + + it "exposes the invoice resources as functional (non-stub) instances" do + expect(client.service_invoices).to respond_to(:create, :list, :retrieve, :cancel) + expect(client.product_invoices).to respond_to(:create, :create_with_state_tax, :list) + end + + it "exposes the entity resources as functional (non-stub) instances" do + expect(client.companies).to respond_to(:create, :list, :retrieve, :remove) + expect(client.legal_people).to respond_to(:create, :list, :find_by_tax_number) + expect(client.natural_people).to respond_to(:create, :list, :find_by_tax_number) + expect(client.webhooks).to respond_to(:create, :test, :get_available_events) + end + + it "exposes the two RTC addon accessors routed to the classic hosts" do + expect(client.service_invoices_rtc).to be_a(Nfe::Resources::ServiceInvoicesRtc) + expect(client.product_invoices_rtc).to be_a(Nfe::Resources::ProductInvoicesRtc) + rtc_main = client.service_invoices_rtc.send(:api_family) + rtc_cte = client.product_invoices_rtc.send(:api_family) + expect(client.configuration.base_url_for(rtc_main)).to eq("https://api.nfe.io") + expect(client.configuration.base_url_for(rtc_cte)).to eq("https://api.nfse.io") + end +end diff --git a/spec/nfe/resources/service_invoices_rtc_spec.rb b/spec/nfe/resources/service_invoices_rtc_spec.rb new file mode 100644 index 0000000..8298789 --- /dev/null +++ b/spec/nfe/resources/service_invoices_rtc_spec.rb @@ -0,0 +1,187 @@ +# frozen_string_literal: true + +require "json" +require "nfe/resources/service_invoices_rtc" + +RSpec.describe Nfe::Resources::ServiceInvoicesRtc do + # The +service_invoices_rtc+ client accessor is wired by the orchestrator + # after this slice, so the resource is instantiated directly here. + subject(:resource) { described_class.new(client) } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + # An RTC payload: the +ibsCbs+ group is what selects the RTC layout on the + # shared +/serviceinvoices+ endpoint (no discriminator header/param). + let(:rtc_payload) do + { + "borrower" => { "name" => "ACME Ltda", "federalTaxNumber" => 11_222_333_000_181 }, + "cityServiceCode" => "0107", + "description" => "Consultoria", + "servicesAmount" => 1000.0, + "ibsCbs" => { + "operationIndicator" => "1005011", + "classCode" => "000001", + "basis" => 1000.0, + "cbs" => { "rate" => 0.009, "amount" => 9.0 }, + "ibs" => { "rate" => 0.001, "amount" => 1.0 }, + "operationType" => "SupplyForPastPay" + } + } + end + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "#create" do + it "returns a ServiceInvoiceRtcPending on 202, parsing invoice_id from Location" do + location = "/v1/companies/co_1/serviceinvoices/inv-rtc-1" + transport.enqueue(response(status: 202, headers: { "location" => location }, body: "")) + + result = resource.create(company_id: "co_1", data: rtc_payload) + + expect(result).to be_a(Nfe::Resources::ServiceInvoiceRtcPending) + expect(result.pending?).to be(true) + expect(result.issued?).to be(false) + expect(result.invoice_id).to eq("inv-rtc-1") + expect(result.location).to eq(location) + expect(last_request.method).to eq("POST") + expect(last_request.url).to start_with("https://api.nfe.io/v1/companies/co_1/serviceinvoices") + expect(last_request.headers["Content-Type"]).to eq("application/json") + end + + it "returns a ServiceInvoiceRtcIssued on 201, hydrating a Nfe::ServiceInvoice" do + transport.enqueue(response(status: 201, body: { "id" => "si_rtc_1", "flowStatus" => "Issued" }.to_json)) + + result = resource.create(company_id: "co_1", data: rtc_payload) + + expect(result).to be_a(Nfe::Resources::ServiceInvoiceRtcIssued) + expect(result.issued?).to be(true) + expect(result.pending?).to be(false) + expect(result.resource).to be_a(Nfe::ServiceInvoice) + expect(result.resource.id).to eq("si_rtc_1") + expect(result.resource.flow_status).to eq("Issued") + end + + it "raises InvoiceProcessingError on a 202 without Location" do + transport.enqueue(response(status: 202, body: "")) + expect { resource.create(company_id: "co_1", data: rtc_payload) } + .to raise_error(Nfe::InvoiceProcessingError) + end + + it "carries the ibsCbs group through to the JSON request body" do + transport.enqueue(response(status: 201, body: { "id" => "si_rtc_1" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload) + + parsed = JSON.parse(last_request.body) + expect(parsed).to include("ibsCbs") + expect(parsed["ibsCbs"]).to include("operationIndicator" => "1005011", "classCode" => "000001") + expect(parsed["ibsCbs"]).to include("cbs" => { "rate" => 0.009, "amount" => 9.0 }) + expect(parsed["servicesAmount"]).to eq(1000.0) + end + + it "forwards idempotency_key on the request when present" do + transport.enqueue(response(status: 201, body: { "id" => "si_rtc_1" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload, idempotency_key: "order-rtc-42") + expect(last_request.idempotency_key).to eq("order-rtc-42") + end + + it "omits the idempotency_key when absent" do + transport.enqueue(response(status: 201, body: { "id" => "si_rtc_1" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload) + expect(last_request.idempotency_key).to be_nil + end + + it "applies per-call request_options without mutating the client" do + transport.enqueue(response(status: 201, body: { "id" => "si_rtc_1" }.to_json)) + opts = Nfe::RequestOptions.new(api_key: "tenant-key") + resource.create(company_id: "co_1", data: rtc_payload, request_options: opts) + expect(last_request.headers["X-NFE-APIKEY"]).to eq("tenant-key") + + transport.enqueue(response(status: 201, body: { "id" => "si_rtc_2" }.to_json)) + resource.create(company_id: "co_1", data: rtc_payload) + expect(last_request.headers["X-NFE-APIKEY"]).to eq("key") + end + + it "rejects an empty company_id before issuing any HTTP request" do + expect { resource.create(company_id: " ", data: rtc_payload) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#retrieve" do + it "hydrates a Nfe::ServiceInvoice" do + transport.enqueue(response(body: { "id" => "si_rtc_1", "flowStatus" => "Issued" }.to_json)) + invoice = resource.retrieve(company_id: "co_1", invoice_id: "si_rtc_1") + + expect(invoice).to be_a(Nfe::ServiceInvoice) + expect(invoice.id).to eq("si_rtc_1") + expect(last_request.method).to eq("GET") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co_1/serviceinvoices/si_rtc_1") + end + + it "raises NotFoundError on 404" do + transport.enqueue(response(status: 404, body: "{}")) + expect { resource.retrieve(company_id: "co_1", invoice_id: "missing") } + .to raise_error(Nfe::NotFoundError) + end + + it "rejects an empty invoice_id before issuing any HTTP request" do + expect { resource.retrieve(company_id: "co_1", invoice_id: "") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#cancel" do + it "DELETEs and returns the updated invoice" do + transport.enqueue(response(body: { "id" => "si_rtc_1", "flowStatus" => "Cancelled" }.to_json)) + invoice = resource.cancel(company_id: "co_1", invoice_id: "si_rtc_1") + + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co_1/serviceinvoices/si_rtc_1") + expect(invoice).to be_a(Nfe::ServiceInvoice) + expect(invoice.flow_status).to eq("Cancelled") + end + end + + describe "#download_cancellation_xml" do + it "returns ASCII-8BIT bytes starting with < and an xml Accept header" do + transport.enqueue(response(body: "".b)) + xml = resource.download_cancellation_xml(company_id: "co_1", invoice_id: "si_rtc_1") + + expect(xml.encoding).to eq(Encoding::ASCII_8BIT) + expect(xml).to start_with("<") + expect(last_request.method).to eq("GET") + expect(last_request.headers["Accept"]).to eq("application/xml") + expect(last_request.url).to end_with("/serviceinvoices/si_rtc_1/cancellation-xml") + end + + it "raises NotFoundError when the body is empty" do + transport.enqueue(response(status: 404, body: "")) + expect { resource.download_cancellation_xml(company_id: "co_1", invoice_id: "missing") } + .to raise_error(Nfe::NotFoundError) + end + + it "rejects an empty invoice_id before issuing any HTTP request" do + expect { resource.download_cancellation_xml(company_id: "co_1", invoice_id: " ") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "routing" do + it "targets the api.nfe.io host for the :main family" do + transport.enqueue(response(body: { "id" => "si_rtc_1" }.to_json)) + resource.retrieve(company_id: "co_1", invoice_id: "si_rtc_1") + expect(last_request.url).to start_with("https://api.nfe.io") + end + end +end diff --git a/spec/nfe/resources/service_invoices_spec.rb b/spec/nfe/resources/service_invoices_spec.rb new file mode 100644 index 0000000..9ffd68c --- /dev/null +++ b/spec/nfe/resources/service_invoices_spec.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::ServiceInvoices do + subject(:invoices) { client.service_invoices } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "#create" do + it "returns a ServiceInvoicePending on 202, parsing invoice_id from Location" do + location = "/v1/companies/co_1/serviceinvoices/inv-abc-1" + transport.enqueue(json(status: 202, headers: { "location" => location }, body: "")) + + result = invoices.create(company_id: "co_1", data: { description: "x" }) + + expect(result).to be_a(Nfe::Resources::ServiceInvoicePending) + expect(result.pending?).to be(true) + expect(result.invoice_id).to eq("inv-abc-1") + expect(result.location).to eq(location) + expect(last_request.method).to eq("POST") + expect(last_request.url).to start_with("https://api.nfe.io/v1/companies/co_1/serviceinvoices") + expect(last_request.headers["Content-Type"]).to eq("application/json") + end + + it "returns a ServiceInvoiceIssued on 201, hydrating the body" do + transport.enqueue(json(status: 201, body: { "id" => "si_1", "flowStatus" => "Issued" }.to_json)) + + result = invoices.create(company_id: "co_1", data: {}) + + expect(result).to be_a(Nfe::Resources::ServiceInvoiceIssued) + expect(result.issued?).to be(true) + expect(result.resource).to be_a(Nfe::ServiceInvoice) + expect(result.resource.id).to eq("si_1") + end + + it "raises InvoiceProcessingError on a 202 without Location" do + transport.enqueue(json(status: 202, body: "")) + expect { invoices.create(company_id: "co_1", data: {}) } + .to raise_error(Nfe::InvoiceProcessingError) + end + + it "forwards idempotency_key on the request" do + transport.enqueue(json(status: 201, body: { "id" => "si_1" }.to_json)) + invoices.create(company_id: "co_1", data: {}, idempotency_key: "order-42") + expect(last_request.idempotency_key).to eq("order-42") + end + + it "applies per-call request_options without mutating the client" do + transport.enqueue(json(status: 201, body: { "id" => "si_1" }.to_json)) + opts = Nfe::RequestOptions.new(api_key: "tenant-key") + invoices.create(company_id: "co_1", data: {}, request_options: opts) + + expect(last_request.headers["X-NFE-APIKEY"]).to eq("tenant-key") + transport.enqueue(json(status: 201, body: { "id" => "si_2" }.to_json)) + invoices.create(company_id: "co_1", data: {}) + expect(last_request.headers["X-NFE-APIKEY"]).to eq("key") + end + + it "rejects an empty company_id before HTTP" do + expect { invoices.create(company_id: " ", data: {}) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#list" do + it "returns a page-style ListResponse with date filters" do + transport.enqueue(json(body: { + "serviceInvoices" => [{ "id" => "a" }, { "id" => "b" }], + "pageIndex" => 0, "pageCount" => 20 + }.to_json)) + + result = invoices.list(company_id: "co_1", page_index: 0, page_count: 20, + issued_begin: "2026-01-01", issued_end: "2026-01-31") + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:id)).to eq(%w[a b]) + expect(result.page.page_index).to eq(0) + expect(result.page.starting_after).to be_nil + expect(last_request.url).to include("issuedBegin=2026-01-01").and include("pageCount=20") + end + end + + describe "#retrieve" do + it "hydrates a ServiceInvoice" do + transport.enqueue(json(body: { "id" => "si_1", "flowStatus" => "Issued" }.to_json)) + invoice = invoices.retrieve(company_id: "co_1", invoice_id: "si_1") + expect(invoice).to be_a(Nfe::ServiceInvoice) + expect(invoice.id).to eq("si_1") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co_1/serviceinvoices/si_1") + end + + it "raises NotFoundError on 404" do + transport.enqueue(json(status: 404, body: "{}")) + expect { invoices.retrieve(company_id: "co_1", invoice_id: "missing") } + .to raise_error(Nfe::NotFoundError) + end + end + + describe "#cancel" do + it "DELETEs and returns the updated invoice" do + transport.enqueue(json(body: { "id" => "si_1", "flowStatus" => "Cancelled" }.to_json)) + invoice = invoices.cancel(company_id: "co_1", invoice_id: "si_1") + expect(last_request.method).to eq("DELETE") + expect(invoice.flow_status).to eq("Cancelled") + end + end + + describe "#send_email" do + it "PUTs to /sendemail and returns the send result" do + transport.enqueue(json(body: { "sent" => true, "message" => "ok" }.to_json)) + result = invoices.send_email(company_id: "co_1", invoice_id: "si_1") + expect(last_request.method).to eq("PUT") + expect(last_request.url).to end_with("/serviceinvoices/si_1/sendemail") + expect(result[:sent]).to be(true) + expect(result[:message]).to eq("ok") + end + end + + describe "#download_pdf" do + it "returns ASCII-8BIT bytes starting with %PDF" do + transport.enqueue(json(body: "%PDF-1.4 binary".b)) + pdf = invoices.download_pdf(company_id: "co_1", invoice_id: "si_1") + expect(pdf.encoding).to eq(Encoding::ASCII_8BIT) + expect(pdf).to start_with("%PDF") + expect(last_request.headers["Accept"]).to eq("application/pdf") + expect(last_request.url).to end_with("/serviceinvoices/si_1/pdf") + end + + it "targets the bulk path when invoice_id is omitted" do + transport.enqueue(json(body: "PK\x03\x04zip".b)) + invoices.download_pdf(company_id: "co_1") + expect(last_request.url).to end_with("/serviceinvoices/pdf") + end + end + + describe "#download_xml" do + it "returns bytes starting with < and the xml Accept header" do + transport.enqueue(json(body: "".b)) + xml = invoices.download_xml(company_id: "co_1", invoice_id: "si_1") + expect(xml).to start_with("<") + expect(last_request.headers["Accept"]).to eq("application/xml") + end + end + + describe "#get_status" do + it "derives status from retrieve without an extra HTTP call" do + transport.enqueue(json(body: { "id" => "si_1", "flowStatus" => "Issued" }.to_json)) + status = invoices.get_status(company_id: "co_1", invoice_id: "si_1") + + expect(status.status).to eq("Issued") + expect(status.complete?).to be(true) + expect(status.failed?).to be(false) + expect(status.invoice).to be_a(Nfe::ServiceInvoice) + expect(transport.requests.length).to eq(1) + end + + it "flags failed for IssueFailed" do + transport.enqueue(json(body: { "id" => "si_1", "flowStatus" => "IssueFailed" }.to_json)) + status = invoices.get_status(company_id: "co_1", invoice_id: "si_1") + expect(status.complete?).to be(true) + expect(status.failed?).to be(true) + end + end +end diff --git a/spec/nfe/resources/state_taxes_spec.rb b/spec/nfe/resources/state_taxes_spec.rb new file mode 100644 index 0000000..988e5a5 --- /dev/null +++ b/spec/nfe/resources/state_taxes_spec.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::StateTaxes do + subject(:state_taxes) { client.state_taxes } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + let(:company_id) { "co_123" } + let(:state_tax_body) { { "code" => "SP", "taxNumber" => "1234567890" } } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "#create" do + before { transport.enqueue(response(body: { "stateTax" => { "id" => "st_1", "code" => "SP" } }.to_json)) } + + it "POSTs the stateTax-wrapped body as JSON to the api.nfse.io host" do + result = state_taxes.create(company_id, state_tax_body) + + expect(result).to be_a(Nfe::NfeStateTax) + expect(result.id).to eq("st_1") + expect(last_request.method).to eq("POST") + expect(last_request.url).to start_with("https://api.nfse.io") + expect(last_request.url).to include("/v2/companies/#{company_id}/statetaxes") + expect(last_request.headers["Content-Type"]).to eq("application/json") + expect(JSON.parse(last_request.body)).to eq("stateTax" => state_tax_body) + end + + it "raises before HTTP when company_id is empty" do + expect { state_taxes.create("", state_tax_body) }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#update" do + before { transport.enqueue(response(body: { "stateTax" => { "id" => "st_1" } }.to_json)) } + + it "PUTs the stateTax-wrapped body as JSON to the id path" do + result = state_taxes.update(company_id, "st_1", state_tax_body) + + expect(result).to be_a(Nfe::NfeStateTax) + expect(last_request.method).to eq("PUT") + expect(last_request.url).to include("/v2/companies/#{company_id}/statetaxes/st_1") + expect(JSON.parse(last_request.body)).to eq("stateTax" => state_tax_body) + end + end + + describe "#list" do + before do + transport.enqueue(response(body: { + "stateTaxes" => [{ "id" => "st_1" }, { "id" => "st_2" }], + "startingAfter" => "st_1" + }.to_json)) + end + + it "returns a cursor-style ListResponse on the api.nfse.io host" do + result = state_taxes.list(company_id, limit: 50) + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.map(&:id)).to eq(%w[st_1 st_2]) + expect(result.data.first).to be_a(Nfe::NfeStateTax) + expect(result.page.starting_after).to eq("st_1") + expect(result.page.page_index).to be_nil + expect(last_request.method).to eq("GET") + expect(last_request.url).to start_with("https://api.nfse.io") + expect(last_request.url).to include("/v2/companies/#{company_id}/statetaxes") + expect(last_request.url).to include("limit=50") + end + end + + describe "#retrieve" do + before { transport.enqueue(response(body: { "stateTax" => { "id" => "st_9" } }.to_json)) } + + it "GETs the id path and hydrates NfeStateTax" do + result = state_taxes.retrieve(company_id, "st_9") + + expect(result).to be_a(Nfe::NfeStateTax) + expect(result.id).to eq("st_9") + expect(last_request.method).to eq("GET") + expect(last_request.url).to include("/v2/companies/#{company_id}/statetaxes/st_9") + end + + it "raises before HTTP when state_tax_id is empty" do + expect { state_taxes.retrieve(company_id, "") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#delete" do + before { transport.enqueue(response(status: 204, body: "")) } + + it "DELETEs the id path and returns nil" do + result = state_taxes.delete(company_id, "st_9") + + expect(result).to be_nil + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to include("/v2/companies/#{company_id}/statetaxes/st_9") + end + + it "raises before HTTP when company_id is empty" do + expect { state_taxes.delete("", "st_9") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end +end diff --git a/spec/nfe/resources/tax_calculation_spec.rb b/spec/nfe/resources/tax_calculation_spec.rb new file mode 100644 index 0000000..34b0795 --- /dev/null +++ b/spec/nfe/resources/tax_calculation_spec.rb @@ -0,0 +1,111 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::TaxCalculation do + subject(:tax_calculation) { client.tax_calculation } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + let(:valid_request) do + { + "operationType" => "OutgoingSale", + "items" => [{ "productId" => "p-1", "cfop" => 5102 }] + } + end + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "routing" do + it "declares the :cte api_family with an empty version" do + expect(tax_calculation.send(:api_family)).to eq(:cte) + expect(tax_calculation.send(:api_version)).to eq("") + end + end + + describe "#calculate" do + let(:payload) do + { + "items" => [ + { + "productId" => "p-1", + "cfop" => 5102, + "icms" => { "cst" => "00", "pICMS" => 18.0 }, + "pis" => { "cst" => "01" }, + "cofins" => { "cst" => "01" }, + "ipi" => { "cst" => "50" }, + "ii" => { "vII" => 0.0 } + } + ] + } + end + + before { transport.enqueue(response(body: payload.to_json)) } + + it "POSTs to the URL-encoded tax-rules engine path on api.nfse.io" do + tax_calculation.calculate("tenant 7/x", valid_request) + + expect(last_request.method).to eq("POST") + expect(last_request.url).to start_with("https://api.nfse.io") + expect(last_request.url).to end_with("/tax-rules/tenant+7%2Fx/engine/calculate") + end + + it "sends the request as JSON with a JSON Content-Type" do + tax_calculation.calculate("tenant-7", valid_request) + + expect(last_request.headers["Content-Type"]).to eq("application/json") + expect(JSON.parse(last_request.body)).to eq(valid_request) + end + + it "hydrates a generated CalculateResponse with a per-item tax breakdown" do + result = tax_calculation.calculate("tenant-7", valid_request) + + expect(result).to be_a(Nfe::Generated::CalculoImpostosV1::CalculateResponse) + item = result.items.first + expect(item).to be_a(Nfe::Generated::CalculoImpostosV1::CalculateItemResponse) + expect(item.cfop).to eq(5102) + expect(item.icms).to be_a(Nfe::Generated::CalculoImpostosV1::Icms) + expect(item.icms.cst).to eq("00") + expect(item.pis.cst).to eq("01") + expect(item.cofins.cst).to eq("01") + expect(item.ipi.cst).to eq("50") + end + + it "accepts a snake_case operation_type key" do + tax_calculation.calculate("tenant-7", { operation_type: "OutgoingSale", items: [{}] }) + expect(last_request.method).to eq("POST") + end + end + + describe "#calculate validation (no HTTP)" do + it "rejects an empty tenant_id before any HTTP request" do + expect { tax_calculation.calculate(" ", valid_request) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects an empty items array before any HTTP request" do + expect { tax_calculation.calculate("tenant-7", { "operationType" => "OutgoingSale", "items" => [] }) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects a request missing operationType before any HTTP request" do + expect { tax_calculation.calculate("tenant-7", { "items" => [{}] }) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + + it "rejects a non-Hash request before any HTTP request" do + expect { tax_calculation.calculate("tenant-7", []) } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end +end diff --git a/spec/nfe/resources/tax_codes_spec.rb b/spec/nfe/resources/tax_codes_spec.rb new file mode 100644 index 0000000..f225040 --- /dev/null +++ b/spec/nfe/resources/tax_codes_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Resources::TaxCodes do + subject(:tax_codes) { client.tax_codes } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "datakey") } + let(:transport) { FakeTransport.new } + let(:payload) do + { + "currentPage" => 1, + "totalPages" => 3, + "totalCount" => 42, + "items" => [ + { "code" => "1", "description" => "Venda" }, + { "code" => "2", "description" => "Compra" } + ] + } + end + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def response(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request = transport.requests.last + + describe "#list_operation_codes" do + before { transport.enqueue(response(body: payload.to_json)) } + + it "GETs the operation-code path on the api.nfse.io host" do + tax_codes.list_operation_codes + + expect(last_request.method).to eq("GET") + expect(last_request.url).to start_with("https://api.nfse.io") + expect(last_request.url).to include("/tax-codes/operation-code") + end + + it "returns a hydrated TaxCodePaginatedResponse (page-style, not ListResponse)" do + result = tax_codes.list_operation_codes + + expect(result).to be_a(Nfe::TaxCodePaginatedResponse) + expect(result).not_to be_a(Nfe::ListResponse) + expect(result.current_page).to eq(1) + expect(result.total_pages).to eq(3) + expect(result.total_count).to eq(42) + expect(result.items.map(&:code)).to eq(%w[1 2]) + expect(result.items.first).to be_a(Nfe::TaxCode) + end + + it "omits pageIndex/pageCount from the URL by default" do + tax_codes.list_operation_codes + + expect(last_request.url).not_to include("pageIndex") + expect(last_request.url).not_to include("pageCount") + end + + it "sends explicit 1-based pageIndex/pageCount preserved as given" do + tax_codes.list_operation_codes(page_index: 2, page_count: 20) + + expect(last_request.url).to include("pageIndex=2").and include("pageCount=20") + end + end + + describe "the four endpoint paths" do + before { transport.enqueue(response(body: payload.to_json)) } + + it "targets /tax-codes/acquisition-purpose" do + tax_codes.list_acquisition_purposes + expect(last_request.url).to include("/tax-codes/acquisition-purpose") + end + + it "targets /tax-codes/issuer-tax-profile" do + tax_codes.list_issuer_tax_profiles + expect(last_request.url).to include("/tax-codes/issuer-tax-profile") + end + + it "targets /tax-codes/recipient-tax-profile" do + tax_codes.list_recipient_tax_profiles + expect(last_request.url).to include("/tax-codes/recipient-tax-profile") + end + end +end diff --git a/spec/nfe/resources/transportation_invoices_spec.rb b/spec/nfe/resources/transportation_invoices_spec.rb new file mode 100644 index 0000000..cdfd48d --- /dev/null +++ b/spec/nfe/resources/transportation_invoices_spec.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::TransportationInvoices do + subject(:resource) { client.transportation_invoices } + + let(:client) { Nfe::Client.new(api_key: "key", data_api_key: "data-key") } + let(:transport) { FakeTransport.new } + let(:access_key) { "3" * 44 } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}", headers: {}) + Nfe::Http::Response.new(status: status, headers: headers, body: body) + end + + def last_request + transport.requests.last + end + + describe "#enable" do + before { transport.enqueue(json(body: { "id" => "s1", "status" => "Active" }.to_json)) } + + it "POSTs to api.nfse.io and returns hydrated settings" do + settings = resource.enable(company_id: "co-1", start_from_nsu: 42) + + expect(settings).to be_a(Nfe::InboundSettings) + expect(settings.status).to eq("Active") + expect(last_request.method).to eq("POST") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/transportationinvoices") + expect(JSON.parse(last_request.body)).to eq({ "startFromNsu" => 42 }) + expect(last_request.headers["Content-Type"]).to eq("application/json") + end + + it "omits nil optional fields from the body" do + resource.enable(company_id: "co-1") + expect(JSON.parse(last_request.body)).to eq({}) + end + + it "rejects an empty company_id without HTTP" do + expect { resource.enable(company_id: " ") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#disable" do + it "DELETEs and returns settings" do + transport.enqueue(json(body: { "status" => "Disabled" }.to_json)) + settings = resource.disable(company_id: "co-1") + + expect(settings.status).to eq("Disabled") + expect(last_request.method).to eq("DELETE") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/transportationinvoices") + end + end + + describe "#get_settings" do + it "GETs the current settings" do + transport.enqueue(json(body: { "status" => "Active", "webhookVersion" => "2" }.to_json)) + settings = resource.get_settings(company_id: "co-1") + + expect(settings.webhook_version).to eq("2") + expect(last_request.method).to eq("GET") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/transportationinvoices") + end + end + + describe "#retrieve" do + it "normalises a formatted access key to 44 digits in the path" do + transport.enqueue(json(body: { "accessKey" => access_key, "nameSender" => "Transp" }.to_json)) + formatted = access_key.scan(/.{4}/).join(" ") + + cte = resource.retrieve(company_id: "co-1", access_key: formatted) + + expect(cte).to be_a(Nfe::InboundInvoiceMetadata) + expect(cte.name_sender).to eq("Transp") + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}") + end + + it "rejects a wrong-length access key without HTTP" do + expect { resource.retrieve(company_id: "co-1", access_key: "123") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#download_xml" do + it "returns binary XML bytes with an XML Accept header" do + transport.enqueue(json(body: "x")) + xml = resource.download_xml(company_id: "co-1", access_key: access_key) + + expect(xml).to start_with("<") + expect(xml.encoding).to eq(Encoding::ASCII_8BIT) + expect(last_request.url).to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/xml") + expect(last_request.headers["Accept"]).to eq("application/xml") + end + end + + describe "#get_event" do + it "GETs the event metadata" do + transport.enqueue(json(body: { "status" => "Authorized" }.to_json)) + event = resource.get_event(company_id: "co-1", access_key: access_key, event_key: "ev-9") + + expect(event).to be_a(Nfe::InboundInvoiceMetadata) + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/events/ev-9") + end + + it "rejects an empty event_key without HTTP" do + expect { resource.get_event(company_id: "co-1", access_key: access_key, event_key: "") } + .to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#download_event_xml" do + it "returns binary event XML bytes" do + transport.enqueue(json(body: "")) + xml = resource.download_event_xml(company_id: "co-1", access_key: access_key, event_key: "ev-9") + + expect(xml).to start_with("<") + expect(last_request.url) + .to eq("https://api.nfse.io/v2/companies/co-1/inbound/#{access_key}/events/ev-9/xml") + expect(last_request.headers["Accept"]).to eq("application/xml") + end + end +end diff --git a/spec/nfe/resources/webhooks_spec.rb b/spec/nfe/resources/webhooks_spec.rb new file mode 100644 index 0000000..e7ff558 --- /dev/null +++ b/spec/nfe/resources/webhooks_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require "json" + +RSpec.describe Nfe::Resources::Webhooks do + subject(:webhooks) { client.webhooks } + + let(:client) { Nfe::Client.new(api_key: "key") } + let(:transport) { FakeTransport.new } + + before { allow(client).to receive(:build_transport).and_return(transport) } + + def json(status: 200, body: "{}") + Nfe::Http::Response.new(status: status, body: body) + end + + def last_request + transport.requests.last + end + + describe "#list" do + it "lists company-scoped webhooks" do + transport.enqueue(json(body: { "data" => [{ "id" => "wh1" }] }.to_json)) + + result = webhooks.list("co-1") + + expect(result).to be_a(Nfe::ListResponse) + expect(result.data.first).to be_a(Nfe::WebhookSubscription) + expect(result.data.first.id).to eq("wh1") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co-1/webhooks") + end + + it "rejects an empty company_id without HTTP" do + expect { webhooks.list("") }.to raise_error(Nfe::InvalidRequestError) + expect(transport.requests).to be_empty + end + end + + describe "#create" do + it "POSTs and hydrates a WebhookSubscription" do + transport.enqueue(json(body: { + "id" => "wh1", "url" => "https://example.com/hook", + "events" => ["invoice.issued"], "secret" => "s3cr3t" + }.to_json)) + + webhook = webhooks.create("co-1", url: "https://example.com/hook", events: ["invoice.issued"]) + + expect(webhook.id).to eq("wh1") + expect(webhook.url).to eq("https://example.com/hook") + expect(webhook.events).to eq(["invoice.issued"]) + expect(webhook.secret).to eq("s3cr3t") + expect(last_request.method).to eq("POST") + end + end + + describe "#retrieve / #update / #delete" do + it "retrieves by id" do + transport.enqueue(json(body: { "id" => "wh1" }.to_json)) + expect(webhooks.retrieve("co-1", "wh1").id).to eq("wh1") + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co-1/webhooks/wh1") + end + + it "updates by id" do + transport.enqueue(json(body: { "id" => "wh1", "active" => false }.to_json)) + expect(webhooks.update("co-1", "wh1", active: false).active).to be(false) + expect(last_request.method).to eq("PUT") + end + + it "deletes and returns nil" do + transport.enqueue(json(status: 200, body: "")) + expect(webhooks.delete("co-1", "wh1")).to be_nil + expect(last_request.method).to eq("DELETE") + end + end + + describe "#test" do + it "POSTs to /test and returns success/message" do + transport.enqueue(json(body: { "success" => true, "message" => "delivered" }.to_json)) + + result = webhooks.test("co-1", "wh1") + + expect(result).to eq({ success: true, message: "delivered" }) + expect(last_request.url).to eq("https://api.nfe.io/v1/companies/co-1/webhooks/wh1/test") + expect(last_request.method).to eq("POST") + end + end + + describe "#get_available_events" do + it "returns exactly the seven static events" do + expect(webhooks.get_available_events).to eq(%w[ + invoice.issued + invoice.cancelled + invoice.failed + invoice.processing + company.created + company.updated + company.deleted + ]) + end + end + + describe "#verify_signature" do + it "delegates to Nfe::Webhook.verify_signature" do + allow(Nfe::Webhook).to receive(:verify_signature).and_return(true) + + result = webhooks.verify_signature(payload: "body", signature: "sha1=abc", secret: "s") + + expect(result).to be(true) + expect(Nfe::Webhook).to have_received(:verify_signature) + .with(payload: "body", signature: "sha1=abc", secret: "s") + end + end +end diff --git a/spec/nfe/results_spec.rb b/spec/nfe/results_spec.rb new file mode 100644 index 0000000..f935f64 --- /dev/null +++ b/spec/nfe/results_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +RSpec.describe Nfe::Pending do + it "exposes invoice_id and location" do + pending = described_class.new(invoice_id: "abc-123", location: "/v1/companies/x/serviceinvoices/abc-123") + + expect(pending.invoice_id).to eq("abc-123") + expect(pending.location).to eq("/v1/companies/x/serviceinvoices/abc-123") + end + + it "compares by value" do + a = described_class.new(invoice_id: "abc", location: "/loc") + b = described_class.new(invoice_id: "abc", location: "/loc") + + expect(a).to eq(b) + end + + it "is frozen and immutable" do + expect(described_class.new(invoice_id: "abc", location: "/loc")).to be_frozen + end + + it "is distinguishable from Nfe::Issued via is_a?" do + result = described_class.new(invoice_id: "abc", location: "/loc") + + expect(result).to be_a(described_class) + expect(result).not_to be_a(Nfe::Issued) + end + + describe Nfe::Issued do + it "exposes resource" do + dto = Object.new + issued = described_class.new(resource: dto) + + expect(issued.resource).to be(dto) + end + + it "compares by value" do + one = described_class.new(resource: "r") + two = described_class.new(resource: "r") + expect(one).to eq(two) + end + + it "is distinguishable from Nfe::Pending via is_a?" do + result = described_class.new(resource: "r") + + expect(result).to be_a(described_class) + expect(result).not_to be_a(Nfe::Pending) + end + end +end diff --git a/spec/nfe/service_invoices_spec.rb b/spec/nfe/service_invoices_spec.rb deleted file mode 100644 index e7ad3ae..0000000 --- a/spec/nfe/service_invoices_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -require_relative '../rspec_helper' - -describe Nfe::ServiceInvoice do - before(:each) do - Nfe.api_key('e12cmDevG5iLhSd9Y7BOpxynL86Detjd2R1D5jsP5UGXA8gwxug0Vojl3H9TIzBpbhI') - Nfe::ServiceInvoice.company_id("55df4dc6b6cd9007e4f13ee8") - end - - it 'should create a ServiceInvoice' do - customer_params = {borrower: { federalTaxNumber: '01946377198', - name: 'Ricardo Caldeira', - email: 'ricardo.nezz@mailinator.com', - address: { - country: 'BRA', - postalCode: '22231110', - street: 'Rua Do Cliente', - number: '1310', - additionalInformation: 'AP 202', - district: 'Centro', - city: { - code: 4204202, - name: 'Chapecó' - }, - state: 'SC' - }}} - service_params = { cityServiceCode: '2690', description: 'Manutenção e suporte técnico.', servicesAmount: 0.15 } - nfe = Nfe::ServiceInvoice.create(customer_params.merge(service_params)) - - expect(nfe["environment"]).to eq('Development') - expect(nfe["borrower"]["name"]).to eq('Ricardo Caldeira') - end - - it 'should list all service invoices' do - service_invoices_list = Nfe::ServiceInvoice.list_all - expect(service_invoices_list["totalResults"]).to be >= 1 - expect(service_invoices_list["serviceInvoices"].size).to be >= 1 - end - - it 'should list service invoices by page' do - service_invoices_list = Nfe::ServiceInvoice.list_all(pageCount: 5, pageIndex: 2) - expect(service_invoices_list["totalResults"]).to be >= 1 - expect(service_invoices_list["totalPages"]).to be >= 1 - expect(service_invoices_list["page"]).to eq(2) - expect(service_invoices_list["serviceInvoices"].size).to be >= 1 - end - - it 'should retrieve a ServiceInvoice' do - service_invoices_list = Nfe::ServiceInvoice.list_all - service_invoice_params = service_invoices_list["serviceInvoices"].first - service_invoice = Nfe::ServiceInvoice.retrieve(service_invoice_params["id"]) - expect(service_invoice["id"]).to eq(service_invoice_params["id"]) - expect(service_invoice["rpsStatus"]).to eq("Normal") - end - - it 'should cancel a ServiceInvoice' do - service_invoices_list = Nfe::ServiceInvoice.list_all - service_invoice = service_invoices_list["serviceInvoices"].first - response = Nfe::ServiceInvoice.cancel(service_invoice["id"]) - expect(response["id"]).to eq(service_invoice["id"]) - expect(response["flowStatus"]).to eq("WaitingSendCancel") - end - - it 'should send a email to Tomador' do - skip "To be implemented" - end - - it 'should retrieve a ServiceInvoice XML file' do - service_invoices_list = Nfe::ServiceInvoice.list_all - service_invoice_params = service_invoices_list["serviceInvoices"].first - - response = Nfe::ServiceInvoice.download(service_invoice_params["id"], :xml) - - expect(response.headers[:content_type]).to eq("application/xml") - expect(response.headers[:content_length].size).to be >= 1 - expect(response.size).to be >= 1 - end - - it 'should retrieve a ServiceInvoice PDF file' do - service_invoices_list = Nfe::ServiceInvoice.list_all - service_invoice_params = service_invoices_list["serviceInvoices"].first - - response = Nfe::ServiceInvoice.download(service_invoice_params["id"], :pdf) - - expect(response.headers[:content_type]).to eq("application/pdf") - expect(response.headers[:content_length].size).to be >= 1 - expect(response.size).to be >= 1 - end - - it 'should not retrieve a ServiceInvoice PDF file when API Key is not valid' do - service_invoices_list = Nfe::ServiceInvoice.list_all - service_invoice_params = service_invoices_list["serviceInvoices"].first - - Nfe.api_key('not_valid_api_keycont') - expect { - Nfe::ServiceInvoice.download(service_invoice_params["id"], :pdf) - }.to raise_error(Nfe::NfeError) - end - - it 'should not retrieve a ServiceInvoice XML file when API Key is not valid' do - service_invoices_list = Nfe::ServiceInvoice.list_all - service_invoice_params = service_invoices_list["serviceInvoices"].first - - Nfe.api_key('not_valid_api_keycont') - expect { - Nfe::ServiceInvoice.download(service_invoice_params["id"], :xml) - }.to raise_error(Nfe::NfeError) - end - - it 'should retrieve Service Invoices from Prefeitura' do - skip "To be implemented" - end - -end diff --git a/spec/nfe/version_spec.rb b/spec/nfe/version_spec.rb new file mode 100644 index 0000000..0f38fff --- /dev/null +++ b/spec/nfe/version_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +RSpec.describe Nfe do + it "pins the major version at 1.0.0" do + expect(Nfe::VERSION).to eq("1.0.0") + end +end diff --git a/spec/nfe/webhook_spec.rb b/spec/nfe/webhook_spec.rb new file mode 100644 index 0000000..12288e6 --- /dev/null +++ b/spec/nfe/webhook_spec.rb @@ -0,0 +1,169 @@ +# frozen_string_literal: true + +require "openssl" +require "json" +require "securerandom" + +RSpec.describe Nfe::Webhook do + let(:secret) { "super-secret-key" } + let(:body) { %({"action":"invoice.issued","payload":{"id":"abc","status":"Issued"}}) } + + def sign(payload, key) + "sha1=#{OpenSSL::HMAC.hexdigest('SHA1', key, payload)}" + end + + describe ".verify_signature" do + it "accepts a valid lowercase-hex signature" do + sig = sign(body, secret) + expect(described_class.verify_signature(payload: body, signature: sig, secret: secret)).to be(true) + end + + it "accepts an uppercase-hex digest as NFE.io sends it" do + digest = OpenSSL::HMAC.hexdigest("SHA1", secret, body).upcase + sig = "sha1=#{digest}" + expect(described_class.verify_signature(payload: body, signature: sig, secret: secret)).to be(true) + end + + it "accepts an uppercase prefix (case-insensitive prefix)" do + digest = OpenSSL::HMAC.hexdigest("SHA1", secret, body) + sig = "SHA1=#{digest}" + expect(described_class.verify_signature(payload: body, signature: sig, secret: secret)).to be(true) + end + + it "round-trips a self-computed signature for a random body and secret" do + random_body = SecureRandom.hex(64) + random_secret = SecureRandom.hex(16) + sig = sign(random_body, random_secret) + expect( + described_class.verify_signature(payload: random_body, signature: sig, secret: random_secret) + ).to be(true) + end + + it "uses the first element when the signature is a single-element array" do + sig = sign(body, secret) + expect(described_class.verify_signature(payload: body, signature: [sig], secret: secret)).to be(true) + end + + context "with negative inputs (must return false and never raise)" do + it "rejects a tampered body" do + sig = sign(body, secret) + tampered = body.sub("abc", "abd") + result = nil + expect { result = described_class.verify_signature(payload: tampered, signature: sig, secret: secret) } + .not_to raise_error + expect(result).to be(false) + end + + it "rejects a valid signature checked against the wrong secret" do + sig = sign(body, secret) + expect(described_class.verify_signature(payload: body, signature: sig, secret: "other-secret")).to be(false) + end + + it "rejects a sha256= downgrade attempt without raising" do + digest = "a" * 64 + sig = "sha256=#{digest}" + result = nil + expect { result = described_class.verify_signature(payload: body, signature: sig, secret: secret) } + .not_to raise_error + expect(result).to be(false) + end + + it "rejects a bare 40-char hex with no prefix" do + bare = OpenSSL::HMAC.hexdigest("SHA1", secret, body) + expect(described_class.verify_signature(payload: body, signature: bare, secret: secret)).to be(false) + end + + it "rejects a wrong-length signature (sha1=abc)" do + result = nil + expect { result = described_class.verify_signature(payload: body, signature: "sha1=abc", secret: secret) } + .not_to raise_error + expect(result).to be(false) + end + + it "rejects non-hex content of the right length" do + sig = "sha1=#{'z' * 40}" + expect(described_class.verify_signature(payload: body, signature: sig, secret: secret)).to be(false) + end + + it "rejects a nil secret" do + sig = sign(body, secret) + expect(described_class.verify_signature(payload: body, signature: sig, secret: nil)).to be(false) + end + + it "rejects an empty secret" do + sig = sign(body, secret) + expect(described_class.verify_signature(payload: body, signature: sig, secret: "")).to be(false) + end + + it "rejects a nil signature" do + expect(described_class.verify_signature(payload: body, signature: nil, secret: secret)).to be(false) + end + + it "rejects an empty-string signature" do + expect(described_class.verify_signature(payload: body, signature: "", secret: secret)).to be(false) + end + + it "rejects an empty array signature" do + expect(described_class.verify_signature(payload: body, signature: [], secret: secret)).to be(false) + end + + it "never raises across the whole negative matrix" do + cases = [nil, "", [], "sha1=abc", "sha256=#{'a' * 64}", "no-prefix", + "sha1=#{'z' * 40}", ["sha1=#{'a' * 40}"]] + cases.each do |candidate| + expect { described_class.verify_signature(payload: body, signature: candidate, secret: secret) } + .not_to raise_error + end + end + end + end + + describe ".construct_event" do + it "returns a WebhookEvent for a valid action/payload envelope" do + sig = sign(body, secret) + event = described_class.construct_event(payload: body, signature: sig, secret: secret) + expect(event).to be_a(Nfe::WebhookEvent) + expect(event.type).to eq("invoice.issued") + expect(event.data).to eq("id" => "abc", "status" => "Issued") + expect(event.id).to eq("abc") + end + + it "unwraps the event/data envelope shape" do + payload = %({"event":"company.updated","data":{"id":"co_1"}}) + sig = sign(payload, secret) + event = described_class.construct_event(payload: payload, signature: sig, secret: secret) + expect(event.type).to eq("company.updated") + expect(event.data).to eq("id" => "co_1") + expect(event.id).to eq("co_1") + end + + it "surfaces nil id when the envelope carries none" do + payload = %({"action":"invoice.failed","payload":{"status":"Failed"}}) + sig = sign(payload, secret) + event = described_class.construct_event(payload: payload, signature: sig, secret: secret) + expect(event.id).to be_nil + end + + it "raises SignatureVerificationError on a bad signature" do + expect do + described_class.construct_event(payload: body, signature: "sha1=#{'a' * 40}", secret: secret) + end.to raise_error(Nfe::SignatureVerificationError) + end + + it "raises SignatureVerificationError on malformed JSON with a valid signature" do + malformed = "{not json" + sig = sign(malformed, secret) + expect do + described_class.construct_event(payload: malformed, signature: sig, secret: secret) + end.to raise_error(Nfe::SignatureVerificationError) + end + + it "raises SignatureVerificationError when the JSON is not an object" do + payload = "[1,2,3]" + sig = sign(payload, secret) + expect do + described_class.construct_event(payload: payload, signature: sig, secret: secret) + end.to raise_error(Nfe::SignatureVerificationError) + end + end +end diff --git a/spec/nfe/webhooks_spec.rb b/spec/nfe/webhooks_spec.rb deleted file mode 100644 index e69de29..0000000 diff --git a/spec/rspec_helper.rb b/spec/rspec_helper.rb deleted file mode 100644 index d5a9c25..0000000 --- a/spec/rspec_helper.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'rspec' -require 'byebug' -require_relative '../lib/nfe' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..ad9fc6d --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require "simplecov" + +SimpleCov.start do + enable_coverage :branch + add_filter "/spec/" + add_filter "lib/nfe/generated/" + minimum_coverage 80 +end + +require "nfe" + +# Shared spec support (fakes, helpers). +Dir[File.expand_path("support/**/*.rb", __dir__)].each { |file| require file } + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + + config.disable_monkey_patching! + config.order = :random + Kernel.srand config.seed +end diff --git a/spec/support/fake_transport.rb b/spec/support/fake_transport.rb new file mode 100644 index 0000000..25e2181 --- /dev/null +++ b/spec/support/fake_transport.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# In-memory transport double for tests. Responds to +call(request)+, dequeuing +# canned outcomes (an Nfe::Http::Response to return, or an exception instance / +# class to raise) and recording every received request for assertions. +# +# Usage: +# fake = FakeTransport.new +# fake.enqueue(Nfe::Http::Response.new(status: 503)) +# fake.enqueue(Nfe::Http::Response.new(status: 200)) +# fake.call(request) # => 503, then 200 +# +# When the queue is exhausted, the last enqueued outcome is repeated, so a +# single enqueued 503 models a permanently failing endpoint. +class FakeTransport + attr_reader :requests + + def initialize(outcomes = []) + @outcomes = outcomes.dup + @requests = [] + end + + # Enqueue a Response to return or an exception (class or instance) to raise. + def enqueue(outcome) + @outcomes << outcome + self + end + + def call(request) + @requests << request + outcome = @outcomes.length > 1 ? @outcomes.shift : @outcomes.first + deliver(outcome) + end + + # Number of times +call+ has been invoked. + def call_count + @requests.length + end + + private + + def deliver(outcome) + case outcome + when Class + raise outcome if outcome <= Exception + + outcome + when Exception + raise outcome + else + outcome + end + end +end