Class: Nfe::Resources::ConsumerInvoices

Inherits:
AbstractResource show all
Defined in:
lib/nfe/resources/consumer_invoices.rb,
sig/nfe/resources/consumer_invoices.rbs

Overview

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 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: ConsumerInvoicePending on HTTP 202 (async) or 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? + FlowStatus.terminal?.

Examples:

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

Constant Summary collapse

ENVELOPE =

Wrapper key for the list envelope.

Returns:

  • (String)
"consumerInvoices"

Instance Attribute Summary

Attributes inherited from AbstractResource

#client

Instance Method Summary collapse

Methods inherited from AbstractResource

#build_list_page, #build_multipart_body, #cursor_list_page, #delete, #dig_key, #download, #full_path, #get, #handle_async_response, #hydrate, #hydrate_list, #initialize, #multipart_part, #page_list_page, #parse_json, #post, #put, #unwrap, #upload_multipart

Constructor Details

This class inherits a constructor from Nfe::Resources::AbstractResource

Instance Method Details

#api_familySymbol

Returns:

  • (Symbol)


56
57
58
# File 'lib/nfe/resources/consumer_invoices.rb', line 56

def api_family
  :cte
end

#api_versionString

The :cte host (+api.nfse.io+) does not bake in a version, so this resource supplies the /v2 segment itself.

Returns:

  • (String)


62
63
64
# File 'lib/nfe/resources/consumer_invoices.rb', line 62

def api_version
  "v2"
end

#cancel(company_id:, invoice_id:) ⇒ Nfe::ConsumerInvoice

Cancel an NFC-e (synchronous); returns the updated model.

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:



127
128
129
130
131
# File 'lib/nfe/resources/consumer_invoices.rb', line 127

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

#create(company_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ConsumerInvoicePending, ConsumerInvoiceIssued

Emit an NFC-e. Returns Nfe::Resources::ConsumerInvoicePending (HTTP 202) or Nfe::Resources::ConsumerInvoiceIssued (HTTP 201/200).

Parameters:

  • company_id (String)
  • data (Hash)

    NFC-e payload (camelCase keys per the API).

  • idempotency_key (String, nil) (defaults to: nil)

    sent as Idempotency-Key.

  • request_options (Nfe::RequestOptions, nil) (defaults to: nil)

    per-call overrides.

  • company_id: (String)
  • data: (Hash[untyped, untyped])
  • idempotency_key: (String, nil) (defaults to: nil)
  • request_options: (Nfe::RequestOptions, nil) (defaults to: nil)

Returns:



76
77
78
79
80
81
82
83
# File 'lib/nfe/resources/consumer_invoices.rb', line 76

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

#create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ConsumerInvoicePending, ConsumerInvoiceIssued

Emit an NFC-e scoped to a specific state-tax registration.

Parameters:

  • company_id (String)
  • state_tax_id (String)
  • data (Hash)
  • idempotency_key (String, nil) (defaults to: nil)
  • request_options (Nfe::RequestOptions, nil) (defaults to: nil)
  • company_id: (String)
  • state_tax_id: (String)
  • data: (Hash[untyped, untyped])
  • idempotency_key: (String, nil) (defaults to: nil)
  • request_options: (Nfe::RequestOptions, nil) (defaults to: nil)

Returns:



93
94
95
96
97
98
99
100
# File 'lib/nfe/resources/consumer_invoices.rb', line 93

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

#disable_range(company_id:, data:) ⇒ Hash

Collectively inutilize a range of NFC-e numbers. NFC-e supports only collective inutilization (no per-invoice disablement).

Parameters:

  • company_id (String)
  • data (Hash)

    { environment, serie, state, begin_number, last_number, reason? }.

  • company_id: (String)
  • data: (Hash[untyped, untyped])

Returns:

  • (Hash)

    the parsed disablement result.



185
186
187
188
189
190
# File 'lib/nfe/resources/consumer_invoices.rb', line 185

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

#discriminate(response) ⇒ Nfe::Resources::ConsumerInvoicePending, Nfe::Resources::ConsumerInvoiceIssued

Interpret an emission response into the discriminated NFC-e result.



208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/nfe/resources/consumer_invoices.rb', line 208

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

#download_pdf(company_id:, invoice_id:) ⇒ String

Download the DANFE NFC-e PDF as binary bytes (unlike ProductInvoices, which returns a URI).

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:

  • (String)

    ASCII-8BIT PDF bytes.



155
156
157
158
159
# File 'lib/nfe/resources/consumer_invoices.rb', line 155

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_rejection_xml(company_id:, invoice_id:) ⇒ String

Download the rejection XML (sefaz refusal) as binary bytes.

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:

  • (String)

    ASCII-8BIT XML bytes.



173
174
175
176
177
# File 'lib/nfe/resources/consumer_invoices.rb', line 173

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

#download_xml(company_id:, invoice_id:) ⇒ String

Download the authorized NFC-e XML as binary bytes.

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:

  • (String)

    ASCII-8BIT XML bytes.



164
165
166
167
168
# File 'lib/nfe/resources/consumer_invoices.rb', line 164

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

#extract_invoice_id(location) ⇒ String?

Extract the trailing id from a Location path.

Parameters:

  • location (String)

Returns:

  • (String, nil)


227
228
229
230
# File 'lib/nfe/resources/consumer_invoices.rb', line 227

def extract_invoice_id(location)
  match = location.match(%r{/([a-z0-9-]+)\z}i)
  match ? match[1] : nil
end

#issued_result(response) ⇒ Nfe::Resources::ConsumerInvoiceIssued



221
222
223
224
# File 'lib/nfe/resources/consumer_invoices.rb', line 221

def issued_result(response)
  invoice = hydrate(Nfe::ConsumerInvoice, parse_json(response.body))
  ConsumerInvoiceIssued.new(resource: invoice)
end

#json_body(data) ⇒ String

Parameters:

  • data (Object)

Returns:

  • (String)


245
246
247
# File 'lib/nfe/resources/consumer_invoices.rb', line 245

def json_body(data)
  JSON.generate(data)
end

#json_headersHash[String, String]

Returns:

  • (Hash[String, String])


241
242
243
# File 'lib/nfe/resources/consumer_invoices.rb', line 241

def json_headers
  { "Content-Type" => "application/json" }
end

#list(company_id:, environment:, **options) ⇒ Nfe::ListResponse

List NFC-e for a company (cursor pagination; wrapper consumerInvoices).

Parameters:

  • company_id (String)
  • options (Hash)

    cursor query params (+starting_after+, limit...).

  • company_id: (String)
  • environment: (String)

Returns:



107
108
109
110
111
112
113
# File 'lib/nfe/resources/consumer_invoices.rb', line 107

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

#list_events(company_id:, invoice_id:) ⇒ Array<Hash>

List the events of an NFC-e.

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:

  • (Array<Hash>)


145
146
147
148
149
# File 'lib/nfe/resources/consumer_invoices.rb', line 145

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

#list_items(company_id:, invoice_id:) ⇒ Array<Hash>

List the line items of an NFC-e.

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:

  • (Array<Hash>)


136
137
138
139
140
# File 'lib/nfe/resources/consumer_invoices.rb', line 136

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

#require_environment(environment) ⇒ void

This method returns an undefined value.

The API rejects a NFC-e listing without an environment; require it client-side (mirrors product_invoices#list).

Parameters:

  • environment (Object)

Raises:



196
197
198
199
200
# File 'lib/nfe/resources/consumer_invoices.rb', line 196

def require_environment(environment)
  return unless environment.nil? || environment.to_s.strip.empty?

  raise Nfe::InvalidRequestError, "environment é obrigatório (Production ou Test)"
end

#retrieve(company_id:, invoice_id:) ⇒ Nfe::ConsumerInvoice

Retrieve a single NFC-e by id.

Parameters:

  • company_id: (String)
  • invoice_id: (String)

Returns:



118
119
120
121
122
# File 'lib/nfe/resources/consumer_invoices.rb', line 118

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

#unwrap_collection(payload, key) ⇒ Array[untyped]

Unwrap a collection envelope, tolerating a bare array or a wrapped one.

Parameters:

  • payload (Object)
  • key (String)

Returns:

  • (Array[untyped])


233
234
235
236
237
238
239
# File 'lib/nfe/resources/consumer_invoices.rb', line 233

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

#validate_pair(company_id, invoice_id) ⇒ Array[String]

Validate a (company_id, invoice_id) pair, returning both normalized.

Parameters:

  • company_id (String)
  • invoice_id (String)

Returns:

  • (Array[String])


203
204
205
# File 'lib/nfe/resources/consumer_invoices.rb', line 203

def validate_pair(company_id, invoice_id)
  [Nfe::IdValidator.company_id(company_id), Nfe::IdValidator.invoice_id(invoice_id)]
end