class Ecs::CalculateCourseEvaluationService < ApplicationService attr_reader :ec_course def initialize(ec_course) @ec_course = ec_course end def call ActiveRecord::Base.transaction do clear_student_score! calculate_student_score_target! calculate_graduation_requirement! end end private def clear_student_score! ec_course.ec_course_student_scores.destroy_all end def requirement_passed?(standard_value, real_value) standard_value && real_value && real_value >= standard_value ? 1 : 0 end def calculate_student_score_target! complete_target_count = 0 course_targets = ec_course.ec_course_targets.includes(ec_achievement_evaluation_relates: :ec_course_achievement_method) course_targets.find_each do |target| target.ec_achievement_evaluation_relates.each do |relate| achievement_method = relate.ec_course_achievement_method total = achievement_method.ec_achievement_evaluation_relates.count percentage = total.zero? ? 0 : achievement_method.percentage.fdiv(total) achievements = EcStudentAchievement.where(ec_course_evaluation_id: achievement_method.ec_course_evaluation_id) achievements = if relate.ec_course_evaluation_subitem_id.blank? || relate.ec_course_evaluation_subitem_id == -1 achievements.where(position: relate.position) else achievements.where(ec_course_evaluation_subitem_id: relate.ec_course_evaluation_subitem_id) end # 遍历学生成绩统计数据 achievements.find_each do |achievement| student_score = EcCourseStudentScore.find_or_initialize_by( ec_course_id: ec_course.id, ec_year_student_id: achievement.ec_year_student_id ) score = achievement_method.score.zero? || achievement.score.nil? ? 0 : (achievement.fdiv(achievement_method.score) * percentage).round(3) if student_score.new_record? student_score.student_name = achievement.student_name student_score.student_number = achievement.student_number student_score.save! create_params = { ec_course_id: ec_course.id, ec_year_student_id: achievement.ec_year_student_id, ec_course_target_id: target.id, eaer_id: relate.id, ec_target_position: target.position, score: score } student_score.ec_student_score_targets.create!(create_params) else score_target = EcStudentScoreTarget.find_or_initialize_by( ec_course_id: ec_course.id, ec_year_student_id: achievement.ec_year_student_id, ec_course_student_score_id: student_score.id, ec_course_target_id: target.id, ec_target_position: target.position, eaer_id: relate.id ) score_target.score = score_target.score.to_f + score score_target.save! end end end # 计算该课程目标是否完成 count = target.ec_student_score_targets.count score = target.ec_student_score_targets.sum(:score) average = count.zero? ? 0 : score.fdiv(count) complete_target_count += 1 if target.standard_grade && target.standard_grade <= average end ec_course.update!(complete_target_count: complete_target_count) end def calculate_graduation_requirement! student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') student_score_map = student_scores.group_by { |item| item.ec_course_target_id } subitem_targets = ec_course.ec_graduation_subitem_course_targets.includes(:ec_graduation_subitem, :ec_course_target) subitem_targets.group_by { |subitem_target| subitem_target.ec_graduation_subitem }.each do |subitem, subitem_target_arr| support = subitem.ec_course_supports.find_by(ec_course_id: ec_course.id) next if support.blank? total_weight = 0.0 total_score = 0.0 subitem_target_arr.each do |subitem_target| target = subitem_target.ec_course_target student_score = student_score_map[target.id].first total_weight += target.weigths.to_f total_score += student_score.average_score.round(2) * target.weigths.to_f end target_value = support.weights.to_f * ec_course.ec_year.calculation_value.to_f real_value = total_weight.zero? ? 0 : (total_score * support.weights.to_f) / (total_weight * 100) cal = support.ec_graduation_requirement_calculation || support.build_ec_graduation_requirement_calculation cal.target_value = target_value.round(3) cal.real_value = real_value.round(3) cal.status = requirement_passed?(target_value, real_value) cal.save! end end end