Class: Agreement

Inherits:
ApplicationRecord show all
Includes:
Models::Auditable
Defined in:
app/models/agreement.rb

Overview

== Schema Information

Table name: agreements
Database name: primary

id :bigint not null, primary key
contract_number :string
contract_pdf_url :text
description :text
reference_number :string
resource_type :string
sign_method :string
signed_date :datetime
state :string
template :string
test :boolean default(FALSE)
title :string
created_at :datetime not null
updated_at :datetime not null
resource_id :integer

Indexes

idx_agreements_state (state)

Constant Summary collapse

TEMPLATES =

Templates.

{ installer_agreement: 'd6d88c27-ca08-452b-9559-e0b499d97a6b' }.freeze
RESOURCE_TYPES =

Recognised resource types.

%w[Certification].freeze
REFERENCE_NUMBER_PATTERN =

Regex pattern matching reference number.

/^.AG\d+/i

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Constants included from Schedulable

Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#sign_methodObject (readonly)



36
# File 'app/models/agreement.rb', line 36

validates :sign_method, presence: true

Class Method Details

.pendingActiveRecord::Relation<Agreement>

A relation of Agreements that are pending. Active Record Scope

Returns:

See Also:



52
# File 'app/models/agreement.rb', line 52

scope :pending, -> { where(state: :pending) }

.select_for_templatesObject



147
148
149
# File 'app/models/agreement.rb', line 147

def self.select_for_templates
  TEMPLATES.map { |a| [a.first.to_s.titleize, a.first.to_s] }
end

.sign_methodsObject



131
132
133
# File 'app/models/agreement.rb', line 131

def self.sign_methods
  %w[esignatures manual]
end

Instance Method Details

#agreement_participantsActiveRecord::Relation<AgreementParticipant>

Returns:

See Also:



32
# File 'app/models/agreement.rb', line 32

has_many :agreement_participants, inverse_of: :agreement


151
152
153
# File 'app/models/agreement.rb', line 151

def agreement_return_link
  "#{WEB_URL}/agreements/#{id}/verify_esignature"
end

#can_be_retrieved?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'app/models/agreement.rb', line 143

def can_be_retrieved?
  uploads.empty? && is_esignature?
end

#communication_template_system_codeObject



224
225
226
# File 'app/models/agreement.rb', line 224

def communication_template_system_code
  'AGREEMENT_UPDATE'
end

#complete_signatureObject



166
167
168
169
170
171
172
173
174
# File 'app/models/agreement.rb', line 166

def complete_signature
  update(signed_date: Time.current)
  agreement_participants.each do |ap|
    ap.update(signed_date: Time.current, signed: true) unless ap.signed?
  end
  return unless resource.is_a?(Certification) && resource.pending?

  resource.request
end


155
156
157
158
159
# File 'app/models/agreement.rb', line 155

def contract_link
  return if contract_number.blank?

  "https://esignatures.io/contracts/#{contract_number}"
end

#is_esignature?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'app/models/agreement.rb', line 135

def is_esignature?
  sign_method == 'esignatures'
end

#is_manual_signature?Boolean

Returns:

  • (Boolean)


139
140
141
# File 'app/models/agreement.rb', line 139

def is_manual_signature?
  sign_method == 'manual'
end

#resourceResource

Returns:

  • (Resource)

See Also:



30
# File 'app/models/agreement.rb', line 30

belongs_to :resource, polymorphic: true, optional: true

#retrieve_esignatures_attachmentObject



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'app/models/agreement.rb', line 228

def retrieve_esignatures_attachment
  return if uploads.any?

  res = Api::Esignatures.retrieve_contract(contract_number)
  contract = JSON.parse(res.body).deep_symbolize_keys[:data]
  update(contract_pdf_url: contract[:contract_pdf_url]) if contract[:contract_pdf_url].present? && contract_pdf_url.nil?

  begin
    if contract_pdf_url.present?
      Upload.uploadify_from_url(file_name: "agreement_#{reference_number}.pdf",
                                url: contract_pdf_url,
                                category: 'agreement_pdf',
                                resource: self)
    end
  rescue StandardError => e
    ErrorReporting.error(e)
    false
  end
end

#send_contract_to_esignatureObject



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'app/models/agreement.rb', line 176

def send_contract_to_esignature
  options = {
    template_id: TEMPLATES[template.to_sym],
    test: Rails.env.development?,
    signers: [],
    custom_branding: {
      company_name: 'WarmlyYours.com',
      logo_url: 'https://ik.warmlyyours.com/img/logo-red-5087d4.png'
    },
    emails: {
      signature_request_subject: 'Your document is ready to sign'
    },
    placeholder_fields: [
      {
        api_key: 'date',
        value: Date.current.to_s
      }
    ]
  }
  agreement_participants.each do |ap|
    options[:signers] << {
      name: ap.party.full_name,
      email: ap.party.email,
      phone: ap.party.phone,
      redirect_url: agreement_return_link
    }
  end

  res = Api::Esignatures.new_contract(options)
  json_res = JSON.parse(res.body).deep_symbolize_keys
  contract = json_res[:data][:contract]

  return false if contract.blank?

  self.contract_number = contract[:id]
  contract[:signers].each do |signer|
    result = agreement_participants.joins(party: :contact_points).merge(ContactPoint.emails.where(detail: signer[:email]))
    result = agreement_participants if result.blank? # If result is zero, then get the particpant that we already have.
    participant = result.first # Assume we only get 1 result as there shouldn't be different participants with the same email.
    Mailer.admin_notification("Agreement #{id} with duplicate participants.", exc) if result.size > 1
    participant.sign_page_url = signer[:sign_page_url]
    participant.signer_reference = signer[:id]
    participant.save
  end
  save
  true
end

#set_reference_numberObject



123
124
125
126
127
128
129
# File 'app/models/agreement.rb', line 123

def set_reference_number
  return if reference_number.present?

  # getting number from a shared sequence now
  next_reference_number = Agreement.next_sequence_value('reference_numbers_seq')
  self.reference_number = "AG#{next_reference_number}"
end

#uploadsActiveRecord::Relation<Upload>

Returns:

  • (ActiveRecord::Relation<Upload>)

See Also:



33
# File 'app/models/agreement.rb', line 33

has_many :uploads, as: :resource, dependent: :destroy

#withdrawObject



161
162
163
164
# File 'app/models/agreement.rb', line 161

def withdraw
  Api::Esignatures.withdraw_contract(contract_number) if contract_number.present?
  true
end