All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openurp.edu.grade.domain.DefaultPlanAuditor.scala Maven / Gradle / Ivy

/*
 * Copyright (C) 2014, The OpenURP Software.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package org.openurp.edu.grade.domain

import org.beangle.commons.collection.Collections
import org.openurp.edu.grade.model.*
import org.openurp.edu.program.model.CourseGroup

import java.time.Instant

class DefaultPlanAuditor extends PlanAuditor {

  def audit(context: AuditPlanContext): AuditPlanResult = {
    val apr = new AuditPlanResult(context.std)
    apr.passed = false
    apr.remark = null
    apr.updatedAt = Instant.now
    context.result = apr
    val plan = context.coursePlan
    if (null == plan || null == context.stdGrade) {
      return context.result
    }

    val creditsRequired = context.coursePlan.credits
    apr.requiredCredits = creditsRequired
    plan.topGroups foreach { g =>
      val topResult = DefaultAuditGroupResultBuilder.buildResult(context, g)
      apr.addGroupResult(topResult)
      initResult(context, g, topResult)
    }
    apr.buildGroupCache() //所有监听启动之前,注册所有的组
    context.listeners.foreach(_.start(context))
    plan.topGroups foreach (g => auditGroup(context, g, apr.getGroupResult(g.name).get))
    context.listeners.foreach(_.end(context))
    apr.stat()
    context.coursePlan.program.offsetType foreach { offsetType =>
      apr.getGroupResult(offsetType.name) foreach { lastTarget =>
        processConvertCredits(lastTarget, apr)
        if lastTarget.passedCredits == 0 && lastTarget.requiredCredits == 0 && lastTarget.courseResults.isEmpty then
          apr.removeGroupResult(lastTarget)
      }
    }
    cleanupElectiveCourses(apr)
    apr
  }

  private def initResult(context: AuditPlanContext, courseGroup: CourseGroup, gr: AuditGroupResult): Unit = {
    val result = context.result
    courseGroup.children foreach { child =>
      val childResult = DefaultAuditGroupResultBuilder.buildResult(context, child)
      gr.addChild(childResult)
      result.addGroupResult(childResult)
      initResult(context, child, childResult)
    }
  }

  private def auditGroup(context: AuditPlanContext, courseGroup: CourseGroup, gr: AuditGroupResult): Unit = {
    val result = context.result
    //先组内课程,然后再审核审核子组
    courseGroup.planCourses foreach { pc =>
      val cr = new AuditCourseResult(pc)
      val courseGrades = context.stdGrade.useGrade(pc.course)
      //不要过滤计划内的课程,对于选修组内的选修课,无成绩的情况下,事后在删除
      cr.updatePassed(courseGrades)
      gr.addCourseResult(cr)
    }

    courseGroup.children foreach { child =>
      val childResult = context.result.getGroupResult(child.name).get
      if (context.listeners.exists(!_.startGroup(context, child, childResult))) {
        result.reduceRequired(childResult.requiredCredits)
        childResult.reduceRequired(childResult.requiredCredits)
      } else {
        auditGroup(context, child, childResult)
      }
    }
  }

  /** 将其他组多出的学分转移到最后的【公选课】上
   *
   * @param target
   * @param result
   */
  protected def processConvertCredits(target: AuditGroupResult, result: AuditPlanResult): Unit = {
    val parents = Collections.newSet[AuditGroupResult] // 从当前节点查找祖先
    val sibling = Collections.newSet[AuditGroupResult] // 同一级别的兄弟节点
    var start = target.parent.orNull
    while (null != start && !parents.contains(start)) {
      parents.add(start)
      start = start.parent.orNull
    }
    target.parent foreach { p =>
      sibling ++= p.children
      sibling.remove(target)
    }
    var otherConverted = 0f
    var siblingConverted = 0f
    for (gr <- result.groupResults) {
      // 自己和父节点过滤掉
      if (gr != target && !parents.contains(gr)) {
        val rest = gr.passedCredits - gr.requiredCredits
        if (sibling.contains(gr)) {
          siblingConverted += (if rest > 0 then rest else 0f)
        } else if (gr.parent.isEmpty) {
          otherConverted += (if rest > 0 then rest else 0f)
        }
      }
    }
    target.convertedCredits = otherConverted + siblingConverted
    for (r <- parents) r.convertedCredits = otherConverted
    target.stat()
    result.stat(false)
  }

  /** 清除空的不及格的选修课
   *
   * @param result
   */
  def cleanupElectiveCourses(result: AuditPlanResult): Unit = {
    for (gr <- result.groupResults; if gr.optional || gr.passed) {
      val empties = gr.courseResults filter (x => !x.compulsory && !x.passed && !x.predicted && !x.taking && !x.hasGrade)
      gr.courseResults.subtractAll(empties)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy