Class: Clickwrap::Import::ExternalReceipt

Inherits:
Object
  • Object
show all
Defined in:
lib/clickwrap/import/external_receipt.rb

Overview

Clickwrap.import_external_receipt! — record that another system owned the presentation, and say so.

=========================================================================== When Stripe or DocuSign owned the presentation, DO NOT PRETEND YOUR APPLICATION CAPTURED IT.

Someone else rendered the page. Someone else chose the wording, the ordering, the call to action, and whether the control started unselected. Someone else observed the click, if a click is even what happened. Your application learned about it afterwards, through an API response or a webhook, and what you hold is their account of it.

An event written here is therefore built so that it CANNOT be mistaken for a local capture, by a person or by a query:

* `event_type` is `external_receipt`, not `capture`;
* `capture_channel` is `imported_provider`;
* `attribution_method` is `imported_provider`;
* there is NO presentation manifest and no manifest digest, because
there is no offer of ours to reproduce;
* `Event#human_action?` is false, so it never satisfies a predicate that
asks whether a person acted through a Clickwrap presentation; and
* the receipt carries the provider's name, their event id, their raw
receipt, and the validation state of whatever check we ran on it.

It participates in host verification — this is real evidence and refusing to record it would only push it somewhere worse — but it participates as what it is. A provider receipt is upgraded into no guarantee the provider did not make.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(policy:, actor:, provider_name:, provider_event_id:, provider_receipt: nil, verified_with: nil, verified_at: nil, occurred_at: nil, subject: nil, tenant: nil, because: nil, statements: nil) ⇒ ExternalReceipt

Returns a new instance of ExternalReceipt.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/clickwrap/import/external_receipt.rb', line 37

def initialize(policy:, actor:, provider_name:, provider_event_id:, provider_receipt: nil,
               verified_with: nil, verified_at: nil, occurred_at: nil, subject: nil,
               tenant: nil, because: nil, statements: nil)
  @policy = policy
  @actor = actor
  @provider_name = provider_name.to_s
  @provider_event_id = provider_event_id.to_s
  @provider_receipt = provider_receipt
  @verified_with = verified_with&.to_s
  @verified_at = coerce_time(verified_at)
  @occurred_at = coerce_time(occurred_at)
  @subject = subject
  @tenant = tenant
  @because = because
  @statement_keys = statements&.map(&:to_s)
end

Instance Attribute Details

#actorObject (readonly)

Returns the value of attribute actor.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def actor
  @actor
end

#becauseObject (readonly)

Returns the value of attribute because.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def because
  @because
end

#occurred_atObject (readonly)

Returns the value of attribute occurred_at.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def occurred_at
  @occurred_at
end

#policyObject (readonly)

Returns the value of attribute policy.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def policy
  @policy
end

#provider_event_idObject (readonly)

Returns the value of attribute provider_event_id.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def provider_event_id
  @provider_event_id
end

#provider_nameObject (readonly)

Returns the value of attribute provider_name.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def provider_name
  @provider_name
end

#provider_receiptObject (readonly)

Returns the value of attribute provider_receipt.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def provider_receipt
  @provider_receipt
end

#subjectObject (readonly)

Returns the value of attribute subject.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def subject
  @subject
end

#tenantObject (readonly)

Returns the value of attribute tenant.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def tenant
  @tenant
end

#verified_atObject (readonly)

Returns the value of attribute verified_at.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def verified_at
  @verified_at
end

#verified_withObject (readonly)

Returns the value of attribute verified_with.



54
55
56
# File 'lib/clickwrap/import/external_receipt.rb', line 54

def verified_with
  @verified_with
end

Instance Method Details

#idempotency_keyObject

One provider event is one Clickwrap event, forever. A webhook delivered three times, a reconciliation sweep, and a backfill script all land on the same key, so the same provider receipt cannot become two pieces of evidence that an auditor would have to reconcile by hand.



89
90
91
# File 'lib/clickwrap/import/external_receipt.rb', line 89

def idempotency_key
  "external_receipt:#{provider_name}:#{provider_event_id}"
end

#import!Object Also known as: call

Returns the Clickwrap::Event, not a Receipt. Callers of an importer almost always want to look straight at the labelling — event_type, capture_channel, provider_name, and the deliberately absent presentation_manifest_digest — because that labelling is the point. Clickwrap.receipt(event.id) is one call away when a receipt is wanted.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/clickwrap/import/external_receipt.rb', line 62

def import!
  validate!

  existing = Event.find_by(policy_key: policy.key, idempotency_key: idempotency_key)
  return existing if existing

  now = Clickwrap.now
  revision = PolicyRevision.freeze_for(policy)
  event = nil

  ::ActiveRecord::Base.transaction do
    event = build_event(now, revision)
    build_statements(event, now)

    event.save!
    event.finalize_integrity!
  end

  event
end