From 4c7b4102dede53b9707fe3758a4a9ff9ccf87bf8 Mon Sep 17 00:00:00 2001 From: Vyatcheslav Suharnikov Date: Tue, 25 Jul 2017 10:48:08 +0300 Subject: PDSUI-2145 Create own user history for Documents and Medical Records --- .../scala/xyz/driver/pdsuicommon/acl/ACL.scala | 14 +++- .../pdsuidomain/entities/DocumentHistory.scala | 90 +++++++++++++++++++++ .../entities/MedicalRecordHistory.scala | 93 ++++++++++++++++++++++ .../json/documenthistory/ApiDocumentHistory.scala | 27 +++++++ .../json/recordhistory/ApiRecordHistory.scala | 27 +++++++ .../services/DocumentHistoryService.scala | 44 ++++++++++ .../services/MedicalRecordHistoryService.scala | 44 ++++++++++ 7 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala create mode 100644 src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala create mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory/ApiDocumentHistory.scala create mode 100644 src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory/ApiRecordHistory.scala create mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala create mode 100644 src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala index 48a86e3..e13b45f 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala @@ -22,7 +22,7 @@ object ACL extends PhiLogging { object UserHistory extends BaseACL( label = "user history", - read = Set(RecordAdmin, TreatmentMatchingAdmin) + read = Set(TreatmentMatchingAdmin) ) object Queue @@ -42,6 +42,12 @@ object ACL extends PhiLogging { update = RepRoles - DocumentExtractor ) + object MedicalRecordHistory + extends BaseACL( + label = "medical record history", + read = Set(RecordAdmin) + ) + object Document extends BaseACL( label = "document", @@ -51,6 +57,12 @@ object ACL extends PhiLogging { delete = Set(RecordOrganizer, RecordAdmin) ) + object DocumentHistory + extends BaseACL( + label = "document history", + read = Set(RecordAdmin) + ) + object ExtractedData extends BaseACL( label = "extracted data", diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala new file mode 100644 index 0000000..a82da12 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/DocumentHistory.scala @@ -0,0 +1,90 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.{LocalDateTime, ZoneId} + +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils +import xyz.driver.pdsuidomain.entities.DocumentHistory._ + +object DocumentHistory { + + implicit def toPhiString(x: DocumentHistory): PhiString = { + import x._ + phi"DocumentHistory(id=$id, executor=$executor, documentId=$documentId, state=$state, action=$action, " + + phi"created=$created)" + } + + sealed trait State + object State { + case object Extract extends State + case object Review extends State + case object Flag extends State + + val All: Set[State] = Set[State](Extract, Review, Flag) + + val fromString: PartialFunction[String, State] = { + case "Extract" => State.Extract + case "Review" => State.Review + case "Flag" => State.Flag + } + + def stateToString(x: State): String = x match { + case State.Extract => "Extract" + case State.Review => "Review" + case State.Flag => "Flag" + } + + implicit def toPhiString(x: State): PhiString = + Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + sealed trait Action extends Product with Serializable { + + def oneOf(xs: Action*): Boolean = xs.contains(this) + + def oneOf(xs: Set[Action]): Boolean = xs.contains(this) + + } + + object Action { + case object Start extends Action + case object Submit extends Action + case object Unassign extends Action + case object Resolve extends Action + case object Flag extends Action + case object Archive extends Action + + val All: Set[Action] = + Set[Action](Start, Submit, Unassign, Resolve, Flag, Archive) + + val fromString: PartialFunction[String, Action] = { + case "Start" => Action.Start + case "Submit" => Action.Submit + case "Unassign" => Action.Unassign + case "Resolve" => Action.Resolve + case "Flag" => Action.Flag + case "Archive" => Action.Archive + } + + def actionToString(x: Action): String = x match { + case Action.Start => "Start" + case Action.Submit => "Submit" + case Action.Unassign => "Unassign" + case Action.Resolve => "Resolve" + case Action.Flag => "Flag" + case Action.Archive => "Archive" + } + + implicit def toPhiString(x: Action): PhiString = + Unsafe(Utils.getClassSimpleName(x.getClass)) + } + +} + +final case class DocumentHistory(id: LongId[DocumentHistory], + executor: StringId[User], + documentId: LongId[Document], + state: State, + action: Action, + created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z"))) diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala new file mode 100644 index 0000000..d01433c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/MedicalRecordHistory.scala @@ -0,0 +1,93 @@ +package xyz.driver.pdsuidomain.entities + +import java.time.{LocalDateTime, ZoneId} + +import xyz.driver.pdsuicommon.domain._ +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.utils.Utils +import xyz.driver.pdsuidomain.entities.MedicalRecordHistory._ + +object MedicalRecordHistory { + + implicit def toPhiString(x: MedicalRecordHistory): PhiString = { + import x._ + phi"MedicalRecordHistory(id=$id, executor=$executor, recordId=$recordId, state=$state, action=$action, " + + phi"created=$created)" + } + + sealed trait State + object State { + case object Clean extends State + case object Organize extends State + case object Review extends State + case object Flag extends State + + val All: Set[State] = Set[State](Clean, Organize, Review, Flag) + + val fromString: PartialFunction[String, State] = { + case "Clean" => State.Clean + case "Organize" => State.Organize + case "Review" => State.Review + case "Flag" => State.Flag + } + + def stateToString(x: State): String = x match { + case State.Clean => "Clean" + case State.Organize => "Organize" + case State.Review => "Review" + case State.Flag => "Flag" + } + + implicit def toPhiString(x: State): PhiString = + Unsafe(Utils.getClassSimpleName(x.getClass)) + } + + sealed trait Action extends Product with Serializable { + + def oneOf(xs: Action*): Boolean = xs.contains(this) + + def oneOf(xs: Set[Action]): Boolean = xs.contains(this) + + } + + object Action { + case object Start extends Action + case object Submit extends Action + case object Unassign extends Action + case object Resolve extends Action + case object Flag extends Action + case object Archive extends Action + + val All: Set[Action] = + Set[Action](Start, Submit, Unassign, Resolve, Flag, Archive) + + val fromString: PartialFunction[String, Action] = { + case "Start" => Action.Start + case "Submit" => Action.Submit + case "Unassign" => Action.Unassign + case "Resolve" => Action.Resolve + case "Flag" => Action.Flag + case "Archive" => Action.Archive + } + + def actionToString(x: Action): String = x match { + case Action.Start => "Start" + case Action.Submit => "Submit" + case Action.Unassign => "Unassign" + case Action.Resolve => "Resolve" + case Action.Flag => "Flag" + case Action.Archive => "Archive" + } + + implicit def toPhiString(x: Action): PhiString = + Unsafe(Utils.getClassSimpleName(x.getClass)) + } + +} + +final case class MedicalRecordHistory(id: LongId[MedicalRecordHistory], + executor: StringId[User], + recordId: LongId[MedicalRecord], + state: State, + action: Action, + created: LocalDateTime = LocalDateTime.now(ZoneId.of("Z"))) diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory/ApiDocumentHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory/ApiDocumentHistory.scala new file mode 100644 index 0000000..5aae774 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/documenthistory/ApiDocumentHistory.scala @@ -0,0 +1,27 @@ +package xyz.driver.pdsuidomain.formats.json.documenthistory + +import java.time.{ZoneId, ZonedDateTime} + +import play.api.libs.json.{Format, Json} +import xyz.driver.pdsuidomain.entities.DocumentHistory + +final case class ApiDocumentHistory(id: Long, + executor: String, + documentId: Long, + state: String, + action: String, + created: ZonedDateTime) + +object ApiDocumentHistory { + implicit val format: Format[ApiDocumentHistory] = + Json.format[ApiDocumentHistory] + + def fromDomain(x: DocumentHistory) = ApiDocumentHistory( + id = x.id.id, + executor = x.executor.id, + documentId = x.documentId.id, + state = DocumentHistory.State.stateToString(x.state), + action = DocumentHistory.Action.actionToString(x.action), + created = ZonedDateTime.of(x.created, ZoneId.of("Z")) + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory/ApiRecordHistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory/ApiRecordHistory.scala new file mode 100644 index 0000000..c55a78f --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/recordhistory/ApiRecordHistory.scala @@ -0,0 +1,27 @@ +package xyz.driver.pdsuidomain.formats.json.recordhistory + +import java.time.{ZoneId, ZonedDateTime} + +import play.api.libs.json.{Format, Json} +import xyz.driver.pdsuidomain.entities.MedicalRecordHistory + +final case class ApiRecordHistory(id: Long, + executor: String, + recordId: Long, + state: String, + action: String, + created: ZonedDateTime) + +object ApiRecordHistory { + implicit val format: Format[ApiRecordHistory] = + Json.format[ApiRecordHistory] + + def fromDomain(x: MedicalRecordHistory) = ApiRecordHistory( + id = x.id.id, + executor = x.executor.id, + recordId = x.recordId.id, + state = MedicalRecordHistory.State.stateToString(x.state), + action = MedicalRecordHistory.Action.actionToString(x.action), + created = ZonedDateTime.of(x.created, ZoneId.of("Z")) + ) +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala new file mode 100644 index 0000000..2d9679d --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentHistoryService.scala @@ -0,0 +1,44 @@ +package xyz.driver.pdsuidomain.services + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext +import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.error.DomainError +import xyz.driver.pdsuidomain.entities.{Document, DocumentHistory} + +import scala.concurrent.Future + +object DocumentHistoryService { + + trait DefaultNotFoundError { + def userMessage: String = "Document history not found" + } + + trait DefaultAccessDeniedError { + def userMessage: String = "Access denied" + } + + sealed trait GetListReply + object GetListReply { + final case class EntityList(xs: Seq[DocumentHistory], totalFound: Int, lastUpdate: Option[LocalDateTime]) + extends GetListReply + + final case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + } + +} + +trait DocumentHistoryService { + + import DocumentHistoryService._ + + def getListByDocumentId(id: LongId[Document], + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala new file mode 100644 index 0000000..f8fe3be --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordHistoryService.scala @@ -0,0 +1,44 @@ +package xyz.driver.pdsuidomain.services + +import java.time.LocalDateTime + +import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext +import xyz.driver.pdsuicommon.db.{Pagination, SearchFilterExpr, Sorting} +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.error.DomainError +import xyz.driver.pdsuidomain.entities.{MedicalRecord, MedicalRecordHistory} + +import scala.concurrent.Future + +object MedicalRecordHistoryService { + + trait DefaultNotFoundError { + def userMessage: String = "Medical record history not found" + } + + trait DefaultAccessDeniedError { + def userMessage: String = "Access denied" + } + + sealed trait GetListReply + object GetListReply { + final case class EntityList(xs: Seq[MedicalRecordHistory], totalFound: Int, lastUpdate: Option[LocalDateTime]) + extends GetListReply + + final case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + } + +} + +trait MedicalRecordHistoryService { + + import MedicalRecordHistoryService._ + + def getListByRecordId(id: LongId[MedicalRecord], + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + +} -- cgit v1.2.3