Class: Nfe::Resources::ServiceInvoicesRtc

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

Overview

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 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 ServiceInvoiceRtcPending (HTTP 202, queued) or a ServiceInvoiceRtcIssued (HTTP 201, materialized). There is no +create_and_wait+/+create_batch+ — poll #retrieve manually.

Examples:

RTC emission selected by the ibsCbs group

client.service_invoices_rtc.create(
  company_id: "co_1",
  data: { borrower: { ... }, servicesAmount: 100.0, ibsCbs: { cbs: { ... }, ibs: { ... } } }
)

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, #extract_invoice_id, #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)


33
34
35
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 33

def api_family
  :main
end

#api_versionString

Returns:

  • (String)


37
38
39
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 37

def api_version
  "v1"
end

#build_pending(response) ⇒ Nfe::Resources::ServiceInvoiceRtcPending

Build a Nfe::Resources::ServiceInvoiceRtcPending from a 202 response, or raise when the Location header is missing/unparsable.



138
139
140
141
142
143
144
145
146
147
148
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 138

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

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

Cancel an RTC service invoice (synchronous); returns the updated model.

Parameters:

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

Returns:



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

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

#create(company_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ServiceInvoiceRtcPending, ServiceInvoiceRtcIssued

Create (emit) an RTC service invoice. Returns a discriminated result: a Nfe::Resources::ServiceInvoiceRtcPending on HTTP 202 (queued, invoice_id parsed from the Location header) or a Nfe::Resources::ServiceInvoiceRtcIssued on HTTP 201 (materialized, hydrating 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.

Parameters:

  • company_id (String)
  • data (Hash)

    invoice payload (camelCase keys); include ibsCbs to select the RTC layout. Mirrors ServiceInvoiceRtcV1::NFSeRequest.

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

    sent as the Idempotency-Key header.

  • 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:

Raises:



64
65
66
67
68
69
70
71
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 64

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

#discriminate(response) ⇒ Nfe::Resources::ServiceInvoiceRtcPending, Nfe::Resources::ServiceInvoiceRtcIssued

Interpret the emission response into the discriminated value object.



130
131
132
133
134
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 130

def discriminate(response)
  return build_pending(response) if response.status == 202

  ServiceInvoiceRtcIssued.new(resource: hydrate(Nfe::ServiceInvoice, parse_json(response.body)))
end

#download_cancellation_xml(company_id:, invoice_id:) ⇒ String

Download the cancellation XML (ADN-only, available after the invoice reaches the Cancelled state). Returns the raw bytes (+ASCII-8BIT+).

Parameters:

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

Returns:

  • (String)

    XML bytes (ASCII-8BIT).

Raises:



109
110
111
112
113
114
115
116
117
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 109

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

#extract_rtc_invoice_id(location) ⇒ String?

Extract the trailing id from a Location path.

Parameters:

  • location (String, nil)

Returns:

  • (String, nil)


151
152
153
154
155
156
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 151

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

#json_body(data) ⇒ String

Parameters:

  • data (Object)

Returns:

  • (String)


125
126
127
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 125

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

#json_headersHash[String, String]

Returns:

  • (Hash[String, String])


121
122
123
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 121

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

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

Retrieve an RTC service invoice by id. The 201/GET body is the standard NFS-e shape, hydrated into ServiceInvoice.

Parameters:

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

Returns:

Raises:



80
81
82
83
84
85
86
87
88
# File 'lib/nfe/resources/service_invoices_rtc.rb', line 80

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