Class: Nfe::Resources::ProductInvoices
- Inherits:
-
AbstractResource
- Object
- AbstractResource
- Nfe::Resources::ProductInvoices
- Defined in:
- lib/nfe/resources/product_invoices.rb,
sig/nfe/resources/product_invoices.rbs
Overview
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 ProductInvoicePending or a ProductInvoiceIssued. There is no +create_and_wait+/+create_batch+ in v1.0 — poll manually with #retrieve + FlowStatus.terminal?.
NOTE: unlike the other invoice resources, the download methods return a NfeFileResource (a URI to the file), NOT raw bytes.
Instance Attribute Summary
Attributes inherited from AbstractResource
Instance Method Summary collapse
- #api_family ⇒ Symbol
-
#api_version ⇒ String
The
:ctehost serves the v2 API; paths embed/v2explicitly, so no version segment is auto-prefixed. - #base_path(company_id) ⇒ String
-
#build_pending(response) ⇒ Nfe::Resources::ProductInvoicePending
Build a ProductInvoicePending from a 202 response, or raise when the Location header is missing/unparsable.
-
#cancel(company_id:, invoice_id:, reason: nil) ⇒ Hash
Cancel a product invoice (async);
reasonforwarded as a query param. -
#create(company_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ProductInvoicePending, ProductInvoiceIssued
Issue a product invoice (NF-e).
-
#create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ProductInvoicePending, ProductInvoiceIssued
Issue a product invoice scoped to a state tax registration.
- #cursor_query(options) ⇒ Hash[Symbol, untyped]
-
#disable(company_id:, invoice_id:, reason: nil) ⇒ Hash
Disable (inutilizar) a single invoice (async).
-
#disable_range(company_id:, data:) ⇒ Hash
Disable a range of invoice numbers (single number = same begin/last).
-
#discriminate(response) ⇒ Nfe::Resources::ProductInvoicePending, Nfe::Resources::ProductInvoiceIssued
Interpret the emission response into the discriminated value object.
-
#download_correction_letter_pdf(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
CC-e DANFE PDF file resource (URI, not bytes).
-
#download_correction_letter_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
CC-e XML file resource (URI, not bytes).
-
#download_epec_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
Contingency authorization (EPEC) XML file resource (URI, not bytes).
-
#download_pdf(company_id:, invoice_id:, force: nil) ⇒ Nfe::NfeFileResource
DANFE PDF file resource (URI, not bytes).
-
#download_rejection_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
Rejection XML file resource (URI, not bytes).
-
#download_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
Authorized NF-e XML file resource (URI, not bytes).
- #extract_invoice_id(location) ⇒ String?
- #file_resource(company_id:, invoice_id:, segment:, query: {}) ⇒ Nfe::NfeFileResource?
- #json_body(data) ⇒ String
- #json_headers ⇒ Hash[String, String]
-
#list(company_id:, environment:, **options) ⇒ Nfe::ListResponse
List product invoices (cursor-style).
-
#list_events(company_id:, invoice_id:, limit: nil, starting_after: nil) ⇒ Nfe::ListResponse
List fiscal events of an invoice (cursor-style).
-
#list_items(company_id:, invoice_id:, limit: nil, starting_after: nil) ⇒ Nfe::ListResponse
List items of an invoice (cursor-style).
- #require_environment(environment) ⇒ void
-
#retrieve(company_id:, invoice_id:) ⇒ Nfe::ProductInvoice
Retrieve a product invoice by id.
-
#send_correction_letter(company_id:, invoice_id:, reason:) ⇒ Hash
Send a correction letter (CC-e).
- #sub_list(company_id:, invoice_id:, segment:, limit:, starting_after:, wrapper_key:) ⇒ Nfe::ListResponse
- #validate_correction_reason(reason) ⇒ void
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_family ⇒ Symbol
29 30 31 |
# File 'lib/nfe/resources/product_invoices.rb', line 29 def api_family :cte end |
#api_version ⇒ String
The :cte host serves the v2 API; paths embed /v2 explicitly, so no
version segment is auto-prefixed.
35 36 37 |
# File 'lib/nfe/resources/product_invoices.rb', line 35 def api_version "" end |
#base_path(company_id) ⇒ String
213 214 215 |
# File 'lib/nfe/resources/product_invoices.rb', line 213 def base_path(company_id) "/v2/companies/#{company_id}/productinvoices" end |
#build_pending(response) ⇒ Nfe::Resources::ProductInvoicePending
Build a Nfe::Resources::ProductInvoicePending from a 202 response, or raise when the Location header is missing/unparsable.
270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/nfe/resources/product_invoices.rb', line 270 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 |
#cancel(company_id:, invoice_id:, reason: nil) ⇒ Hash
Cancel a product invoice (async); reason forwarded as a query param.
107 108 109 110 111 112 |
# File 'lib/nfe/resources/product_invoices.rb', line 107 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 |
#create(company_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ProductInvoicePending, ProductInvoiceIssued
Issue a product invoice (NF-e). Returns a discriminated result: a Nfe::Resources::ProductInvoicePending on HTTP 202 or a Nfe::Resources::ProductInvoiceIssued on 201.
49 50 51 52 53 54 55 |
# File 'lib/nfe/resources/product_invoices.rb', line 49 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: ) discriminate(response) end |
#create_with_state_tax(company_id:, state_tax_id:, data:, idempotency_key: nil, request_options: nil) ⇒ ProductInvoicePending, ProductInvoiceIssued
Issue a product invoice scoped to a state tax registration.
65 66 67 68 69 70 71 72 |
# File 'lib/nfe/resources/product_invoices.rb', line 65 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: ) discriminate(response) end |
#cursor_query(options) ⇒ Hash[Symbol, untyped]
231 232 233 234 235 236 |
# File 'lib/nfe/resources/product_invoices.rb', line 231 def cursor_query() { startingAfter: [:starting_after], endingBefore: [:ending_before], limit: [:limit], q: [:q] }.compact end |
#disable(company_id:, invoice_id:, reason: nil) ⇒ Hash
Disable (inutilizar) a single invoice (async). reason optional.
193 194 195 196 197 198 |
# File 'lib/nfe/resources/product_invoices.rb', line 193 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_range(company_id:, data:) ⇒ Hash
Disable a range of invoice numbers (single number = same begin/last).
205 206 207 208 209 |
# File 'lib/nfe/resources/product_invoices.rb', line 205 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 |
#discriminate(response) ⇒ Nfe::Resources::ProductInvoicePending, Nfe::Resources::ProductInvoiceIssued
Interpret the emission response into the discriminated value object.
262 263 264 265 266 |
# File 'lib/nfe/resources/product_invoices.rb', line 262 def discriminate(response) return build_pending(response) if response.status == 202 ProductInvoiceIssued.new(resource: hydrate(Nfe::ProductInvoice, parse_json(response.body))) end |
#download_correction_letter_pdf(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
CC-e DANFE PDF file resource (URI, not bytes).
179 180 181 |
# File 'lib/nfe/resources/product_invoices.rb', line 179 def download_correction_letter_pdf(company_id:, invoice_id:) file_resource(company_id: company_id, invoice_id: invoice_id, segment: "correctionletter/pdf") end |
#download_correction_letter_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
CC-e XML file resource (URI, not bytes).
186 187 188 |
# File 'lib/nfe/resources/product_invoices.rb', line 186 def download_correction_letter_xml(company_id:, invoice_id:) file_resource(company_id: company_id, invoice_id: invoice_id, segment: "correctionletter/xml") end |
#download_epec_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
Contingency authorization (EPEC) XML file resource (URI, not bytes).
155 156 157 |
# File 'lib/nfe/resources/product_invoices.rb', line 155 def download_epec_xml(company_id:, invoice_id:) file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml-epec") end |
#download_pdf(company_id:, invoice_id:, force: nil) ⇒ Nfe::NfeFileResource
DANFE PDF file resource (URI, not bytes). force regenerates the PDF.
133 134 135 136 |
# File 'lib/nfe/resources/product_invoices.rb', line 133 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 |
#download_rejection_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
Rejection XML file resource (URI, not bytes).
148 149 150 |
# File 'lib/nfe/resources/product_invoices.rb', line 148 def download_rejection_xml(company_id:, invoice_id:) file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml-rejection") end |
#download_xml(company_id:, invoice_id:) ⇒ Nfe::NfeFileResource
Authorized NF-e XML file resource (URI, not bytes).
141 142 143 |
# File 'lib/nfe/resources/product_invoices.rb', line 141 def download_xml(company_id:, invoice_id:) file_resource(company_id: company_id, invoice_id: invoice_id, segment: "xml") end |
#extract_invoice_id(location) ⇒ String?
282 283 284 285 286 287 |
# File 'lib/nfe/resources/product_invoices.rb', line 282 def extract_invoice_id(location) return nil if location.nil? match = location.match(%r{productinvoices/([a-z0-9-]+)}i) match ? match[1] : nil end |
#file_resource(company_id:, invoice_id:, segment:, query: {}) ⇒ Nfe::NfeFileResource?
254 255 256 257 258 259 |
# File 'lib/nfe/resources/product_invoices.rb', line 254 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 |
#json_body(data) ⇒ String
221 222 223 |
# File 'lib/nfe/resources/product_invoices.rb', line 221 def json_body(data) JSON.generate(data) end |
#json_headers ⇒ Hash[String, String]
217 218 219 |
# File 'lib/nfe/resources/product_invoices.rb', line 217 def json_headers { "Content-Type" => "application/json" } end |
#list(company_id:, environment:, **options) ⇒ Nfe::ListResponse
List product invoices (cursor-style). environment is REQUIRED.
81 82 83 84 85 86 87 |
# File 'lib/nfe/resources/product_invoices.rb', line 81 def list(company_id:, environment:, **) cid = Nfe::IdValidator.company_id(company_id) require_environment(environment) query = cursor_query().merge(environment: environment) response = get(base_path(cid), query: query) hydrate_list(Nfe::ProductInvoice, parse_json(response.body), wrapper_key: "productInvoices") end |
#list_events(company_id:, invoice_id:, limit: nil, starting_after: nil) ⇒ Nfe::ListResponse
List fiscal events of an invoice (cursor-style).
125 126 127 128 |
# File 'lib/nfe/resources/product_invoices.rb', line 125 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 |
#list_items(company_id:, invoice_id:, limit: nil, starting_after: nil) ⇒ Nfe::ListResponse
List items of an invoice (cursor-style).
117 118 119 120 |
# File 'lib/nfe/resources/product_invoices.rb', line 117 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 |
#require_environment(environment) ⇒ void
This method returns an undefined value.
225 226 227 228 229 |
# File 'lib/nfe/resources/product_invoices.rb', line 225 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::ProductInvoice
Retrieve a product invoice by id.
94 95 96 97 98 99 |
# File 'lib/nfe/resources/product_invoices.rb', line 94 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 |
#send_correction_letter(company_id:, invoice_id:, reason:) ⇒ Hash
Send a correction letter (CC-e). reason must be 15..1000 chars; the
length is validated client-side before any HTTP request.
167 168 169 170 171 172 173 174 |
# File 'lib/nfe/resources/product_invoices.rb', line 167 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 |
#sub_list(company_id:, invoice_id:, segment:, limit:, starting_after:, wrapper_key:) ⇒ Nfe::ListResponse
246 247 248 249 250 251 252 |
# File 'lib/nfe/resources/product_invoices.rb', line 246 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 |
#validate_correction_reason(reason) ⇒ void
This method returns an undefined value.
238 239 240 241 242 243 244 |
# File 'lib/nfe/resources/product_invoices.rb', line 238 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 |