Class: Assinafy::Resources::DocumentResource
- Inherits:
-
BaseResource
- Object
- BaseResource
- Assinafy::Resources::DocumentResource
- Defined in:
- lib/assinafy/resources/document_resource.rb,
sig/assinafy.rbs
Overview
Document upload, retrieval, download, lifecycle, and verification.
See https://api.assinafy.com.br/v1/docs#document for the full documentation of these endpoints.
Constant Summary collapse
- MAX_UPLOAD_BYTES =
25 * 1024 * 1024
- READY_STATUSES =
%w[metadata_ready pending_signature certificated].freeze
- FAILED_STATUSES =
%w[failed rejected_by_signer rejected_by_user expired].freeze
- ARTIFACT_TYPES =
%w[original certificated certificate-page bundle pades].freeze
Constants inherited from BaseResource
BaseResource::AUTH_HEADERS, BaseResource::PAGINATION_HEADERS, BaseResource::PATH_SEGMENT
Instance Method Summary collapse
-
#activities(document_id) ⇒ Array<Hash>
List the activity log for a document.
-
#append_tags(document_id, tags, account_id_override = nil) ⇒ Array<Hash>
Attach additional tags to a document without removing existing tags.
-
#create_from_template(template_id, signers_or_payload, options = {}, account_id_override = nil) ⇒ Hash
Create a document from a template, optionally creating its virtual assignment.
-
#delete(document_id) ⇒ nil
Permanently delete a document.
-
#detach_tag(document_id, tag_id, account_id_override = nil) ⇒ Hash
Detach a single tag from a document.
-
#details(document_id) ⇒ Hash
(also: #get)
Fetch a document by ID.
-
#download(document_id, artifact_name = 'certificated') ⇒ String
Download a document artifact as raw bytes.
-
#download_page(document_id, page_id) ⇒ String
Download a single page artifact.
-
#estimate_cost_from_template(template_id, signers_or_payload, account_id_override = nil) ⇒ Hash
Estimate the cost of creating a document from a template without consuming credits.
-
#fully_signed?(document_id) ⇒ Boolean
Convenience: true when the document is
certificated, or when the embedded assignment summary reports all signers complete. -
#list(params = {}, account_id_override = nil) ⇒ Hash{Symbol=>Array,Hash}
List documents for an account.
-
#list_tags(document_id, account_id_override = nil) ⇒ Array<Hash>
List tags attached to a document.
-
#public_info(document_id) ⇒ Hash
Fetch the unauthenticated, public-facing metadata of a document.
-
#rename(document_id, name) ⇒ Hash
Rename a document.
-
#replace_tags(document_id, tags, account_id_override = nil) ⇒ Array<Hash>
Replace the document's full tag set.
-
#search(query, params = {}, account_id_override = nil) ⇒ Hash{Symbol=>Array,Hash}
Lightweight search over an account's documents (id/name/status/artifacts), without the heavier per-document detail returned by #list.
-
#send_token(document_id, recipient: nil, channel: nil, email: nil) ⇒ nil, Hash
Send a 6-digit access token for the document to a signer (public endpoint).
-
#signing_progress(document_id) ⇒ Hash{Symbol=>Integer,Float}
Convenience: derive a total, pending, percentage progress Hash from the document's assignment summary.
-
#statuses ⇒ Array<Hash>
List the catalog of document status codes.
-
#thumbnail(document_id) ⇒ String
Download the document thumbnail (PNG/JPEG bytes).
-
#upload(source, options = {}) ⇒ Hash
Upload a PDF and create a document.
-
#verify(hash) ⇒ Hash
Verify a certificated document by its signature hash.
- #wait_until_ready(document_id, max_wait_seconds: 30, poll_interval_seconds: 2) ⇒ Hash
Methods inherited from BaseResource
Constructor Details
This class inherits a constructor from Assinafy::Resources::BaseResource
Instance Method Details
#activities(document_id) ⇒ Array<Hash>
List the activity log for a document.
433 434 435 436 437 438 439 |
# File 'lib/assinafy/resources/document_resource.rb', line 433 def activities(document_id) doc_id = require_id(document_id, 'Document ID') call_array('Failed to fetch document activities') do http_get("documents/#{doc_id}/activities") end end |
#append_tags(document_id, tags, account_id_override = nil) ⇒ Array<Hash>
Attach additional tags to a document without removing existing tags.
768 769 770 771 772 773 774 775 776 |
# File 'lib/assinafy/resources/document_resource.rb', line 768 def (document_id, , account_id_override = nil) acc_id = account_id(account_id_override) doc_id = require_id(document_id, 'Document ID') call_array('Failed to append document tags') do http_post("accounts/#{acc_id}/documents/#{doc_id}/tags", body_params(tags: tag_names())) end end |
#create_from_template(template_id, signers_or_payload, options = {}, account_id_override = nil) ⇒ Hash
Create a document from a template, optionally creating its virtual assignment.
510 511 512 513 514 515 516 517 518 519 520 |
# File 'lib/assinafy/resources/document_resource.rb', line 510 def create_from_template(template_id, signers_or_payload, = {}, account_id_override = nil) tmpl_id = require_id(template_id, 'Template ID') acc_id = account_id(account_id_override) body = template_body(signers_or_payload, ) @logger.info("Creating document from template #{tmpl_id} for account #{acc_id}") call('Failed to create document from template') do http_post("accounts/#{acc_id}/templates/#{tmpl_id}/documents", body) end end |
#delete(document_id) ⇒ nil
Permanently delete a document. Only allowed for "deletable" statuses.
452 453 454 455 456 457 458 |
# File 'lib/assinafy/resources/document_resource.rb', line 452 def delete(document_id) doc_id = require_id(document_id, 'Document ID') call_void('Failed to delete document') do http_delete("documents/#{doc_id}") end end |
#detach_tag(document_id, tag_id, account_id_override = nil) ⇒ Hash
Detach a single tag from a document. The tag itself is not deleted.
792 793 794 795 796 797 798 799 800 |
# File 'lib/assinafy/resources/document_resource.rb', line 792 def detach_tag(document_id, tag_id, account_id_override = nil) acc_id = account_id(account_id_override) doc_id = require_id(document_id, 'Document ID') tid = require_id(tag_id, 'Tag ID') call('Failed to detach document tag') do http_delete("accounts/#{acc_id}/documents/#{doc_id}/tags/#{tid}") end end |
#details(document_id) ⇒ Hash Also known as: get
Fetch a document by ID.
230 231 232 233 234 235 236 |
# File 'lib/assinafy/resources/document_resource.rb', line 230 def details(document_id) doc_id = require_id(document_id, 'Document ID') call('Failed to fetch document details') do http_get("documents/#{doc_id}") end end |
#download(document_id, artifact_name = 'certificated') ⇒ String
Download a document artifact as raw bytes.
352 353 354 355 356 357 358 359 |
# File 'lib/assinafy/resources/document_resource.rb', line 352 def download(document_id, artifact_name = 'certificated') doc_id = require_id(document_id, 'Document ID') art = artifact_type(artifact_name) call_binary('Failed to download document') do http_get("documents/#{doc_id}/download/#{art}") end end |
#download_page(document_id, page_id) ⇒ String
Download a single page artifact.
396 397 398 399 400 401 402 403 |
# File 'lib/assinafy/resources/document_resource.rb', line 396 def download_page(document_id, page_id) doc_id = require_id(document_id, 'Document ID') pid = require_id(page_id, 'Page ID') call_binary('Failed to download page') do http_get("documents/#{doc_id}/pages/#{pid}/download") end end |
#estimate_cost_from_template(template_id, signers_or_payload, account_id_override = nil) ⇒ Hash
Estimate the cost of creating a document from a template without consuming credits.
553 554 555 556 557 558 559 560 561 |
# File 'lib/assinafy/resources/document_resource.rb', line 553 def estimate_cost_from_template(template_id, signers_or_payload, account_id_override = nil) tmpl_id = require_id(template_id, 'Template ID') acc_id = account_id(account_id_override) body = template_body(signers_or_payload) call('Failed to estimate cost from template') do http_post("accounts/#{acc_id}/templates/#{tmpl_id}/documents/estimate-cost", body) end end |
#fully_signed?(document_id) ⇒ Boolean
Convenience: true when the document is certificated, or when the
embedded assignment summary reports all signers complete.
814 815 816 817 818 819 820 821 822 823 824 |
# File 'lib/assinafy/resources/document_resource.rb', line 814 def fully_signed?(document_id) doc = details(document_id) return true if doc['status'] == 'certificated' summary = doc.dig('assignment', 'summary') if summary && summary['signer_count'].is_a?(Integer) summary['signer_count'] > 0 && summary['signer_count'] == summary['completed_count'] else false end end |
#list(params = {}, account_id_override = nil) ⇒ Hash{Symbol=>Array,Hash}
List documents for an account.
119 120 121 122 123 124 125 |
# File 'lib/assinafy/resources/document_resource.rb', line 119 def list(params = {}, account_id_override = nil) acc_id = account_id(account_id_override) call_list('Failed to list documents') do http_get("accounts/#{acc_id}/documents", params) end end |
#list_tags(document_id, account_id_override = nil) ⇒ Array<Hash>
List tags attached to a document.
703 704 705 706 707 708 709 710 |
# File 'lib/assinafy/resources/document_resource.rb', line 703 def (document_id, account_id_override = nil) acc_id = account_id(account_id_override) doc_id = require_id(document_id, 'Document ID') call_array('Failed to list document tags') do http_get("accounts/#{acc_id}/documents/#{doc_id}/tags") end end |
#public_info(document_id) ⇒ Hash
Fetch the unauthenticated, public-facing metadata of a document. The OpenAPI declares the full Document schema, while the current sandbox returns the smaller payload shown below; the SDK passes either through.
614 615 616 617 618 619 620 |
# File 'lib/assinafy/resources/document_resource.rb', line 614 def public_info(document_id) doc_id = require_id(document_id, 'Document ID') call('Failed to fetch public document info') do http_get("public/documents/#{doc_id}", {}, workspace_auth: false) end end |
#rename(document_id, name) ⇒ Hash
Rename a document.
266 267 268 269 270 271 272 273 |
# File 'lib/assinafy/resources/document_resource.rb', line 266 def rename(document_id, name) doc_id = require_id(document_id, 'Document ID') new_name = require_present(name, 'Name') call('Failed to rename document') do http_patch("documents/#{doc_id}", body_params(name: new_name)) end end |
#replace_tags(document_id, tags, account_id_override = nil) ⇒ Array<Hash>
Replace the document's full tag set. Passing an empty array detaches all tags from the document.
736 737 738 739 740 741 742 743 744 |
# File 'lib/assinafy/resources/document_resource.rb', line 736 def (document_id, , account_id_override = nil) acc_id = account_id(account_id_override) doc_id = require_id(document_id, 'Document ID') call_array('Failed to replace document tags') do http_put("accounts/#{acc_id}/documents/#{doc_id}/tags", body_params(tags: tag_names(, allow_empty: true))) end end |
#search(query, params = {}, account_id_override = nil) ⇒ Hash{Symbol=>Array,Hash}
Lightweight search over an account's documents (id/name/status/artifacts), without the heavier per-document detail returned by #list.
159 160 161 162 163 164 165 166 |
# File 'lib/assinafy/resources/document_resource.rb', line 159 def search(query, params = {}, account_id_override = nil) acc_id = account_id(account_id_override) filters = require_payload(params, 'Document search parameters') call_list('Failed to search documents') do http_get("accounts/#{acc_id}/documents/search", filters.merge(search: query)) end end |
#send_token(document_id, recipient: nil, channel: nil, email: nil) ⇒ nil, Hash
Send a 6-digit access token for the document to a signer (public endpoint).
The current OpenAPI permits no body or an { email: } body, while the
deployed sandbox requires { recipient:, channel: } when a recipient is supplied.
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
# File 'lib/assinafy/resources/document_resource.rb', line 658 def send_token(document_id, recipient: nil, channel: nil, email: nil) doc_id = require_id(document_id, 'Document ID') if email.nil? && recipient.nil? && channel.nil? payload = nil elsif !email.nil? if recipient || channel raise ValidationError.new('Use either email or recipient/channel, not both') end payload = { email: require_present(email, 'Email') } else require_present(recipient, 'Recipient') delivery_channel = require_present(channel, 'Channel').to_s unless %w[email whatsapp].include?(delivery_channel) raise ValidationError.new('Channel must be email or whatsapp') end payload = { recipient: recipient, channel: delivery_channel } end call('Failed to send signer token') do http_put("public/documents/#{doc_id}/send-token", payload && body_params(payload), workspace_auth: false) end end |
#signing_progress(document_id) ⇒ Hash{Symbol=>Integer,Float}
Convenience: derive a total, pending, percentage progress Hash from the document's assignment summary.
837 838 839 840 841 842 843 844 845 846 847 848 |
# File 'lib/assinafy/resources/document_resource.rb', line 837 def signing_progress(document_id) doc = details(document_id) summary = doc.dig('assignment', 'summary') signers = doc.dig('assignment', 'signers') || [] total = (summary && summary['signer_count']) || signers.length signed = (summary && summary['completed_count']) || 0 pending = [total - signed, 0].max percentage = total > 0 ? (signed.to_f / total * 10_000).round / 100.0 : 0.0 { signed: signed, total: total, pending: pending, percentage: percentage } end |
#statuses ⇒ Array<Hash>
List the catalog of document status codes.
190 191 192 193 194 |
# File 'lib/assinafy/resources/document_resource.rb', line 190 def statuses call_array('Failed to list document statuses') do http_get('documents/statuses') end end |
#thumbnail(document_id) ⇒ String
Download the document thumbnail (PNG/JPEG bytes).
374 375 376 377 378 379 380 |
# File 'lib/assinafy/resources/document_resource.rb', line 374 def thumbnail(document_id) doc_id = require_id(document_id, 'Document ID') call_binary('Failed to download document thumbnail') do http_get("documents/#{doc_id}/thumbnail") end end |
#upload(source, options = {}) ⇒ Hash
The SDK enforces the .pdf extension and 25 MB limit; the API
performs authoritative PDF-structure validation.
Upload a PDF and create a document.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/assinafy/resources/document_resource.rb', line 56 def upload(source, = {}) = require_payload(, 'Upload options') buffer, file_name = read_source(source, max_bytes: MAX_UPLOAD_BYTES) validate_pdf_source!(buffer, file_name, max_bytes: MAX_UPLOAD_BYTES) acc_id = account_id([:account_id]) @logger.info("Uploading document (#{buffer.bytesize} bytes)") payload = { file: file_part(buffer, file_name, 'application/pdf') } payload[:name] = [:name] if [:name] document = call('Document upload failed') do http_post("accounts/#{acc_id}/documents", payload) end document_id = uploaded_document_id(document) @logger.info("Document uploaded: #{document_id}") document end |
#verify(hash) ⇒ Hash
Verify a certificated document by its signature hash.
587 588 589 590 591 592 593 |
# File 'lib/assinafy/resources/document_resource.rb', line 587 def verify(hash) h = require_id(hash, 'Signature hash') call('Failed to verify document') do http_get("documents/#{h}/verify", {}, workspace_auth: false) end end |
#wait_until_ready(document_id, max_wait_seconds: 30, poll_interval_seconds: 2) ⇒ Hash
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
# File 'lib/assinafy/resources/document_resource.rb', line 294 def wait_until_ready(document_id, max_wait_seconds: 30, poll_interval_seconds: 2) doc_id = require_id(document_id, 'Document ID') unless max_wait_seconds.is_a?(Numeric) && max_wait_seconds > 0 && poll_interval_seconds.is_a?(Numeric) && poll_interval_seconds > 0 raise ValidationError.new('Wait and poll intervals must be positive numbers') end clock = Process::CLOCK_MONOTONIC deadline = Process.clock_gettime(clock) + max_wait_seconds attempts = 0 # @type var last_document: Assinafy::api_object? last_document = nil @logger.info("Waiting for document to be ready: #{doc_id}") while Process.clock_gettime(clock) < deadline attempts += 1 begin doc = last_document = details(doc_id) status = doc['status'] || 'unknown' @logger.debug("Document status check #{attempts}: #{status}") return doc if READY_STATUSES.include?(status) raise_processing_error!(doc_id, doc, status) if FAILED_STATUSES.include?(status) rescue NetworkError => e @logger.warn("Error checking document status: #{e.}") end remaining = deadline - Process.clock_gettime(clock) break unless remaining > 0 sleep([poll_interval_seconds, remaining].min) end raise Assinafy::Error.new( 'Timeout waiting for document to be ready', { document_id: doc_id, attempts: attempts, document: last_document } ) end |