diff --git a/.rubocop.yml b/.rubocop.yml
index ab266ac2..623c3db2 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -26,6 +26,9 @@ Style/Documentation:
Lint/MissingSuper:
Enabled: false
+Metrics/ParameterLists:
+ Max: 10
+
Metrics/MethodLength:
Max: 25
Exclude:
diff --git a/app/controllers/api/submissions_controller.rb b/app/controllers/api/submissions_controller.rb
index 433f183a..b5d57583 100644
--- a/app/controllers/api/submissions_controller.rb
+++ b/app/controllers/api/submissions_controller.rb
@@ -9,25 +9,26 @@ module Api
template = current_account.templates.find(params[:template_id])
submissions =
- if (params[:emails] || params[:email]).present?
+ if (emails = (params[:emails] || params[:email]).presence)
Submissions.create_from_emails(template:,
user: current_user,
source: :api,
mark_as_sent: params[:send_email] != 'false',
- emails: params[:emails] || params[:email])
+ emails:)
else
submissions_attrs = normalize_submissions_params!(submissions_params[:submission], template)
- Submissions.create_from_submitters(template:,
- user: current_user,
- source: :api,
- mark_as_sent: params[:send_email] != 'false',
- submissions_attrs:)
+ Submissions.create_from_submitters(
+ template:,
+ user: current_user,
+ source: :api,
+ mark_as_sent: params[:send_email] != 'false',
+ submitters_order: params[:submitters_order] || 'preserved',
+ submissions_attrs:
+ )
end
- submitters = submissions.flat_map(&:submitters)
-
- Submitters.send_signature_requests(submitters, send_email: params[:send_email] != 'false')
+ Submissions.send_signature_requests(submissions, send_email: params[:send_email] != 'false')
render json: submitters
rescue UnknownFieldName, UnknownSubmitterName => e
diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb
index f4a99853..854908d5 100644
--- a/app/controllers/submissions_controller.rb
+++ b/app/controllers/submissions_controller.rb
@@ -26,16 +26,14 @@ class SubmissionsController < ApplicationController
Submissions.create_from_submitters(template: @template,
user: current_user,
source: :invite,
+ submitters_order: params[:preserve_order] == '1' ? 'preserved' : 'random',
mark_as_sent: params[:send_email] == '1',
submissions_attrs: submissions_params[:submission].to_h.values)
end
- submitters = submissions.flat_map(&:submitters)
+ Submissions.send_signature_requests(submissions, params)
- Submitters.send_signature_requests(submitters, params)
-
- redirect_to template_path(@template),
- notice: "#{submitters.size} #{'recipient'.pluralize(submitters.size)} added"
+ redirect_to template_path(@template), notice: 'New recipients have been added'
end
def destroy
diff --git a/app/jobs/process_submitter_completion_job.rb b/app/jobs/process_submitter_completion_job.rb
index 9effc871..89178615 100644
--- a/app/jobs/process_submitter_completion_job.rb
+++ b/app/jobs/process_submitter_completion_job.rb
@@ -4,6 +4,10 @@ class ProcessSubmitterCompletionJob < ApplicationJob
def perform(submitter)
is_all_completed = !submitter.submission.submitters.exists?(completed_at: nil)
+ if !is_all_completed && submitter.submission.submitters_order_preserved?
+ enqueue_next_submitter_request_notification(submitter)
+ end
+
Submissions::EnsureResultGenerated.call(submitter)
if submitter.account.encrypted_configs.exists?(key: EncryptedConfig::WEBHOOK_URL_KEY)
@@ -25,8 +29,23 @@ class ProcessSubmitterCompletionJob < ApplicationJob
SubmitterMailer.completed_email(submitter, user, bcc:).deliver_later!
end
- to = submitter.submission.submitters.order(:completed_at).select(&:email?).map(&:friendly_name).join(', ')
+ to = submitter.submission.submitters.sort_by(&:completed_at).select(&:email?).map(&:friendly_name).join(', ')
SubmitterMailer.documents_copy_email(submitter, to:).deliver_later! if to.present?
end
+
+ def enqueue_next_submitter_request_notification(submitter)
+ next_submitter_item =
+ submitter.submission.template_submitters.find do |e|
+ sub = submitter.submission.submitters.find { |s| s.uuid == e['uuid'] }
+
+ sub.completed_at.blank? && sub.sent_at.blank?
+ end
+
+ return unless next_submitter_item
+
+ next_submitter = submitter.submission.submitters.find { |s| s.uuid == next_submitter_item['uuid'] }
+
+ Submitters.send_signature_requests([next_submitter], send_email: true)
+ end
end
diff --git a/app/jobs/send_submitter_invitation_email_job.rb b/app/jobs/send_submitter_invitation_email_job.rb
new file mode 100644
index 00000000..2bc4fddb
--- /dev/null
+++ b/app/jobs/send_submitter_invitation_email_job.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class SendSubmitterInvitationEmailJob < ApplicationJob
+ def perform(submitter)
+ SubmitterMailer.invitation_email(submitter).deliver_now!
+
+ submitter.sent_at ||= Time.current
+ submitter.save
+ end
+end
diff --git a/app/models/submission.rb b/app/models/submission.rb
index 323b7586..1283c7b5 100644
--- a/app/models/submission.rb
+++ b/app/models/submission.rb
@@ -7,6 +7,7 @@
# id :bigint not null, primary key
# deleted_at :datetime
# source :text not null
+# submitters_order :string not null
# template_fields :text
# template_schema :text
# template_submitters :text
@@ -37,6 +38,7 @@ class Submission < ApplicationRecord
serialize :template_submitters, JSON
attribute :source, :string, default: 'link'
+ attribute :submitters_order, :string, default: 'random'
has_many :template_schema_documents,
->(e) { where(uuid: (e.template_schema.presence || e.template.schema).pluck('attachment_uuid')) },
@@ -50,4 +52,9 @@ class Submission < ApplicationRecord
embed: 'embed',
link: 'link'
}, scope: false, prefix: true
+
+ enum :submitters_order, {
+ random: 'random',
+ preserved: 'preserved'
+ }, scope: false, prefix: true
end
diff --git a/app/views/submissions/_detailed_form.html.erb b/app/views/submissions/_detailed_form.html.erb
index e42e05be..c54fbf4a 100644
--- a/app/views/submissions/_detailed_form.html.erb
+++ b/app/views/submissions/_detailed_form.html.erb
@@ -34,6 +34,7 @@
+ <%= render('submitters_order', f:, template:) if Accounts.can_send_emails?(current_account) %>
<%= render 'send_email', f:, template: %>
<%= render 'send_sms', f: %>
diff --git a/app/views/submissions/_email_form.html.erb b/app/views/submissions/_email_form.html.erb
index 786ccf51..c7513b61 100644
--- a/app/views/submissions/_email_form.html.erb
+++ b/app/views/submissions/_email_form.html.erb
@@ -35,7 +35,10 @@
<% end %>
- <%= render 'send_email', f:, template: %>
+
+ <%= render 'send_email', f:, template: %>
+ <%= render('submitters_order', f:, template:) if Accounts.can_send_emails?(current_account) %>
+
<%= f.button button_title(title: 'Add Recipients'), class: 'base-button' %>
diff --git a/app/views/submissions/_phone_form.html.erb b/app/views/submissions/_phone_form.html.erb
index 1ed62d74..321d6713 100644
--- a/app/views/submissions/_phone_form.html.erb
+++ b/app/views/submissions/_phone_form.html.erb
@@ -38,6 +38,7 @@
<%= render 'send_sms', f: %>
+ <%= render('submitters_order', f:, template:) if Accounts.can_send_emails?(current_account) %>
<%= f.button button_title(title: 'Add Recipients'), class: 'base-button' %>
diff --git a/app/views/submissions/_send_email.html.erb b/app/views/submissions/_send_email.html.erb
index 1aa640ed..1bee1be9 100644
--- a/app/views/submissions/_send_email.html.erb
+++ b/app/views/submissions/_send_email.html.erb
@@ -2,7 +2,7 @@
<% is_smtp_configured = Accounts.can_send_emails?(current_account) %>
<%= f.label :send_email, for: uuid = SecureRandom.uuid, class: 'flex items-center cursor-pointer' do %>
<%= f.check_box :send_email, id: uuid, class: 'base-checkbox', disabled: !is_smtp_configured, checked: is_smtp_configured %>
- Send Email
+ Send emails
<% end %>
<% unless is_smtp_configured %>
diff --git a/app/views/submissions/_submitters_order.html.erb b/app/views/submissions/_submitters_order.html.erb
new file mode 100644
index 00000000..a37de594
--- /dev/null
+++ b/app/views/submissions/_submitters_order.html.erb
@@ -0,0 +1,11 @@
+<% if template.submitters.size > 1 %>
+
+ <%= f.label :preserve_order, for: uuid = SecureRandom.uuid, class: 'flex items-center cursor-pointer' do %>
+ <%= f.check_box :preserve_order, id: uuid, class: 'base-checkbox', checked: template.submissions.last&.submitters_order.in?(['preserved', nil]) %>
+ Preserve submitters order
+
+ <%= svg_icon('info_circle', class: 'w-4 h-4') %>
+
+ <% end %>
+
+<% end %>
diff --git a/db/migrate/20230909213212_add_submitters_order_to_submissions.rb b/db/migrate/20230909213212_add_submitters_order_to_submissions.rb
new file mode 100644
index 00000000..b462f554
--- /dev/null
+++ b/db/migrate/20230909213212_add_submitters_order_to_submissions.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddSubmittersOrderToSubmissions < ActiveRecord::Migration[7.0]
+ class MigrationSubmission < ApplicationRecord
+ self.table_name = 'submissions'
+ end
+
+ def change
+ add_column :submissions, :submitters_order, :string
+
+ MigrationSubmission.where(submitters_order: nil).update_all(submitters_order: 'random')
+
+ change_column_null :submissions, :submitters_order, false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 89264725..c16b0b99 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2023_09_02_171216) do
+ActiveRecord::Schema[7.0].define(version: 2023_09_09_213212) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -101,6 +101,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_02_171216) do
t.text "template_schema"
t.text "template_submitters"
t.text "source", null: false
+ t.string "submitters_order", null: false
t.index ["created_by_user_id"], name: "index_submissions_on_created_by_user_id"
t.index ["template_id"], name: "index_submissions_on_template_id"
end
diff --git a/lib/submissions.rb b/lib/submissions.rb
index b329627b..f1276466 100644
--- a/lib/submissions.rb
+++ b/lib/submissions.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module Submissions
+ DEFAULT_SUBMITTERS_ORDER = 'random'
+
module_function
def update_template_fields!(submission)
@@ -24,9 +26,11 @@ module Submissions
end
end
- def create_from_submitters(template:, user:, submissions_attrs:, source:, mark_as_sent: false)
+ def create_from_submitters(template:, user:, submissions_attrs:, source:, mark_as_sent: false,
+ submitters_order: DEFAULT_SUBMITTERS_ORDER)
submissions_attrs.map do |attrs|
- submission = template.submissions.new(created_by_user: user, source:, template_submitters: template.submitters)
+ submission = template.submissions.new(created_by_user: user, source:,
+ template_submitters: template.submitters, submitters_order:)
attrs[:submitters].each_with_index do |submitter_attrs, index|
uuid =
@@ -36,15 +40,31 @@ module Submissions
next if uuid.blank?
- submission.submitters.new(email: submitter_attrs[:email],
- phone: submitter_attrs[:phone].to_s.gsub(/[^0-9+]/, ''),
- name: submitter_attrs[:name],
- sent_at: mark_as_sent && submitter_attrs[:email].present? ? Time.current : nil,
- values: submitter_attrs[:values] || {},
- uuid:)
+ is_order_sent = submitters_order == 'random' || index.zero?
+
+ submission.submitters.new(
+ email: submitter_attrs[:email],
+ phone: submitter_attrs[:phone].to_s.gsub(/[^0-9+]/, ''),
+ name: submitter_attrs[:name],
+ sent_at: mark_as_sent && submitter_attrs[:email].present? && is_order_sent ? Time.current : nil,
+ values: submitter_attrs[:values] || {},
+ uuid:
+ )
end
submission.tap(&:save!)
end
end
+
+ def send_signature_requests(submissions, params)
+ submissions.each do |submission|
+ if submission.submitters_order_preserved?
+ first_submitter = submission.submitters.find { |e| e.uuid == submission.template_submitters.first['uuid'] }
+
+ Submitters.send_signature_requests([first_submitter], params)
+ else
+ Submitters.send_signature_requests(submission.submitters, params)
+ end
+ end
+ end
end
diff --git a/lib/submitters.rb b/lib/submitters.rb
index a23684bc..ee3b5e8d 100644
--- a/lib/submitters.rb
+++ b/lib/submitters.rb
@@ -35,7 +35,7 @@ module Submitters
submitters.each do |submitter|
next if submitter.email.blank?
- SubmitterMailer.invitation_email(submitter, message: params[:message]).deliver_later!
+ SendSubmitterInvitationEmailJob.perform_later(submitter)
end
end
end