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 =
{ installer_agreement: 'd6d88c27-ca08-452b-9559-e0b499d97a6b' }
RESOURCE_TYPES =
%w[Certification].freeze
REFERENCE_NUMBER_PATTERN =
/^.AG\d+/i

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

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 Models::EventPublishable

#publish_event

Instance Attribute Details

#sign_methodObject (readonly)



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

validates :sign_method, presence: true

Class Method Details

.pendingActiveRecord::Relation<Agreement>

A relation of Agreements that are pending. Active Record Scope

Returns:

See Also:



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

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

.select_for_templatesObject



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

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

.sign_methodsObject



127
128
129
# File 'app/models/agreement.rb', line 127

def self.sign_methods
  %w[esignatures manual]
end

Instance Method Details

#agreement_participantsActiveRecord::Relation<AgreementParticipant>

Returns:

See Also:



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

has_many :agreement_participants, inverse_of: :agreement


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

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

#can_be_retrieved?Boolean

Returns:

  • (Boolean)


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

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

#communication_template_system_codeObject



220
221
222
# File 'app/models/agreement.rb', line 220

def communication_template_system_code
  'AGREEMENT_UPDATE'
end

#complete_signatureObject



162
163
164
165
166
167
168
169
170
# File 'app/models/agreement.rb', line 162

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


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

def contract_link
  return unless contract_number.present?

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

#is_esignature?Boolean

Returns:

  • (Boolean)


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

def is_esignature?
  sign_method == 'esignatures'
end

#is_manual_signature?Boolean

Returns:

  • (Boolean)


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

def is_manual_signature?
  sign_method == 'manual'
end

#resourceResource

Returns:

  • (Resource)

See Also:



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

belongs_to :resource, polymorphic: true, optional: true

#retrieve_esignatures_attachmentObject



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'app/models/agreement.rb', line 224

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



172
173
174
175
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
# File 'app/models/agreement.rb', line 172

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}"
      }
    ]
  }
  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 unless contract.present?

  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 unless result.present? # 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



119
120
121
122
123
124
125
# File 'app/models/agreement.rb', line 119

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:



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

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

#withdrawObject



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

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