aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuidomain/entities/PatientEligibleTrial.scala
blob: 8d5af0d4ff62f094f2b38461b546a1b1ee37b8c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package xyz.driver.pdsuidomain.entities

import java.time.LocalDateTime

import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, StringId, UuidId}
import xyz.driver.pdsuicommon.logging._

object PatientCriterion {
  implicit def toPhiString(x: PatientCriterion): PhiString = {
    import x._
    phi"PatientCriterion(id=$id, patientLabelId=$patientLabelId, trialId=${Unsafe(trialId)}, nctId=${Unsafe(nctId)}, " +
      phi"criterionId=$criterionId, criterionValue=${Unsafe(criterionValue)}, " +
      phi"isImplicitMatch=$criterionIsDefining), criterionIsDefining=${Unsafe(criterionIsDefining)}, " +
      phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, verifiedEligibilityStatus=${Unsafe(verifiedEligibilityStatus)}, " +
      phi"isVerified=${Unsafe(isVerified)}, lastUpdate=${Unsafe(lastUpdate)}"
  }

  /**
    * @see https://driverinc.atlassian.net/wiki/display/MTCH/EV+Business+Process
    */
  def getEligibilityStatus(criterionValue: Option[Boolean],
                           primaryValue: Option[FuzzyValue]): Option[FuzzyValue] = {
    primaryValue match {
      case None => None
      case Some(FuzzyValue.Maybe) => Some(FuzzyValue.Maybe)
      case Some(_) if criterionValue.isEmpty => Some(FuzzyValue.Maybe)
      case Some(status) => Some(FuzzyValue.fromBoolean(
        FuzzyValue.fromBoolean(criterionValue.getOrElse(
          throw new IllegalArgumentException("Criterion should not be empty"))
        ) == status
      ))
    }
  }

}

/**
  * @param eligibilityStatus - a value, that selects an eligibility verifier (EV)
  * @param verifiedEligibilityStatus - a copy of eligibilityStatus, when a patient goes to routes curator (RC)
  * @param isVerified - is EV selected the eligibilityStatus?
  */
final case class PatientCriterion(id: LongId[PatientCriterion],
                                  patientLabelId: LongId[PatientLabel],
                                  trialId: Long,
                                  nctId: StringId[Trial],
                                  criterionId: LongId[Criterion],
                                  criterionText: String,
                                  criterionValue: Option[Boolean],
                                  criterionIsDefining: Boolean,
                                  eligibilityStatus: Option[FuzzyValue],
                                  verifiedEligibilityStatus: Option[FuzzyValue],
                                  isVerified: Boolean,
                                  isVisible: Boolean,
                                  lastUpdate: LocalDateTime) {
  def isIneligible: Boolean = eligibilityStatus.contains(FuzzyValue.No) && isVerified
}

object PatientTrialArm {

  implicit def toPhiString(x: PatientTrialArm): PhiString = {
    import x._
    phi"PatientTrialArm(armId=$armId, trialArmGroupId=$trialArmGroupId)"
  }
}

final case class PatientTrialArm(armId: LongId[Arm], trialArmGroupId: LongId[PatientTrialArmGroup])

object PatientEligibleTrial {
  implicit def toPhiString(x: PatientEligibleTrial): PhiString = {
    import x._
    phi"PatientEligibleTrial(id=$id, patientId=$patientId, trialId=$trialId, hypothesisId=$hypothesisId)"
  }
}

final case class PatientEligibleTrial(id: UuidId[PatientEligibleTrial],
                                      patientId: UuidId[Patient],
                                      trialId: StringId[Trial],
                                      hypothesisId: UuidId[Hypothesis])

object PatientTrialArmGroup {

  implicit def toPhiString(x: PatientTrialArmGroup): PhiString = {
    import x._
    phi"PatientTrialArmGroup(id=$id, eligibleTrialId=$eligibleTrialId, " +
      phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, isVerified=$isVerified)"
  }

  /**
    * @see https://driverinc.atlassian.net/wiki/display/DMPD/EV+Business+Process
    */
  def getEligibilityStatusForEvToRc(criterionList: List[(Option[Boolean], Option[FuzzyValue])]): Option[FuzzyValue] = {
    def isEligible = {
      // Eligible, if for all (verified for EV) label-criteria eligibilityStatus=NULL or YES and at least one has status=YES
      // If method executes from PatientService (when EV submit patient) need to check value PatientCriterion.isVerified
      val verifiedList = criterionList.filter { case (isVerifiedOpt, _) => isVerifiedOpt.isEmpty || isVerifiedOpt.get }
      verifiedList.forall { case (_, eligibilityStatus) =>
        eligibilityStatus.isEmpty || eligibilityStatus.contains(FuzzyValue.Yes)
      } && verifiedList.exists { case (_, eligibilityStatus) => eligibilityStatus.contains(FuzzyValue.Yes) }
    }

    if (criterionList.exists { case (isVerified, eligibilityStatus) =>
      eligibilityStatus.contains(FuzzyValue.No) && (isVerified.isEmpty || isVerified.get)
    }) { Some(FuzzyValue.No)
    } else if (criterionList.forall { case (_, eligibilityStatus) => eligibilityStatus.isEmpty }) {
      None
    } else if (isEligible) {
      Some(FuzzyValue.Yes)
    } else {
      Some(FuzzyValue.Maybe)
    }
  }

  /**
    * @see https://driverinc.atlassian.net/wiki/display/DMPD/EV+Business+Process
    */
  def getEligibilityStatusForRc(criterionList: TraversableOnce[PatientCriterion]): Option[FuzzyValue] = {
    def isEligible: Boolean = criterionList.forall(_.verifiedEligibilityStatus.contains(FuzzyValue.Yes))
    def isIneligible: Boolean = criterionList.exists(_.verifiedEligibilityStatus.contains(FuzzyValue.No))
    def isUnknown: Boolean = criterionList.forall(_.verifiedEligibilityStatus.isEmpty)

    if (isEligible) Some(FuzzyValue.Yes)
    else if (isIneligible) Some(FuzzyValue.No)
    else if (isUnknown) None
    else Some(FuzzyValue.Maybe)
  }
}

final case class PatientTrialArmGroup(id: LongId[PatientTrialArmGroup],
                                      eligibleTrialId: UuidId[PatientEligibleTrial],
                                      eligibilityStatus: Option[FuzzyValue],
                                      isVerified: Boolean)

object PatientTrialArmGroupView {

  implicit def toPhiString(x: PatientTrialArmGroupView): PhiString = {
    import x._
    phi"PatientTrialArmGroupView(id=$id, patientId=$patientId, trialId=$trialId, hypothesisId=$hypothesisId, " +
      phi"eligibilityStatus=${Unsafe(eligibilityStatus)}, isVerified=$isVerified)"
  }
}

final case class PatientTrialArmGroupView(id: LongId[PatientTrialArmGroup],
                                          patientId: UuidId[Patient],
                                          trialId: StringId[Trial],
                                          hypothesisId: UuidId[Hypothesis],
                                          eligibilityStatus: Option[FuzzyValue],
                                          isVerified: Boolean) {

  def applyTo(trialArmGroup: PatientTrialArmGroup) = {
    trialArmGroup.copy(
      eligibilityStatus = this.eligibilityStatus,
      isVerified = this.isVerified
    )
  }
}