diff --git a/app/controllers/api/templates_controller.rb b/app/controllers/api/templates_controller.rb index cd25da88..e32b103e 100644 --- a/app/controllers/api/templates_controller.rb +++ b/app/controllers/api/templates_controller.rb @@ -85,8 +85,11 @@ module Api render json: @template.as_json(only: %i[id archived_at]) end + VALID_AUDIENCE_VALUES = %w[single_sided employee_then_manager manager_then_employee simultaneous].freeze + def pdf template = build_template + audience = params[:audience] fields_from_request = params[:fields] if params[:fields].present? template.save! @@ -99,6 +102,8 @@ module Api template.update!(schema: schema) + apply_audience(template, audience) + finalize_template_creation(template, documents) rescue StandardError => e template.destroy! @@ -201,6 +206,17 @@ module Api end end + def apply_audience(template, audience) + return if audience.blank? + + unless audience.in?(VALID_AUDIENCE_VALUES) + Rails.logger.warn("Invalid audience value '#{audience}' for template #{template.id}.") + return + end + + template.update!(preferences: template.preferences.merge('submitters_order' => audience)) + end + def finalize_template_creation(template, documents) enqueue_template_created_webhooks(template) SearchEntries.enqueue_reindex(template) @@ -252,7 +268,7 @@ module Api external_data_fields: {}, submitters: [%i[name uuid is_requester invite_by_uuid optional_invite_by_uuid linked_to_uuid email]], fields: [[:uuid, :question_id, :submitter_uuid, :name, :type, - :required, :readonly, :default_value, + :required, :readonly, :default_value, :prefill, :title, :description, { preferences: {}, conditions: [%i[field_uuid value action operation]], diff --git a/app/javascript/template_builder/field_settings.vue b/app/javascript/template_builder/field_settings.vue index 55df8305..56fe6b98 100644 --- a/app/javascript/template_builder/field_settings.vue +++ b/app/javascript/template_builder/field_settings.vue @@ -595,10 +595,14 @@ export default { }, methods: { formatPrefillFieldName (fieldName) { - // Convert snake_case to Title Case for display + const wordMap = { + firstname: 'First Name', + lastname: 'Last Name' + } + return fieldName .split('_') - .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .map(word => wordMap[word.toLowerCase()] || (word.charAt(0).toUpperCase() + word.slice(1))) .join(' ') }, onChangeValidation (event) { diff --git a/spec/requests/templates_spec.rb b/spec/requests/templates_spec.rb index 9f4e247c..da585858 100644 --- a/spec/requests/templates_spec.rb +++ b/spec/requests/templates_spec.rb @@ -150,6 +150,85 @@ describe 'Templates API' do end end + describe 'POST /api/templates/pdf' do + let(:pdf_base64) { Base64.strict_encode64(Rails.root.join('spec/fixtures/sample-document.pdf').read) } + let(:base_params) do + { + name: 'Test Template', + documents: [{ name: 'sample-document.pdf', file: pdf_base64 }] + } + end + + it 'creates a template with audience set as submitters_order' do + post '/api/templates/pdf', + headers: { 'x-auth-token': author.access_token.token }, + params: base_params.merge(audience: 'manager_then_employee').to_json, + env: { 'CONTENT_TYPE' => 'application/json' } + + expect(response).to have_http_status(:ok) + + template = Template.last + expect(template.preferences['submitters_order']).to eq('manager_then_employee') + end + + it 'creates a template with simultaneous audience' do + post '/api/templates/pdf', + headers: { 'x-auth-token': author.access_token.token }, + params: base_params.merge(audience: 'simultaneous').to_json, + env: { 'CONTENT_TYPE' => 'application/json' } + + expect(response).to have_http_status(:ok) + expect(Template.last.preferences['submitters_order']).to eq('simultaneous') + end + + it 'ignores audience when not provided' do + post '/api/templates/pdf', + headers: { 'x-auth-token': author.access_token.token }, + params: base_params.to_json, + env: { 'CONTENT_TYPE' => 'application/json' } + + expect(response).to have_http_status(:ok) + expect(Template.last.preferences['submitters_order']).to eq('single_sided') + end + + it 'ignores an invalid audience value' do + post '/api/templates/pdf', + headers: { 'x-auth-token': author.access_token.token }, + params: base_params.merge(audience: 'invalid_value').to_json, + env: { 'CONTENT_TYPE' => 'application/json' } + + expect(response).to have_http_status(:ok) + expect(Template.last.preferences['submitters_order']).to eq('single_sided') + end + + it 'stores prefill attribute on fields' do + employee_uuid = SecureRandom.uuid + fields = [ + { + uuid: SecureRandom.uuid, + submitter_uuid: employee_uuid, + name: 'First Name', + type: 'text', + prefill: 'employee_first_name', + areas: [{ x: 0.1, y: 0.1, w: 0.2, h: 0.03, page: 0 }] + } + ] + + post '/api/templates/pdf', + headers: { 'x-auth-token': author.access_token.token }, + params: base_params.merge( + submitters: [{ name: 'Employee', uuid: employee_uuid }], + fields: + ).to_json, + env: { 'CONTENT_TYPE' => 'application/json' } + + expect(response).to have_http_status(:ok) + + stored_field = Template.last.fields.find { |f| f['name'] == 'First Name' } + expect(stored_field['prefill']).to eq('employee_first_name') + end + end + describe 'POST /api/templates/:id/clone' do it 'clones a template' do template = create(:template, account:,