diff --git a/app/controllers/api/submissions_controller.rb b/app/controllers/api/submissions_controller.rb index f1b515eaa..261b9852d 100644 --- a/app/controllers/api/submissions_controller.rb +++ b/app/controllers/api/submissions_controller.rb @@ -167,7 +167,7 @@ def create_submissions(template, params) template:, user: current_user, source: :api, - submitters_order: params[:submitters_order] || params[:order] || 'preserved', + submitters_order: params[:submitters_order] || params[:order] || template.effective_submitters_order, submissions_attrs:, params: ) diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb index 66940486a..76cd0a439 100644 --- a/app/controllers/submissions_controller.rb +++ b/app/controllers/submissions_controller.rb @@ -56,7 +56,7 @@ def create Submissions.create_from_submitters(template: @template, user: current_user, source: :invite, - submitters_order: params[:preserve_order] == '1' ? 'preserved' : 'random', + submitters_order: @template.effective_submitters_order, submissions_attrs: submissions_params[:submission].to_h.values, params: params.merge('send_completed_email' => true)) end diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index 1e0e8e0e8..521ef3cee 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -21,7 +21,9 @@ def show @form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS) return render :awaiting if (@form_configs[:enforce_signing_order] || - submission.template&.preferences&.dig('submitters_order') == 'preserved') && + submission.template_signing_order.in?( + %w[employee_then_manager manager_then_employee] + )) && !Submitters.current_submitter_order?(@submitter) Submissions.preload_with_pages(submission) diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index c98836d18..371f3490a 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -99,8 +99,10 @@ def create end def update - @template.assign_attributes(template_params) + # Capture current submitters_order before any changes + old_submitters_order = @template.preferences['submitters_order'] + @template.assign_attributes(template_params) is_name_changed = @template.name_changed? @template.save! @@ -109,7 +111,13 @@ def update enqueue_template_updated_webhooks(@template) - head :ok + # If submitters_order changed (e.g., fields removed making it single_sided), fire preferences webhook + new_submitters_order = @template.preferences['submitters_order'] + if old_submitters_order != new_submitters_order && new_submitters_order.present? + enqueue_template_preferences_updated_webhooks(@template) + end + + render json: { preferences: @template.preferences } end def destroy @@ -173,6 +181,13 @@ def enqueue_template_updated_webhooks(template) end end + def enqueue_template_preferences_updated_webhooks(template) + WebhookUrls.for_template(template, 'template.preferences_updated').each do |webhook_url| + SendTemplatePreferencesUpdatedWebhookRequestJob.perform_async('template_id' => template.id, + 'webhook_url_id' => webhook_url.id) + end + end + def handle_account_override return unless authorized_clone_account_id?(params[:account_id]) diff --git a/app/controllers/templates_preferences_controller.rb b/app/controllers/templates_preferences_controller.rb index e2ec9ee3b..22cde5711 100644 --- a/app/controllers/templates_preferences_controller.rb +++ b/app/controllers/templates_preferences_controller.rb @@ -1,6 +1,13 @@ # frozen_string_literal: true class TemplatesPreferencesController < ApplicationController + include IframeAuthentication + include PartnershipContext + + skip_before_action :verify_authenticity_token + skip_before_action :authenticate_via_token! + + before_action :authenticate_from_referer load_and_authorize_resource :template def show; end @@ -8,10 +15,23 @@ def show; end def create authorize!(:update, @template) + old_submitters_order = @template.preferences['submitters_order'] @template.preferences = @template.preferences.merge(template_params[:preferences]) - @template.preferences = @template.preferences.reject { |_, v| (v.is_a?(String) || v.is_a?(Hash)) && v.blank? } + @templahttp://app.lvh.me:3000/retain/team/tasks_list_builder/13/editte.preferences = @template.preferences.reject { |_, v| (v.is_a?(String) || v.is_a?(Hash)) && v.blank? } + + # Handle single_sided case (when template has < 2 unique submitters) + if @template.unique_submitter_uuids.size < 2 && @template.preferences['submitters_order'].present? + @template.preferences['submitters_order'] = 'single_sided' + end + @template.save! + # Enqueue webhook if submitters_order changed + new_submitters_order = @template.preferences['submitters_order'] + if old_submitters_order != new_submitters_order && new_submitters_order.present? + enqueue_template_preferences_updated_webhooks(@template) + end + head :ok end @@ -51,4 +71,11 @@ def template_params end end end + + def enqueue_template_preferences_updated_webhooks(template) + WebhookUrls.for_template(template, 'template.preferences_updated').each do |webhook_url| + SendTemplatePreferencesUpdatedWebhookRequestJob.perform_async('template_id' => template.id, + 'webhook_url_id' => webhook_url.id) + end + end end diff --git a/app/models/submission.rb b/app/models/submission.rb index 2abfbb5b4..08424cb08 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -53,7 +53,7 @@ class Submission < ApplicationRecord serialize :preferences, coder: JSON attribute :source, :string, default: 'link' - attribute :submitters_order, :string, default: 'random' + attribute :submitters_order, :string, default: 'employee_then_manager' attribute :slug, :string, default: -> { SecureRandom.base58(14) } @@ -94,10 +94,16 @@ class Submission < ApplicationRecord }, scope: false, prefix: true enum :submitters_order, { - random: 'random', - preserved: 'preserved' + single_sided: 'single_sided', + employee_then_manager: 'employee_then_manager', + manager_then_employee: 'manager_then_employee', + simultaneous: 'simultaneous' }, scope: false, prefix: true + def signing_order_enforced? + template_signing_order.in?(%w[employee_then_manager manager_then_employee]) + end + def expired? expire_at && expire_at <= Time.current end @@ -106,6 +112,10 @@ def last_completed_submitter submitters.where.not(completed_at: nil).order(:completed_at).last end + def template_signing_order + template&.preferences&.dig('submitters_order') + end + def schema_documents if template_id? template_schema_documents diff --git a/app/models/template.rb b/app/models/template.rb index e73991248..18976a6a7 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -54,6 +54,7 @@ class Template < ApplicationRecord has_one :search_entry, as: :record, inverse_of: :record, dependent: :destroy before_validation :maybe_set_default_folder, on: :create + before_save :update_submitters_order, if: :fields_changed? attribute :preferences, :string, default: -> { {} } attribute :fields, :string, default: -> { [] } @@ -87,6 +88,15 @@ def application_key external_id end + def unique_submitter_uuids + fields.filter_map { |f| f['submitter_uuid'] }.uniq + end + + def effective_submitters_order + preferences['submitters_order'].presence || + (unique_submitter_uuids.size < 2 ? 'single_sided' : 'employee_then_manager') + end + private def maybe_set_default_folder @@ -96,4 +106,23 @@ def maybe_set_default_folder self.folder ||= partnership.default_template_folder(author) end end + + def update_submitters_order + submitter_count = unique_submitter_uuids.size + current_order = preferences['submitters_order'] + + if submitter_count < 2 + # Always set to single_sided for templates with 0 or 1 submitter + preferences['submitters_order'] = 'single_sided' + elsif submitter_count == 2 + # Set to employee_then_manager when there are exactly 2 submitters + # Only set if not already configured to something else + if current_order.blank? || current_order == 'single_sided' + preferences['submitters_order'] = 'employee_then_manager' + end + elsif current_order == 'single_sided' + # Clear single_sided if template now has 3+ submitters + preferences.delete('submitters_order') + end + end end diff --git a/lib/params/submission_create_validator.rb b/lib/params/submission_create_validator.rb index 5737e1dd8..6b7649afd 100644 --- a/lib/params/submission_create_validator.rb +++ b/lib/params/submission_create_validator.rb @@ -3,6 +3,7 @@ module Params class SubmissionCreateValidator < BaseValidator def call + binding.pry if params[:submission].blank? && (params[:emails].present? || params[:email].present?) validate_creation_from_emails(params) elsif params.key?(:submitters) @@ -56,7 +57,9 @@ def validate_creation_from_submitters(params) required(message_params, :body) end - value_in(params, :order, %w[preserved random], allow_nil: true) + value_in( + params, :order, %w[employee_then_manager manager_then_employee simultaneous single_sided], allow_nil: true + ) if params[:submitters].present? in_path(params, :submitters) do |submitters_params| @@ -117,7 +120,9 @@ def validate_creation_from_submission(params) required(message_params, :body) end - value_in(params, :order, %w[preserved random], allow_nil: true) + value_in( + params, :order, %w[employee_then_manager manager_then_employee simultaneous single_sided], allow_nil: true + ) return true if params[:submission].is_a?(Array) diff --git a/lib/submissions.rb b/lib/submissions.rb index 0fb3b0e08..1ffba7956 100644 --- a/lib/submissions.rb +++ b/lib/submissions.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Submissions - DEFAULT_SUBMITTERS_ORDER = 'random' + DEFAULT_SUBMITTERS_ORDER = 'single_sided' PRELOAD_ALL_PAGES_AMOUNT = 200 @@ -143,9 +143,18 @@ def send_signature_requests(submissions, delay: nil) submitters = submission.submitters.reject(&:completed_at?) - if submission.submitters_order_preserved? - first_submitter = - submission.template_submitters.filter_map { |s| submitters.find { |e| e.uuid == s['uuid'] } }.first + if submission.signing_order_enforced? + first_submitter = if submission.template_signing_order == 'manager_then_employee' + # For manager_then_employee, send to the second submitter first + submission.template_submitters[1..].filter_map do |s| + submitters.find { |e| e.uuid == s['uuid'] } + end.first + else + # For employee_then_manager and preserved, send to the first submitter + submission.template_submitters.filter_map do |s| + submitters.find { |e| e.uuid == s['uuid'] } + end.first + end Submitters.send_signature_requests([first_submitter], delay_seconds:) if first_submitter else diff --git a/lib/submissions/create_from_submitters.rb b/lib/submissions/create_from_submitters.rb index 4ad407df9..1bf6cca28 100644 --- a/lib/submissions/create_from_submitters.rb +++ b/lib/submissions/create_from_submitters.rb @@ -36,6 +36,9 @@ def call(template:, user:, submissions_attrs:, source:, submitters_order:, param submission.template_schema = submission.template.schema if submission.template_schema.blank? uuid = template_submitter['uuid'] + + # Skip submitters without fields for single_sided forms + next if submitters_order == 'single_sided' && template.unique_submitter_uuids.exclude?(uuid) else if submitter_attrs[:roles].present? && submitter_attrs[:roles].size == 1 submitter_attrs[:role] = submitter_attrs[:roles].first @@ -46,6 +49,9 @@ def call(template:, user:, submissions_attrs:, source:, submitters_order:, param next if uuid.blank? next if submitter_attrs.slice('email', 'phone', 'name').compact_blank.blank? + # Skip submitters without fields for single_sided forms + next if submitters_order == 'single_sided' && template.unique_submitter_uuids.exclude?(uuid) + submission.template_fields = submission.template.fields if submitter_attrs[:completed].present? && submission.template_fields.blank? @@ -54,7 +60,22 @@ def call(template:, user:, submissions_attrs:, source:, submitters_order:, param submission.template_submitters << template_submitter.except('optional_invite_by_uuid', 'invite_by_uuid') - is_order_sent = submitters_order == 'random' || index.zero? + # Find the position of this submitter in the original template submitters array + template_submitter_index = template.submitters.index { |s| s['uuid'] == uuid } + + is_order_sent = case submitters_order + # Legacy + when 'random', 'simultaneous' + true + when 'manager_then_employee' + # Send to second party (index 1) first + template_submitter_index == 1 + when 'employee_then_manager' + # Send to first party (index 0) first + template_submitter_index.zero? + else # 'preserved' Legacy + index.zero? + end build_submitter(submission:, attrs: submitter_attrs, uuid:, is_order_sent:, user:, params:, diff --git a/lib/submitters.rb b/lib/submitters.rb index 7ad012479..21cc7821b 100644 --- a/lib/submitters.rb +++ b/lib/submitters.rb @@ -164,11 +164,14 @@ def send_signature_requests(submitters, delay_seconds: nil) def current_submitter_order?(submitter) submitter_items = submitter.submission.template_submitters || submitter.submission.template.submitters + submitters_order = submitter.submission.template_signing_order - before_items = submitter_items[0...(submitter_items.find_index { |e| e['uuid'] == submitter.uuid })] + ordered_items = submitters_order == 'manager_then_employee' ? submitter_items.reverse : submitter_items - before_items.reduce(true) do |acc, item| - acc && submitter.submission.submitters.find { |e| e.uuid == item['uuid'] }&.completed_at? + before_items = ordered_items[0...ordered_items.find_index { |e| e['uuid'] == submitter.uuid }] + + before_items.all? do |item| + submitter.submission.submitters.find { |e| e.uuid == item['uuid'] }&.completed_at? end end diff --git a/spec/lib/submissions/create_from_submitters_spec.rb b/spec/lib/submissions/create_from_submitters_spec.rb new file mode 100644 index 000000000..9f93fb01b --- /dev/null +++ b/spec/lib/submissions/create_from_submitters_spec.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Submissions::CreateFromSubmitters do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + let(:template) { create(:template, account:, author: user, submitter_count: 2) } + + let(:submitter_attrs) do + template.submitters.map do |s| + HashWithIndifferentAccess.new({ 'uuid' => s['uuid'], 'email' => Faker::Internet.email }) + end + end + + def call(template:, submitters_order:) + described_class.call( + template:, + user:, + submissions_attrs: [HashWithIndifferentAccess.new({ 'submitters' => submitter_attrs })], + source: :api, + submitters_order: + ) + end + + describe 'is_order_sent for employee_then_manager' do + it 'sets sent_at only on the first submitter (Employee)' do + submissions = call(template:, submitters_order: 'employee_then_manager') + submitters = submissions.first.submitters.sort_by { |s| template.submitters.index { |ts| ts['uuid'] == s.uuid } } + + expect(submitters[0].sent_at).not_to be_nil + expect(submitters[1].sent_at).to be_nil + end + end + + describe 'is_order_sent for manager_then_employee' do + it 'sets sent_at only on the second submitter (Manager)' do + submissions = call(template:, submitters_order: 'manager_then_employee') + submitters = submissions.first.submitters.sort_by { |s| template.submitters.index { |ts| ts['uuid'] == s.uuid } } + + expect(submitters[0].sent_at).to be_nil + expect(submitters[1].sent_at).not_to be_nil + end + end + + describe 'is_order_sent for simultaneous' do + it 'sets sent_at on all submitters' do + submissions = call(template:, submitters_order: 'simultaneous') + + expect(submissions.first.submitters).to all(have_attributes(sent_at: be_present)) + end + end + + describe 'single_sided skipping' do + before do + manager_uuid = template.submitters[1]['uuid'] + template.update_column(:fields, template.fields.reject { |f| f['submitter_uuid'] == manager_uuid }) + end + + it 'skips submitters without fields' do + submissions = call(template:, submitters_order: 'single_sided') + submitter_uuids = submissions.first.submitters.map(&:uuid) + + expect(submitter_uuids).to include(template.submitters[0]['uuid']) + expect(submitter_uuids).not_to include(template.submitters[1]['uuid']) + end + end +end diff --git a/spec/lib/submissions_spec.rb b/spec/lib/submissions_spec.rb new file mode 100644 index 000000000..2f89d42eb --- /dev/null +++ b/spec/lib/submissions_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Submissions do + describe '.send_signature_requests' do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + let(:template) { create(:template, account:, author: user, submitter_count: 2) } + let(:submission) { create(:submission, template:, created_by_user: user) } + + let(:employee_uuid) { template.submitters[0]['uuid'] } + let(:manager_uuid) { template.submitters[1]['uuid'] } + + let!(:employee) { create(:submitter, submission:, uuid: employee_uuid) } + let!(:manager) { create(:submitter, submission:, uuid: manager_uuid) } + + before do + allow(Submitters).to receive(:send_signature_requests) + end + + def set_order(order) + template.update_column(:preferences, { 'submitters_order' => order }) + submission.reload + end + + context 'with employee_then_manager order' do + before { set_order('employee_then_manager') } + + it 'sends signature request only to the employee first' do + described_class.send_signature_requests([submission]) + + expect(Submitters).to have_received(:send_signature_requests).with([employee], delay_seconds: nil) + end + end + + context 'with manager_then_employee order' do + before { set_order('manager_then_employee') } + + it 'sends signature request only to the manager first' do + described_class.send_signature_requests([submission]) + + expect(Submitters).to have_received(:send_signature_requests).with([manager], delay_seconds: nil) + end + end + + context 'with simultaneous order' do + before { set_order('simultaneous') } + + it 'sends signature requests to all submitters' do + described_class.send_signature_requests([submission]) + + expect(Submitters).to have_received(:send_signature_requests).with(match_array([employee, manager]), + delay_seconds: nil) + end + end + end +end diff --git a/spec/lib/submitters_spec.rb b/spec/lib/submitters_spec.rb new file mode 100644 index 000000000..b01e4ede2 --- /dev/null +++ b/spec/lib/submitters_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Submitters do + describe '.current_submitter_order?' do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + let(:template) { create(:template, account:, author: user, submitter_count: 2) } + let(:submission) { create(:submission, template:, created_by_user: user) } + + let(:employee_uuid) { template.submitters[0]['uuid'] } + let(:manager_uuid) { template.submitters[1]['uuid'] } + + let!(:employee) { create(:submitter, submission:, uuid: employee_uuid) } + let!(:manager) { create(:submitter, submission:, uuid: manager_uuid) } + + def set_order(order) + template.update_column(:preferences, { 'submitters_order' => order }) + submission.reload + end + + context 'with manager_then_employee order' do + before { set_order('manager_then_employee') } + + it 'returns true for the manager (index 1)' do + expect(described_class.current_submitter_order?(manager.reload)).to be true + end + + it 'returns false for the employee when manager has not completed' do + manager.update!(completed_at: nil) + expect(described_class.current_submitter_order?(employee.reload)).to be false + end + + it 'returns true for the employee when manager has completed' do + manager.update!(completed_at: Time.current) + expect(described_class.current_submitter_order?(employee.reload)).to be true + end + end + + context 'with employee_then_manager order' do + before { set_order('employee_then_manager') } + + it 'returns true for the first submitter (Employee)' do + expect(described_class.current_submitter_order?(employee.reload)).to be true + end + + it 'returns false for the manager when employee has not completed' do + employee.update!(completed_at: nil) + expect(described_class.current_submitter_order?(manager.reload)).to be false + end + + it 'returns true for the manager when employee has completed' do + employee.update!(completed_at: Time.current) + expect(described_class.current_submitter_order?(manager.reload)).to be true + end + end + end +end diff --git a/spec/models/submission_spec.rb b/spec/models/submission_spec.rb new file mode 100644 index 000000000..99b3a6820 --- /dev/null +++ b/spec/models/submission_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +RSpec.describe Submission do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + let(:template) { create(:template, account:, author: user) } + let(:submission) { create(:submission, template:, created_by_user: user) } + + describe '#template_signing_order' do + it 'returns the submitters_order from template preferences' do + template.update!(preferences: { 'submitters_order' => 'employee_then_manager' }) + expect(submission.template_signing_order).to eq('employee_then_manager') + end + + it 'returns nil when template has no submitters_order preference' do + template.update_column(:preferences, {}) + expect(submission.reload.template_signing_order).to be_nil + end + + it 'returns nil when submission has no template' do + submission.update!(template: nil) + expect(submission.template_signing_order).to be_nil + end + end + + describe '#signing_order_enforced?' do + it 'returns true for employee_then_manager' do + template.update!(preferences: { 'submitters_order' => 'employee_then_manager' }) + expect(submission.signing_order_enforced?).to be true + end + + it 'returns true for manager_then_employee' do + template.update!(preferences: { 'submitters_order' => 'manager_then_employee' }) + expect(submission.signing_order_enforced?).to be true + end + + it 'returns false for simultaneous' do + template.update!(preferences: { 'submitters_order' => 'simultaneous' }) + expect(submission.signing_order_enforced?).to be false + end + + it 'returns false for single_sided' do + template.update!(preferences: { 'submitters_order' => 'single_sided' }) + expect(submission.signing_order_enforced?).to be false + end + end +end diff --git a/spec/models/template_spec.rb b/spec/models/template_spec.rb new file mode 100644 index 000000000..945b62d71 --- /dev/null +++ b/spec/models/template_spec.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +RSpec.describe Template do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + + describe '#unique_submitter_uuids' do + it 'returns unique submitter UUIDs from fields' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid1', 'type' => 'signature' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'date' } + ]) + + expect(template.unique_submitter_uuids).to match_array(%w[uuid1 uuid2]) + end + + it 'filters out nil submitter_uuids' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => nil, 'type' => 'image' }, + { 'type' => 'signature' } + ]) + + expect(template.unique_submitter_uuids).to eq(['uuid1']) + end + + it 'returns empty array when no fields' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(fields: []) + + expect(template.unique_submitter_uuids).to eq([]) + end + end + + describe '#effective_submitters_order' do + it 'returns preferences submitters_order when set' do + template = create(:template, account:, author: user) + template.update_column(:preferences, { 'submitters_order' => 'manager_then_employee' }) + + expect(template.effective_submitters_order).to eq('manager_then_employee') + end + + it 'returns single_sided when preferences not set and template has fewer than 2 unique submitters' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update_column(:preferences, {}) + template.update_column(:fields, [{ 'submitter_uuid' => 'uuid1', 'type' => 'text' }]) + + expect(template.reload.effective_submitters_order).to eq('single_sided') + end + + it 'returns employee_then_manager when preferences not set and template has 2+ unique submitters' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update_column(:preferences, {}) + template.update_column(:fields, [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' } + ]) + + expect(template.reload.effective_submitters_order).to eq('employee_then_manager') + end + end + + describe '#update_submitters_order' do + context 'when template has less than 2 unique submitters' do + it 'sets submitters_order to single_sided' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(preferences: { 'submitters_order' => 'employee_then_manager' }, + fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' } + ]) + + # Remove uuid2 fields to trigger single_sided + template.update!(fields: [{ 'submitter_uuid' => 'uuid1', 'type' => 'text' }]) + + expect(template.reload.preferences['submitters_order']).to eq('single_sided') + end + + it 'always sets single_sided when only one unique submitter' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(fields: [{ 'submitter_uuid' => 'uuid1', 'type' => 'text' }]) + + expect(template.reload.preferences['submitters_order']).to eq('single_sided') + + template.update!(fields: [{ 'submitter_uuid' => 'uuid1', 'type' => 'signature' }]) + + expect(template.reload.preferences['submitters_order']).to eq('single_sided') + end + end + + context 'when template has 2 or more unique submitters' do + it 'sets employee_then_manager when adding second submitter' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(preferences: { 'submitters_order' => 'single_sided' }, + fields: [{ 'submitter_uuid' => 'uuid1', 'type' => 'text' }]) + + # Add second submitter + template.update!(fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' } + ]) + + expect(template.reload.preferences['submitters_order']).to eq('employee_then_manager') + end + + it 'sets employee_then_manager when submitters_order is blank and 2 submitters added' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' } + ]) + + expect(template.reload.preferences['submitters_order']).to eq('employee_then_manager') + end + + it 'preserves employee_then_manager when multiple submitters' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(preferences: { 'submitters_order' => 'employee_then_manager' }, + fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' } + ]) + + template.update!(fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' }, + { 'submitter_uuid' => 'uuid1', 'type' => 'date' } + ]) + + expect(template.reload.preferences['submitters_order']).to eq('employee_then_manager') + end + end + + context 'when removing fields transitions from multi to single submitter' do + it 'changes from employee_then_manager to single_sided' do + template = create(:template, account:, author: user, submitter_count: 0, attachment_count: 0) + template.update!(preferences: { 'submitters_order' => 'employee_then_manager' }, + fields: [ + { 'submitter_uuid' => 'uuid1', 'type' => 'text' }, + { 'submitter_uuid' => 'uuid2', 'type' => 'signature' } + ]) + + # Remove all uuid2 fields + template.update!(fields: [{ 'submitter_uuid' => 'uuid1', 'type' => 'text' }]) + + expect(template.reload.preferences['submitters_order']).to eq('single_sided') + end + end + end +end diff --git a/spec/requests/submissions_spec.rb b/spec/requests/submissions_spec.rb index 28b5a9bba..1796ca784 100644 --- a/spec/requests/submissions_spec.rb +++ b/spec/requests/submissions_spec.rb @@ -287,7 +287,7 @@ def index_submission_body(submission) id: submission.id, name: submission.name, source: 'link', - submitters_order: 'random', + submitters_order: 'employee_then_manager', slug: submission.slug, audit_log_url: nil, combined_document_url: nil, @@ -347,7 +347,7 @@ def show_submission_body(submission) name: submission.name, source: 'link', status: 'pending', - submitters_order: 'random', + submitters_order: 'employee_then_manager', slug: submission.slug, audit_log_url: nil, combined_document_url: nil,