Class: Anvil::Signature

Inherits:
Resources::Base show all
Defined in:
lib/anvil/resources/signature.rb

Constant Summary collapse

STATUSES =

Etch packet statuses

%w[draft sent partial_complete complete].freeze

Instance Attribute Summary

Attributes inherited from Resources::Base

#attributes, #client

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Resources::Base

#==, build_from_response, #initialize, #inspect, #method_missing, #respond_to_missing?, #to_h, #to_json, with_client

Constructor Details

This class inherits a constructor from Anvil::Resources::Base

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Anvil::Resources::Base

Class Method Details

.create(name:, signers:, files: nil, **options) ⇒ Signature

Create a new signature packet

Parameters:

  • name (String)

    Name of the packet

  • signers (Array<Hash>)

    Array of signer information

  • files (Array<Hash>) (defaults to: nil)

    Array of files to sign

  • options (Hash)

    Additional options

Returns:

  • (Signature)

    The created signature packet



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/anvil/resources/signature.rb', line 184

def create(name:, signers:, files: nil, **options)
  api_key = options.delete(:api_key)
  client = api_key ? Client.new(api_key: api_key) : self.client

  payload = build_create_payload(name, signers, files, options)

  # Use full GraphQL endpoint URL
  response = client.post(client.config.graphql_url, {
                           query: create_packet_mutation,
                           variables: { input: payload }
                         })

  data = response.data
  unless data[:data] && data[:data][:createEtchPacket]
    raise APIError, "Failed to create signature packet: #{data[:errors]}"
  end

  new(data[:data][:createEtchPacket], client: client)
end

.find(packet_eid, client: nil) ⇒ Object

Find a signature packet by ID

Raises:



205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/anvil/resources/signature.rb', line 205

def find(packet_eid, client: nil)
  client ||= self.client

  response = client.post(client.config.graphql_url, {
                           query: find_packet_query,
                           variables: { eid: packet_eid }
                         })

  data = response.data
  raise NotFoundError, "Signature packet not found: #{packet_eid}" unless data[:data] && data[:data][:etchPacket]

  new(data[:data][:etchPacket], client: client)
end

.generate_signing_url(packet_eid:, signer_eid:, client_user_id: nil, client: nil) ⇒ Object

Generate a signing URL for a signer

Raises:



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/anvil/resources/signature.rb', line 240

def generate_signing_url(packet_eid:, signer_eid:, client_user_id: nil, client: nil)
  client ||= self.client

  payload = {
    packetEid: packet_eid,
    signerEid: signer_eid
  }
  payload[:clientUserId] = client_user_id if client_user_id

  response = client.post(client.config.graphql_url, {
                           query: generate_url_mutation,
                           variables: { input: payload }
                         })

  data = response.data
  raise APIError, 'Failed to generate signing URL' unless data[:data] && data[:data][:generateEtchSignURL]

  data[:data][:generateEtchSignURL][:url]
end

.list(limit: 10, offset: 0, status: nil, client: nil) ⇒ Object

List all signature packets



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/anvil/resources/signature.rb', line 220

def list(limit: 10, offset: 0, status: nil, client: nil)
  client ||= self.client

  variables = { limit: limit, offset: offset }
  variables[:status] = status if status

  response = client.post(client.config.graphql_url, {
                           query: list_packets_query,
                           variables: variables
                         })

  data = response.data
  if data[:data] && data[:data][:etchPackets]
    data[:data][:etchPackets].map { |packet| new(packet, client: client) }
  else
    []
  end
end

Instance Method Details

#complete?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/anvil/resources/signature.rb', line 37

def complete?
  status == 'complete'
end

#completed?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/anvil/resources/signature.rb', line 41

def completed?
  complete?
end

#delete!Boolean

Delete the signature packet

Returns:

  • (Boolean)

    true if deleted

Raises:



107
108
109
110
111
112
# File 'lib/anvil/resources/signature.rb', line 107

def delete!
  data = client.graphql(self.class.send(:remove_packet_mutation), variables: { eid: eid })
  raise APIError, "Failed to delete signature packet: #{eid}" unless data

  true
end

#documentsObject

Get documents



68
69
70
# File 'lib/anvil/resources/signature.rb', line 68

def documents
  Array(attributes[:documents])
end

#draft?Boolean

Check packet status

Returns:

  • (Boolean)


25
26
27
# File 'lib/anvil/resources/signature.rb', line 25

def draft?
  status == 'draft'
end

#eidObject



12
13
14
# File 'lib/anvil/resources/signature.rb', line 12

def eid
  attributes[:eid]
end

#expire_tokens!Boolean

Expire all active signing sessions

Returns:

  • (Boolean)

    true if tokens expired

Raises:



155
156
157
158
159
160
161
162
163
# File 'lib/anvil/resources/signature.rb', line 155

def expire_tokens!
  data = client.graphql(
    self.class.send(:expire_signer_tokens_mutation),
    variables: { eid: eid }
  )
  raise APIError, "Failed to expire signer tokens: #{eid}" unless data

  true
end

#idObject



8
9
10
# File 'lib/anvil/resources/signature.rb', line 8

def id
  attributes[:eid] || attributes[:id]
end

#in_progress?Boolean

Has the packet been sent to signers?

Returns:

  • (Boolean)


46
47
48
# File 'lib/anvil/resources/signature.rb', line 46

def in_progress?
  sent? || partially_complete?
end

#nameObject



20
21
22
# File 'lib/anvil/resources/signature.rb', line 20

def name
  attributes[:name]
end

#notify_signer(signer_eid) ⇒ Boolean

Send a reminder notification to a signer

Parameters:

  • signer_eid (String)

    The EID of the signer to notify

Returns:

  • (Boolean)

    true if notification sent

Raises:



130
131
132
133
134
135
136
# File 'lib/anvil/resources/signature.rb', line 130

def notify_signer(signer_eid)
  data = client.graphql(self.class.send(:notify_signer_mutation),
                        variables: { signerEid: signer_eid, packetEid: eid })
  raise APIError, "Failed to notify signer: #{signer_eid}" unless data

  true
end

#partially_complete?Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/anvil/resources/signature.rb', line 33

def partially_complete?
  status == 'partial_complete'
end

#reload!Object

Reload from API



73
74
75
76
77
# File 'lib/anvil/resources/signature.rb', line 73

def reload!
  refreshed = self.class.find(eid, client: client)
  @attributes = refreshed.attributes
  self
end

#send!self

Send a draft packet to signers

Returns:

  • (self)

    The sent signature packet

Raises:



96
97
98
99
100
101
102
# File 'lib/anvil/resources/signature.rb', line 96

def send!
  data = client.graphql(self.class.send(:send_packet_mutation), variables: { eid: eid })
  raise APIError, "Failed to send signature packet: #{eid}" unless data && data[:sendEtchPacket]

  @attributes = symbolize_keys(data[:sendEtchPacket])
  self
end

#sent?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/anvil/resources/signature.rb', line 29

def sent?
  status == 'sent'
end

#signersObject

Get all signers



61
62
63
64
65
# File 'lib/anvil/resources/signature.rb', line 61

def signers
  Array(attributes[:signers]).map do |signer|
    SignatureSigner.new(signer, packet: self)
  end
end

#signing_url(signer_id:, client_user_id: nil) ⇒ Object

Get signing URL for a specific signer



51
52
53
54
55
56
57
58
# File 'lib/anvil/resources/signature.rb', line 51

def signing_url(signer_id:, client_user_id: nil)
  self.class.generate_signing_url(
    packet_eid: eid,
    signer_eid: signer_id,
    client_user_id: client_user_id,
    client: client
  )
end

#skip_signer(signer_eid) ⇒ self

Skip a signer in the signature flow

Parameters:

  • signer_eid (String)

    The EID of the signer to skip

Returns:

  • (self)

    The updated signature packet

Raises:



118
119
120
121
122
123
124
# File 'lib/anvil/resources/signature.rb', line 118

def skip_signer(signer_eid)
  data = client.graphql(self.class.send(:skip_signer_mutation),
                        variables: { signerEid: signer_eid, packetEid: eid })
  raise APIError, "Failed to skip signer: #{signer_eid}" unless data

  reload!
end

#statusObject



16
17
18
# File 'lib/anvil/resources/signature.rb', line 16

def status
  attributes[:status]
end

#update(**options) ⇒ self

Update the signature packet

Parameters:

  • options (Hash)

    Fields to update (name, signers, email_subject, email_body)

Returns:

  • (self)

    The updated signature packet

Raises:



83
84
85
86
87
88
89
90
91
# File 'lib/anvil/resources/signature.rb', line 83

def update(**options)
  payload = build_update_payload(options)

  data = client.graphql(self.class.send(:update_packet_mutation), variables: { eid: eid, input: payload })
  raise APIError, "Failed to update signature packet: #{eid}" unless data && data[:updateEtchPacket]

  @attributes = symbolize_keys(data[:updateEtchPacket])
  self
end

#void!Boolean

Void signed documents

Returns:

  • (Boolean)

    true if voided

Raises:



141
142
143
144
145
146
147
148
149
150
# File 'lib/anvil/resources/signature.rb', line 141

def void!
  data = client.graphql(
    self.class.send(:void_document_group_mutation),
    variables: { eid: eid }
  )
  raise APIError, "Failed to void signature packet: #{eid}" unless data

  reload!
  true
end