mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-12 16:14:58 +08:00
114 lines
3.4 KiB
Ruby
114 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class InvalidStatusError < StandardError; end
|
|
|
|
class FormResponse < ApplicationRecord
|
|
include Discard::Model
|
|
|
|
default_scope -> { kept }
|
|
|
|
belongs_to :form
|
|
belongs_to :created_by, class_name: 'User'
|
|
belongs_to :submitted_by, class_name: 'User', optional: true
|
|
belongs_to :parent, polymorphic: true, inverse_of: :form_responses
|
|
|
|
has_one :step_orderable_element, as: :orderable, dependent: :destroy
|
|
|
|
enum :status, { pending: 0, submitted: 1, locked: 2 }
|
|
|
|
has_many :form_field_values, dependent: :destroy
|
|
|
|
belongs_to :previous_form_response,
|
|
-> { unscope(where: :discarded_at) },
|
|
class_name: 'FormResponse',
|
|
inverse_of: :next_form_response,
|
|
optional: true,
|
|
dependent: :destroy
|
|
|
|
has_one :next_form_response,
|
|
class_name: 'FormResponse',
|
|
foreign_key: 'previous_form_response_id',
|
|
inverse_of: :previous_form_response,
|
|
dependent: :destroy
|
|
|
|
def step
|
|
step_orderable_element&.step
|
|
end
|
|
|
|
def create_value!(created_by, form_field, value, not_applicable: false)
|
|
ActiveRecord::Base.transaction(requires_new: true) do
|
|
current_form_field_value = form_field_values.where(latest: true).last
|
|
|
|
form_field_values.where(form_field: form_field).find_each do |form_field_value|
|
|
form_field_value.update!(latest: false)
|
|
end
|
|
|
|
new_form_field_value = "Form#{form_field.data['type']}Value".constantize.new(
|
|
form_field: form_field,
|
|
form_response: self,
|
|
# these can change if the form_response is reset, as submitted_by will be kept the same, but created_by will change
|
|
created_by: created_by,
|
|
submitted_by: created_by,
|
|
submitted_at: DateTime.current,
|
|
not_applicable: not_applicable
|
|
)
|
|
|
|
# for RepositoryRowsField we need to directly set previous data to the new value,
|
|
# before save, to perserve existing repository row snapshots
|
|
new_form_field_value.data = current_form_field_value&.data if form_field.data['type'] == 'RepositoryRowsField'
|
|
|
|
new_form_field_value.update!(value: value)
|
|
|
|
new_form_field_value
|
|
end
|
|
end
|
|
|
|
def submit!(user)
|
|
update!(
|
|
status: :submitted,
|
|
submitted_by: user,
|
|
submitted_at: DateTime.current
|
|
)
|
|
end
|
|
|
|
def reset!(user)
|
|
raise InvalidStatusError, 'Cannot reset form that has not been submitted yet!' if status != 'submitted'
|
|
|
|
ActiveRecord::Base.transaction(requires_new: true) do
|
|
new_form_response = dup
|
|
new_form_response.update!(status: 'pending', created_by: user, previous_form_response: self)
|
|
|
|
form_field_values.latest.find_each do |form_field_value|
|
|
form_field_value.dup.update!(form_response: new_form_response, created_by: user)
|
|
end
|
|
|
|
# if attached to step, reattach new form response
|
|
|
|
discard
|
|
|
|
self&.step_orderable_element&.update!(orderable: new_form_response)
|
|
|
|
new_form_response
|
|
end
|
|
end
|
|
|
|
def duplicate(parent, user, position = nil)
|
|
ActiveRecord::Base.transaction do
|
|
new_form_response = FormResponse.create!(
|
|
status: :pending,
|
|
form_id: form_id,
|
|
discarded_at: nil,
|
|
submitted_by: nil,
|
|
created_by_id: user.id,
|
|
parent: parent
|
|
)
|
|
|
|
parent.step_orderable_elements.create!(
|
|
position: position || parent.step_orderable_elements.length,
|
|
orderable: new_form_response
|
|
)
|
|
|
|
new_form_response
|
|
end
|
|
end
|
|
end
|