diff --git a/app/views/shared/_settings_nav.html.erb b/app/views/shared/_settings_nav.html.erb
index ab414a4b..b4aad85c 100644
--- a/app/views/shared/_settings_nav.html.erb
+++ b/app/views/shared/_settings_nav.html.erb
@@ -16,6 +16,9 @@
<%= link_to 'Storage', settings_storage_index_path, class: 'text-base hover:bg-base-300' %>
+
+ <%= link_to 'SMS', settings_sms_path, class: 'text-base hover:bg-base-300' %>
+
<% end %>
<%= link_to 'E-Signature', settings_esign_path, class: 'text-base hover:bg-base-300' %>
diff --git a/app/views/sms_settings/_placeholder.html.erb b/app/views/sms_settings/_placeholder.html.erb
new file mode 100644
index 00000000..4e8d5d62
--- /dev/null
+++ b/app/views/sms_settings/_placeholder.html.erb
@@ -0,0 +1,11 @@
+
+ <%= svg_icon('info_circle', class: 'w-6 h-6') %>
+
+
Send signature requests via SMS
+
+ Unlock with DocuSeal Enterprise
+
+ ">Learn More
+
+
+
diff --git a/app/views/sms_settings/index.html.erb b/app/views/sms_settings/index.html.erb
new file mode 100644
index 00000000..ce3d516c
--- /dev/null
+++ b/app/views/sms_settings/index.html.erb
@@ -0,0 +1,8 @@
+
+ <%= render 'shared/settings_nav' %>
+
+
SMS
+ <%= render 'placeholder' %>
+
+
+
diff --git a/app/views/submissions/_detailed_form.html.erb b/app/views/submissions/_detailed_form.html.erb
new file mode 100644
index 00000000..6c7aecdc
--- /dev/null
+++ b/app/views/submissions/_detailed_form.html.erb
@@ -0,0 +1,43 @@
+<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
+
+
+
+
+
+
+ <% template.submitters.each do |item| %>
+
+ <% end %>
+
+
+
+
+
+ <%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
+ Add Recipient
+
+
+
+ <%= render 'send_email', f:, template: %>
+ <%= render 'send_sms', f: %>
+
+
+ <%= f.button button_title(title: 'Add Recipients'), class: 'base-button' %>
+
+<% end %>
diff --git a/app/views/submissions/_email_form.html.erb b/app/views/submissions/_email_form.html.erb
new file mode 100644
index 00000000..46f18110
--- /dev/null
+++ b/app/views/submissions/_email_form.html.erb
@@ -0,0 +1,42 @@
+<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
+ <% if template.submitters.size == 1 %>
+
+ <% else %>
+
+
+
+
+
+
+ <% template.submitters.each do |item| %>
+
+
+
+
+
+ <% end %>
+
+
+
+
+
+ <%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
+ Add Recipient
+
+
+ <% end %>
+ <%= render 'send_email', f:, template: %>
+
+ <%= f.button button_title(title: 'Add Recipients'), class: 'base-button' %>
+
+<% end %>
diff --git a/app/views/submissions/_phone_form.html.erb b/app/views/submissions/_phone_form.html.erb
new file mode 100644
index 00000000..aac741c1
--- /dev/null
+++ b/app/views/submissions/_phone_form.html.erb
@@ -0,0 +1,44 @@
+<%= form_for '', url: template_submissions_path(template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
+
+
+
+ <%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
+ Add Recipient
+
+
+ <%= render 'send_sms', f: %>
+
+ <%= f.button button_title(title: 'Add Recipients'), class: 'base-button' %>
+
+<% end %>
diff --git a/app/views/submissions/_send_email.html.erb b/app/views/submissions/_send_email.html.erb
new file mode 100644
index 00000000..f131fc12
--- /dev/null
+++ b/app/views/submissions/_send_email.html.erb
@@ -0,0 +1,37 @@
+
+<% unless AccountConfig.exists?(key: AccountConfig::SUBMITTER_INVITATION_EMAIL_KEY) %>
+
+<% end %>
diff --git a/app/views/submissions/_send_sms.html.erb b/app/views/submissions/_send_sms.html.erb
new file mode 100644
index 00000000..4637e3ac
--- /dev/null
+++ b/app/views/submissions/_send_sms.html.erb
@@ -0,0 +1,3 @@
+
+ <%= render 'sms_settings/placeholder' %>
+
diff --git a/app/views/submissions/_send_sms_button.html.erb b/app/views/submissions/_send_sms_button.html.erb
new file mode 100644
index 00000000..5658b2a8
--- /dev/null
+++ b/app/views/submissions/_send_sms_button.html.erb
@@ -0,0 +1,5 @@
+
+
+ <%= link_to submitter.sent_at? ? 'Re-send SMS' : 'Send SMS', "#{Docuseal::CONSOLE_URL}/#{Docuseal.multitenant? ? 'plans' : 'on_premise'}", class: 'btn btn-sm btn-primary text-gray-400 w-full' %>
+
+
diff --git a/app/views/submissions/new.html.erb b/app/views/submissions/new.html.erb
index e6d964da..c0241180 100644
--- a/app/views/submissions/new.html.erb
+++ b/app/views/submissions/new.html.erb
@@ -1,81 +1,26 @@
-<%= render 'shared/turbo_modal', title: 'New Recipients' do %>
- <%= form_for '', url: template_submissions_path(@template), html: { class: 'space-y-4', autocomplete: 'off' }, data: { turbo_frame: :_top } do |f| %>
- <% if @template.submitters.size == 1 %>
-
- <% else %>
-
-
-
-
-
-
- <% @template.submitters.each do |item| %>
-
-
-
-
-
- <% end %>
-
-
-
-
-
- <%= svg_icon('user_plus', class: 'w-4 h-4 stroke-2') %>
- Add Recipient
-
-
- <% end %>
-
- <% if Accounts.can_send_emails?(@submitter.submission.template.account) %>
+ <% if Accounts.can_send_emails?(@submitter.submission.template.account) && @submitter.email.present? %>
<%= button_to button_title(title: 'Send copy to Email', disabled_with: 'Sending', icon: svg_icon('mail_forward', class: 'w-6 h-6')), send_submission_email_index_path, params: { submitter_slug: @submitter.slug }, form: { onsubmit: 'event.submitter.disabled = true' }, class: 'white-button w-full' %>
OR
<% end %>
diff --git a/app/views/submit_form/show.html.erb b/app/views/submit_form/show.html.erb
index c998d401..8567844f 100644
--- a/app/views/submit_form/show.html.erb
+++ b/app/views/submit_form/show.html.erb
@@ -33,7 +33,7 @@
diff --git a/app/views/templates/_submission.html.erb b/app/views/templates/_submission.html.erb
new file mode 100644
index 00000000..16dc6015
--- /dev/null
+++ b/app/views/templates/_submission.html.erb
@@ -0,0 +1,116 @@
+<% status_badges = { 'awaiting' => 'badge-info', 'sent' => 'badge-info', 'completed' => 'badge-success', 'opened' => 'badge-warning' } %>
+
+ <% submitters = (submission.template_submitters || submission.template.submitters).filter_map { |item| submission.submitters.find { |e| e.uuid == item['uuid'] } } %>
+ <% is_submission_completed = submitters.all?(&:completed_at?) %>
+ <% if submitters.size == 1 %>
+
+ <% submitter = submitters.first %>
+
+
+
+
+ <%= submitter.status %>
+
+
+
+ <%= submitter.name || submitter.email || submitter.phone %>
+
+
+
+
+
+ <% if submitter.completed_at? %>
+
+ <% else %>
+ <%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-sm btn-neutral text-white md:w-36 flex', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy Link', copy_title_md: 'Copy', copied_title_md: 'Copied' %>
+ <% end %>
+ View
+ <%= button_to button_title(title: nil, disabled_with: 'Remov', icon: svg_icon('trash', class: 'w-6 h-6')), submission_path(submission), class: 'btn btn-outline btn-sm', title: 'Delete', method: :delete, data: { turbo_confirm: 'Are you sure?' }, onclick: 'event.stopPropagation()' %>
+
+ <% else %>
+
+
+ <% if is_submission_completed %>
+ <% latest_submitter = submitters.select(&:completed_at?).max_by(&:completed_at) %>
+
+
+ <%= latest_submitter.status %>
+
+
+ <% end %>
+
+ <% submitters.each_with_index do |submitter, index| %>
+
+
+ <% unless is_submission_completed %>
+
+
+ <%= submitter.status %>
+
+
+ <% end %>
+
+ <%= submitter.name || submitter.email || submitter.phone %>
+
+
+ <% if submitter.completed_at? && !is_submission_completed %>
+
+ <% elsif !is_submission_completed %>
+
+ <%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-xs text-xs btn-neutral text-white md:w-36 flex', icon_class: 'w-4 h-4 text-white', copy_title: 'Copy Link' %>
+
+ <% end %>
+
+ <% end %>
+
+
+
+
+ <% if is_submission_completed %>
+ <% latest_submitter = submitters.select(&:completed_at?).max_by(&:completed_at) %>
+
+ <% end %>
+ View
+ <%= button_to button_title(title: nil, disabled_with: 'Remov', icon: svg_icon('trash', class: 'w-6 h-6')), submission_path(submission), class: 'btn btn-outline btn-sm', title: 'Delete', method: :delete, data: { turbo_confirm: 'Are you sure?' }, onclick: 'event.stopPropagation()' %>
+
+ <% end %>
+
diff --git a/app/views/templates/show.html.erb b/app/views/templates/show.html.erb
index 73f730d5..c7d9dd2e 100644
--- a/app/views/templates/show.html.erb
+++ b/app/views/templates/show.html.erb
@@ -38,126 +38,9 @@
<% end %>
-<% status_badges = { 'awaiting' => 'badge-info', 'sent' => 'badge-info', 'completed' => 'badge-success', 'opened' => 'badge-warning' } %>
<% if @submissions.present? %>
- <% @submissions.each do |submission| %>
-
- <% submitters = (submission.template_submitters || submission.template.submitters).filter_map { |item| submission.submitters.find { |e| e.uuid == item['uuid'] } } %>
- <% is_submission_completed = submitters.all?(&:completed_at?) %>
- <% if submitters.size == 1 %>
-
- <% submitter = submitters.first %>
-
-
-
-
- <%= submitter.status %>
-
-
-
- <%= submitter.email %>
-
-
-
-
-
- <% if submitter.completed_at? %>
-
- <% else %>
- <%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-sm btn-neutral text-white md:w-36 flex', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy Link' %>
- <% end %>
- View
- <%= button_to button_title(title: nil, disabled_with: 'Remov', icon: svg_icon('trash', class: 'w-6 h-6')), submission_path(submission), class: 'btn btn-outline btn-sm', title: 'Delete', method: :delete, data: { turbo_confirm: 'Are you sure?' }, onclick: 'event.stopPropagation()' %>
-
- <% else %>
-
-
- <% if is_submission_completed %>
- <% latest_submitter = submitters.select(&:completed_at?).max_by(&:completed_at) %>
-
-
- <%= latest_submitter.status %>
-
-
- <% end %>
-
- <% submitters.each_with_index do |submitter, index| %>
-
-
- <% unless is_submission_completed %>
-
-
- <%= submitter.status %>
-
-
- <% end %>
-
- <%= submitter.email %>
-
-
- <% if submitter.completed_at? && !is_submission_completed %>
-
- <% elsif !is_submission_completed %>
-
- <%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-xs text-xs btn-neutral text-white md:w-36 flex', icon_class: 'w-4 h-4 text-white', copy_title: 'Copy Link' %>
-
- <% end %>
-
- <% end %>
-
-
-
-
- <% if is_submission_completed %>
- <% latest_submitter = submitters.select(&:completed_at?).max_by(&:completed_at) %>
-
- <% end %>
- View
- <%= button_to button_title(title: nil, disabled_with: 'Remov', icon: svg_icon('trash', class: 'w-6 h-6')), submission_path(submission), class: 'btn btn-outline btn-sm', title: 'Delete', method: :delete, data: { turbo_confirm: 'Are you sure?' }, onclick: 'event.stopPropagation()' %>
-
- <% end %>
-
- <% end %>
+ <%= render partial: 'submission', collection: @submissions %>
<%= render 'shared/pagination', pagy: @pagy, items_name: 'submissions' %>
<% else %>
diff --git a/config/routes.rb b/config/routes.rb
index 8904cc7c..688a5464 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -64,6 +64,7 @@ Rails.application.routes.draw do
resources :submitters, only: %i[], param: 'slug' do
resources :download, only: %i[index], controller: 'submissions_download'
+ resources :send_email, only: %i[create], controller: 'submitters_send_email'
resources :debug, only: %i[index], controller: 'submissions_debug' if Rails.env.development?
end
@@ -71,6 +72,7 @@ Rails.application.routes.draw do
unless Docuseal.multitenant?
resources :storage, only: %i[index create], controller: 'storage_settings'
resources :email, only: %i[index create], controller: 'email_settings'
+ resources :sms, only: %i[index], controller: 'sms_settings'
end
resource :esign, only: %i[show create new update destroy], controller: 'esign_settings'
resources :users, only: %i[index]
diff --git a/db/migrate/20230902171216_add_phone_and_name_to_submitters.rb b/db/migrate/20230902171216_add_phone_and_name_to_submitters.rb
new file mode 100644
index 00000000..60a14000
--- /dev/null
+++ b/db/migrate/20230902171216_add_phone_and_name_to_submitters.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddPhoneAndNameToSubmitters < ActiveRecord::Migration[7.0]
+ def change
+ add_column :submitters, :name, :string
+ add_column :submitters, :phone, :string
+
+ change_column_null :submitters, :email, true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8fb1d7f1..89264725 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_08_19_190316) do
+ActiveRecord::Schema[7.0].define(version: 2023_09_02_171216) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -108,7 +108,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_19_190316) do
create_table "submitters", force: :cascade do |t|
t.bigint "submission_id", null: false
t.string "uuid", null: false
- t.string "email", null: false
+ t.string "email"
t.string "slug", null: false
t.text "values", null: false
t.string "ua"
@@ -118,6 +118,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_19_190316) do
t.datetime "completed_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.string "name"
+ t.string "phone"
t.index ["email"], name: "index_submitters_on_email"
t.index ["slug"], name: "index_submitters_on_slug", unique: true
t.index ["submission_id"], name: "index_submitters_on_submission_id"
diff --git a/lib/replace_email_variables.rb b/lib/replace_email_variables.rb
index eba1ac71..33ffa859 100644
--- a/lib/replace_email_variables.rb
+++ b/lib/replace_email_variables.rb
@@ -16,18 +16,22 @@ module ReplaceEmailVariables
slug: submitter.slug, **Docuseal.default_url_options
)
- submission_link =
- Rails.application.routes.url_helpers.submission_url(
- submitter.submission, **Docuseal.default_url_options
- )
+ if submitter.submission
+ submission_link =
+ Rails.application.routes.url_helpers.submission_url(
+ submitter.submission, **Docuseal.default_url_options
+ )
+ end
- text = text.gsub(TEMAPLTE_NAME, submitter.template.name)
- text = text.gsub(SUBMITTER_EMAIL, submitter.email)
+ text = text.gsub(TEMAPLTE_NAME, submitter.template.name) if submitter.template
+ text = text.gsub(SUBMITTER_EMAIL, submitter.email) if submitter.email
text = text.gsub(SUBMITTER_LINK, submitter_link)
- text = text.gsub(SUBMISSION_LINK, submission_link)
+ text = text.gsub(SUBMISSION_LINK, submission_link) if submission_link
text = text.gsub(DOCUMENTS_LINKS, build_documents_links_text(submitter))
- text.gsub(ACCOUNT_NAME, submitter.template.account.name)
+ text.gsub(ACCOUNT_NAME, submitter.template.account.name) if submitter.template
+
+ text
end
def build_documents_links_text(submitter)
diff --git a/lib/submissions.rb b/lib/submissions.rb
index 3a8cbe19..b329627b 100644
--- a/lib/submissions.rb
+++ b/lib/submissions.rb
@@ -11,33 +11,35 @@ module Submissions
submission.save!
end
- def create_from_emails(template:, user:, emails:, source:, send_email: false)
+ def create_from_emails(template:, user:, emails:, source:, mark_as_sent: false)
emails = emails.to_s.scan(User::EMAIL_REGEXP) unless emails.is_a?(Array)
emails.map do |email|
submission = template.submissions.new(created_by_user: user, source:, template_submitters: template.submitters)
submission.submitters.new(email:,
uuid: template.submitters.first['uuid'],
- sent_at: send_email ? Time.current : nil)
+ sent_at: mark_as_sent ? Time.current : nil)
submission.tap(&:save!)
end
end
- def create_from_submitters(template:, user:, submissions_attrs:, source:, send_email: false)
+ def create_from_submitters(template:, user:, submissions_attrs:, source:, mark_as_sent: false)
submissions_attrs.map do |attrs|
submission = template.submissions.new(created_by_user: user, source:, template_submitters: template.submitters)
attrs[:submitters].each_with_index do |submitter_attrs, index|
uuid =
submitter_attrs[:uuid].presence ||
- template.submitters.find { |e| e['name'] == submitter_attrs[:name] }&.dig('uuid') ||
+ template.submitters.find { |e| e['name'] == submitter_attrs[:role] }&.dig('uuid') ||
template.submitters[index]&.dig('uuid')
next if uuid.blank?
submission.submitters.new(email: submitter_attrs[:email],
- sent_at: send_email ? Time.current : nil,
+ 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:)
end
diff --git a/lib/submissions/generate_export_files.rb b/lib/submissions/generate_export_files.rb
index 0cd1e6e0..e490d0ed 100644
--- a/lib/submissions/generate_export_files.rb
+++ b/lib/submissions/generate_export_files.rb
@@ -91,15 +91,23 @@ module Submissions
def build_submission_data(submitter, submitter_name, submitters_count)
[
+ {
+ name: column_name('Name', submitter_name, submitters_count),
+ value: submitter.name
+ },
{
name: column_name('Email', submitter_name, submitters_count),
value: submitter.email
},
+ {
+ name: column_name('Phone', submitter_name, submitters_count),
+ value: submitter.phone
+ },
{
name: column_name('Completed At', submitter_name, submitters_count),
value: submitter.completed_at
}
- ]
+ ].reject { |e| e[:value].blank? }
end
def column_name(name, submitter_name, submitters_count = 1)
diff --git a/lib/submitters.rb b/lib/submitters.rb
index 4b11bb5d..605c4750 100644
--- a/lib/submitters.rb
+++ b/lib/submitters.rb
@@ -28,4 +28,14 @@ module Submitters
record: submitter
)
end
+
+ def send_signature_requests(submitters, params)
+ return unless params[:send_email] == true || params[:send_email] == '1'
+
+ submitters.each do |submitter|
+ next if submitter.email.blank?
+
+ SubmitterMailer.invitation_email(submitter, message: params[:message]).deliver_later!
+ end
+ end
end
diff --git a/lib/submitters/serialize_for_webhook.rb b/lib/submitters/serialize_for_webhook.rb
index f00406de..fbdadc6b 100644
--- a/lib/submitters/serialize_for_webhook.rb
+++ b/lib/submitters/serialize_for_webhook.rb
@@ -14,7 +14,7 @@ module Submitters
.except('uuid', 'values', 'slug')
.merge('values' => values,
'documents' => documents,
- 'submitter_name' => submitter_name)
+ 'role' => submitter_name)
end
def build_values_array(submitter)
diff --git a/spec/system/submit_form_spec.rb b/spec/system/submit_form_spec.rb
index 37504aca..fe9c7957 100644
--- a/spec/system/submit_form_spec.rb
+++ b/spec/system/submit_form_spec.rb
@@ -27,12 +27,12 @@ RSpec.describe 'Submit Form' do
click_button 'Start'
fill_in 'First Name', with: 'Adam'
- click_on 'Next'
+ click_on 'next'
click_on 'type_text_button'
fill_in 'signature_text_input', with: 'Adam'
expect do
- click_on 'Submit'
+ click_on 'submit'
end.not_to(change(Submitter, :count))
submitter = Submitter.find_by(email: 'john.dou@example.com')
@@ -58,10 +58,10 @@ RSpec.describe 'Submit Form' do
it 'completes the form' do
fill_in 'First Name', with: 'Sally'
- click_on 'Next'
+ click_on 'next'
click_on 'type_text_button'
fill_in 'signature_text_input', with: 'Sally'
- click_on 'Submit'
+ click_on 'submit'
submitter.reload
@@ -75,12 +75,12 @@ RSpec.describe 'Submit Form' do
it 'sends completed email' do
fill_in 'First Name', with: 'Adam'
- click_on 'Next'
+ click_on 'next'
click_on 'type_text_button'
fill_in 'signature_text_input', with: 'Adam'
expect do
- click_on 'Submit'
+ click_on 'submit'
end.to change(enqueued_jobs, :size).by(3)
end
end