512 lines
21 KiB
Ruby
512 lines
21 KiB
Ruby
# encoding: utf-8
|
|
class QuestionnaireSurvey
|
|
|
|
include Mongoid::Document
|
|
include Mongoid::Timestamps
|
|
include Slug
|
|
|
|
ResultChart = 0
|
|
ResultExtern = 1
|
|
ResultFile = 2
|
|
ResultCriteria = 3
|
|
include OrbitCategory::Categorizable
|
|
|
|
scope :can_display, ->{where(is_hidden: false)}
|
|
field :already_fix_data, :type => Boolean, :default => false
|
|
field :copy_id
|
|
field :except_clone_relations, :type=>Array, :default => []
|
|
field :title, as: :slug_title, type: String, localize: true
|
|
field :description, :localize => true
|
|
|
|
field :create_user_id
|
|
field :update_user_id
|
|
|
|
field :postdate, :type => DateTime
|
|
field :deadline, :type => DateTime
|
|
|
|
field :is_hidden, :type => Boolean, :default => false
|
|
field :needs_login, :type => Boolean, :default => false
|
|
field :answer_repeat, :type => Boolean, :default => false
|
|
field :total_points, type: Integer, :default => 0
|
|
field :total_weight, type: Integer
|
|
field :result_type, :type => Integer, :default => 0
|
|
field :extern_link
|
|
mount_uploader :upload_file, AssetUploader
|
|
field :result_criteria, type: Array, :default => []
|
|
|
|
field :jump_mode, :type => Boolean, :default => false
|
|
|
|
field :redirect_mode, :type => Boolean, :default => false
|
|
field :redirect_url, :type => String
|
|
|
|
# validates :title, :at_least_one => true
|
|
# validates :title, :presence => { :message => I18n.t("survey.title") }
|
|
|
|
has_many :survey_questions, :autosave => true, :dependent => :destroy
|
|
has_many :survey_answers, :autosave => true, :dependent => :destroy
|
|
has_many :survey_answer_groups, :autosave => true, :dependent => :destroy
|
|
has_many :survey_sections, :autosave => true, :dependent => :destroy
|
|
|
|
accepts_nested_attributes_for :survey_questions, :allow_destroy => true
|
|
|
|
before_save :check_deadline#, :update_avliable_language
|
|
|
|
has_many :survey_paginations, :autosave => true, :dependent => :destroy
|
|
accepts_nested_attributes_for :survey_paginations, :allow_destroy => true
|
|
before_create do
|
|
self.already_fix_data = true
|
|
if self.copy_id.present?
|
|
clone_new(true)
|
|
self.created_at = DateTime.now
|
|
self.updated_at = DateTime.now
|
|
end
|
|
end
|
|
def get_answer_repeat
|
|
self.needs_login && self.answer_repeat
|
|
end
|
|
def update_user
|
|
User.find(update_user_id) rescue nil
|
|
end
|
|
|
|
def update_user=(user)
|
|
self.update_user_id = user.id
|
|
end
|
|
|
|
def self.time_range(data)
|
|
|
|
r = "#{data.postdate.to_date}"
|
|
|
|
if data.deadline
|
|
r += " - #{data.deadline.to_date}"
|
|
else
|
|
r += " - #{I18n.t(:no_deadline)}"
|
|
end
|
|
|
|
r
|
|
end
|
|
|
|
def self.result(data)
|
|
if ( data.result_type == QuestionnaireSurvey::ResultChart && data.deadline && Time.now > data.deadline ) ||
|
|
( data.result_type == QuestionnaireSurvey::ResultExtern && !data.extern_link.blank? ) ||
|
|
( data.result_type == QuestionnaireSurvey::ResultFile && data.upload_file? )
|
|
('<a target="_blank" href="'+ OrbitHelper.url_to_show(data.to_param) + '?method=result&force_chart=true' + '"><span class="result"><i class="icon-align-left"></i></span></a>').html_safe
|
|
else
|
|
''
|
|
end
|
|
end
|
|
|
|
def self.write(data)
|
|
unless data.deadline && Time.now > data.deadline
|
|
('<a target="_blank" href="'+ OrbitHelper.url_to_show(data.to_param) + '"><span class="write"><i class="icon-edit"></i></span></a>').html_safe
|
|
else
|
|
''
|
|
end
|
|
end
|
|
|
|
def generate_chart_data(match_args={})
|
|
survey_questions = self.survey_questions.all
|
|
tmp_answer_repeat = self.needs_login && self.answer_repeat
|
|
survey_answers = []
|
|
if tmp_answer_repeat
|
|
survey_answers = self.survey_answers.where(match_args).order_by(created_at: :desc)
|
|
else
|
|
survey_answer_ids = self.survey_answer_groups.where(match_args).pluck(:survey_answer_ids).map{|ids| ids ? ids[-1] : nil}
|
|
survey_answers = self.survey_answers.where(:id.in=>survey_answer_ids).order_by(created_at: :desc)
|
|
end
|
|
survey_answers = survey_answers.to_a
|
|
chart_data = {}
|
|
answers =(0...survey_answers.count).map{{}}
|
|
survey_answers.each_with_index do |answer,i|
|
|
answers[i]["name"] = User.find(answer.user).member_name rescue ""
|
|
end
|
|
SurveysHelper.set_locale(I18n.locale)
|
|
survey_questions.each do |question|
|
|
qid = question.id.to_s
|
|
use_custom_option = question.custom_option_new_option
|
|
chart_data[qid] = {}
|
|
case question.type
|
|
when SurveyQuestion::Radio, SurveyQuestion::Select
|
|
options = question.survey_question_options.map{|v| [v.name,v.id.to_s]}
|
|
survey_answers.each_with_index do |answer,i|
|
|
answers[i][qid] = SurveysHelper.parse_exel_value(answer[qid],
|
|
options: options,
|
|
chart_data: chart_data[qid],
|
|
use_custom_option: use_custom_option)
|
|
end
|
|
when SurveyQuestion::Check
|
|
options = question.survey_question_options.map{|v| [v.name,v.id.to_s]}
|
|
survey_answers.each_with_index do |answer,i|
|
|
answers[i][qid] = SurveysHelper.parse_exel_checkbox_value(answer[qid],
|
|
options: options,
|
|
chart_data: chart_data[qid],
|
|
use_custom_option: use_custom_option)
|
|
end
|
|
when SurveyQuestion::Radiogroup
|
|
options = question.survey_question_options.map{|v| [v.name,v.id.to_s]}
|
|
radiogroups = question.survey_question_radiogroups.map{|v| [v.name,v.id.to_s]}
|
|
survey_answers.each_with_index do |answer,i|
|
|
answers[i][qid] = SurveysHelper.parse_exel_rg_value(answer[qid],
|
|
options: options,
|
|
radiogroups: radiogroups,
|
|
chart_data: chart_data[qid],
|
|
use_custom_option: use_custom_option)
|
|
end
|
|
when SurveyQuestion::DoubleLevelOption
|
|
custom_option_title = question.custom_option_title.to_s
|
|
survey_answers.each_with_index do |answer,i|
|
|
answers[i][qid] = SurveysHelper.parse_exel_double_level_value(answer[qid],
|
|
other_title: custom_option_title,
|
|
use_custom_option: use_custom_option,
|
|
chart_data: chart_data[qid])
|
|
end
|
|
else
|
|
survey_answers.each_with_index do |answer,i|
|
|
answers[i][qid] = answer[qid]
|
|
end
|
|
end
|
|
end
|
|
|
|
[chart_data, survey_questions, answers]
|
|
end
|
|
|
|
def expired?
|
|
(self.deadline < Time.now) rescue false
|
|
end
|
|
def clone_new(clone_mode=false)
|
|
@records_all = {}
|
|
if clone_mode
|
|
clone_target = self.class.find(object.copy_id) rescue nil
|
|
else
|
|
clone_target = self
|
|
end
|
|
new_object,clone_target = clone_new_for_object(self,clone_target,clone_mode)
|
|
new_object
|
|
end
|
|
def clone_new_for_object(object,clone_target=nil,clone_mode=false)
|
|
if clone_mode
|
|
new_object = object
|
|
clone_target = object.class.find(object.copy_id) rescue nil if clone_target.nil?
|
|
else
|
|
clone_target = object if clone_target.nil?
|
|
new_object = object.dup
|
|
end
|
|
return if (self.except_clone_relations.to_s.include?(new_object.class.to_s.underscore) rescue false)
|
|
@records_all["#{new_object.class.to_s.underscore.singularize}_ids"] = {} if @records_all["#{new_object.class.to_s.underscore.singularize}_ids"].nil?
|
|
begin
|
|
@records_all["#{new_object.class.to_s.underscore.singularize}_ids"][clone_target.id] = object.id
|
|
rescue
|
|
nil
|
|
end
|
|
if !clone_target.nil? && !new_object.nil?
|
|
initialize_fields = ["uid","created_at","updated_at"]
|
|
initialize_fields.each do |f|
|
|
new_object.send("#{f}=",nil) if new_object.fields.keys.include?(f)
|
|
end
|
|
relations_fields = clone_target.relations.except("impressions").keys
|
|
all_fields = clone_target.fields.keys - relations_fields
|
|
all_fields = all_fields - relations_fields.map{|k| "#{k}_id"}
|
|
all_fields = all_fields - relations_fields.map{|k| "#{k.singularize}_ids"}
|
|
new_object_class_name = new_object.class.to_s.underscore
|
|
relations_fields = clone_target.relations.except("impressions").keys
|
|
unsort_relation_keys = clone_target.relations.keys
|
|
unless @parent_level
|
|
fields_to_delete = [new_object_class_name]
|
|
tmp_relations_fields = [new_object_class_name]
|
|
while relations_fields.count > 0
|
|
tmp_singularize_relations_fields = tmp_relations_fields.map{|f| f.singularize}
|
|
approve_append = nil
|
|
relations_fields.each do |k|
|
|
belongs_to_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :belongs_to}.keys
|
|
has_many_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :has_many}.keys
|
|
if (belongs_to_class - tmp_singularize_relations_fields).count == 0
|
|
other_has_many_class = (has_many_class - unsort_relation_keys)
|
|
if other_has_many_class.count == 0
|
|
tmp_relations_fields << k
|
|
else
|
|
result = other_has_many_class.map do |k|
|
|
belongs_to_class = k.classify.constantize.relations.select{|kk,v| v.macro == :belongs_to}.keys
|
|
has_many_class = k.classify.constantize.relations.select{|kk,v| v.macro == :has_many}.keys
|
|
if (belongs_to_class - tmp_singularize_relations_fields).count == 0
|
|
true
|
|
else
|
|
fields_to_delete = fields_to_delete.concat(belongs_to_class)
|
|
tmp_relations_fields.concat(belongs_to_class)
|
|
false
|
|
end
|
|
end
|
|
if result.select{|t| !t}.count == 0
|
|
if (fields_to_delete.map{|f| f.pluralize} - tmp_relations_fields).count == 0
|
|
tmp_relations_fields << k
|
|
elsif clone_target.relations[k].class_name.constantize.fields.keys.include?("key")
|
|
tmp_relations_fields << k
|
|
elsif (clone_target.relations[k].class_name.constantize.relations.keys.map{|f| f.singularize} & fields_to_delete).count != 0
|
|
approve_append = k
|
|
end
|
|
end
|
|
end
|
|
elsif !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore) && !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore.pluralize)
|
|
tmp_relations_fields << k
|
|
end
|
|
end
|
|
tmp_relations_fields << approve_append if approve_append.present?
|
|
approve_append = nil
|
|
relations_fields = relations_fields - tmp_relations_fields
|
|
end
|
|
relations_fields = tmp_relations_fields
|
|
fields_to_delete.each{|f| relations_fields.delete(f)}
|
|
@clone_mode = clone_mode
|
|
end
|
|
@parent_level = true
|
|
if clone_mode
|
|
all_fields.each do |f|
|
|
next if f == "uid"
|
|
unless new_object.send("#{f}_changed?") && new_object.send("#{f}_changed_from_default?")
|
|
new_object.send("#{f}=",clone_target.send(f))
|
|
end
|
|
end
|
|
end
|
|
relations_fields.each do |f|
|
|
no_dup_flag = false
|
|
if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].macro == :has_one
|
|
no_dup_flag = new_object.send(f).present?
|
|
elsif clone_target.relations[f].macro == :has_many
|
|
no_dup_flag = new_object.send(f).to_a.count != 0
|
|
elsif clone_target.relations[f].macro == :embeds_many #Fix localize fields
|
|
if new_object.send(f).to_a.count != 0
|
|
need_fix_fields = new_object.send(f).to_a[0].fields.select{|k,v| (v.options[:localize] rescue false)}.keys
|
|
locale = I18n.locale.to_s
|
|
embeded_records = new_object.send(f).map do |embeded_record|
|
|
need_fix_fields.each do |f|
|
|
if (embeded_record[f][locale].class != String rescue false)
|
|
embeded_record.send("#{f}_translations=",embeded_record[f][locale])
|
|
else
|
|
embeded_record.send("#{f}_translations=",embeded_record[f])
|
|
end
|
|
end
|
|
embeded_record
|
|
end
|
|
new_object.send("#{f}=",embeded_records)
|
|
end
|
|
end
|
|
if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].class_name == "MemberProfile"
|
|
if @records_all["#{f}_ids"].nil?
|
|
new_object.send("#{f}_id=",clone_target.send("#{f}_id"))
|
|
else
|
|
new_object.send("#{f}_id=",(@records_all["#{f}_ids"][clone_target.send("#{f}_id")]))
|
|
end
|
|
elsif clone_target.relations[f].macro == :has_one
|
|
next if (self.except_clone_relations.to_s.include?(f) rescue false)
|
|
need_clone_relation = clone_target.send(f)
|
|
clone_relation = new_object.send(f)
|
|
clone_relation = need_clone_relation.dup if clone_relation.nil?
|
|
initialize_fields.each do |f|
|
|
clone_relation.send("#{f}=",nil) if clone_relation.fields.keys.include?(f)
|
|
end
|
|
check_fields = clone_relation.fields.except(initialize_fields)
|
|
check_fields.keys.each do |f|
|
|
if (clone_relation.send(f).class.to_s.match(/uploader/i) rescue false)
|
|
if clone_relation[f].blank? && (clone_relation.send(f).file.nil? rescue true)
|
|
clone_relation[f] = r[f]
|
|
source_filepath = r.send(f).file.file
|
|
if @clone_mode
|
|
dest_filepath = clone_relation.send(f).file.file
|
|
FileUtils.mkdir_p(File.dirname(dest_filepath))
|
|
FileUtils.cp(source_filepath,dest_filepath)
|
|
end
|
|
elsif (clone_relation.send(f).file rescue nil)
|
|
clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s)
|
|
end
|
|
file_flag = true
|
|
end
|
|
end
|
|
new_object.send("#{f}=",clone_relation)
|
|
elsif clone_target.relations[f].macro == :has_many
|
|
next if (self.except_clone_relations.to_s.include?(f) rescue false)
|
|
clone_relations = []
|
|
need_clone_relations = clone_target.send(f).asc(:_id).to_a
|
|
file_flag = false
|
|
need_clone_relations.each_with_index do |r,i|
|
|
clone_relation = new_object.send(f)[i]
|
|
clone_relation = r.dup if clone_relation.nil?
|
|
initialize_fields.each do |f|
|
|
clone_relation.send("#{f}=",nil) if clone_relation.fields.keys.include?(f)
|
|
end
|
|
check_fields = clone_relation.fields.except(initialize_fields)
|
|
check_fields.keys.each do |f|
|
|
if (clone_relation.send(f).class.to_s.match(/uploader/i) rescue false)
|
|
if clone_relation[f].blank? && (clone_relation.send(f).file.nil? rescue true)
|
|
clone_relation[f] = r[f]
|
|
source_filepath = r.send(f).file.file
|
|
if @clone_mode
|
|
dest_filepath = clone_relation.send(f).file.file
|
|
FileUtils.mkdir_p(File.dirname(dest_filepath))
|
|
FileUtils.cp(source_filepath,dest_filepath)
|
|
end
|
|
elsif (clone_relation.send(f).file rescue nil)
|
|
clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s)
|
|
end
|
|
file_flag = true
|
|
end
|
|
end
|
|
clone_relations << clone_relation
|
|
end
|
|
if !no_dup_flag || (no_dup_flag && file_flag)
|
|
new_object_relations = new_object.send(f).to_a
|
|
if new_object_relations.count != 0
|
|
if clone_relations.count > new_object_relations.count
|
|
clone_relations = clone_relations[0...new_object_relations.count]
|
|
else
|
|
clone_relations = clone_relations.concat(new_object.send(f)[clone_relations.count...new_object_relations.count])
|
|
end
|
|
new_object.send("#{f}=",clone_relations)
|
|
else
|
|
new_object.send("#{f}=",clone_relations)
|
|
end
|
|
end
|
|
count_array = (0...new_object.send(f).to_a.count).to_a
|
|
count_array.each do |i|
|
|
clone_new_for_object(new_object.send(f)[i],need_clone_relations[i],true)
|
|
end
|
|
end
|
|
end
|
|
new_object.copy_id = clone_target.id if new_object.fields.keys.include?("copy_id")
|
|
return new_object, clone_target
|
|
end
|
|
end
|
|
def update_answer_score
|
|
if self.survey_questions.where(:need_update_score => true).count != 0
|
|
puts "Updating answer's scores"
|
|
tmp_weights = []
|
|
tmp_score_data = self.survey_questions.map do |question|
|
|
qid = question.id.to_s
|
|
tmp = {}
|
|
weight = (question.weight.nil? ? 1 : question.weight)
|
|
tmp_weights << weight
|
|
case question.type
|
|
when SurveyQuestion::Radio, SurveyQuestion::Select, SurveyQuestion::Check, SurveyQuestion::Radiogroup
|
|
question.survey_question_options.each do |opt|
|
|
oid = opt.id.to_s
|
|
tmp[oid] = {"base"=>(opt.points.to_i * weight)}
|
|
end
|
|
when SurveyQuestion::Oneline, SurveyQuestion::Multiline, SurveyQuestion::DateTime
|
|
tmp = 0
|
|
when SurveyQuestion::DoubleLevelOption
|
|
question.survey_question_options.each do |opt|
|
|
oid = opt.id.to_s
|
|
tmp[oid] = {"base"=>(opt.points.to_i * weight)}
|
|
opt.level2.each do |opt2|
|
|
tmp[oid][opt2.id.to_s] = opt2.points.to_i * weight
|
|
end
|
|
end
|
|
end
|
|
[qid,tmp]
|
|
end.to_h
|
|
self.survey_answers.each do |answer|
|
|
total = 0
|
|
individual_total = []
|
|
tmp_total_weight = 0
|
|
tmp_score_data.each_with_index do |(qid,tmp),i|
|
|
if answer[qid]
|
|
tmp_total_weight += tmp_weights[i]
|
|
if tmp.class == Fixnum #Oneline, Multiline, DateTime
|
|
total += tmp
|
|
individual_total << tmp
|
|
else
|
|
if answer[qid].class == Array #Check , DoubleLevelOption
|
|
t = 0
|
|
answer[qid].each do |d|
|
|
if d.class != BSON::Document
|
|
break
|
|
end
|
|
level2s = []
|
|
oid = nil
|
|
if d.has_key?("level1_id")
|
|
oid = d["level1_id"]
|
|
level2s = Array(d["level1_ids"])
|
|
else
|
|
oid = d['oid']
|
|
end
|
|
t2 += tmp[oid]["base"] rescue nil
|
|
if t2
|
|
t += t2
|
|
level2s.each do |level2_id|
|
|
t += tmp[oid][level2_id]
|
|
end
|
|
end
|
|
end
|
|
total += t
|
|
individual_total << t
|
|
elsif answer[qid].class == BSON::Document #Radio, Select, Radiogroup
|
|
if (answer[qid].has_key?('oid') rescue true)
|
|
t = tmp[answer[qid]['oid']]["base"] rescue nil
|
|
if t
|
|
total += t
|
|
individual_total << t
|
|
end
|
|
else
|
|
tmp[answer[qid]].each do |oid,d|
|
|
t = tmp[oid]["base"] rescue nil
|
|
if t
|
|
total += t
|
|
individual_total << t
|
|
end
|
|
end
|
|
end
|
|
else
|
|
total += 0
|
|
individual_total << 0
|
|
end
|
|
end
|
|
else
|
|
total += 0
|
|
individual_total << 0
|
|
end
|
|
end
|
|
answer.scored_points = total
|
|
answer.individual_total = individual_total
|
|
if tmp_total_weight != 0
|
|
answer.avg_points = (individual_total.to_f / tmp_total_weight).round
|
|
else
|
|
answer.avg_points = 0
|
|
end
|
|
answer.save
|
|
end
|
|
self.survey_questions.update_all(:need_update_score => false)
|
|
end
|
|
end
|
|
def update_total_weight
|
|
self.total_weight = self.survey_questions.pluck(:weight).map{|w| w.nil? ? 1 : w}.sum
|
|
self.save
|
|
end
|
|
def get_total_weight(ans=nil)
|
|
if ans.nil?
|
|
if self.total_weight.nil?
|
|
self.update_total_weight
|
|
self.total_weight
|
|
else
|
|
self.total_weight
|
|
end
|
|
else
|
|
self.survey_questions.where(:id.in=>ans.attributes.keys).pluck(:weight).map{|w| w.nil? ? 1 : w}.sum
|
|
end
|
|
end
|
|
protected
|
|
|
|
def check_deadline
|
|
if(!self.deadline.nil? and (self.deadline < self.postdate ))
|
|
self.deadline = nil
|
|
end
|
|
end
|
|
# def update_avliable_language
|
|
# VALID_LOCALES.each do |locale|
|
|
# if (title_translations[locale].blank? rescue true)
|
|
# self["available_for_#{locale}".to_sym] = false
|
|
# else
|
|
# self["available_for_#{locale}".to_sym] = true
|
|
# end
|
|
# end
|
|
# end
|
|
|
|
# paginates_per 10
|
|
|
|
end |