diff --git a/app/controllers/api/submission_documents_controller.rb b/app/controllers/api/submission_documents_controller.rb index 148d499f..56940f0f 100644 --- a/app/controllers/api/submission_documents_controller.rb +++ b/app/controllers/api/submission_documents_controller.rb @@ -5,34 +5,17 @@ module Api load_and_authorize_resource :submission def index + is_merge = params[:merge] == 'true' && + (@submission.schema_documents || @submission.template.schema_documents).size > 1 + documents = if @submission.submitters.all?(&:completed_at?) - last_submitter = @submission.submitters.max_by(&:completed_at) - - if last_submitter.documents_attachments.blank? - last_submitter.documents_attachments = Submissions::EnsureResultGenerated.call(last_submitter) - end - - last_submitter.documents_attachments + build_completed_documents(@submission, merge: is_merge) else - values_hash = Submissions::GeneratePreviewAttachments.build_values_hash(@submission) - - if @submission.preview_documents.present? && - @submission.preview_documents.all? { |s| s.metadata['values_hash'] == values_hash } - @submission.preview_documents - else - ApplicationRecord.no_touching do - @submission.preview_documents.each(&:destroy) - end - - Submissions::GeneratePreviewAttachments.call(@submission, values_hash:) - end + build_preview_documents(@submission, merge: is_merge) end - ActiveRecord::Associations::Preloader.new( - records: documents, - associations: [:blob] - ).call + ActiveRecord::Associations::Preloader.new(records: documents, associations: [:blob]).call expires_at = Accounts.link_expires_at(current_account) @@ -43,5 +26,50 @@ module Api end } end + + private + + def build_completed_documents(submission, merge: false) + last_submitter = submission.submitters.max_by(&:completed_at) + + if merge + if submission.merged_document_attachment.blank? + submission.merged_document_attachment = + Submissions::GenerateCombinedAttachment.call(last_submitter, with_audit: false) + end + + [submission.merged_document_attachment] + else + if last_submitter.documents_attachments.blank? + last_submitter.documents_attachments = Submissions::EnsureResultGenerated.call(last_submitter) + end + + last_submitter.documents_attachments + end + end + + def build_preview_documents(submission, merge: false) + values_hash = Submissions::GeneratePreviewAttachments.build_values_hash(submission) + + if merge + if submission.preview_merged_document_attachment.present? && + submission.preview_merged_document_attachment.metadata['values_hash'] == values_hash + [submission.preview_merged_document_attachment] + else + ApplicationRecord.no_touching { submission.preview_merged_document_attachment&.destroy } + + Submissions::GeneratePreviewAttachments.call(submission, values_hash:, merge: true) + end + elsif submission.preview_documents.present? && + submission.preview_documents.all? { |s| s.metadata['values_hash'] == values_hash } + submission.preview_documents + else + ApplicationRecord.no_touching do + submission.preview_documents.each(&:destroy) + end + + Submissions::GeneratePreviewAttachments.call(submission, values_hash:) + end + end end end diff --git a/app/models/submission.rb b/app/models/submission.rb index 04a7ad85..5630af76 100644 --- a/app/models/submission.rb +++ b/app/models/submission.rb @@ -63,6 +63,8 @@ class Submission < ApplicationRecord has_one_attached :audit_trail has_one_attached :combined_document + has_one_attached :merged_document + has_one_attached :preview_merged_document has_many_attached :preview_documents has_many_attached :documents diff --git a/lib/submissions/generate_combined_attachment.rb b/lib/submissions/generate_combined_attachment.rb index faf55471..bafd20a7 100644 --- a/lib/submissions/generate_combined_attachment.rb +++ b/lib/submissions/generate_combined_attachment.rb @@ -4,8 +4,8 @@ module Submissions module GenerateCombinedAttachment module_function - def call(submitter) - pdf = build_combined_pdf(submitter) + def call(submitter, with_audit: true) + pdf = build_combined_pdf(submitter, with_audit:) submission = submitter.submission account = submission.account @@ -39,7 +39,7 @@ module Submissions blob: ActiveStorage::Blob.create_and_upload!( io: io.tap(&:rewind), filename: "#{submission.name || submission.template.name}.pdf" ), - name: 'combined_document', + name: with_audit ? 'combined_document' : 'merged_document', record: submission ) end @@ -58,14 +58,16 @@ module Submissions pdf.sign(io, write_options: { validate: false }, **sign_params) end - def build_combined_pdf(submitter) + def build_combined_pdf(submitter, with_audit:) pdfs_index = Submissions::GenerateResultAttachments.generate_pdfs(submitter) - audit_trail = I18n.with_locale(submitter.account.locale) do - Submissions::GenerateAuditTrail.build_audit_trail(submitter.submission) - end + if with_audit + audit_trail = I18n.with_locale(submitter.account.locale) do + Submissions::GenerateAuditTrail.build_audit_trail(submitter.submission) + end - audit_trail.dispatch_message(:complete_objects) + audit_trail.dispatch_message(:complete_objects) + end result = HexaPDF::Document.new @@ -79,7 +81,7 @@ module Submissions pdf.pages.each { |page| result.pages << result.import(page) } end - audit_trail.pages.each { |page| result.pages << result.import(page) } + audit_trail&.pages&.each { |page| result.pages << result.import(page) } result end diff --git a/lib/submissions/generate_preview_attachments.rb b/lib/submissions/generate_preview_attachments.rb index b57b80a1..ff5a85a8 100644 --- a/lib/submissions/generate_preview_attachments.rb +++ b/lib/submissions/generate_preview_attachments.rb @@ -5,7 +5,7 @@ module Submissions module_function # rubocop:disable Metrics - def call(submission, values_hash: nil, submitter: nil) + def call(submission, values_hash: nil, submitter: nil, merge: false) values_hash ||= if submitter build_submitter_values_hash(submitter) else @@ -42,48 +42,74 @@ module Submissions template = submission.template - image_pdfs = [] - original_documents = submission.schema_documents.preload(:blob) + if merge + result = HexaPDF::Document.new - result_attachments = - (submission.template_schema || template.schema).filter_map do |item| + (submission.template_schema || template.schema).each do |item| pdf = pdfs_index[item['attachment_uuid']] - next if pdf.nil? + next unless pdf - if original_documents.find { |a| a.uuid == item['attachment_uuid'] }.image? - pdf = GenerateResultAttachments.normalize_image_pdf(pdf) + pdf.dispatch_message(:complete_objects) - image_pdfs << pdf - end - - build_pdf_attachment(pdf:, submission:, submitter:, - uuid: item['attachment_uuid'], - values_hash:, - name: item['name']) - end - - return ApplicationRecord.no_touching { result_attachments.map { |e| e.tap(&:save!) } } if image_pdfs.size < 2 - - images_pdf = - image_pdfs.each_with_object(HexaPDF::Document.new) do |pdf, doc| - pdf.pages.each { |page| doc.pages << doc.import(page) } + pdf.pages.each { |page| result.pages << result.import(page) } end - images_pdf = GenerateResultAttachments.normalize_image_pdf(images_pdf) - - images_pdf_attachment = - build_pdf_attachment( - pdf: images_pdf, + attachment = build_pdf_attachment( + pdf: result, submission:, - submitter:, - uuid: GenerateResultAttachments.images_pdf_uuid(original_documents.select(&:image?)), values_hash:, - name: submission.name || template.name + name: 'preview_merged_document', + filename: "#{submission.name || template.name}.pdf" ) - ApplicationRecord.no_touching do - (result_attachments + [images_pdf_attachment]).map { |e| e.tap(&:save!) } + ApplicationRecord.no_touching { attachment.save! } + + [attachment] + else + image_pdfs = [] + original_documents = submission.schema_documents.preload(:blob) + + result_attachments = + (submission.template_schema || template.schema).filter_map do |item| + pdf = pdfs_index[item['attachment_uuid']] + + next if pdf.nil? + + if original_documents.find { |a| a.uuid == item['attachment_uuid'] }.image? + pdf = GenerateResultAttachments.normalize_image_pdf(pdf) + + image_pdfs << pdf + end + + build_pdf_attachment(pdf:, submission:, submitter:, + uuid: item['attachment_uuid'], + values_hash:, + filename: "#{item['name']}.pdf") + end + + return ApplicationRecord.no_touching { result_attachments.map { |e| e.tap(&:save!) } } if image_pdfs.size < 2 + + images_pdf = + image_pdfs.each_with_object(HexaPDF::Document.new) do |pdf, doc| + pdf.pages.each { |page| doc.pages << doc.import(page) } + end + + images_pdf = GenerateResultAttachments.normalize_image_pdf(images_pdf) + + images_pdf_attachment = + build_pdf_attachment( + pdf: images_pdf, + submission:, + submitter:, + uuid: GenerateResultAttachments.images_pdf_uuid(original_documents.select(&:image?)), + values_hash:, + filename: "#{submission.name || template.name}.pdf" + ) + + ApplicationRecord.no_touching do + (result_attachments + [images_pdf_attachment]).map { |e| e.tap(&:save!) } + end end end @@ -102,7 +128,8 @@ module Submissions ) end - def build_pdf_attachment(pdf:, submission:, submitter:, uuid:, name:, values_hash:) + def build_pdf_attachment(pdf:, submission:, filename:, values_hash:, submitter: nil, uuid: nil, + name: 'preview_documents') io = StringIO.new begin @@ -114,13 +141,13 @@ module Submissions end ActiveStorage::Attachment.new( - blob: ActiveStorage::Blob.create_and_upload!(io: io.tap(&:rewind), filename: "#{name}.pdf"), + blob: ActiveStorage::Blob.create_and_upload!(io: io.tap(&:rewind), filename:), io_data: io.string, metadata: { original_uuid: uuid, values_hash:, analyzed: true, - sha256: Base64.urlsafe_encode64(Digest::SHA256.digest(io.string)) }, - name: 'preview_documents', + sha256: Base64.urlsafe_encode64(Digest::SHA256.digest(io.string)) }.compact, + name: name, record: submitter || submission ) end