diff --git a/.github/workflows/dependency-graph.yml b/.github/workflows/dependency-graph.yml
index 5d5acc5d0..a1e26e79f 100644
--- a/.github/workflows/dependency-graph.yml
+++ b/.github/workflows/dependency-graph.yml
@@ -8,5 +8,5 @@ jobs:
name: Update Dependency Graph
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: scalacenter/sbt-dependency-submission@v2
diff --git a/.github/workflows/sbt-docker-prepublish.yml b/.github/workflows/sbt-docker-prepublish.yml
index 120a6993c..dc767235d 100644
--- a/.github/workflows/sbt-docker-prepublish.yml
+++ b/.github/workflows/sbt-docker-prepublish.yml
@@ -10,15 +10,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install locales
run: sudo apt-get -y install locales
- name: Fix up git URLs
run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig
- name: Set up JDK
- uses: actions/setup-java@v2
+ uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: temurin
- name: Docker Login
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
diff --git a/.github/workflows/sbt-docker-publish.yml b/.github/workflows/sbt-docker-publish.yml
index a3e7f9736..a90b87c2b 100644
--- a/.github/workflows/sbt-docker-publish.yml
+++ b/.github/workflows/sbt-docker-publish.yml
@@ -10,15 +10,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install locales
run: sudo apt-get -y install locales
- name: Fix up git URLs
run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig
- name: Set up JDK
- uses: actions/setup-java@v2
+ uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: temurin
- name: Docker Login
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin
diff --git a/.github/workflows/sbt-test.yml b/.github/workflows/sbt-test.yml
index 2fc9014fc..d1eb01eee 100644
--- a/.github/workflows/sbt-test.yml
+++ b/.github/workflows/sbt-test.yml
@@ -1,7 +1,6 @@
name: sbt test
-on:
- push:
+on: [push, pull_request]
jobs:
test:
@@ -9,15 +8,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install locales
run: sudo apt-get -y install locales
- name: Fix up git URLs
run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig
- name: Set up JDK
- uses: actions/setup-java@v2
+ uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: temurin
- name: Run Tests
run: sbt "coverage; test; coverageReport; coverageAggregate;"
diff --git a/build.sbt b/build.sbt
index a88917a70..b969a697d 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,4 +1,4 @@
-scalaVersion := "2.13.10"
+scalaVersion := "2.13.13"
enablePlugins(JavaServerAppPackaging)
enablePlugins(DockerPlugin)
@@ -27,13 +27,14 @@ import java.text.SimpleDateFormat
import java.util.Calendar
-val specs2V = "4.19.0" // based on spray 1.3.x built in support
+val specs2V = "4.20.5" // based on spray 1.3.x built in support
val akkaV = "2.7.+"
+
val sprayV = "1.3.+"
-val scalalikeV = "4.0.0"
-val akkaHttpVersion = "10.2.10"
-val akkaVersion = "2.7.0"
-val testContainersVersion = "1.17.6"
+val scalalikeV = "4.2.1"
+val akkaHttpVersion = "10.5.3"
+val akkaVersion = "2.8.5"
+val testContainersVersion = "1.19.7"
resolvers += Resolver.typesafeRepo("releases")
@@ -41,10 +42,9 @@ val buildSettings = Seq(
scalariformPreferences := scalariformPreferences.value
.setPreference(DanglingCloseParenthesis, Force)
.setPreference(AlignSingleLineCaseStatements, true),
- organization := "ch.openolitor.scalamacros",
- version := "2.6.28",
- scalaVersion := "2.13.10",
- crossScalaVersions := Seq("2.13.8", "2.13.10"),
+ version := "2.6.29",
+ scalaVersion := "2.13.13",
+ crossScalaVersions := Seq("2.13.8", "2.13.13"),
resolvers ++= Resolver.sonatypeOssRepos("snapshots"),
resolvers ++= Resolver.sonatypeOssRepos("releases"),
resolvers += "Sonatype Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/",
@@ -53,7 +53,7 @@ val buildSettings = Seq(
libraryDependencies ++= {
Seq(
- "org.scala-lang.modules" %% "scala-xml" % "2.1.0",
+ "org.scala-lang.modules" %% "scala-xml" % "2.2.0",
"javax.xml.bind" % "jaxb-api" % "2.3.1",
"com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
"com.typesafe.akka" %% "akka-http-caching" % akkaHttpVersion,
@@ -73,21 +73,21 @@ val buildSettings = Seq(
"org.specs2" %% "specs2-junit" % specs2V % "test",
"org.specs2" %% "specs2-scalacheck" % specs2V % "test",
"org.mockito" %% "mockito-scala" % "1.17.7" % "test",
- "org.scalaz" %% "scalaz-core" % "7.3.6", // ### Scala 3
+ "org.scalaz" %% "scalaz-core" % "7.3.8", // ### Scala 3
//use scala logging to log outside of the actor system
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5", // ### Scala 3
- "org.scalikejdbc" %% "scalikejdbc-async" % "0.15.0",
+ "org.scalikejdbc" %% "scalikejdbc-async" % "0.19.0",
"org.scalikejdbc" %% "scalikejdbc-config" % scalalikeV, // ### Scala 3
"org.scalikejdbc" %% "scalikejdbc-test" % scalalikeV % "test", // ### Scala 3
"org.scalikejdbc" %% "scalikejdbc-syntax-support-macro" % scalalikeV, // ### Scala 3
"org.scalikejdbc" %% "scalikejdbc-joda-time" % scalalikeV, // ### Scala 3
- "com.github.jasync-sql" % "jasync-mysql" % "2.1.+",
+ "com.github.jasync-sql" % "jasync-mysql" % "2.2.4",
"com.h2database" % "h2" % "2.1.214" % "test",
"org.testcontainers" % "mariadb" % testContainersVersion % "test",
"io.findify" %% "s3mock" % "0.2.6" % "test",
- "ch.qos.logback" % "logback-classic" % "1.4.5",
- "org.mariadb.jdbc" % "mariadb-java-client" % "3.1.0",
- "mysql" % "mysql-connector-java" % "8.0.31",
+ "ch.qos.logback" % "logback-classic" % "1.5.3",
+ "org.mariadb.jdbc" % "mariadb-java-client" % "3.1.4",
+ "mysql" % "mysql-connector-java" % "8.0.33",
// Libreoffice document API
"org.odftoolkit" % "simple-odf" % "0.9.0" withSources(),
"com.scalapenos" %% "stamina-json" % "0.1.6", // ### NO Scala 3
@@ -100,27 +100,27 @@ val buildSettings = Seq(
"com.github.blemale" %% "scaffeine" % "5.2.1", // ### Scala 3
"de.zalando" %% "beard" % "0.3.3" exclude("ch.qos.logback", "logback-classic") from "https://github.com/OpenOlitor/beard/releases/download/0.3.3/beard_2.13-0.3.3.jar", // ### NO Scala 3, NO Scala 2.13
// transitive dependencies of legacy de.zalando.beard
- "org.antlr" % "antlr4" % "4.8-1",
- "io.monix" %% "monix" % "3.4.0", // ### Scala 3
- "net.codecrete.qrbill" % "qrbill-generator" % "2.4.3",
- "io.nayuki" % "qrcodegen" % "1.6.0",
- "org.apache.pdfbox" % "pdfbox" % "2.0.26",
- "org.apache.pdfbox" % "pdfbox-parent" % "2.0.26" pomOnly(),
- "org.apache.xmlgraphics" % "batik-transcoder" % "1.16",
- "org.apache.xmlgraphics" % "batik-codec" % "1.16",
+ "org.antlr" % "antlr4" % "4.13.1",
+ "io.monix" %% "monix" % "3.4.1", // ### Scala 3
+ "net.codecrete.qrbill" % "qrbill-generator" % "3.2.0",
+ "io.nayuki" % "qrcodegen" % "1.8.0",
+ "org.apache.pdfbox" % "pdfbox" % "2.0.30",
+ "org.apache.pdfbox" % "pdfbox-parent" % "2.0.30" pomOnly(),
+ "org.apache.xmlgraphics" % "batik-transcoder" % "1.17",
+ "org.apache.xmlgraphics" % "batik-codec" % "1.17",
"com.tegonal" %% "cf-env-config-loader" % "1.1.2", // ### NO Scala 3, NO Scala 2.13
"com.eatthepath" % "java-otp" % "0.4.0",
- "org.apache.pdfbox" % "pdfbox-tools" % "2.0.27"
+ "org.apache.pdfbox" % "pdfbox-tools" % "2.0.30"
)
},
dependencyOverrides ++= Seq(
"org.scala-lang.modules" %% "scala-parser-combinators" % "2.1.1",
"xerces" % "xercesImpl" % "2.12.2",
- "org.apache.commons" % "commons-compress" % "1.22",
- "io.netty" % "netty-handler" % "4.1.85.Final",
+ "org.apache.commons" % "commons-compress" % "1.26.0",
+ "io.netty" % "netty-handler" % "4.1.107.Final",
"org.apache.jena" % "jena-core" % "4.6.1",
"com.google.protobuf" % "protobuf-java" % "3.21.10",
- "com.google.guava" % "guava" % "31.1-jre"
+ "com.google.guava" % "guava" % "33.0.0-jre"
)
)
@@ -189,7 +189,7 @@ val updateLatest = sys.env.get("DOCKER_UPDATE_LATEST") match {
}
dockerUpdateLatest := updateLatest
-dockerBaseImage := "eclipse-temurin:17-alpine"
+dockerBaseImage := "eclipse-temurin:21-alpine"
dockerExposedPorts ++= Seq(9003)
// the directories created, e.g. /var/log/openolitor-server, are created using user id 1000,
diff --git a/project/build.properties b/project/build.properties
index 40f4d4b6b..b089b60c7 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1,2 @@
-sbt.version=1.8.0
\ No newline at end of file
+sbt.version=1.9.9
+
diff --git a/project/plugins.sbt b/project/plugins.sbt
index c874537a3..b5eee33fb 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,13 +1,13 @@
-addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.11")
+addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.16")
addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.3")
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "1.0.0")
-addSbtPlugin("org.scalaxb" % "sbt-scalaxb" % "1.9.0")
+addSbtPlugin("org.scalaxb" % "sbt-scalaxb" % "1.12.0")
-addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.5")
//addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.5.10")
-addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.6")
+addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.11")
-dependencyOverrides += "org.scala-lang.modules" %% "scala-xml" % "2.1.0"
+dependencyOverrides += "org.scala-lang.modules" %% "scala-xml" % "2.2.0"
diff --git a/scalastyle-config.xml b/scalastyle-config.xml
index 7e3596f12..c05a9b669 100644
--- a/scalastyle-config.xml
+++ b/scalastyle-config.xml
@@ -8,21 +8,28 @@
diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf
index 34e2d2880..4961ccf8a 100644
--- a/src/main/resources/application.conf
+++ b/src/main/resources/application.conf
@@ -306,9 +306,9 @@ openolitor {
slick {
profile = "slick.jdbc.MySQLProfile$"
db {
- url = "jdbc:mysql://localhost:3306/csa1?cachePrepStmts=true&cacheCallableStmts=true&cacheServerConfiguration=true&useLocalSessionState=true&elideSetAutoCommits=true&alwaysSendSetIsolation=false&enableQueryTimeouts=false&connectionAttributes=none&verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&rewriteBatchedStatements=true"
- user = "user_csa1"
- password = "changeThisPasswrod"
+ url = "jdbc:mysql://localhost:3307/try?cachePrepStmts=true&cacheCallableStmts=true&cacheServerConfiguration=true&useLocalSessionState=true&elideSetAutoCommits=true&alwaysSendSetIsolation=false&enableQueryTimeouts=false&connectionAttributes=none&verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=UTC&rewriteBatchedStatements=true"
+ user = "super"
+ password = "thedefaultdbpasswordneedstobechanged"
driver = "com.mysql.cj.jdbc.Driver"
connectionPool = HikariCP
numThreads = 5
@@ -320,10 +320,10 @@ openolitor {
# Mandant specific db settings
db: {
default: {
- url = "jdbc:mysql://localhost:3306/csa1"
+ url = "jdbc:mysql://localhost:3307/try"
driver = "com.mysql.cj.jdbc.Driver"
- user = "user_csa1"
- password = "changeThisPasswrod"
+ user = "super"
+ password = "thedefaultdbpasswordneedstobechanged"
}
}
diff --git a/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzAktionenService.scala b/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzAktionenService.scala
index dac797021..9e5e42b3c 100644
--- a/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzAktionenService.scala
+++ b/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzAktionenService.scala
@@ -28,7 +28,7 @@ import ch.openolitor.arbeitseinsatz.ArbeitseinsatzCommandHandler._
import ch.openolitor.core._
import ch.openolitor.core.db._
import ch.openolitor.core.domain._
-import ch.openolitor.stammdaten.EmailHandler
+import ch.openolitor.stammdaten.MailCommandForwarder
import akka.util.Timeout
import scala.concurrent.duration._
@@ -42,39 +42,22 @@ import ch.openolitor.core.repositories.EventPublishingImplicits._
import scala.concurrent.ExecutionContext.Implicits._
object ArbeitseinsatzAktionenService {
- def apply(implicit sysConfig: SystemConfig, system: ActorSystem, mailService: ActorRef): ArbeitseinsatzAktionenService = new DefaultArbeitseinsatzAktionenService(sysConfig, system, mailService)
+ def apply(implicit sysConfig: SystemConfig, system: ActorSystem): ArbeitseinsatzAktionenService = new DefaultArbeitseinsatzAktionenService(sysConfig, system)
}
-class DefaultArbeitseinsatzAktionenService(sysConfig: SystemConfig, override val system: ActorSystem, override val mailService: ActorRef)
- extends ArbeitseinsatzAktionenService(sysConfig, mailService) with DefaultArbeitseinsatzWriteRepositoryComponent {
+class DefaultArbeitseinsatzAktionenService(sysConfig: SystemConfig, override val system: ActorSystem)
+ extends ArbeitseinsatzAktionenService(sysConfig) with DefaultArbeitseinsatzWriteRepositoryComponent {
}
/**
* Actor zum Verarbeiten der Aktionen für das Arbeitseinsatz Modul
*/
-class ArbeitseinsatzAktionenService(override val sysConfig: SystemConfig, override val mailService: ActorRef) extends EventService[PersistentEvent] with LazyLogging with AsyncConnectionPoolContextAware with EmailHandler
- with ArbeitseinsatzDBMappings with MailServiceReference with ArbeitseinsatzEventStoreSerializer {
+class ArbeitseinsatzAktionenService(override val sysConfig: SystemConfig) extends EventService[PersistentEvent] with LazyLogging with AsyncConnectionPoolContextAware
+ with ArbeitseinsatzDBMappings with ArbeitseinsatzEventStoreSerializer {
self: ArbeitseinsatzWriteRepositoryComponent =>
- implicit val timeout = Timeout(15.seconds) //sending mails might take a little longer
-
val handle: Handle = {
- case SendEmailToArbeitsangebotPersonenEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
case e =>
logger.warn(s"Unknown event:$e")
}
-
- protected def checkBccAndSend(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], person: PersonEmailData, context: Product, mailService: ActorRef)(implicit originator: PersonId = meta.originator): Unit = {
- DB localTxPostPublish { implicit session => implicit publisher =>
- lazy val bccAddress = config.getString("smtp.bcc")
- arbeitseinsatzWriteRepository.getProjekt map { projekt: Projekt =>
- projekt.sendEmailToBcc match {
- case true => sendEmail(meta, subject, body, replyTo, Some(bccAddress), person, None, context, mailService)
- case false => sendEmail(meta, subject, body, replyTo, None, person, None, context, mailService)
- }
- }
- }
- }
-
}
diff --git a/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzCommandHandler.scala b/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzCommandHandler.scala
index 21acf0fa2..8957e714e 100644
--- a/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzCommandHandler.scala
+++ b/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzCommandHandler.scala
@@ -32,8 +32,9 @@ import ch.openolitor.core.domain._
import ch.openolitor.core.models.PersonId
import ch.openolitor.stammdaten.models.{ Person, PersonContactPermissionModify, PersonEmailData }
import ch.openolitor.mailtemplates.engine.MailTemplateService
-import akka.actor.ActorSystem
+import akka.actor.{ ActorRef, ActorSystem }
import ch.openolitor.core.security.Subject
+import ch.openolitor.stammdaten.{ DefaultMailCommandForwarderComponent, MailCommandForwarderComponent, ProjektHelper }
import scalikejdbc._
import scala.concurrent.ExecutionContext.Implicits._
@@ -41,13 +42,17 @@ import scala.util._
object ArbeitseinsatzCommandHandler {
case class ArbeitsangebotArchivedCommand(id: ArbeitsangebotId, originator: PersonId = PersonId(100)) extends UserCommand
+
case class SendEmailToArbeitsangebotPersonenCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[ArbeitsangebotId]) extends UserCommand
+
case class SendEmailToArbeitsangebotPersonenEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: ArbeitsangebotMailContext) extends PersistentGeneratedEvent with JSONSerializable
+
case class ChangeContactPermissionForUserCommand(originator: PersonId, subject: Subject, personId: PersonId) extends UserCommand
}
-trait ArbeitseinsatzCommandHandler extends CommandHandler with ArbeitseinsatzDBMappings with ConnectionPoolContextAware with MailTemplateService {
- self: ArbeitseinsatzReadRepositorySyncComponent =>
+trait ArbeitseinsatzCommandHandler extends CommandHandler with ArbeitseinsatzDBMappings with ConnectionPoolContextAware with MailTemplateService with ProjektHelper {
+ self: ArbeitseinsatzReadRepositorySyncComponent with MailCommandForwarderComponent =>
+
import ArbeitseinsatzCommandHandler._
import EntityStore._
@@ -56,63 +61,73 @@ trait ArbeitseinsatzCommandHandler extends CommandHandler with ArbeitseinsatzDBM
/*
* Custom update command handling
*/
- case ArbeitsangebotArchivedCommand(id, personId) => idFactory => meta =>
- DB readOnly { implicit session =>
- arbeitseinsatzReadRepository.getById(arbeitsangebotMapping, id) map { arbeitsangebot =>
- arbeitsangebot.status match {
- case (Bereit) =>
- val copy = arbeitsangebot.copy(status = Archiviert)
- Success(Seq(EntityUpdateEvent(id, copy)))
- case _ =>
- Failure(new InvalidStateException("Der Arbeitseinsatz muss 'Bereit' sein."))
- }
- } getOrElse Failure(new InvalidStateException(s"Keine Arbeitseinsatz zu Id $id gefunden"))
- }
+ case ArbeitsangebotArchivedCommand(id, personId) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ arbeitseinsatzReadRepository.getById(arbeitsangebotMapping, id) map { arbeitsangebot =>
+ arbeitsangebot.status match {
+ case (Bereit) =>
+ val copy = arbeitsangebot.copy(status = Archiviert)
+ Success(Seq(EntityUpdateEvent(id, copy)))
+ case _ =>
+ Failure(new InvalidStateException("Der Arbeitseinsatz muss 'Bereit' sein."))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Arbeitseinsatz zu Id $id gefunden"))
+ }
+
+ case SendEmailToArbeitsangebotPersonenCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateArbeitsangebot(body, subject, ids)) {
+ val events = ids flatMap { arbeitsangebotId: ArbeitsangebotId =>
+ arbeitseinsatzReadRepository.getById(arbeitsangebotMapping, arbeitsangebotId) map { arbeitsangebot =>
+ arbeitseinsatzReadRepository.getPersonenByArbeitsangebot(arbeitsangebotId) map { person =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = ArbeitsangebotMailContext(personEmailData, arbeitsangebot)
- case SendEmailToArbeitsangebotPersonenCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateArbeitsangebot(body, subject, ids)) {
- val events = ids flatMap { arbeitsangebotId: ArbeitsangebotId =>
- arbeitseinsatzReadRepository.getById(arbeitsangebotMapping, arbeitsangebotId) map { arbeitsangebot =>
- arbeitseinsatzReadRepository.getPersonenByArbeitsangebot(arbeitsangebotId) map { person =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = ArbeitsangebotMailContext(personEmailData, arbeitsangebot)
- DefaultResultingEvent(factory => SendEmailToArbeitsangebotPersonenEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToArbeitsangebotPersonenEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
}
+ Success(events.flatten)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events.flatten)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case ChangeContactPermissionForUserCommand(originator, subject, personId) => idFactory => meta =>
- DB readOnly { implicit session =>
- val entityToSave = arbeitseinsatzReadRepository.getById(personMapping, personId) map { user =>
- copyTo[Person, PersonContactPermissionModify](user, "contactPermission" -> !user.contactPermission)
- }
- entityToSave match {
- case Some(personContactPermissionModify) => Success(Seq(EntityUpdateEvent(personId, personContactPermissionModify)))
- case _ => Failure(new InvalidStateException(s"This person was not found."))
+ case ChangeContactPermissionForUserCommand(originator, subject, personId) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ val entityToSave = arbeitseinsatzReadRepository.getById(personMapping, personId) map { user =>
+ copyTo[Person, PersonContactPermissionModify](user, "contactPermission" -> !user.contactPermission)
+ }
+ entityToSave match {
+ case Some(personContactPermissionModify) => Success(Seq(EntityUpdateEvent(personId, personContactPermissionModify)))
+ case _ => Failure(new InvalidStateException(s"This person was not found."))
+ }
}
- }
/*
* Insert command handling
*/
- case e @ InsertEntityCommand(personId, entity: ArbeitskategorieModify) => idFactory => meta =>
- handleEntityInsert[ArbeitskategorieModify, ArbeitskategorieId](idFactory, meta, entity, ArbeitskategorieId.apply)
- case e @ InsertEntityCommand(personId, entity: ArbeitsangebotModify) => idFactory => meta =>
- handleEntityInsert[ArbeitsangebotModify, ArbeitsangebotId](idFactory, meta, entity, ArbeitsangebotId.apply)
- case e @ InsertEntityCommand(personId, entity: ArbeitseinsatzModify) => idFactory => meta =>
- handleEntityInsert[ArbeitseinsatzModify, ArbeitseinsatzId](idFactory, meta, entity, ArbeitseinsatzId.apply)
- case e @ InsertEntityCommand(personId, entity: ArbeitsangeboteDuplicate) => idFactory => meta =>
- val events = entity.daten.map { datum =>
- val arbeitsangebotDuplicate = copyTo[ArbeitsangeboteDuplicate, ArbeitsangebotDuplicate](entity, "zeitVon" -> datum)
- insertEntityEvent[ArbeitsangebotDuplicate, ArbeitsangebotId](idFactory, meta, arbeitsangebotDuplicate, ArbeitsangebotId.apply)
- }
- Success(events)
+ case e @ InsertEntityCommand(personId, entity: ArbeitskategorieModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ArbeitskategorieModify, ArbeitskategorieId](idFactory, meta, entity, ArbeitskategorieId.apply)
+ case e @ InsertEntityCommand(personId, entity: ArbeitsangebotModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ArbeitsangebotModify, ArbeitsangebotId](idFactory, meta, entity, ArbeitsangebotId.apply)
+ case e @ InsertEntityCommand(personId, entity: ArbeitseinsatzModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ArbeitseinsatzModify, ArbeitseinsatzId](idFactory, meta, entity, ArbeitseinsatzId.apply)
+ case e @ InsertEntityCommand(personId, entity: ArbeitsangeboteDuplicate) => idFactory =>
+ meta =>
+ val events = entity.daten.map { datum =>
+ val arbeitsangebotDuplicate = copyTo[ArbeitsangeboteDuplicate, ArbeitsangebotDuplicate](entity, "zeitVon" -> datum)
+ insertEntityEvent[ArbeitsangebotDuplicate, ArbeitsangebotId](idFactory, meta, arbeitsangebotDuplicate, ArbeitsangebotId.apply)
+ }
+ Success(events)
}
private def checkTemplateArbeitsangebot(body: String, subject: String, ids: Seq[ArbeitsangebotId])(implicit session: DBSession): Boolean = {
@@ -132,7 +147,9 @@ trait ArbeitseinsatzCommandHandler extends CommandHandler with ArbeitseinsatzDBM
}
}
-class DefaultArbeitseinsatzCommandHandler(override val sysConfig: SystemConfig, override val system: ActorSystem) extends ArbeitseinsatzCommandHandler
- with DefaultArbeitseinsatzReadRepositorySyncComponent {
+class DefaultArbeitseinsatzCommandHandler(override val sysConfig: SystemConfig, override val system: ActorSystem, override val mailService: ActorRef) extends ArbeitseinsatzCommandHandler
+ with DefaultArbeitseinsatzReadRepositorySyncComponent
+ with DefaultMailCommandForwarderComponent {
+ override def projektReadRepository = arbeitseinsatzReadRepository
}
diff --git a/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzEntityStoreView.scala b/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzEntityStoreView.scala
index f38013e44..d6c9003c6 100644
--- a/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzEntityStoreView.scala
+++ b/src/main/scala/ch/openolitor/arbeitseinsatz/ArbeitseinsatzEntityStoreView.scala
@@ -29,10 +29,10 @@ import ch.openolitor.core.db.ConnectionPoolContextAware
import ch.openolitor.core.domain._
object ArbeitseinsatzEntityStoreView {
- def props(mailService: ActorRef, dbEvolutionActor: ActorRef, airbrakeNotifier: ActorRef)(implicit sysConfig: SystemConfig, system: ActorSystem): Props = Props(classOf[DefaultArbeitseinsatzEntityStoreView], mailService, dbEvolutionActor, sysConfig, system, airbrakeNotifier)
+ def props(dbEvolutionActor: ActorRef, airbrakeNotifier: ActorRef)(implicit sysConfig: SystemConfig, system: ActorSystem): Props = Props(classOf[DefaultArbeitseinsatzEntityStoreView], dbEvolutionActor, sysConfig, system, airbrakeNotifier)
}
-class DefaultArbeitseinsatzEntityStoreView(override val mailService: ActorRef, val dbEvolutionActor: ActorRef, implicit val sysConfig: SystemConfig, implicit val system: ActorSystem, val airbrakeNotifier: ActorRef) extends ArbeitseinsatzEntityStoreView
+class DefaultArbeitseinsatzEntityStoreView(val dbEvolutionActor: ActorRef, implicit val sysConfig: SystemConfig, implicit val system: ActorSystem, val airbrakeNotifier: ActorRef) extends ArbeitseinsatzEntityStoreView
with DefaultArbeitseinsatzWriteRepositoryComponent
/**
@@ -48,11 +48,11 @@ trait ArbeitseinsatzEntityStoreView extends EntityStoreView
/**
* Instanzieren der jeweiligen Insert, Update und Delete Child Actors
*/
-trait ArbeitseinsatzEntityStoreViewComponent extends EntityStoreViewComponent with ActorSystemReference with MailServiceReference with SystemConfigReference {
+trait ArbeitseinsatzEntityStoreViewComponent extends EntityStoreViewComponent with ActorSystemReference with SystemConfigReference {
override val insertService = ArbeitseinsatzInsertService(sysConfig, system)
override val updateService = ArbeitseinsatzUpdateService(sysConfig, system)
override val deleteService = ArbeitseinsatzDeleteService(sysConfig, system)
- override val aktionenService = ArbeitseinsatzAktionenService(sysConfig, system, mailService)
+ override val aktionenService = ArbeitseinsatzAktionenService(sysConfig, system)
}
diff --git a/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzReadRepositorySync.scala b/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzReadRepositorySync.scala
index 8c37c8799..20f425488 100644
--- a/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzReadRepositorySync.scala
+++ b/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzReadRepositorySync.scala
@@ -25,11 +25,12 @@ package ch.openolitor.arbeitseinsatz.repositories
import ch.openolitor.arbeitseinsatz.models._
import ch.openolitor.core.repositories._
import ch.openolitor.stammdaten.models.{ KundeId, Person, Projekt }
+import ch.openolitor.stammdaten.repositories.{ ProjektReadRepositorySync, ProjektReadRepositorySyncImpl }
import ch.openolitor.util.parsing.{ GeschaeftsjahrFilter, QueryFilter }
import com.typesafe.scalalogging.LazyLogging
import scalikejdbc.DBSession
-trait ArbeitseinsatzReadRepositorySync extends BaseReadRepositorySync {
+trait ArbeitseinsatzReadRepositorySync extends BaseReadRepositorySync with ProjektReadRepositorySync {
def getArbeitskategorien(implicit session: DBSession): List[Arbeitskategorie]
def getArbeitsangebote(implicit session: DBSession, gjFilter: Option[GeschaeftsjahrFilter], queryString: Option[QueryFilter]): List[Arbeitsangebot]
@@ -43,10 +44,9 @@ trait ArbeitseinsatzReadRepositorySync extends BaseReadRepositorySync {
def getArbeitseinsatzabrechnung(implicit session: DBSession, queryString: Option[QueryFilter]): List[ArbeitseinsatzAbrechnung]
def getArbeitseinsatzDetailByArbeitsangebot(arbeitsangebotId: ArbeitsangebotId)(implicit session: DBSession): List[ArbeitseinsatzDetail]
def getPersonenByArbeitsangebot(arbeitsangebotId: ArbeitsangebotId)(implicit session: DBSession): List[Person]
- def getProjekt(implicit session: DBSession): Option[Projekt]
}
-trait ArbeitseinsatzReadRepositorySyncImpl extends ArbeitseinsatzReadRepositorySync with LazyLogging with ArbeitseinsatzRepositoryQueries {
+trait ArbeitseinsatzReadRepositorySyncImpl extends ArbeitseinsatzReadRepositorySync with LazyLogging with ArbeitseinsatzRepositoryQueries with ProjektReadRepositorySyncImpl {
def getArbeitskategorien(implicit session: DBSession): List[Arbeitskategorie] = {
getArbeitskategorienQuery.apply()
}
@@ -94,8 +94,4 @@ trait ArbeitseinsatzReadRepositorySyncImpl extends ArbeitseinsatzReadRepositoryS
def getPersonenByArbeitsangebot(arbeitsangebotId: ArbeitsangebotId)(implicit session: DBSession): List[Person] = {
getPersonenByArbeitsangebotQuery(arbeitsangebotId).apply()
}
-
- def getProjekt(implicit session: DBSession): Option[Projekt] = {
- getProjektQuery.apply()
- }
}
diff --git a/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzRepositoryQueries.scala b/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzRepositoryQueries.scala
index 2cc1bed43..5be3727dd 100644
--- a/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzRepositoryQueries.scala
+++ b/src/main/scala/ch/openolitor/arbeitseinsatz/repositories/ArbeitseinsatzRepositoryQueries.scala
@@ -28,6 +28,7 @@ import ch.openolitor.stammdaten.models._
import ch.openolitor.core.Macros._
import ch.openolitor.stammdaten.StammdatenDBMappings
import ch.openolitor.stammdaten.models.KundeId
+import ch.openolitor.stammdaten.repositories.StammdatenProjektRepositoryQueries
import ch.openolitor.util.querybuilder.UriQueryParamToSQLSyntaxBuilder
import ch.openolitor.util.parsing.{ GeschaeftsjahrFilter, QueryFilter }
import com.typesafe.scalalogging.LazyLogging
@@ -36,7 +37,7 @@ import scalikejdbc._
import scala.language.postfixOps
-trait ArbeitseinsatzRepositoryQueries extends LazyLogging with ArbeitseinsatzDBMappings with StammdatenDBMappings {
+trait ArbeitseinsatzRepositoryQueries extends LazyLogging with ArbeitseinsatzDBMappings with StammdatenDBMappings with StammdatenProjektRepositoryQueries {
lazy val arbeitskategorie = arbeitskategorieMapping.syntax("arbeitskategorie")
lazy val arbeitsangebot = arbeitsangebotMapping.syntax("arbeitsangebot")
@@ -48,7 +49,6 @@ trait ArbeitseinsatzRepositoryQueries extends LazyLogging with ArbeitseinsatzDBM
lazy val depotlieferungAbo = depotlieferungAboMapping.syntax("depotlieferungAbo")
lazy val heimlieferungAbo = heimlieferungAboMapping.syntax("heimlieferungAbo")
lazy val postlieferungAbo = postlieferungAboMapping.syntax("postlieferungAbo")
- lazy val projekt = projektMapping.syntax("projekt")
protected def getArbeitskategorienQuery = {
withSQL {
@@ -252,12 +252,4 @@ trait ArbeitseinsatzRepositoryQueries extends LazyLogging with ArbeitseinsatzDBM
.where.eq(arbeitseinsatz.arbeitsangebotId, arbeitsangebotId)
}.map(personMapping(person)).list
}
-
- protected def getProjektQuery = {
- withSQL {
- select
- .from(projektMapping as projekt)
- }.map(projektMapping(projekt)).single
- }
-
}
diff --git a/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungAktionenService.scala b/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungAktionenService.scala
index 5edb36d2d..8c7cedfa9 100644
--- a/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungAktionenService.scala
+++ b/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungAktionenService.scala
@@ -26,7 +26,6 @@ import ch.openolitor.core._
import ch.openolitor.core.db._
import ch.openolitor.core.domain._
import ch.openolitor.buchhaltung.models._
-import ch.openolitor.stammdaten.models.{ KundeId, Person, PersonEmailData, Projekt }
import ch.openolitor.core.models.PersonId
import scalikejdbc._
import com.typesafe.scalalogging.LazyLogging
@@ -42,35 +41,33 @@ import ch.openolitor.buchhaltung.repositories.DefaultBuchhaltungWriteRepositoryC
import ch.openolitor.buchhaltung.repositories.BuchhaltungWriteRepositoryComponent
import ch.openolitor.core.repositories.EventPublishingImplicits._
import ch.openolitor.core.repositories.EventPublisher
-import ch.openolitor.stammdaten.EmailHandler
+import ch.openolitor.stammdaten.MailCommandForwarder
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
object BuchhaltungAktionenService {
- def apply(implicit sysConfig: SystemConfig, system: ActorSystem, mailService: ActorRef): BuchhaltungAktionenService = new DefaultBuchhaltungAktionenService(sysConfig, system, mailService)
+ def apply(implicit sysConfig: SystemConfig, system: ActorSystem): BuchhaltungAktionenService = new DefaultBuchhaltungAktionenService(sysConfig, system)
}
-class DefaultBuchhaltungAktionenService(sysConfig: SystemConfig, override val system: ActorSystem, override val mailService: ActorRef)
- extends BuchhaltungAktionenService(sysConfig, mailService, system.dispatcher) with DefaultBuchhaltungWriteRepositoryComponent {}
+class DefaultBuchhaltungAktionenService(sysConfig: SystemConfig, override val system: ActorSystem)
+ extends BuchhaltungAktionenService(sysConfig, system.dispatcher) with DefaultBuchhaltungWriteRepositoryComponent {}
/**
* Actor zum Verarbeiten der Aktionen für das Buchhaltung Modul
*/
-class BuchhaltungAktionenService(override val sysConfig: SystemConfig, override val mailService: ActorRef, override implicit val executionContext: ExecutionContext) extends EventService[PersistentEvent]
+class BuchhaltungAktionenService(override val sysConfig: SystemConfig, override implicit val executionContext: ExecutionContext) extends EventService[PersistentEvent]
with LazyLogging
with AsyncConnectionPoolContextAware
with BuchhaltungDBMappings
- with MailServiceReference
with BuchhaltungEventStoreSerializer
with MailTemplateService
- with EmailHandler
with SystemConfigReference
with ExecutionContextAware {
self: BuchhaltungWriteRepositoryComponent =>
val Zero = 0
- override val False = false
+ val False = false
implicit val timeout = Timeout(config.getStringOption("openolitor.emailTimeOut").getOrElse("15").toInt.seconds)
@@ -97,8 +94,6 @@ class BuchhaltungAktionenService(override val sysConfig: SystemConfig, override
rechnungPDFStored(meta, rechnungId, fileStoreId)
case MahnungPDFStoredEvent(meta, rechnungId, fileStoreId) =>
mahnungPDFStored(meta, rechnungId, fileStoreId)
- case SendEmailToInvoiceSubscribersEvent(meta, subject, body, replyTo, invoice, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, invoice, context, mailService)
case e =>
logger.warn(s"Unknown event:$e")
}
@@ -285,16 +280,4 @@ class BuchhaltungAktionenService(override val sysConfig: SystemConfig, override
}
}
}
-
- protected def checkBccAndSend(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], person: PersonEmailData, invoiceReference: Option[String], context: Product, mailService: ActorRef)(implicit originator: PersonId = meta.originator): Unit = {
- DB localTxPostPublish { implicit session => implicit publisher =>
- lazy val bccAddress = config.getString("smtp.bcc")
- buchhaltungWriteRepository.getProjekt map { projekt: Projekt =>
- projekt.sendEmailToBcc match {
- case true => sendEmail(meta, subject, body, replyTo, Some(bccAddress), person, invoiceReference, context, mailService)
- case false => sendEmail(meta, subject, body, replyTo, None, person, invoiceReference, context, mailService)
- }
- }
- }
- }
}
diff --git a/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungCommandHandler.scala b/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungCommandHandler.scala
index cf2dee3cd..7b1f0810b 100644
--- a/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungCommandHandler.scala
+++ b/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungCommandHandler.scala
@@ -33,7 +33,7 @@ import scalikejdbc.DB
import scalikejdbc.DBSession
import ch.openolitor.buchhaltung.models._
import ch.openolitor.core.exceptions.InvalidStateException
-import akka.actor.ActorSystem
+import akka.actor.{ ActorRef, ActorSystem }
import ch.openolitor.core._
import ch.openolitor.core.filestore.FileTypeFilenameMapping
import ch.openolitor.core.db.ConnectionPoolContextAware
@@ -42,6 +42,7 @@ import ch.openolitor.core.db.AsyncConnectionPoolContextAware
import ch.openolitor.buchhaltung.repositories.DefaultBuchhaltungReadRepositorySyncComponent
import ch.openolitor.buchhaltung.repositories.BuchhaltungReadRepositorySyncComponent
import ch.openolitor.core.Macros.copyTo
+import ch.openolitor.stammdaten.{ DefaultMailCommandForwarderComponent, MailCommandForwarderComponent, ProjektHelper }
import scala.concurrent.ExecutionContext
@@ -92,8 +93,9 @@ trait BuchhaltungCommandHandler extends CommandHandler
with AsyncConnectionPoolContextAware
with FileTypeFilenameMapping
with MailTemplateService
+ with ProjektHelper
with ExecutionContextAware {
- self: BuchhaltungReadRepositorySyncComponent =>
+ self: BuchhaltungReadRepositorySyncComponent with MailCommandForwarderComponent =>
import BuchhaltungCommandHandler._
import EntityStore._
@@ -262,8 +264,13 @@ trait BuchhaltungCommandHandler extends CommandHandler
val mailContext = RechnungMailContext(personEmailData, rechnung)
if (attachInvoice) {
val documentToAttach = if (rechnung.mahnungFileStoreIds.isEmpty) rechnung.fileStoreId else Some(rechnung.mahnungFileStoreIds.head)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, documentToAttach, mailContext)
+
DefaultResultingEvent(factory => SendEmailToInvoiceSubscribersEvent(factory.newMetadata(), subject, body, replyTo, documentToAttach, mailContext))
} else {
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
DefaultResultingEvent(factory => SendEmailToInvoiceSubscribersEvent(factory.newMetadata(), subject, body, replyTo, None, mailContext))
}
}
@@ -395,7 +402,9 @@ trait BuchhaltungCommandHandler extends CommandHandler
}
}
-class DefaultBuchhaltungCommandHandler(override val sysConfig: SystemConfig, override val system: ActorSystem) extends BuchhaltungCommandHandler
- with DefaultBuchhaltungReadRepositorySyncComponent {
+class DefaultBuchhaltungCommandHandler(override val sysConfig: SystemConfig, override val system: ActorSystem, override val mailService: ActorRef) extends BuchhaltungCommandHandler
+ with DefaultBuchhaltungReadRepositorySyncComponent with DefaultMailCommandForwarderComponent with MailServiceReference {
override implicit protected val executionContext: ExecutionContext = system.dispatcher
+
+ override def projektReadRepository = buchhaltungReadRepository
}
diff --git a/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungEntityStoreView.scala b/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungEntityStoreView.scala
index eaba479bd..d3e83bf6a 100644
--- a/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungEntityStoreView.scala
+++ b/src/main/scala/ch/openolitor/buchhaltung/BuchhaltungEntityStoreView.scala
@@ -32,10 +32,10 @@ import ch.openolitor.buchhaltung.repositories.BuchhaltungWriteRepositoryComponen
import akka.actor.ActorRef
object BuchhaltungEntityStoreView {
- def props(mailService: ActorRef, dbEvolutionActor: ActorRef, airbrakeNotifier: ActorRef)(implicit sysConfig: SystemConfig, system: ActorSystem): Props = Props(classOf[DefaultBuchhaltungEntityStoreView], mailService, dbEvolutionActor, sysConfig, system, airbrakeNotifier)
+ def props(dbEvolutionActor: ActorRef, airbrakeNotifier: ActorRef)(implicit sysConfig: SystemConfig, system: ActorSystem): Props = Props(classOf[DefaultBuchhaltungEntityStoreView], dbEvolutionActor, sysConfig, system, airbrakeNotifier)
}
-class DefaultBuchhaltungEntityStoreView(override val mailService: ActorRef, override val dbEvolutionActor: ActorRef, implicit val sysConfig: SystemConfig, implicit val system: ActorSystem, val airbrakeNotifier: ActorRef) extends BuchhaltungEntityStoreView
+class DefaultBuchhaltungEntityStoreView(override val dbEvolutionActor: ActorRef, implicit val sysConfig: SystemConfig, implicit val system: ActorSystem, val airbrakeNotifier: ActorRef) extends BuchhaltungEntityStoreView
with DefaultBuchhaltungWriteRepositoryComponent
/**
@@ -51,7 +51,7 @@ trait BuchhaltungEntityStoreView extends EntityStoreView
/**
* Instanzieren der jeweiligen Insert, Update und Delete Child Actors
*/
-trait BuchhaltungEntityStoreViewComponent extends EntityStoreViewComponent with MailServiceReference {
+trait BuchhaltungEntityStoreViewComponent extends EntityStoreViewComponent {
val sysConfig: SystemConfig
val system: ActorSystem
@@ -59,5 +59,5 @@ trait BuchhaltungEntityStoreViewComponent extends EntityStoreViewComponent with
override val updateService = BuchhaltungUpdateService(sysConfig, system)
override val deleteService = BuchhaltungDeleteService(sysConfig, system)
- override val aktionenService = BuchhaltungAktionenService(sysConfig, system, mailService)
+ override val aktionenService = BuchhaltungAktionenService(sysConfig, system)
}
\ No newline at end of file
diff --git a/src/main/scala/ch/openolitor/buchhaltung/reporting/RechnungReportData.scala b/src/main/scala/ch/openolitor/buchhaltung/reporting/RechnungReportData.scala
index e6901274f..a9322fb6c 100644
--- a/src/main/scala/ch/openolitor/buchhaltung/reporting/RechnungReportData.scala
+++ b/src/main/scala/ch/openolitor/buchhaltung/reporting/RechnungReportData.scala
@@ -94,7 +94,7 @@ trait RechnungReportData extends AsyncConnectionPoolContextAware with Buchhaltun
case _ => Language.DE
}
billFormat.setLanguage(language)
- billFormat.setOutputSize(OutputSize.QR_BILL_WITH_HORIZONTAL_LINE)
+ billFormat.setOutputSize(OutputSize.QR_BILL_EXTRA_SPACE)
billFormat.setSeparatorType(SeparatorType.DASHED_LINE_WITH_SCISSORS)
bill.setFormat(billFormat)
//this value is mandatory for the qrCode. In case of generating qrCode
diff --git a/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungReadRepositorySync.scala b/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungReadRepositorySync.scala
index a08cbffb3..9ea903cad 100644
--- a/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungReadRepositorySync.scala
+++ b/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungReadRepositorySync.scala
@@ -27,9 +27,10 @@ import ch.openolitor.core.repositories._
import ch.openolitor.stammdaten.models._
import com.typesafe.scalalogging.LazyLogging
import ch.openolitor.buchhaltung.models._
+import ch.openolitor.stammdaten.repositories.{ ProjektReadRepositorySync, ProjektReadRepositorySyncImpl }
import ch.openolitor.util.parsing.{ FilterExpr, QueryFilter }
-trait BuchhaltungReadRepositorySync extends BaseReadRepositorySync {
+trait BuchhaltungReadRepositorySync extends BaseReadRepositorySync with ProjektReadRepositorySync {
def getRechnungen(implicit session: DBSession, cpContext: ConnectionPoolContext): List[Rechnung]
def getKundenRechnungen(kundeId: KundeId)(implicit session: DBSession, cpContext: ConnectionPoolContext): List[Rechnung]
def getRechnungDetail(id: RechnungId)(implicit session: DBSession, cpContext: ConnectionPoolContext): Option[RechnungDetail]
@@ -47,10 +48,9 @@ trait BuchhaltungReadRepositorySync extends BaseReadRepositorySync {
def getKontoDatenProjekt(implicit session: DBSession): Option[KontoDaten]
def getKontoDatenKunde(id: KundeId)(implicit session: DBSession): Option[KontoDaten]
- def getProjekt(implicit session: DBSession): Option[Projekt]
}
-trait BuchhaltungReadRepositorySyncImpl extends BuchhaltungReadRepositorySync with LazyLogging with BuchhaltungRepositoryQueries {
+trait BuchhaltungReadRepositorySyncImpl extends BuchhaltungReadRepositorySync with LazyLogging with BuchhaltungRepositoryQueries with ProjektReadRepositorySyncImpl {
def getRechnungen(implicit session: DBSession, cpContext: ConnectionPoolContext): List[Rechnung] = {
getRechnungenQuery(None, None, None).apply()
}
@@ -102,8 +102,4 @@ trait BuchhaltungReadRepositorySyncImpl extends BuchhaltungReadRepositorySync wi
def getZahlungsExportDetail(id: ZahlungsExportId)(implicit session: DBSession, cpContext: ConnectionPoolContext): Option[ZahlungsExport] = {
getZahlungsExportQuery(id).apply()
}
-
- def getProjekt(implicit session: DBSession): Option[Projekt] = {
- getProjektQuery.apply()
- }
}
diff --git a/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungRepositoryQueries.scala b/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungRepositoryQueries.scala
index e5176da1e..f8942f0a0 100644
--- a/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungRepositoryQueries.scala
+++ b/src/main/scala/ch/openolitor/buchhaltung/repositories/BuchhaltungRepositoryQueries.scala
@@ -27,12 +27,13 @@ import ch.openolitor.buchhaltung.BuchhaltungDBMappings
import ch.openolitor.core.Macros._
import ch.openolitor.stammdaten.models._
import ch.openolitor.stammdaten.StammdatenDBMappings
+import ch.openolitor.stammdaten.repositories.StammdatenProjektRepositoryQueries
import ch.openolitor.util.parsing.{ FilterAttributeList, FilterExpr, GeschaeftsjahrFilter, QueryFilter }
import ch.openolitor.util.querybuilder.UriQueryParamToSQLSyntaxBuilder
import com.typesafe.scalalogging.LazyLogging
import scalikejdbc._
-trait BuchhaltungRepositoryQueries extends LazyLogging with BuchhaltungDBMappings with StammdatenDBMappings {
+trait BuchhaltungRepositoryQueries extends LazyLogging with BuchhaltungDBMappings with StammdatenDBMappings with StammdatenProjektRepositoryQueries {
lazy val rechnung = rechnungMapping.syntax("rechnung")
lazy val rechnungsPosition = rechnungsPositionMapping.syntax("rechnungsPosition")
lazy val kunde = kundeMapping.syntax("kunde")
@@ -45,7 +46,6 @@ trait BuchhaltungRepositoryQueries extends LazyLogging with BuchhaltungDBMapping
lazy val zusatzAbo = zusatzAboMapping.syntax("zusatzAbo")
lazy val kontoDaten = kontoDatenMapping.syntax("kontoDaten")
lazy val person = personMapping.syntax("pers")
- lazy val projekt = projektMapping.syntax("projekt")
protected def getRechnungenQuery(filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter], queryString: Option[QueryFilter]) = {
queryString match {
@@ -254,11 +254,4 @@ trait BuchhaltungRepositoryQueries extends LazyLogging with BuchhaltungDBMapping
.where.eq(kontoDaten.kunde, kundeId)
}.map(kontoDatenMapping(kontoDaten)).single
}
-
- protected def getProjektQuery = {
- withSQL {
- select
- .from(projektMapping as projekt)
- }.map(projektMapping(projekt)).single
- }
}
diff --git a/src/main/scala/ch/openolitor/core/ExecutionContextAware.scala b/src/main/scala/ch/openolitor/core/ExecutionContextAware.scala
index 1beb5d4e2..7fddf9eb6 100644
--- a/src/main/scala/ch/openolitor/core/ExecutionContextAware.scala
+++ b/src/main/scala/ch/openolitor/core/ExecutionContextAware.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core
import scala.concurrent.ExecutionContext
diff --git a/src/main/scala/ch/openolitor/core/FileStoreReference.scala b/src/main/scala/ch/openolitor/core/FileStoreReference.scala
index c5adf614c..fbad5917e 100644
--- a/src/main/scala/ch/openolitor/core/FileStoreReference.scala
+++ b/src/main/scala/ch/openolitor/core/FileStoreReference.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core
import ch.openolitor.core.filestore.FileStore
diff --git a/src/main/scala/ch/openolitor/core/StartingServices.scala b/src/main/scala/ch/openolitor/core/StartingServices.scala
index 06d63aa1d..ea3c48ebc 100644
--- a/src/main/scala/ch/openolitor/core/StartingServices.scala
+++ b/src/main/scala/ch/openolitor/core/StartingServices.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core
import akka.actor.{ ActorRef, ActorSystem }
@@ -60,12 +82,13 @@ trait StartingServices extends LazyLogging {
logger.debug(s"oo-system:$system")
val dbEvolutionActor = Await.result(system ? SystemActor.Child(DBEvolutionActor.props(evolution), "db-evolution"), duration).asInstanceOf[ActorRef]
logger.debug(s"oo-system:$system -> dbEvolutionActor:$dbEvolutionActor")
- val entityStore = Await.result(system ? SystemActor.Child(EntityStore.props(dbEvolutionActor, evolution), "entity-store"), duration).asInstanceOf[ActorRef]
+ val mailService = Await.result(system ? SystemActor.Child(MailService.props(dbEvolutionActor, fileStore), "mail-service"), duration).asInstanceOf[ActorRef]
+ logger.debug(s"oo-system:$system -> eventStore:$mailService")
+
+ val entityStore = Await.result(system ? SystemActor.Child(EntityStore.props(dbEvolutionActor, evolution, mailService), "entity-store"), duration).asInstanceOf[ActorRef]
logger.debug(s"oo-system:$system -> entityStore:$entityStore")
val eventStore = Await.result(system ? SystemActor.Child(SystemEventStore.props(dbEvolutionActor), "event-store"), duration).asInstanceOf[ActorRef]
logger.debug(s"oo-system:$system -> eventStore:$eventStore")
- val mailService = Await.result(system ? SystemActor.Child(MailService.props(dbEvolutionActor, fileStore), "mail-service"), duration).asInstanceOf[ActorRef]
- logger.debug(s"oo-system:$system -> eventStore:$mailService")
// STAMMDATEN
val stammdatenEntityStoreView = Await.result(system ? SystemActor.Child(StammdatenEntityStoreView.props(mailService, dbEvolutionActor, airbrakeNotifier), "stammdaten-entity-store-view"), duration).asInstanceOf[ActorRef]
@@ -78,14 +101,14 @@ trait StartingServices extends LazyLogging {
Await.result(system ? SystemActor.Child(StammdatenGeneratedEventsListener.props, "stammdaten-generated-events-listener"), duration).asInstanceOf[ActorRef]
// BUCHHALTUNG
- val buchhaltungEntityStoreView = Await.result(system ? SystemActor.Child(BuchhaltungEntityStoreView.props(mailService, dbEvolutionActor, airbrakeNotifier), "buchhaltung-entity-store-view"), duration).asInstanceOf[ActorRef]
+ val buchhaltungEntityStoreView = Await.result(system ? SystemActor.Child(BuchhaltungEntityStoreView.props(dbEvolutionActor, airbrakeNotifier), "buchhaltung-entity-store-view"), duration).asInstanceOf[ActorRef]
// start listeners for buchhaltung
Await.result(system ? SystemActor.Child(BuchhaltungDBEventEntityListener.props, "buchhaltung-dbevent-entity-listener"), duration).asInstanceOf[ActorRef]
Await.result(system ? SystemActor.Child(BuchhaltungReportEventListener.props(entityStore), "buchhaltung-report-event-listener"), duration).asInstanceOf[ActorRef]
// ARBEITSEINSATZ
- val arbeitseinsatzEntityStoreView = Await.result(system ? SystemActor.Child(ArbeitseinsatzEntityStoreView.props(mailService, dbEvolutionActor, airbrakeNotifier), "arbeitseinsatz-entity-store-view"), duration).asInstanceOf[ActorRef]
+ val arbeitseinsatzEntityStoreView = Await.result(system ? SystemActor.Child(ArbeitseinsatzEntityStoreView.props(dbEvolutionActor, airbrakeNotifier), "arbeitseinsatz-entity-store-view"), duration).asInstanceOf[ActorRef]
// MAILTEMPLATE
val mailTemplateEntityStoreView = Await.result(system ? SystemActor.Child(MailTemplateEntityStoreView.props(dbEvolutionActor, airbrakeNotifier), "mailtemplate-entity-store-view"), duration).asInstanceOf[ActorRef]
diff --git a/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO69_kunde_aktiv.scala b/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO69_kunde_aktiv.scala
index fa5f3e5b3..7016409d4 100644
--- a/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO69_kunde_aktiv.scala
+++ b/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO69_kunde_aktiv.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core.db.evolution.scripts.v2
import ch.openolitor.core.SystemConfig
diff --git a/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO829_add_zusatzabo_info_to_abo.scala b/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO829_add_zusatzabo_info_to_abo.scala
index 562d27897..0cb68a19c 100644
--- a/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO829_add_zusatzabo_info_to_abo.scala
+++ b/src/main/scala/ch/openolitor/core/db/evolution/scripts/v2/OO829_add_zusatzabo_info_to_abo.scala
@@ -8,7 +8,7 @@
* *
* This program is free software: you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by *
-* the Free Software Foundation, either versiON 3 of the License, *
+* 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 *
diff --git a/src/main/scala/ch/openolitor/core/domain/AggregateRoot.scala b/src/main/scala/ch/openolitor/core/domain/AggregateRoot.scala
index 8d4984367..c9cc0c4e6 100644
--- a/src/main/scala/ch/openolitor/core/domain/AggregateRoot.scala
+++ b/src/main/scala/ch/openolitor/core/domain/AggregateRoot.scala
@@ -69,13 +69,11 @@ trait AggregateRoot extends PersistentActor with ActorLogging with PersistenceEv
log.debug(s"$persistenceId: initialize aquire transaction nr to $lastAquiredTransactionNr")
}
- protected def afterEventPersisted(evt: PersistentEvent): Unit = {
+ protected final def afterEventPersisted(evt: PersistentEvent): Unit = {
updateState(recovery = false)(evt)
publish(evt)
setLastProcessedSequenceNr(evt.meta)
-
- sender() ! state
}
protected def aquireTransactionNr(): Long = {
diff --git a/src/main/scala/ch/openolitor/core/domain/CommandHandlerComponent.scala b/src/main/scala/ch/openolitor/core/domain/CommandHandlerComponent.scala
index 2c68d56ae..8413bd1b0 100644
--- a/src/main/scala/ch/openolitor/core/domain/CommandHandlerComponent.scala
+++ b/src/main/scala/ch/openolitor/core/domain/CommandHandlerComponent.scala
@@ -26,10 +26,10 @@ import ch.openolitor.buchhaltung.DefaultBuchhaltungCommandHandler
import ch.openolitor.core.SystemConfig
import ch.openolitor.kundenportal.DefaultKundenportalCommandHandler
import ch.openolitor.arbeitseinsatz.DefaultArbeitseinsatzCommandHandler
-import ch.openolitor.stammdaten.DefaultStammdatenCommandHandler
+import ch.openolitor.stammdaten.{ DefaultMailCommandForwarderComponent, DefaultStammdatenCommandHandler, MailCommandForwarder }
import ch.openolitor.reports.DefaultReportsCommandHandler
-import akka.actor.ActorSystem
-import ch.openolitor.mailtemplates.{ DefaultMailTemplateCommandHanlder }
+import akka.actor.{ ActorRef, ActorSystem }
+import ch.openolitor.mailtemplates.DefaultMailTemplateCommandHanlder
trait CommandHandlerComponent {
val stammdatenCommandHandler: CommandHandler
@@ -44,12 +44,13 @@ trait CommandHandlerComponent {
trait DefaultCommandHandlerComponent extends CommandHandlerComponent {
val sysConfig: SystemConfig
val system: ActorSystem
+ val mailService: ActorRef
- override val stammdatenCommandHandler = new DefaultStammdatenCommandHandler(sysConfig, system)
- override val buchhaltungCommandHandler = new DefaultBuchhaltungCommandHandler(sysConfig, system)
- override val arbeitseinsatzCommandHandler = new DefaultArbeitseinsatzCommandHandler(sysConfig, system)
- override val reportsCommandHandler = new DefaultReportsCommandHandler(sysConfig, system)
+ override val stammdatenCommandHandler: CommandHandler = new DefaultStammdatenCommandHandler(sysConfig, system, mailService)
+ override val buchhaltungCommandHandler: CommandHandler = new DefaultBuchhaltungCommandHandler(sysConfig, system, mailService)
+ override val arbeitseinsatzCommandHandler: CommandHandler = new DefaultArbeitseinsatzCommandHandler(sysConfig, system, mailService)
+ override val reportsCommandHandler: CommandHandler = new DefaultReportsCommandHandler(sysConfig, system)
override val mailTemplateCommandHandler: CommandHandler = new DefaultMailTemplateCommandHanlder(sysConfig, system)
- override val kundenportalCommandHandler = new DefaultKundenportalCommandHandler(sysConfig, system)
- override val baseCommandHandler = new BaseCommandHandler()
+ override val kundenportalCommandHandler: CommandHandler = new DefaultKundenportalCommandHandler(sysConfig, system)
+ override val baseCommandHandler: CommandHandler = new BaseCommandHandler()
}
diff --git a/src/main/scala/ch/openolitor/core/domain/EntityStore.scala b/src/main/scala/ch/openolitor/core/domain/EntityStore.scala
index 8183bf2c5..a389a1911 100644
--- a/src/main/scala/ch/openolitor/core/domain/EntityStore.scala
+++ b/src/main/scala/ch/openolitor/core/domain/EntityStore.scala
@@ -51,7 +51,7 @@ object EntityStore {
val persistenceId = "entity-store"
case class EntityStoreState(dbSeeds: Map[Class[_ <: BaseId], Long]) extends State
- def props(dbEvolutionActor: ActorRef, evolution: Evolution)(implicit sysConfig: SystemConfig): Props = Props(classOf[DefaultEntityStore], sysConfig, dbEvolutionActor, evolution)
+ def props(dbEvolutionActor: ActorRef, evolution: Evolution, mailService: ActorRef)(implicit sysConfig: SystemConfig): Props = Props(classOf[DefaultEntityStore], sysConfig, dbEvolutionActor, evolution, mailService)
//base commands
case class InsertEntityCommand[E <: AnyRef](originator: PersonId, entity: E) extends UserCommand {
@@ -288,7 +288,7 @@ trait EntityStore extends AggregateRoot
override val receiveCommand: Receive = uninitialized
}
-class DefaultEntityStore(override val sysConfig: SystemConfig, override val dbEvolutionActor: ActorRef, override val evolution: Evolution) extends EntityStore
+class DefaultEntityStore(override val sysConfig: SystemConfig, override val dbEvolutionActor: ActorRef, override val evolution: Evolution, override val mailService: ActorRef) extends EntityStore
with DefaultCommandHandlerComponent {
lazy val system: ActorSystem = context.system
}
diff --git a/src/main/scala/ch/openolitor/core/domain/Events.scala b/src/main/scala/ch/openolitor/core/domain/Events.scala
index 82ab74b13..4c8a00f25 100644
--- a/src/main/scala/ch/openolitor/core/domain/Events.scala
+++ b/src/main/scala/ch/openolitor/core/domain/Events.scala
@@ -40,6 +40,17 @@ case class EventTransactionMetadata(originator: PersonId, version: Int, timestam
}
}
+/**
+ * Event metadata managed by OpenOlitor.
+ *
+ * @param originator the originator of the command that led to this event metadata.
+ * @param version the version of the event store or more specific aggregate root.
+ * @param timestamp the timestamp when the event has been created by the event store.
+ * @param transactionNr the transaction number identifying one or more events that resulted out of a command.
+ * @param seqNr this is not to be confused with the sequenceNr which is managed by akka persistence. It is just representing the sequence nr of
+ * events within the given transactionNr. The name is misleading and unfortunately often mistaken for akka persistence's sequenceId.
+ * @param source the persistence id of the aggregate root that created the event with this metadata.
+ */
case class EventMetadata(originator: PersonId, version: Int, timestamp: DateTime, transactionNr: Long, seqNr: Long, source: String)
trait PersistentEvent extends Serializable {
@@ -57,7 +68,10 @@ object SystemEvents {
val SystemPersonId = PersonId(0)
case class PersonLoggedIn(personId: PersonId, timestamp: DateTime, secondFactorType: Option[SecondFactorType]) extends SystemEvent with JSONSerializable
+
case class PersonChangedOtpSecret(personId: PersonId, secret: String) extends SystemEvent with JSONSerializable
+
case class PersonChangedSecondFactorType(personId: PersonId, secondFactorType: Option[SecondFactorType]) extends SystemEvent with JSONSerializable
+
case class SystemStarted(timestamp: DateTime) extends SystemEvent
}
diff --git a/src/main/scala/ch/openolitor/core/mailservice/MailService.scala b/src/main/scala/ch/openolitor/core/mailservice/MailService.scala
index db6fecb75..bba8adc88 100644
--- a/src/main/scala/ch/openolitor/core/mailservice/MailService.scala
+++ b/src/main/scala/ch/openolitor/core/mailservice/MailService.scala
@@ -25,10 +25,10 @@ package ch.openolitor.core.mailservice
import java.util.UUID
import akka.actor._
import akka.persistence.SnapshotMetadata
-import ch.openolitor.core.domain.{ AggregateRoot, _ }
+import ch.openolitor.core.domain.{AggregateRoot, _}
import ch.openolitor.core.models.PersonId
import ch.openolitor.core.db.ConnectionPoolContextAware
-import ch.openolitor.core.{ JSONSerializable, SystemConfig }
+import ch.openolitor.core.{JSONSerializable, SystemConfig}
import ch.openolitor.core.filestore._
import ch.openolitor.util.ConfigUtil._
import courier._
@@ -41,7 +41,7 @@ import scala.collection.compat.immutable.ArraySeq
import scala.collection.immutable.TreeSet
import scala.concurrent.duration._
import scala.concurrent.Await
-import scala.util.{ Failure, Success }
+import scala.util.{Failure, Success}
object MailService {
@@ -50,22 +50,62 @@ object MailService {
case class MailServiceState(startTime: DateTime, mailQueue: TreeSet[MailEnqueued]) extends State
- case class SendMailCommandWithCallback[M <: AnyRef](originator: PersonId, entity: Mail, retryDuration: Option[Duration], commandMeta: M)(implicit p: Persister[M, _]) extends UserCommand
+ case class SendMailCommandWithCallback[M <: AnyRef](originator: PersonId, entity: Mail, retryDuration: Option[Duration], commandMeta: M)(implicit
+ p: Persister[M,
+ _]) extends
+ UserCommand
+
case class SendMailCommand(originator: PersonId, entity: Mail, retryDuration: Option[Duration]) extends UserCommand
//events raised by this aggregateroot
case class MailServiceInitialized(meta: EventMetadata) extends PersistentEvent
+
// resulting send mail event
- case class SendMailEvent(meta: EventMetadata, uid: String, mail: Mail, expires: DateTime, commandMeta: Option[AnyRef]) extends PersistentEvent with JSONSerializable
+ case class SendMailEvent(meta: EventMetadata, uid: String, mail: Mail, expires: DateTime, commandMeta: Option[AnyRef]) extends PersistentEvent with
+ JSONSerializable
+
case class MailSentEvent(meta: EventMetadata, uid: String, commandMeta: Option[AnyRef]) extends PersistentEvent with JSONSerializable
- case class SendMailFailedEvent(meta: EventMetadata, uid: String, numberOfRetries: Int, commandMeta: Option[AnyRef]) extends PersistentEvent with JSONSerializable
- def props(dbEvolutionActor: ActorRef, fileStore: FileStore)(implicit sysConfig: SystemConfig): Props = Props(classOf[DefaultMailService], sysConfig, dbEvolutionActor, fileStore)
+ case class SendMailFailedEvent(meta: EventMetadata, uid: String, numberOfRetries: Int, commandMeta: Option[AnyRef]) extends PersistentEvent with
+ JSONSerializable
+
+ def props(dbEvolutionActor: ActorRef, fileStore: FileStore)(implicit sysConfig: SystemConfig): Props = Props(classOf[DefaultMailService], sysConfig,
+ dbEvolutionActor, fileStore)
case object CheckMailQueue
+
case object CheckMailQueueComplete
}
+/**
+ * TODO: rename to MailEventStore or MailStore.
+ *
+ * The mail event store should be called from other commands and not out of event processing. Make sure to check and filter already sent mails beforehand
+ * when calling it from processing events. This can be achieved by managing an entity that has a `sent: Option[DateTime]`.
+ *
+ * The following pattern requires filtering as mentioned above:
+ * ┌─────────┐ ┌──────────┐ vvvvvv ┌────────────┐ ┌──────────┐
+ * │ Command ├──────► Event(s) ├─── Filter ───► Command(s) ├──────► Event(s) │
+ * └─────────┘ └──────────┘ ^^^^^^ └────────────┘ └──────────┘
+ *
+ * The preferred method is to trigger it via [[ch.openolitor.stammdaten.MailCommandForwarder]] which can be caked in using the component:
+ * [[ch.openolitor.stammdaten.MailCommandForwarderComponent]].
+ *
+ * This results in mail sending commands being triggered by the initial command:
+ * ┌─────────┐ ┌────────────┐ ┌──────────┐
+ * │ Command ├──────► Command(s) ├──────► Event(s) │
+ * └────┬────┘ └────────────┘ └──────────┘
+ * │ │
+ * │ │ ┌──────────┐
+ * │ └───────────► Event(s) │
+ * │ └──────────┘
+ *
+ * Note that there is no [[EntityStoreView]] that reads the `journal` based on [[MailService.persistenceId]]. Therefore, this aggregate root only reacts to
+ * [[ch.openolitor.core.mailservice.MailService.SendMailEvent]]s in live mode and does not replay them on recovery.
+ *
+ * In the case of encountering resending of emails, we can assume that they are created because `entity-store` events are reprocessed that trigger sending
+ * email commands.
+ */
trait MailService extends AggregateRoot
with ConnectionPoolContextAware
with FileStoreComponent
@@ -76,7 +116,9 @@ trait MailService extends AggregateRoot
import MailService._
override val fileStore: FileStore = null
+
override def persistenceId: String = MailService.persistenceId
+
type S = MailServiceState
lazy val fromAddress: String = sysConfig.mandantConfiguration.config.getString("smtp.from")
lazy val maxNumberOfRetries: Int = sysConfig.mandantConfiguration.config.getInt("smtp.number-of-retries")
@@ -98,11 +140,6 @@ trait MailService extends AggregateRoot
override var state: MailServiceState = MailServiceState(DateTime.now, TreeSet.empty[MailEnqueued])
- override protected def afterEventPersisted(evt: PersistentEvent): Unit = {
- updateState(recovery = false)(evt)
- publish(evt)
- }
-
def initialize(): Unit = {
// start mail queue checker
context.system.scheduler.scheduleWithFixedDelay(0 seconds, 10 seconds, self, CheckMailQueue)(context.system.dispatcher)
@@ -161,7 +198,7 @@ trait MailService extends AggregateRoot
val result = envelope match {
case Right(e) => Await.ready(mailer(e), 20 seconds).value match {
case Some(e) => Right(e)
- case None => Left("Error sending the email")
+ case None => Left("Error sending the email")
}
case Left(e) => Left(e)
}
@@ -225,10 +262,10 @@ trait MailService extends AggregateRoot
override def restoreFromSnapshot(metadata: SnapshotMetadata, state: State): Unit = {
log.debug(s"restoreFromSnapshot:$state")
state match {
- case Removed => context become removed
- case Created => context become uninitialized
+ case Removed => context become removed
+ case Created => context become uninitialized
case s: MailServiceState => this.state = s
- case other: Any => log.error(s"Received unsupported state:$other")
+ case other: Any => log.error(s"Received unsupported state:$other")
}
}
@@ -311,7 +348,6 @@ trait MailService extends AggregateRoot
}
class DefaultMailService(override val sysConfig: SystemConfig, override val dbEvolutionActor: ActorRef, override val fileStore: FileStore) extends MailService
- with DefaultCommandHandlerComponent
with DefaultMailRetryHandler {
lazy val system: ActorSystem = context.system
}
diff --git a/src/main/scala/ch/openolitor/core/security/BasicAuthenticatorProvider.scala b/src/main/scala/ch/openolitor/core/security/BasicAuthenticatorProvider.scala
index a45d8ef9f..31737357d 100644
--- a/src/main/scala/ch/openolitor/core/security/BasicAuthenticatorProvider.scala
+++ b/src/main/scala/ch/openolitor/core/security/BasicAuthenticatorProvider.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core.security
import akka.http.scaladsl.model.headers.{ BasicHttpCredentials, HttpChallenges }
diff --git a/src/main/scala/ch/openolitor/core/security/LoginService.scala b/src/main/scala/ch/openolitor/core/security/LoginService.scala
index 54c64aa2b..aca4e60f1 100644
--- a/src/main/scala/ch/openolitor/core/security/LoginService.scala
+++ b/src/main/scala/ch/openolitor/core/security/LoginService.scala
@@ -1,17 +1,39 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core.security
-import akka.http.caching.scaladsl.{ Cache, CachingSettings }
+import akka.http.caching.scaladsl.{Cache, CachingSettings}
import akka.http.caching.LfuCache
import akka.pattern.ask
import akka.util.Timeout
-import ch.openolitor.core.{ ActorReferences, ExecutionContextAware, SystemConfigReference }
+import ch.openolitor.core.{ActorReferences, ExecutionContextAware, SystemConfigReference}
import ch.openolitor.core.Macros.copyTo
import ch.openolitor.core.db.AsyncConnectionPoolContextAware
import ch.openolitor.core.domain.SystemEvents
import ch.openolitor.core.mailservice.Mail
-import ch.openolitor.core.mailservice.MailService.{ SendMailCommand, SendMailEvent }
+import ch.openolitor.core.mailservice.MailService.{MailServiceState, SendMailCommand, SendMailEvent}
import ch.openolitor.core.models.PersonId
-import ch.openolitor.stammdaten.StammdatenCommandHandler.{ PasswortGewechseltEvent, PasswortResetCommand, PasswortResetGesendetEvent, PasswortWechselCommand }
+import ch.openolitor.stammdaten.StammdatenCommandHandler.{PasswortGewechseltEvent, PasswortResetCommand, PasswortResetGesendetEvent, PasswortWechselCommand}
import ch.openolitor.stammdaten.models._
import ch.openolitor.stammdaten.repositories.StammdatenReadRepositoryAsyncComponent
import ch.openolitor.util.ConfigUtil._
@@ -351,7 +373,7 @@ trait LoginService extends LazyLogging
val mail = Mail(1, person.email.get, None, None, None, "OpenOlitor Second Factor",
s"""Code: ${secondFactor.code}""", None)
mailService ? SendMailCommand(SystemEvents.SystemPersonId, mail, Some(5 minutes)) map {
- case _: SendMailEvent =>
+ case _: SendMailEvent | MailServiceState =>
true.right
case other =>
logger.debug(s"Sending Mail failed resulting in $other")
diff --git a/src/main/scala/ch/openolitor/core/ws/ClientMessagesRouteService.scala b/src/main/scala/ch/openolitor/core/ws/ClientMessagesRouteService.scala
index 4a993dd63..08789e583 100644
--- a/src/main/scala/ch/openolitor/core/ws/ClientMessagesRouteService.scala
+++ b/src/main/scala/ch/openolitor/core/ws/ClientMessagesRouteService.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.core.ws
import akka.actor.{ ActorRef, ActorSystem }
diff --git a/src/main/scala/ch/openolitor/mailtemplates/MailTemplateCommandHandler.scala b/src/main/scala/ch/openolitor/mailtemplates/MailTemplateCommandHandler.scala
index 1b98ebc48..af1b562e4 100644
--- a/src/main/scala/ch/openolitor/mailtemplates/MailTemplateCommandHandler.scala
+++ b/src/main/scala/ch/openolitor/mailtemplates/MailTemplateCommandHandler.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.mailtemplates
import akka.actor.ActorSystem
diff --git a/src/main/scala/ch/openolitor/mailtemplates/MailTemplateEntityStoreView.scala b/src/main/scala/ch/openolitor/mailtemplates/MailTemplateEntityStoreView.scala
index f7fd92ee9..b7bb6cc3c 100644
--- a/src/main/scala/ch/openolitor/mailtemplates/MailTemplateEntityStoreView.scala
+++ b/src/main/scala/ch/openolitor/mailtemplates/MailTemplateEntityStoreView.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.mailtemplates
import akka.actor.{ ActorRef, ActorSystem, Props }
diff --git a/src/main/scala/ch/openolitor/mailtemplates/engine/MailTemplateService.scala b/src/main/scala/ch/openolitor/mailtemplates/engine/MailTemplateService.scala
index e86c2bc41..d4f246649 100644
--- a/src/main/scala/ch/openolitor/mailtemplates/engine/MailTemplateService.scala
+++ b/src/main/scala/ch/openolitor/mailtemplates/engine/MailTemplateService.scala
@@ -1,3 +1,25 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
package ch.openolitor.mailtemplates.engine
import scala.concurrent._
@@ -14,7 +36,7 @@ import org.joda.time.DateTime
/**
* This trait provides functionality to generate mail payloads based on either custom or a default template
*/
-trait MailTemplateService extends SystemConfigReference with LazyLogging {
+trait MailTemplateService extends LazyLogging {
val format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ssZ")
/**
diff --git a/src/main/scala/ch/openolitor/stammdaten/DefaultMailCommandForwarder.scala b/src/main/scala/ch/openolitor/stammdaten/DefaultMailCommandForwarder.scala
new file mode 100644
index 000000000..5bc70fbb6
--- /dev/null
+++ b/src/main/scala/ch/openolitor/stammdaten/DefaultMailCommandForwarder.scala
@@ -0,0 +1,65 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
+package ch.openolitor.stammdaten
+
+import akka.actor.ActorRef
+import akka.pattern.ask
+import akka.util.Timeout
+import ch.openolitor.core.db.AsyncConnectionPoolContextAware
+import ch.openolitor.core.domain.EventTransactionMetadata
+import ch.openolitor.core.eventsourcing.CoreEventStoreSerializer
+import ch.openolitor.core.mailservice.MailService._
+import ch.openolitor.core.models._
+import ch.openolitor.mailtemplates.engine.MailTemplateService
+import ch.openolitor.mailtemplates.eventsourcing.MailTemplateEventStoreSerializer
+import ch.openolitor.stammdaten.eventsourcing.StammdatenEventStoreSerializer
+import ch.openolitor.stammdaten.models._
+import com.typesafe.scalalogging.LazyLogging
+
+import scala.concurrent.duration._
+import scala.concurrent.ExecutionContext
+import scala.util._
+
+class DefaultMailCommandForwarder(mailService: ActorRef) extends MailCommandForwarder with MailTemplateService with CoreEventStoreSerializer with LazyLogging {
+ implicit val timeout = Timeout(15.seconds) // sending mails might take a little longer
+
+ def sendEmail(meta: EventTransactionMetadata, emailSubject: String, body: String, replyTo: Option[String], bcc: Option[String], person: PersonEmailData, docReference: Option[String], mailContext: Product)(implicit originator: PersonId = meta.originator, executionContext: ExecutionContext): Unit = {
+ generateMail(emailSubject, body, mailContext) match {
+ case Success(mailPayload) =>
+ person.email map { email =>
+ val mail = bcc match {
+ case Some(bccAddress) => mailPayload.toMail(1, email, None, Some(bccAddress), replyTo, docReference)
+ case None => mailPayload.toMail(1, email, None, None, replyTo, docReference)
+ }
+ mailService ? SendMailCommandWithCallback(originator, mail, Some(60 minutes), person.id) map {
+ case _: SendMailEvent | MailServiceState =>
+ //ok
+ case other =>
+ logger.debug(s"Sending Mail failed resulting in $other")
+ }
+ }
+ case Failure(e) =>
+ logger.warn(s"Failed preparing mail", e)
+ }
+ }
+}
diff --git a/src/main/scala/ch/openolitor/stammdaten/EmailHandler.scala b/src/main/scala/ch/openolitor/stammdaten/MailCommandForwarder.scala
similarity index 63%
rename from src/main/scala/ch/openolitor/stammdaten/EmailHandler.scala
rename to src/main/scala/ch/openolitor/stammdaten/MailCommandForwarder.scala
index 573f1e596..3c5d38dcb 100644
--- a/src/main/scala/ch/openolitor/stammdaten/EmailHandler.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/MailCommandForwarder.scala
@@ -24,44 +24,29 @@ package ch.openolitor.stammdaten
import ch.openolitor.core.models._
import ch.openolitor.stammdaten.models._
-import ch.openolitor.core.domain.EventMetadata
+import ch.openolitor.core.domain.{ EventMetadata, EventTransactionMetadata }
import ch.openolitor.mailtemplates.engine.MailTemplateService
import ch.openolitor.core.mailservice.MailService._
import ch.openolitor.core.repositories.EventPublishingImplicits._
import ch.openolitor.core.db.AsyncConnectionPoolContextAware
import ch.openolitor.stammdaten.eventsourcing.StammdatenEventStoreSerializer
import ch.openolitor.core.EventStream
-
import akka.actor.ActorRef
import akka.pattern.ask
import akka.util.Timeout
import scalikejdbc._
import com.typesafe.scalalogging.LazyLogging
+
import scala.util._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
-trait EmailHandler extends MailTemplateService with AsyncConnectionPoolContextAware with StammdatenEventStoreSerializer with LazyLogging {
+trait MailCommandForwarder {
+ def sendEmail(meta: EventTransactionMetadata, emailSubject: String, body: String, replyTo: Option[String], bcc: Option[String], person: PersonEmailData, docReference: Option[String], mailContext: Product)(implicit originator: PersonId = meta.originator, executionContext: ExecutionContext): Unit
+}
- def sendEmail(meta: EventMetadata, emailSubject: String, body: String, replyTo: Option[String], bcc: Option[String], person: PersonEmailData, docReference: Option[String], mailContext: Product, mailService: ActorRef)(implicit originator: PersonId = meta.originator, timeout: Timeout, executionContext: ExecutionContext, eventStream: EventStream): Unit = {
- DB localTxPostPublish { implicit session => implicit publisher =>
- generateMail(emailSubject, body, mailContext) match {
- case Success(mailPayload) =>
- person.email map { email =>
- val mail = bcc match {
- case Some(bccAddress) => mailPayload.toMail(1, email, None, Some(bccAddress), replyTo, docReference)
- case None => mailPayload.toMail(1, email, None, None, replyTo, docReference)
- }
- mailService ? SendMailCommandWithCallback(originator, mail, Some(60 minutes), person.id) map {
- case _: SendMailEvent =>
- //ok
- case other =>
- logger.debug(s"Sending Mail failed resulting in $other")
- }
- }
- case Failure(e) =>
- logger.warn(s"Failed preparing mail", e)
- }
- }
+object MailCommandForwarder {
+ def apply(mailService: ActorRef): MailCommandForwarder = {
+ new DefaultMailCommandForwarder(mailService)
}
-}
+}
\ No newline at end of file
diff --git a/src/main/scala/ch/openolitor/stammdaten/MailCommandForwarderComponent.scala b/src/main/scala/ch/openolitor/stammdaten/MailCommandForwarderComponent.scala
new file mode 100644
index 000000000..f4101edfd
--- /dev/null
+++ b/src/main/scala/ch/openolitor/stammdaten/MailCommandForwarderComponent.scala
@@ -0,0 +1,33 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
+package ch.openolitor.stammdaten
+
+import ch.openolitor.core.MailServiceReference
+
+trait MailCommandForwarderComponent {
+ val mailCommandForwarder: MailCommandForwarder
+}
+
+trait DefaultMailCommandForwarderComponent extends MailCommandForwarderComponent with MailServiceReference {
+ override lazy val mailCommandForwarder = MailCommandForwarder(mailService)
+}
diff --git a/src/main/scala/ch/openolitor/stammdaten/ProjektHelper.scala b/src/main/scala/ch/openolitor/stammdaten/ProjektHelper.scala
new file mode 100644
index 000000000..7251dbda1
--- /dev/null
+++ b/src/main/scala/ch/openolitor/stammdaten/ProjektHelper.scala
@@ -0,0 +1,40 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
+
+package ch.openolitor.stammdaten
+
+import ch.openolitor.core.SystemConfigReference
+import ch.openolitor.stammdaten.repositories.ProjektReadRepositorySync
+import scalikejdbc.DBSession
+
+trait ProjektHelper extends SystemConfigReference {
+ lazy val bccAddress = config.getString("smtp.bcc")
+
+ def projektReadRepository: ProjektReadRepositorySync
+
+ def determineBcc(implicit session: DBSession): Option[String] = {
+ projektReadRepository.getProjekt flatMap { projekt =>
+ Option.when(projekt.sendEmailToBcc)(bccAddress)
+ }
+ }
+}
diff --git a/src/main/scala/ch/openolitor/stammdaten/StammdatenAktionenService.scala b/src/main/scala/ch/openolitor/stammdaten/StammdatenAktionenService.scala
index fa720752a..5a7687789 100644
--- a/src/main/scala/ch/openolitor/stammdaten/StammdatenAktionenService.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/StammdatenAktionenService.scala
@@ -44,6 +44,7 @@ import ch.openolitor.util.ConfigUtil._
import scalikejdbc.DBSession
import ch.openolitor.core.repositories.EventPublishingImplicits._
import ch.openolitor.core.repositories.EventPublisher
+import ch.openolitor.mailtemplates.engine.MailTemplateService
import scala.concurrent.ExecutionContext.Implicits._
import scalikejdbc.DB
@@ -71,7 +72,7 @@ abstract class StammdatenAktionenService(override val sysConfig: SystemConfig, o
with SammelbestellungenHandler
with LieferungHandler
with SystemConfigReference
- with EmailHandler {
+ with MailTemplateService {
self: StammdatenWriteRepositoryComponent with MailTemplateReadRepositoryComponent =>
// implicitly expose the eventStream
@@ -109,20 +110,6 @@ abstract class StammdatenAktionenService(override val sysConfig: SystemConfig, o
changeRolle(meta, personId, rolle)
case OtpResetEvent(meta, _, personId, otpSecret) =>
resetOtp(meta, personId, otpSecret)
- case SendEmailToPersonEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
- case SendEmailToKundeEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
- case SendEmailToAbotypSubscriberEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
- case SendEmailToZusatzabotypSubscriberEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
- case SendEmailToTourSubscriberEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
- case SendEmailToDepotSubscriberEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
- case SendEmailToAboSubscriberEvent(meta, subject, body, replyTo, context) =>
- checkBccAndSend(meta, subject, body, replyTo, context.person, context, mailService)
case e =>
logger.warn(s"Unknown event:$e")
}
@@ -177,8 +164,6 @@ abstract class StammdatenAktionenService(override val sysConfig: SystemConfig, o
}
def sammelbestellungVersenden(meta: EventMetadata, id: SammelbestellungId)(implicit personId: PersonId = meta.originator) = {
- val format = DateTimeFormat.forPattern("dd.MM.yyyy")
-
DB localTxPostPublish { implicit session => implicit publisher =>
//send mails to Produzenten
stammdatenWriteRepository.getProjekt map { projekt =>
@@ -203,7 +188,7 @@ abstract class StammdatenAktionenService(override val sysConfig: SystemConfig, o
val mail = mailPayload.toMail(1, produzent.email, None, None, None, None)
mailService ? SendMailCommandWithCallback(personId, mail, Some(60 minutes), id) map
{
- case _: SendMailEvent =>
+ case _: SendMailEvent | MailServiceState =>
//ok
case other =>
logger.debug(s"Sending Mail failed resulting in $other")
@@ -262,18 +247,6 @@ abstract class StammdatenAktionenService(override val sysConfig: SystemConfig, o
}
}
- def checkBccAndSend(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], person: PersonEmailData, context: Product, mailService: ActorRef)(implicit originator: PersonId = meta.originator): Unit = {
- DB localTxPostPublish { implicit session => implicit publisher =>
- lazy val bccAddress = config.getString("smtp.bcc")
- stammdatenWriteRepository.getProjekt map { projekt =>
- projekt.sendEmailToBcc match {
- case true => sendEmail(meta, subject, body, replyTo, Some(bccAddress), person, None, context, mailService)
- case false => sendEmail(meta, subject, body, replyTo, None, person, None, context, mailService)
- }
- }
- }
- }
-
private def sendEinladung(meta: EventMetadata, einladungCreate: EinladungCreate, baseLink: String, mailTemplateType: TemplateType)(implicit originator: PersonId): Unit = {
DB localTxPostPublish { implicit session => implicit publisher =>
stammdatenWriteRepository.getById(personMapping, einladungCreate.personId) map { person =>
@@ -301,7 +274,7 @@ abstract class StammdatenAktionenService(override val sysConfig: SystemConfig, o
val mail = mailPayload.toMail(1, person.email.get, None, None, None, None)
mailService ? SendMailCommandWithCallback(originator, mail, Some(60 minutes), einladung.id) map
{
- case _: SendMailEvent =>
+ case _: SendMailEvent | MailServiceState =>
//ok
case other =>
logger.debug(s"Sending Mail failed resulting in $other")
diff --git a/src/main/scala/ch/openolitor/stammdaten/StammdatenCommandHandler.scala b/src/main/scala/ch/openolitor/stammdaten/StammdatenCommandHandler.scala
index bad02785b..2e83f0b7a 100644
--- a/src/main/scala/ch/openolitor/stammdaten/StammdatenCommandHandler.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/StammdatenCommandHandler.scala
@@ -22,7 +22,7 @@
\* */
package ch.openolitor.stammdaten
-import ch.openolitor.buchhaltung.models.{ RechnungsPositionStatus, RechnungsPositionTyp }
+import ch.openolitor.buchhaltung.models.{RechnungsPositionStatus, RechnungsPositionTyp}
import ch.openolitor.core.domain._
import ch.openolitor.core.models._
import ch.openolitor.util.ConfigUtil._
@@ -33,7 +33,8 @@ import scalikejdbc.DB
import ch.openolitor.stammdaten.models._
import ch.openolitor.stammdaten.repositories._
import ch.openolitor.core.exceptions._
-import akka.actor.ActorSystem
+import akka.actor.{ActorRef, ActorSystem}
+import akka.persistence.journal.EmptyEventSeq
import ch.openolitor.core._
import ch.openolitor.core.db.ConnectionPoolContextAware
import ch.openolitor.core.Macros._
@@ -41,72 +42,138 @@ import ch.openolitor.mailtemplates.engine.MailTemplateService
import ch.openolitor.buchhaltung.models.RechnungsPositionCreate
import ch.openolitor.buchhaltung.models.RechnungsPositionId
import ch.openolitor.util.OtpUtil
-import org.joda.time.{ DateTime, LocalDate, LocalTime }
+import org.joda.time.{DateTime, LocalDate, LocalTime}
import java.util.UUID
import scalikejdbc.DBSession
object StammdatenCommandHandler {
case class LieferplanungAbschliessenCommand(originator: PersonId, id: LieferplanungId) extends UserCommand
+
case class LieferplanungModifyCommand(originator: PersonId, lieferplanungModify: LieferplanungPositionenModify) extends UserCommand
+
case class LieferplanungAbrechnenCommand(originator: PersonId, id: LieferplanungId) extends UserCommand
+
case class AbwesenheitCreateCommand(originator: PersonId, abw: AbwesenheitCreate) extends UserCommand
+
case class SammelbestellungAnProduzentenVersendenCommand(originator: PersonId, id: SammelbestellungId) extends UserCommand
+
case class PasswortWechselCommand(originator: PersonId, personId: PersonId, passwort: Array[Char], einladung: Option[EinladungId]) extends UserCommand
+
case class AuslieferungenAlsAusgeliefertMarkierenCommand(originator: PersonId, ids: Seq[AuslieferungId]) extends UserCommand
- case class CreateAnzahlLieferungenRechnungsPositionenCommand(originator: PersonId, aboRechnungCreate: AboRechnungsPositionBisAnzahlLieferungenCreate) extends UserCommand
+
+ case class CreateAnzahlLieferungenRechnungsPositionenCommand(originator: PersonId, aboRechnungCreate: AboRechnungsPositionBisAnzahlLieferungenCreate)
+ extends UserCommand
+
case class CreateBisGuthabenRechnungsPositionenCommand(originator: PersonId, aboRechnungCreate: AboRechnungsPositionBisGuthabenCreate) extends UserCommand
+
case class LoginDeaktivierenCommand(originator: PersonId, kundeId: KundeId, personId: PersonId) extends UserCommand
+
case class LoginAktivierenCommand(originator: PersonId, kundeId: KundeId, personId: PersonId) extends UserCommand
+
case class EinladungSendenCommand(originator: PersonId, kundeId: KundeId, personId: PersonId) extends UserCommand
+
case class SammelbestellungenAlsAbgerechnetMarkierenCommand(originator: PersonId, datum: DateTime, ids: Seq[SammelbestellungId]) extends UserCommand
+
case class PasswortResetCommand(originator: PersonId, personId: PersonId) extends UserCommand
+
case class RolleWechselnCommand(originator: PersonId, kundeId: KundeId, personId: PersonId, rolle: Rolle) extends UserCommand
+
case class OtpResetCommand(originator: PersonId, kundeId: KundeId, personId: PersonId) extends UserCommand
+
case class UpdateKundeCommand(originator: PersonId, kundeId: KundeId, kunde: KundeModify) extends UserCommand
+
case class CreateKundeCommand(originator: PersonId, kunde: KundeModify) extends UserCommand
+
case class RemoveLieferungCommand(originator: PersonId, lieferungId: LieferungId) extends UserCommand
+
// TODO person id for calculations
case class AboAktivierenCommand(aboId: AboId, originator: PersonId = PersonId(100)) extends UserCommand
+
case class AboDeaktivierenCommand(aboId: AboId, originator: PersonId = PersonId(100)) extends UserCommand
case class DeleteAbwesenheitCommand(originator: PersonId, id: AbwesenheitId) extends UserCommand
+
case class SendEmailToKundenCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[KundeId]) extends UserCommand
+
case class SendEmailToPersonenCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[PersonId]) extends UserCommand
- case class SendEmailToAbosSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[AboId]) extends UserCommand
- case class SendEmailToAbotypSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[AbotypId]) extends UserCommand
- case class SendEmailToZusatzabotypSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[AbotypId]) extends UserCommand
- case class SendEmailToTourSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[TourId]) extends UserCommand
- case class SendEmailToDepotSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[DepotId]) extends UserCommand
+
+ case class SendEmailToAbosSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[AboId]) extends
+ UserCommand
+
+ case class SendEmailToAbotypSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[AbotypId]) extends
+ UserCommand
+
+ case class SendEmailToZusatzabotypSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[AbotypId])
+ extends UserCommand
+
+ case class SendEmailToTourSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[TourId]) extends
+ UserCommand
+
+ case class SendEmailToDepotSubscribersCommand(originator: PersonId, subject: String, body: String, replyTo: Option[String], ids: Seq[DepotId]) extends
+ UserCommand
case class LieferplanungAbschliessenEvent(meta: EventMetadata, id: LieferplanungId) extends PersistentEvent with JSONSerializable
+
case class LieferplanungAbrechnenEvent(meta: EventMetadata, id: LieferplanungId) extends PersistentEvent with JSONSerializable
+
case class LieferplanungDataModifiedEvent(meta: EventMetadata, result: LieferplanungDataModify) extends PersistentEvent with JSONSerializable
+
case class AbwesenheitCreateEvent(meta: EventMetadata, id: AbwesenheitId, abw: AbwesenheitCreate) extends PersistentEvent with JSONSerializable
+
@Deprecated
case class BestellungVersendenEvent(meta: EventMetadata, id: BestellungId) extends PersistentEvent with JSONSerializable
+
case class SammelbestellungVersendenEvent(meta: EventMetadata, id: SammelbestellungId) extends PersistentEvent with JSONSerializable
- case class PasswortGewechseltEvent(meta: EventMetadata, personId: PersonId, passwort: Array[Char], einladungId: Option[EinladungId]) extends PersistentEvent with JSONSerializable
+
+ case class PasswortGewechseltEvent(meta: EventMetadata, personId: PersonId, passwort: Array[Char], einladungId: Option[EinladungId]) extends
+ PersistentEvent with JSONSerializable
+
case class LoginDeaktiviertEvent(meta: EventMetadata, kundeId: KundeId, personId: PersonId) extends PersistentEvent with JSONSerializable
+
case class LoginAktiviertEvent(meta: EventMetadata, kundeId: KundeId, personId: PersonId) extends PersistentEvent with JSONSerializable
+
case class EinladungGesendetEvent(meta: EventMetadata, einladung: EinladungCreate) extends PersistentEvent with JSONSerializable
+
case class AuslieferungAlsAusgeliefertMarkierenEvent(meta: EventMetadata, id: AuslieferungId) extends PersistentEvent with JSONSerializable
+
@Deprecated
case class BestellungAlsAbgerechnetMarkierenEvent(meta: EventMetadata, datum: DateTime, id: BestellungId) extends PersistentEvent with JSONSerializable
- case class SammelbestellungAlsAbgerechnetMarkierenEvent(meta: EventMetadata, datum: DateTime, id: SammelbestellungId) extends PersistentEvent with JSONSerializable
+
+ case class SammelbestellungAlsAbgerechnetMarkierenEvent(meta: EventMetadata, datum: DateTime, id: SammelbestellungId) extends PersistentEvent with
+ JSONSerializable
+
case class PasswortResetGesendetEvent(meta: EventMetadata, einladung: EinladungCreate) extends PersistentEvent with JSONSerializable
+
case class RolleGewechseltEvent(meta: EventMetadata, kundeId: KundeId, personId: PersonId, rolle: Rolle) extends PersistentEvent with JSONSerializable
+
case class OtpResetEvent(meta: EventMetadata, kundeId: KundeId, personId: PersonId, otpSecret: String) extends PersistentEvent with JSONSerializable
case class AboAktiviertEvent(meta: EventMetadata, aboId: AboId) extends PersistentGeneratedEvent with JSONSerializable
+
case class AboDeaktiviertEvent(meta: EventMetadata, aboId: AboId) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToPersonEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: PersonMailContext) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToKundeEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: KundeMailContext) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToAboSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: AboMailContext) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToAbotypSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: AbotypMailContext) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToZusatzabotypSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: ZusatzabotypMailContext) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToTourSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: TourMailContext) extends PersistentGeneratedEvent with JSONSerializable
- case class SendEmailToDepotSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: DepotMailContext) extends PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToPersonEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: PersonMailContext) extends
+ PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToKundeEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: KundeMailContext) extends
+ PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToAboSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: AboMailContext) extends
+ PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToAbotypSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: AbotypMailContext)
+ extends PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToZusatzabotypSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String],
+ context: ZusatzabotypMailContext) extends PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToTourSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: TourMailContext) extends
+ PersistentGeneratedEvent with JSONSerializable
+
+ case class SendEmailToDepotSubscriberEvent(meta: EventMetadata, subject: String, body: String, replyTo: Option[String], context: DepotMailContext) extends
+ PersistentGeneratedEvent with JSONSerializable
+
case class UpdateKundeEvent(meta: EventMetadata, kundeId: KundeId, kunde: KundeModify) extends PersistentGeneratedEvent with JSONSerializable
}
@@ -115,257 +182,295 @@ trait StammdatenCommandHandler extends CommandHandler
with ConnectionPoolContextAware
with LieferungDurchschnittspreisHandler
with MailTemplateService
- with ExecutionContextAware {
+ with MailCommandForwarderComponent
+ with ExecutionContextAware
+ with ProjektHelper {
self: StammdatenReadRepositorySyncComponent =>
+
import StammdatenCommandHandler._
import EntityStore._
override val handle: PartialFunction[UserCommand, IdFactory => EventTransactionMetadata => Try[Seq[ResultingEvent]]] = {
- case DeleteAbwesenheitCommand(_, id) => _ => _ =>
- DB readOnly { implicit session =>
- stammdatenReadRepository.getLieferung(id) map { lieferung =>
- lieferung.status match {
- case (Offen | Ungeplant) =>
- Success(Seq(EntityDeleteEvent(id)))
- case _ =>
- Failure(new InvalidStateException("Die der Abwesenheit zugeordnete Lieferung muss Offen oder Ungeplant sein."))
- }
- } getOrElse Failure(new InvalidStateException(s"Keine Lieferung zu Abwesenheit Nr. $id gefunden"))
- }
+ case DeleteAbwesenheitCommand(_, id) => _ =>
+ _ =>
+ DB readOnly { implicit session =>
+ stammdatenReadRepository.getLieferung(id) map { lieferung =>
+ lieferung.status match {
+ case (Offen | Ungeplant) =>
+ Success(Seq(EntityDeleteEvent(id)))
+ case _ =>
+ Failure(new InvalidStateException("Die der Abwesenheit zugeordnete Lieferung muss Offen oder Ungeplant sein."))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Lieferung zu Abwesenheit Nr. $id gefunden"))
+ }
- case SendEmailToKundenCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateKunden(body, subject, ids)) {
- val events = ids flatMap { kundeId =>
- stammdatenReadRepository.getPersonen(kundeId) flatMap { person =>
- val personData = copyTo[Person, PersonData](person)
- stammdatenReadRepository.getById(kundeMapping, kundeId) map { kunde =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = KundeMailContext(personEmailData, kunde)
- DefaultResultingEvent(factory => SendEmailToKundeEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ case SendEmailToKundenCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateKunden(body, subject, ids)) {
+ val events = ids flatMap { kundeId =>
+ stammdatenReadRepository.getPersonen(kundeId) flatMap { person =>
+ val personData = copyTo[Person, PersonData](person)
+ stammdatenReadRepository.getById(kundeMapping, kundeId) map { kunde =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = KundeMailContext(personEmailData, kunde)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToKundeEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
}
+ Success(events)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case SendEmailToPersonenCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplatePersonen(body, subject, ids)) {
- val events = ids flatMap { id =>
- stammdatenReadRepository.getById(personMapping, id) map { person =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = PersonMailContext(personEmailData)
- DefaultResultingEvent(factory => SendEmailToPersonEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ case SendEmailToPersonenCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplatePersonen(body, subject, ids)) {
+ val events = ids flatMap { id =>
+ stammdatenReadRepository.getById(personMapping, id) map { person =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = PersonMailContext(personEmailData)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToPersonEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
+ Success(events)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case SendEmailToAbotypSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateAbotyp(body, subject, ids)) {
- val events = ids flatMap { abotypId =>
- stammdatenReadRepository.getPersonenForAbotyp(abotypId) flatMap { person =>
- val personData = copyTo[Person, PersonData](person)
- stammdatenReadRepository.getAbotypById(abotypId) map { abotypId =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = AbotypMailContext(personEmailData, abotypId)
- DefaultResultingEvent(factory => SendEmailToAbotypSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ case SendEmailToAbotypSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateAbotyp(body, subject, ids)) {
+ val events = ids flatMap { abotypId =>
+ stammdatenReadRepository.getPersonenForAbotyp(abotypId) flatMap { person =>
+ val personData = copyTo[Person, PersonData](person)
+ stammdatenReadRepository.getAbotypById(abotypId) map { abotypId =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = AbotypMailContext(personEmailData, abotypId)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToAbotypSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
}
+ Success(events)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case SendEmailToZusatzabotypSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateAbotyp(body, subject, ids)) {
- val events = ids flatMap { abotypId =>
- stammdatenReadRepository.getPersonenForZusatzabotyp(abotypId) flatMap { person =>
- val personData = copyTo[Person, PersonData](person)
- stammdatenReadRepository.getAbotypById(abotypId) map { abotypId =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = AbotypMailContext(personEmailData, abotypId)
- DefaultResultingEvent(factory => SendEmailToAbotypSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ case SendEmailToZusatzabotypSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateAbotyp(body, subject, ids)) {
+ val events = ids flatMap { abotypId =>
+ stammdatenReadRepository.getPersonenForZusatzabotyp(abotypId) flatMap { person =>
+ val personData = copyTo[Person, PersonData](person)
+ stammdatenReadRepository.getAbotypById(abotypId) map { abotypId =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = AbotypMailContext(personEmailData, abotypId)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToAbotypSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
}
+ Success(events)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case SendEmailToTourSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateTour(body, subject, ids)) {
- val events = ids flatMap { tourId =>
- stammdatenReadRepository.getPersonen(tourId) flatMap { person =>
- val personData = copyTo[Person, PersonData](person)
- stammdatenReadRepository.getById(tourMapping, tourId) map { tour =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = TourMailContext(personEmailData, tour)
- DefaultResultingEvent(factory => SendEmailToTourSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ case SendEmailToTourSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateTour(body, subject, ids)) {
+ val events = ids flatMap { tourId =>
+ stammdatenReadRepository.getPersonen(tourId) flatMap { person =>
+ val personData = copyTo[Person, PersonData](person)
+ stammdatenReadRepository.getById(tourMapping, tourId) map { tour =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = TourMailContext(personEmailData, tour)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToTourSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
}
+ Success(events)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case SendEmailToDepotSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateDepot(body, subject, ids)) {
- val events = ids flatMap { depotId =>
- stammdatenReadRepository.getPersonen(depotId) flatMap { person =>
- val personData = copyTo[Person, PersonData](person)
- stammdatenReadRepository.getById(depotMapping, depotId) map { depot =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = DepotMailContext(personEmailData, depot)
- DefaultResultingEvent(factory => SendEmailToDepotSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ case SendEmailToDepotSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateDepot(body, subject, ids)) {
+ val events = ids flatMap { depotId =>
+ stammdatenReadRepository.getPersonen(depotId) flatMap { person =>
+ val personData = copyTo[Person, PersonData](person)
+ stammdatenReadRepository.getById(depotMapping, depotId) map { depot =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = DepotMailContext(personEmailData, depot)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
+ DefaultResultingEvent(factory => SendEmailToDepotSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
+ }
}
}
+ Success(events)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
- case SendEmailToAbosSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory => meta =>
- DB readOnly { implicit session =>
- if (checkTemplateAbosSubscribers(body, subject, ids)) {
- val events = ids flatMap { aboId: AboId =>
- stammdatenReadRepository.getById(zusatzAboMapping, aboId) orElse
- stammdatenReadRepository.getById(depotlieferungAboMapping, aboId) orElse
- stammdatenReadRepository.getById(heimlieferungAboMapping, aboId) orElse
- stammdatenReadRepository.getById(postlieferungAboMapping, aboId) map { abo =>
+ case SendEmailToAbosSubscribersCommand(personId, subject, body, replyTo, ids) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ if (checkTemplateAbosSubscribers(body, subject, ids)) {
+ val events = ids flatMap { aboId: AboId =>
+ stammdatenReadRepository.getById(zusatzAboMapping, aboId) orElse
+ stammdatenReadRepository.getById(depotlieferungAboMapping, aboId) orElse
+ stammdatenReadRepository.getById(heimlieferungAboMapping, aboId) orElse
+ stammdatenReadRepository.getById(postlieferungAboMapping, aboId) map { abo =>
stammdatenReadRepository.getPersonen(abo.kundeId) map { person =>
val personEmailData = copyTo[Person, PersonEmailData](person)
val mailContext = AboMailContext(personEmailData, abo)
+
+ mailCommandForwarder.sendEmail(meta, subject, body, replyTo, determineBcc, personEmailData, None, mailContext)
+
DefaultResultingEvent(factory => SendEmailToAboSubscriberEvent(factory.newMetadata(), subject, body, replyTo, mailContext))
}
}
+ }
+ Success(events.flatten)
+ } else {
+ Failure(new InvalidStateException("The template is not valid"))
}
- Success(events.flatten)
- } else {
- Failure(new InvalidStateException("The template is not valid"))
}
- }
-
- case LieferplanungAbschliessenCommand(personId, id) => idFactory => meta =>
- DB readOnly { implicit session =>
- stammdatenReadRepository.getById(lieferplanungMapping, id) map { lieferplanung =>
- lieferplanung.status match {
- case Offen =>
- stammdatenReadRepository.countEarlierLieferungOffen(id) match {
- case Some(0) =>
- val distinctSammelbestellungen = getDistinctSammelbestellungModifyByLieferplan(lieferplanung.id)
- val bestellEvents = distinctSammelbestellungen.map { sammelbestellungCreate =>
- val insertEvent = EntityInsertEvent(idFactory.newId(SammelbestellungId.apply), sammelbestellungCreate)
-
- // TODO OO-589
- //val bestellungVersendenEvent = SammelbestellungVersendenEvent(factory.newMetadata(meta), sammelbestellungId)
- Seq(insertEvent) //, bestellungVersendenEvent)
- }.toSeq.flatten
-
- val lpAbschliessenEvent = DefaultResultingEvent(factory => LieferplanungAbschliessenEvent(factory.newMetadata(), id))
-
- val createAuslieferungHeimEvent = getCreateAuslieferungHeimEvent(idFactory, meta, lieferplanung)(personId, session)
- val createAuslieferungDepotPostEvent = getCreateDepotAuslieferungAndPostAusliferungEvent(idFactory, meta, lieferplanung)(personId, session)
- Success(lpAbschliessenEvent +: bestellEvents ++: createAuslieferungHeimEvent ++: createAuslieferungDepotPostEvent)
- case _ =>
- Failure(new InvalidStateException("Es dürfen keine früheren Lieferungen in offnen Lieferplanungen hängig sein."))
- }
- case _ =>
- Failure(new InvalidStateException("Eine Lieferplanung kann nur im Status 'Offen' abgeschlossen werden"))
- }
- } getOrElse Failure(new InvalidStateException(s"Keine Lieferplanung mit der Nr. $id gefunden"))
- }
+ case LieferplanungAbschliessenCommand(personId, id) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ stammdatenReadRepository.getById(lieferplanungMapping, id) map { lieferplanung =>
+ lieferplanung.status match {
+ case Offen =>
+ stammdatenReadRepository.countEarlierLieferungOffen(id) match {
+ case Some(0) =>
+ val distinctSammelbestellungen = getDistinctSammelbestellungModifyByLieferplan(lieferplanung.id)
+
+ val bestellEvents = distinctSammelbestellungen.map { sammelbestellungCreate =>
+ val insertEvent = EntityInsertEvent(idFactory.newId(SammelbestellungId.apply), sammelbestellungCreate)
+
+ Seq(insertEvent)
+ }.toSeq.flatten
+
+ val lpAbschliessenEvent = DefaultResultingEvent(factory => LieferplanungAbschliessenEvent(factory.newMetadata(), id))
+
+ val createAuslieferungHeimEvent = getCreateAuslieferungHeimEvent(idFactory, meta, lieferplanung)(personId, session)
+ val createAuslieferungDepotPostEvent = getCreateDepotAuslieferungAndPostAusliferungEvent(idFactory, meta, lieferplanung)(personId, session)
+ Success(lpAbschliessenEvent +: bestellEvents ++: createAuslieferungHeimEvent ++: createAuslieferungDepotPostEvent)
+ case _ =>
+ Failure(new InvalidStateException("Es dürfen keine früheren Lieferungen in offnen Lieferplanungen hängig sein."))
+ }
+ case _ =>
+ Failure(new InvalidStateException("Eine Lieferplanung kann nur im Status 'Offen' abgeschlossen werden"))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Lieferplanung mit der Nr. $id gefunden"))
+ }
- case LieferplanungModifyCommand(_, lieferplanungPositionenModify) => idFactory => _ =>
- DB readOnly { implicit session =>
- stammdatenReadRepository.getById(lieferplanungMapping, lieferplanungPositionenModify.id) map { lieferplanung =>
- lieferplanung.status match {
- case _@ Offen =>
- Success(DefaultResultingEvent(factory => LieferplanungDataModifiedEvent(factory.newMetadata(), LieferplanungDataModify(lieferplanungPositionenModify.id, Set.empty, lieferplanungPositionenModify.lieferungen))) :: Nil)
- case _@ Abgeschlossen =>
- val allLieferpositionen = lieferplanungPositionenModify.lieferungen flatMap { lieferungPositionenModify =>
- lieferungPositionenModify.lieferpositionen.lieferpositionen
- }
+ case LieferplanungModifyCommand(_, lieferplanungPositionenModify) => idFactory =>
+ _ =>
+ DB readOnly { implicit session =>
+ stammdatenReadRepository.getById(lieferplanungMapping, lieferplanungPositionenModify.id) map { lieferplanung =>
+ lieferplanung.status match {
+ case _@Offen =>
+ Success(DefaultResultingEvent(factory => LieferplanungDataModifiedEvent(factory.newMetadata(), LieferplanungDataModify
+ (lieferplanungPositionenModify.id, Set.empty, lieferplanungPositionenModify.lieferungen))) :: Nil)
+ case _@Abgeschlossen =>
+ val allLieferpositionen = lieferplanungPositionenModify.lieferungen flatMap { lieferungPositionenModify =>
+ lieferungPositionenModify.lieferpositionen.lieferpositionen
+ }
- val allLieferungpositionPerProduzent = allLieferpositionen.groupBy(_.produzentId)
+ val allLieferungpositionPerProduzent = allLieferpositionen.groupBy(_.produzentId)
- val sammelBestellungToCreate = allLieferungpositionPerProduzent flatMap { l =>
- stammdatenReadRepository.getById(lieferungMapping, l._2.head.lieferungId) map { lieferung: Lieferung =>
- stammdatenReadRepository.getSammelbestellungenByProduzent(l._1, lieferplanung.id) match {
- case Nil => Some(SammelbestellungCreate(idFactory.newId(SammelbestellungId.apply), l._1, lieferplanung.id, lieferung.datum))
- case _ => None
+ val sammelBestellungToCreate = allLieferungpositionPerProduzent flatMap { l =>
+ stammdatenReadRepository.getById(lieferungMapping, l._2.head.lieferungId) map { lieferung: Lieferung =>
+ stammdatenReadRepository.getSammelbestellungenByProduzent(l._1, lieferplanung.id) match {
+ case Nil => Some(SammelbestellungCreate(idFactory.newId(SammelbestellungId.apply), l._1, lieferplanung.id, lieferung.datum))
+ case _ => None
+ }
}
}
- }
- Success(DefaultResultingEvent(factory => LieferplanungDataModifiedEvent(factory.newMetadata(), LieferplanungDataModify(lieferplanungPositionenModify.id, sammelBestellungToCreate.flatten.toSet, lieferplanungPositionenModify.lieferungen))) :: Nil)
- case _ =>
- Failure(new InvalidStateException("Eine Lieferplanung kann nur im Status 'Offen' oder 'Abgeschlossen' aktualisiert werden"))
- }
- } getOrElse Failure(new InvalidStateException(s"Keine Lieferplanung mit der Nr. ${lieferplanungPositionenModify.id} gefunden"))
- }
-
- case LieferplanungAbrechnenCommand(_, id: LieferplanungId) => _ => _ =>
- DB readOnly { implicit session =>
- stammdatenReadRepository.getById(lieferplanungMapping, id) map { lieferplanung =>
- lieferplanung.status match {
- case Abgeschlossen =>
- Success(Seq(DefaultResultingEvent(factory => LieferplanungAbrechnenEvent(factory.newMetadata(), id))))
- case _ =>
- Failure(new InvalidStateException("Eine Lieferplanung kann nur im Status 'Abgeschlossen' verrechnet werden"))
- }
- } getOrElse Failure(new InvalidStateException(s"Keine Lieferplanung mit der Nr. $id gefunden"))
- }
+ Success(DefaultResultingEvent(factory => LieferplanungDataModifiedEvent(factory.newMetadata(), LieferplanungDataModify
+ (lieferplanungPositionenModify.id, sammelBestellungToCreate.flatten.toSet, lieferplanungPositionenModify.lieferungen))) :: Nil)
+ case _ =>
+ Failure(new InvalidStateException("Eine Lieferplanung kann nur im Status 'Offen' oder 'Abgeschlossen' aktualisiert werden"))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Lieferplanung mit der Nr. ${lieferplanungPositionenModify.id} gefunden"))
+ }
- case AbwesenheitCreateCommand(_, abw: AbwesenheitCreate) => idFactory => meta =>
- DB readOnly { implicit session =>
- stammdatenReadRepository.countAbwesend(abw.lieferungId, abw.aboId) match {
- case Some(0) =>
- handleEntityInsert[AbwesenheitCreate, AbwesenheitId](idFactory, meta, abw, AbwesenheitId.apply)
- case _ =>
- Failure(new InvalidStateException("Eine Abwesenheit kann nur einmal erfasst werden"))
+ case LieferplanungAbrechnenCommand(_, id: LieferplanungId) => _ =>
+ _ =>
+ DB readOnly { implicit session =>
+ stammdatenReadRepository.getById(lieferplanungMapping, id) map { lieferplanung =>
+ lieferplanung.status match {
+ case Abgeschlossen =>
+ Success(Seq(DefaultResultingEvent(factory => LieferplanungAbrechnenEvent(factory.newMetadata(), id))))
+ case _ =>
+ Failure(new InvalidStateException("Eine Lieferplanung kann nur im Status 'Abgeschlossen' verrechnet werden"))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Lieferplanung mit der Nr. $id gefunden"))
}
- }
- case SammelbestellungAnProduzentenVersendenCommand(_, id: SammelbestellungId) => _ => _ =>
- DB readOnly { implicit session =>
- stammdatenReadRepository.getById(sammelbestellungMapping, id) map { sammelbestellung =>
- sammelbestellung.status match {
- case Offen | Abgeschlossen =>
- Success(Seq(DefaultResultingEvent(factory => SammelbestellungVersendenEvent(factory.newMetadata(), id))))
+ case AbwesenheitCreateCommand(_, abw: AbwesenheitCreate) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ stammdatenReadRepository.countAbwesend(abw.lieferungId, abw.aboId) match {
+ case Some(0) =>
+ handleEntityInsert[AbwesenheitCreate, AbwesenheitId](idFactory, meta, abw, AbwesenheitId.apply)
case _ =>
- Failure(new InvalidStateException("Eine Bestellung kann nur in den Status 'Offen' oder 'Abgeschlossen' versendet werden"))
+ Failure(new InvalidStateException("Eine Abwesenheit kann nur einmal erfasst werden"))
}
- } getOrElse Failure(new InvalidStateException(s"Keine Bestellung mit der Nr. $id gefunden"))
- }
+ }
+
+ case SammelbestellungAnProduzentenVersendenCommand(_, id: SammelbestellungId) => _ =>
+ _ =>
+ DB readOnly { implicit session =>
+ stammdatenReadRepository.getById(sammelbestellungMapping, id) map { sammelbestellung =>
+ sammelbestellung.status match {
+ case Offen | Abgeschlossen =>
+ Success(Seq(DefaultResultingEvent(factory => SammelbestellungVersendenEvent(factory.newMetadata(), id))))
+ case _ =>
+ Failure(new InvalidStateException("Eine Bestellung kann nur in den Status 'Offen' oder 'Abgeschlossen' versendet werden"))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Bestellung mit der Nr. $id gefunden"))
+ }
- case AuslieferungenAlsAusgeliefertMarkierenCommand(_, ids: Seq[AuslieferungId]) => _ => _ =>
- DB readOnly { implicit session =>
- val (events, _) = ids map { id =>
- stammdatenReadRepository.getById(depotAuslieferungMapping, id) orElse
- stammdatenReadRepository.getById(tourAuslieferungMapping, id) orElse
- stammdatenReadRepository.getById(postAuslieferungMapping, id) map { auslieferung =>
+ case AuslieferungenAlsAusgeliefertMarkierenCommand(_, ids: Seq[AuslieferungId]) => _ =>
+ _ =>
+ DB readOnly { implicit session =>
+ val (events, _) = ids map { id =>
+ stammdatenReadRepository.getById(depotAuslieferungMapping, id) orElse
+ stammdatenReadRepository.getById(tourAuslieferungMapping, id) orElse
+ stammdatenReadRepository.getById(postAuslieferungMapping, id) map { auslieferung =>
auslieferung.status match {
case Erfasst =>
val copy = auslieferung match {
@@ -381,199 +486,254 @@ trait StammdatenCommandHandler extends CommandHandler
Failure(new InvalidStateException(s"Eine Auslieferung kann nur im Status 'Erfasst' als ausgeliefert markiert werden. Nr. $id"))
}
} getOrElse Failure(new InvalidStateException(s"Keine Auslieferung mit der Nr. $id gefunden"))
- } partition (_.isSuccess)
+ } partition (_.isSuccess)
- if (events.isEmpty) {
- Failure(new InvalidStateException(s"Keine der Auslieferungen konnte abgearbeitet werden"))
- } else {
- Success(events map (_.get))
+ if (events.isEmpty) {
+ Failure(new InvalidStateException(s"Keine der Auslieferungen konnte abgearbeitet werden"))
+ } else {
+ Success(events map (_.get))
+ }
}
- }
- case SammelbestellungenAlsAbgerechnetMarkierenCommand(_, datum, ids: Seq[SammelbestellungId]) => _ => _ =>
- DB readOnly { implicit session =>
- val (events, _) = ids map { id =>
- stammdatenReadRepository.getById(sammelbestellungMapping, id) map { sammelbestellung =>
- sammelbestellung.status match {
- case Abgeschlossen =>
- Success(DefaultResultingEvent(factory => SammelbestellungAlsAbgerechnetMarkierenEvent(factory.newMetadata(), datum, id)))
- case _ =>
- Failure(new InvalidStateException(s"Eine Sammelbestellung kann nur im Status 'Abgeschlossen' als abgerechnet markiert werden. Nr. $id"))
- }
- } getOrElse Failure(new InvalidStateException(s"Keine Sammelbestellung mit der Nr. $id gefunden"))
- } partition (_.isSuccess)
+ case SammelbestellungenAlsAbgerechnetMarkierenCommand(_, datum, ids: Seq[SammelbestellungId]) => _ =>
+ _ =>
+ DB readOnly { implicit session =>
+ val (events, _) = ids map { id =>
+ stammdatenReadRepository.getById(sammelbestellungMapping, id) map { sammelbestellung =>
+ sammelbestellung.status match {
+ case Abgeschlossen =>
+ Success(DefaultResultingEvent(factory => SammelbestellungAlsAbgerechnetMarkierenEvent(factory.newMetadata(), datum, id)))
+ case _ =>
+ Failure(new InvalidStateException(s"Eine Sammelbestellung kann nur im Status 'Abgeschlossen' als abgerechnet markiert werden. Nr. $id"))
+ }
+ } getOrElse Failure(new InvalidStateException(s"Keine Sammelbestellung mit der Nr. $id gefunden"))
+ } partition (_.isSuccess)
- if (events.isEmpty) {
- Failure(new InvalidStateException(s"Keine der Sammelbestellung konnte abgearbeitet werden"))
- } else {
- Success(events map (_.get))
+ if (events.isEmpty) {
+ Failure(new InvalidStateException(s"Keine der Sammelbestellung konnte abgearbeitet werden"))
+ } else {
+ Success(events map (_.get))
+ }
}
- }
- case CreateAnzahlLieferungenRechnungsPositionenCommand(_, aboRechnungCreate) => idFactory => meta =>
- createAboRechnungsPositionenAnzahlLieferungen(idFactory, meta, aboRechnungCreate)
+ case CreateAnzahlLieferungenRechnungsPositionenCommand(_, aboRechnungCreate) => idFactory =>
+ meta =>
+ createAboRechnungsPositionenAnzahlLieferungen(idFactory, meta, aboRechnungCreate)
- case CreateBisGuthabenRechnungsPositionenCommand(_, aboRechnungCreate) => idFactory => meta =>
- createAboRechnungsPositionenBisGuthaben(idFactory, meta, aboRechnungCreate)
+ case CreateBisGuthabenRechnungsPositionenCommand(_, aboRechnungCreate) => idFactory =>
+ meta =>
+ createAboRechnungsPositionenBisGuthaben(idFactory, meta, aboRechnungCreate)
- case PasswortWechselCommand(_, personId, pwd, einladungId) => _ => _ =>
- Success(Seq(DefaultResultingEvent(factory => PasswortGewechseltEvent(factory.newMetadata(), personId, pwd, einladungId))))
+ case PasswortWechselCommand(_, personId, pwd, einladungId) => _ =>
+ _ =>
+ Success(Seq(DefaultResultingEvent(factory => PasswortGewechseltEvent(factory.newMetadata(), personId, pwd, einladungId))))
- case LoginDeaktivierenCommand(originator, kundeId, personId) if originator != personId => _ => _ =>
- Success(Seq(DefaultResultingEvent(factory => LoginDeaktiviertEvent(factory.newMetadata(), kundeId, personId))))
+ case LoginDeaktivierenCommand(originator, kundeId, personId) if originator != personId => _ =>
+ _ =>
+ Success(Seq(DefaultResultingEvent(factory => LoginDeaktiviertEvent(factory.newMetadata(), kundeId, personId))))
- case LoginAktivierenCommand(originator, kundeId, personId) if originator != personId => _ => _ =>
- Success(Seq(DefaultResultingEvent(factory => LoginAktiviertEvent(factory.newMetadata(), kundeId, personId))))
+ case LoginAktivierenCommand(originator, kundeId, personId) if originator != personId => _ =>
+ _ =>
+ Success(Seq(DefaultResultingEvent(factory => LoginAktiviertEvent(factory.newMetadata(), kundeId, personId))))
- case EinladungSendenCommand(originator, kundeId, personId) if originator != personId => idFactory => meta =>
- sendEinladung(idFactory, meta, kundeId, personId)
+ case EinladungSendenCommand(originator, kundeId, personId) if originator != personId => idFactory =>
+ meta =>
+ sendEinladung(idFactory, meta, kundeId, personId)
- case PasswortResetCommand(_, personId) => idFactory => meta =>
- sendPasswortReset(idFactory, meta, personId)
+ case PasswortResetCommand(_, personId) => idFactory =>
+ meta =>
+ sendPasswortReset(idFactory, meta, personId)
- case RolleWechselnCommand(originator, kundeId, personId, rolle) if originator != personId => idFactory => meta =>
- changeRolle(idFactory, meta, kundeId, personId, rolle)
- case OtpResetCommand(_, kundeId, personId) => _ => _ =>
- Success(Seq(DefaultResultingEvent(factory => OtpResetEvent(factory.newMetadata(), kundeId, personId, OtpUtil.generateOtpSecretString))))
+ case RolleWechselnCommand(originator, kundeId, personId, rolle) if originator != personId => idFactory =>
+ meta =>
+ changeRolle(idFactory, meta, kundeId, personId, rolle)
+ case OtpResetCommand(_, kundeId, personId) => _ =>
+ _ =>
+ Success(Seq(DefaultResultingEvent(factory => OtpResetEvent(factory.newMetadata(), kundeId, personId, OtpUtil.generateOtpSecretString))))
- case AboAktivierenCommand(aboId, _) => _ => _ =>
- Success(Seq(DefaultResultingEvent(factory => AboAktiviertEvent(factory.newMetadata(), aboId))))
+ case AboAktivierenCommand(aboId, _) => _ =>
+ _ =>
+ Success(Seq(DefaultResultingEvent(factory => AboAktiviertEvent(factory.newMetadata(), aboId))))
- case AboDeaktivierenCommand(aboId, _) => _ => _ =>
- Success(Seq(DefaultResultingEvent(factory => AboDeaktiviertEvent(factory.newMetadata(), aboId))))
+ case AboDeaktivierenCommand(aboId, _) => _ =>
+ _ =>
+ Success(Seq(DefaultResultingEvent(factory => AboDeaktiviertEvent(factory.newMetadata(), aboId))))
- case UpdateKundeCommand(_, kundeId, kunde) => idFactory => meta =>
- updateKunde(idFactory, meta, kundeId, kunde)
+ case UpdateKundeCommand(_, kundeId, kunde) => idFactory =>
+ meta =>
+ updateKunde(idFactory, meta, kundeId, kunde)
- case CreateKundeCommand(_, kunde) => idFactory => meta =>
- createKunde(idFactory, meta, kunde)
+ case CreateKundeCommand(_, kunde) => idFactory =>
+ meta =>
+ createKunde(idFactory, meta, kunde)
- case RemoveLieferungCommand(_, lieferungId) => idFactory => meta =>
- removeLieferung(idFactory, meta, lieferungId)
+ case RemoveLieferungCommand(_, lieferungId) => idFactory =>
+ meta =>
+ removeLieferung(idFactory, meta, lieferungId)
/*
* Insert command handling
*/
- case e @ InsertEntityCommand(_, entity: CustomKundentypCreate) => idFactory => meta =>
- handleEntityInsert[CustomKundentypCreate, CustomKundentypId](idFactory, meta, entity, CustomKundentypId.apply)
- case e @ InsertEntityCommand(_, entity: LieferungenAbotypCreate) => idFactory => meta =>
- val events = entity.daten.map { datum =>
- val lieferungCreate = copyTo[LieferungenAbotypCreate, LieferungAbotypCreate](entity, "datum" -> datum)
- insertEntityEvent[LieferungAbotypCreate, LieferungId](idFactory, meta, lieferungCreate, LieferungId.apply)
- }
- Success(events)
- case e @ InsertEntityCommand(_, entity: LieferungAbotypCreate) => idFactory => meta =>
- handleEntityInsert[LieferungAbotypCreate, LieferungId](idFactory, meta, entity, LieferungId.apply)
- case e @ InsertEntityCommand(_, entity: LieferplanungCreate) => idFactory => meta =>
- handleEntityInsert[LieferplanungCreate, LieferplanungId](idFactory, meta, entity, LieferplanungId.apply)
- case e @ InsertEntityCommand(_, entity: LieferungPlanungAdd) => idFactory => meta =>
- handleEntityInsert[LieferungPlanungAdd, LieferungId](idFactory, meta, entity, LieferungId.apply)
- case e @ InsertEntityCommand(_, entity: LieferpositionenModify) => idFactory => meta =>
- handleEntityInsert[LieferpositionenModify, LieferpositionId](idFactory, meta, entity, LieferpositionId.apply)
- case e @ InsertEntityCommand(_, entity: PendenzModify) => idFactory => meta =>
- handleEntityInsert[PendenzModify, PendenzId](idFactory, meta, entity, PendenzId.apply)
- case e @ InsertEntityCommand(_, entity: PersonCreate) => idFactory => meta =>
- handleEntityInsert[PersonCreate, PersonId](idFactory, meta, entity, PersonId.apply)
- case e @ InsertEntityCommand(_, entity: PersonCategoryCreate) => idFactory => meta =>
- handleEntityInsert[PersonCategoryCreate, PersonCategoryId](idFactory, meta, entity, PersonCategoryId.apply)
- case e @ InsertEntityCommand(_, entity: ProduzentModify) => idFactory => meta =>
- handleEntityInsert[ProduzentModify, ProduzentId](idFactory, meta, entity, ProduzentId.apply)
- case e @ InsertEntityCommand(_, entity: ProduktModify) => idFactory => meta =>
- handleEntityInsert[ProduktModify, ProduktId](idFactory, meta, entity, ProduktId.apply)
- case e @ InsertEntityCommand(_, entity: ProduktProduktekategorie) => idFactory => meta =>
- handleEntityInsert[ProduktProduktekategorie, ProduktProduktekategorieId](idFactory, meta, entity, ProduktProduktekategorieId.apply)
- case e @ InsertEntityCommand(_, entity: ProduktProduzent) => idFactory => meta =>
- handleEntityInsert[ProduktProduzent, ProduktProduzentId](idFactory, meta, entity, ProduktProduzentId.apply)
- case e @ InsertEntityCommand(_, entity: ProduktekategorieModify) => idFactory => meta =>
- handleEntityInsert[ProduktekategorieModify, ProduktekategorieId](idFactory, meta, entity, ProduktekategorieId.apply)
- case e @ InsertEntityCommand(_, entity: ProjektModify) => idFactory => meta =>
- handleEntityInsert[ProjektModify, ProjektId](idFactory, meta, entity, ProjektId.apply)
- case e @ InsertEntityCommand(_, entity: TourCreate) => idFactory => meta =>
- handleEntityInsert[TourCreate, TourId](idFactory, meta, entity, TourId.apply)
- case e @ InsertEntityCommand(_, entity: AbwesenheitCreate) => idFactory => meta =>
- handleEntityInsert[AbwesenheitCreate, AbwesenheitId](idFactory, meta, entity, AbwesenheitId.apply)
- case e @ InsertEntityCommand(_, entity: AbotypModify) => idFactory => meta =>
- handleEntityInsert[AbotypModify, AbotypId](idFactory, meta, entity, AbotypId.apply)
- case e @ InsertEntityCommand(_, entity: ZusatzAbotypModify) => idFactory => meta =>
- handleEntityInsert[ZusatzAbotypModify, AbotypId](idFactory, meta, entity, AbotypId.apply)
- case e @ InsertEntityCommand(_, entity: DepotModify) => idFactory => meta =>
- handleEntityInsert[DepotModify, DepotId](idFactory, meta, entity, DepotId.apply)
- case e @ InsertEntityCommand(_, entity: DepotlieferungModify) => idFactory => meta =>
- handleEntityInsert[DepotlieferungModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
- case e @ InsertEntityCommand(_, entity: HeimlieferungModify) => idFactory => meta =>
- handleEntityInsert[HeimlieferungModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
- case e @ InsertEntityCommand(_, entity: PostlieferungModify) => idFactory => meta =>
- handleEntityInsert[PostlieferungModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
- case e @ InsertEntityCommand(_, entity: DepotlieferungAbotypModify) => idFactory => meta =>
- handleEntityInsert[DepotlieferungAbotypModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
- case e @ InsertEntityCommand(_, entity: HeimlieferungAbotypModify) => idFactory => meta =>
- handleEntityInsert[HeimlieferungAbotypModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
- case e @ InsertEntityCommand(_, entity: PostlieferungAbotypModify) => idFactory => meta =>
- handleEntityInsert[PostlieferungAbotypModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
- case e @ InsertEntityCommand(_, entity: DepotlieferungAboCreate) => idFactory => meta =>
- handleEntityInsert[DepotlieferungAboCreate, AboId](idFactory, meta, entity, AboId.apply)
- case e @ InsertEntityCommand(_, entity: HeimlieferungAboCreate) => idFactory => meta =>
- handleEntityInsert[HeimlieferungAboCreate, AboId](idFactory, meta, entity, AboId.apply)
- case e @ InsertEntityCommand(_, entity: PostlieferungAboCreate) => idFactory => meta =>
- handleEntityInsert[PostlieferungAboCreate, AboId](idFactory, meta, entity, AboId.apply)
- case e @ InsertEntityCommand(_, entity: ZusatzAboModify) => idFactory => meta =>
- handleEntityInsert[ZusatzAboModify, AboId](idFactory, meta, entity, AboId.apply)
- case e @ InsertEntityCommand(_, entity: ZusatzAboCreate) => idFactory => meta =>
- handleEntityInsert[ZusatzAboCreate, AboId](idFactory, meta, entity, AboId.apply)
- case e @ InsertEntityCommand(_, entity: PendenzCreate) => idFactory => meta =>
- handleEntityInsert[PendenzCreate, PendenzId](idFactory, meta, entity, PendenzId.apply)
- case e @ InsertEntityCommand(_, entity: VertriebModify) => idFactory => meta =>
- handleEntityInsert[VertriebModify, VertriebId](idFactory, meta, entity, VertriebId.apply)
- case e @ InsertEntityCommand(_, entity: ProjektVorlageCreate) => idFactory => meta =>
- handleEntityInsert[ProjektVorlageCreate, ProjektVorlageId](idFactory, meta, entity, ProjektVorlageId.apply)
+ case e@InsertEntityCommand(_, entity: CustomKundentypCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[CustomKundentypCreate, CustomKundentypId](idFactory, meta, entity, CustomKundentypId.apply)
+ case e@InsertEntityCommand(_, entity: LieferungenAbotypCreate) => idFactory =>
+ meta =>
+ val events = entity.daten.map { datum =>
+ val lieferungCreate = copyTo[LieferungenAbotypCreate, LieferungAbotypCreate](entity, "datum" -> datum)
+ insertEntityEvent[LieferungAbotypCreate, LieferungId](idFactory, meta, lieferungCreate, LieferungId.apply)
+ }
+ Success(events)
+ case e@InsertEntityCommand(_, entity: LieferungAbotypCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[LieferungAbotypCreate, LieferungId](idFactory, meta, entity, LieferungId.apply)
+ case e@InsertEntityCommand(_, entity: LieferplanungCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[LieferplanungCreate, LieferplanungId](idFactory, meta, entity, LieferplanungId.apply)
+ case e@InsertEntityCommand(_, entity: LieferungPlanungAdd) => idFactory =>
+ meta =>
+ handleEntityInsert[LieferungPlanungAdd, LieferungId](idFactory, meta, entity, LieferungId.apply)
+ case e@InsertEntityCommand(_, entity: LieferpositionenModify) => idFactory =>
+ meta =>
+ handleEntityInsert[LieferpositionenModify, LieferpositionId](idFactory, meta, entity, LieferpositionId.apply)
+ case e@InsertEntityCommand(_, entity: PendenzModify) => idFactory =>
+ meta =>
+ handleEntityInsert[PendenzModify, PendenzId](idFactory, meta, entity, PendenzId.apply)
+ case e@InsertEntityCommand(_, entity: PersonCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[PersonCreate, PersonId](idFactory, meta, entity, PersonId.apply)
+ case e@InsertEntityCommand(_, entity: PersonCategoryCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[PersonCategoryCreate, PersonCategoryId](idFactory, meta, entity, PersonCategoryId.apply)
+ case e@InsertEntityCommand(_, entity: ProduzentModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ProduzentModify, ProduzentId](idFactory, meta, entity, ProduzentId.apply)
+ case e@InsertEntityCommand(_, entity: ProduktModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ProduktModify, ProduktId](idFactory, meta, entity, ProduktId.apply)
+ case e@InsertEntityCommand(_, entity: ProduktProduktekategorie) => idFactory =>
+ meta =>
+ handleEntityInsert[ProduktProduktekategorie, ProduktProduktekategorieId](idFactory, meta, entity, ProduktProduktekategorieId.apply)
+ case e@InsertEntityCommand(_, entity: ProduktProduzent) => idFactory =>
+ meta =>
+ handleEntityInsert[ProduktProduzent, ProduktProduzentId](idFactory, meta, entity, ProduktProduzentId.apply)
+ case e@InsertEntityCommand(_, entity: ProduktekategorieModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ProduktekategorieModify, ProduktekategorieId](idFactory, meta, entity, ProduktekategorieId.apply)
+ case e@InsertEntityCommand(_, entity: ProjektModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ProjektModify, ProjektId](idFactory, meta, entity, ProjektId.apply)
+ case e@InsertEntityCommand(_, entity: TourCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[TourCreate, TourId](idFactory, meta, entity, TourId.apply)
+ case e@InsertEntityCommand(_, entity: AbwesenheitCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[AbwesenheitCreate, AbwesenheitId](idFactory, meta, entity, AbwesenheitId.apply)
+ case e@InsertEntityCommand(_, entity: AbotypModify) => idFactory =>
+ meta =>
+ handleEntityInsert[AbotypModify, AbotypId](idFactory, meta, entity, AbotypId.apply)
+ case e@InsertEntityCommand(_, entity: ZusatzAbotypModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ZusatzAbotypModify, AbotypId](idFactory, meta, entity, AbotypId.apply)
+ case e@InsertEntityCommand(_, entity: DepotModify) => idFactory =>
+ meta =>
+ handleEntityInsert[DepotModify, DepotId](idFactory, meta, entity, DepotId.apply)
+ case e@InsertEntityCommand(_, entity: DepotlieferungModify) => idFactory =>
+ meta =>
+ handleEntityInsert[DepotlieferungModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
+ case e@InsertEntityCommand(_, entity: HeimlieferungModify) => idFactory =>
+ meta =>
+ handleEntityInsert[HeimlieferungModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
+ case e@InsertEntityCommand(_, entity: PostlieferungModify) => idFactory =>
+ meta =>
+ handleEntityInsert[PostlieferungModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
+ case e@InsertEntityCommand(_, entity: DepotlieferungAbotypModify) => idFactory =>
+ meta =>
+ handleEntityInsert[DepotlieferungAbotypModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
+ case e@InsertEntityCommand(_, entity: HeimlieferungAbotypModify) => idFactory =>
+ meta =>
+ handleEntityInsert[HeimlieferungAbotypModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
+ case e@InsertEntityCommand(_, entity: PostlieferungAbotypModify) => idFactory =>
+ meta =>
+ handleEntityInsert[PostlieferungAbotypModify, VertriebsartId](idFactory, meta, entity, VertriebsartId.apply)
+ case e@InsertEntityCommand(_, entity: DepotlieferungAboCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[DepotlieferungAboCreate, AboId](idFactory, meta, entity, AboId.apply)
+ case e@InsertEntityCommand(_, entity: HeimlieferungAboCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[HeimlieferungAboCreate, AboId](idFactory, meta, entity, AboId.apply)
+ case e@InsertEntityCommand(_, entity: PostlieferungAboCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[PostlieferungAboCreate, AboId](idFactory, meta, entity, AboId.apply)
+ case e@InsertEntityCommand(_, entity: ZusatzAboModify) => idFactory =>
+ meta =>
+ handleEntityInsert[ZusatzAboModify, AboId](idFactory, meta, entity, AboId.apply)
+ case e@InsertEntityCommand(_, entity: ZusatzAboCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[ZusatzAboCreate, AboId](idFactory, meta, entity, AboId.apply)
+ case e@InsertEntityCommand(_, entity: PendenzCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[PendenzCreate, PendenzId](idFactory, meta, entity, PendenzId.apply)
+ case e@InsertEntityCommand(_, entity: VertriebModify) => idFactory =>
+ meta =>
+ handleEntityInsert[VertriebModify, VertriebId](idFactory, meta, entity, VertriebId.apply)
+ case e@InsertEntityCommand(_, entity: ProjektVorlageCreate) => idFactory =>
+ meta =>
+ handleEntityInsert[ProjektVorlageCreate, ProjektVorlageId](idFactory, meta, entity, ProjektVorlageId.apply)
/*
* Custom update command handling
*/
- case UpdateEntityCommand(personId, id: KundeId, entity: KundeModify) => idFactory => _ =>
- updateKundeEntity(idFactory, personId, id, entity)
-
- case UpdateEntityCommand(_, id: AboId, entity: AboGuthabenModify) => idFactory => meta =>
- DB readOnly { implicit session =>
- //TODO: assemble text using gettext
- stammdatenReadRepository.getAboDetail(id) match {
- case Some(abo) => {
- val text = s"Guthaben manuell angepasst. Abo Nr.: ${id.id}; Bisher: ${abo.guthaben}; Neu: ${entity.guthabenNeu}; Grund: ${entity.bemerkung}"
- val pendenzEvent = addKundenPendenz(idFactory, meta, id, text, Erledigt)
- Success(Seq(Some(EntityUpdateEvent(id, entity)), pendenzEvent).flatten)
+ case UpdateEntityCommand(personId, id: KundeId, entity: KundeModify) => idFactory =>
+ _ =>
+ updateKundeEntity(idFactory, personId, id, entity)
+
+ case UpdateEntityCommand(_, id: AboId, entity: AboGuthabenModify) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ //TODO: assemble text using gettext
+ stammdatenReadRepository.getAboDetail(id) match {
+ case Some(abo) => {
+ val text = s"Guthaben manuell angepasst. Abo Nr.: ${id.id}; Bisher: ${abo.guthaben}; Neu: ${entity.guthabenNeu}; Grund: ${entity.bemerkung}"
+ val pendenzEvent = addKundenPendenz(idFactory, meta, id, text, Erledigt)
+ Success(Seq(Some(EntityUpdateEvent(id, entity)), pendenzEvent).flatten)
+ }
+ case None =>
+ Failure(new InvalidStateException(s"UpdateEntityCommand: Abo konnte nicht gefunden werden"))
}
- case None =>
- Failure(new InvalidStateException(s"UpdateEntityCommand: Abo konnte nicht gefunden werden"))
}
- }
- case UpdateEntityCommand(_, id: AboId, entity: AboVertriebsartModify) => idFactory => meta =>
- DB readOnly { implicit session =>
- //TODO: assemble text using gettext
- val newLieferungen = stammdatenReadRepository.getLieferungen(entity.vertriebIdNeu)
- stammdatenReadRepository.getAbo(id) match {
- case Some(abo) =>
- val text = s"Vertriebsart angepasst. Abo Nr.: ${id.id}, Neu: ${entity.vertriebsartIdNeu}; Grund: ${entity.bemerkung}"
- var absencesText = ""
- var pendenzStatus: PendenzStatus = Erledigt
- stammdatenReadRepository.getById(vertriebMapping, abo.vertriebId) match {
- case Some(vertrieb) =>
- stammdatenReadRepository.getLieferungen(vertrieb.id).filter(lOld => (lOld.datum isAfter DateTime.now) && (newLieferungen.count(l => l.datum == lOld.datum) == 0)) map { l =>
- if (stammdatenReadRepository.getAbwesenheit(abo.id, l.datum).length > 0) {
- absencesText = s"; Bitte Abwesenheiten prüfen!"
- pendenzStatus = Ausstehend
+ case UpdateEntityCommand(_, id: AboId, entity: AboVertriebsartModify) => idFactory =>
+ meta =>
+ DB readOnly { implicit session =>
+ //TODO: assemble text using gettext
+ val newLieferungen = stammdatenReadRepository.getLieferungen(entity.vertriebIdNeu)
+ stammdatenReadRepository.getAbo(id) match {
+ case Some(abo) =>
+ val text = s"Vertriebsart angepasst. Abo Nr.: ${id.id}, Neu: ${entity.vertriebsartIdNeu}; Grund: ${entity.bemerkung}"
+ var absencesText = ""
+ var pendenzStatus: PendenzStatus = Erledigt
+ stammdatenReadRepository.getById(vertriebMapping, abo.vertriebId) match {
+ case Some(vertrieb) =>
+ stammdatenReadRepository.getLieferungen(vertrieb.id).filter(lOld => (lOld.datum isAfter DateTime.now) && (newLieferungen.count(l => l.datum
+ == lOld.datum) == 0)) map { l =>
+ if (stammdatenReadRepository.getAbwesenheit(abo.id, l.datum).length > 0) {
+ absencesText = s"; Bitte Abwesenheiten prüfen!"
+ pendenzStatus = Ausstehend
+ }
}
- }
- case None => Failure(new InvalidStateException(s"UpdateEntityCommand: Some error happened when creating a pendenz"))
- }
- val pendenzEvent = addKundenPendenz(idFactory, meta, id, text + absencesText, pendenzStatus)
- Success(Seq(Some(EntityUpdateEvent(id, entity)), pendenzEvent).flatten)
- case None =>
- Failure(new InvalidStateException(s"UpdateEntityCommand: Some error happened when creating a pendenz"))
+ case None => Failure(new InvalidStateException(s"UpdateEntityCommand: Some error happened when creating a pendenz"))
+ }
+ val pendenzEvent = addKundenPendenz(idFactory, meta, id, text + absencesText, pendenzStatus)
+ Success(Seq(Some(EntityUpdateEvent(id, entity)), pendenzEvent).flatten)
+ case None =>
+ Failure(new InvalidStateException(s"UpdateEntityCommand: Some error happened when creating a pendenz"))
+ }
}
- }
}
- def addKundenPendenz(idFactory: IdFactory, meta: EventTransactionMetadata, id: AboId, bemerkung: String, status: PendenzStatus)(implicit session: DBSession): Option[ResultingEvent] = {
+ def addKundenPendenz(idFactory: IdFactory, meta: EventTransactionMetadata, id: AboId, bemerkung: String, status: PendenzStatus)(implicit
+ session: DBSession)
+ : Option[ResultingEvent] = {
// zusätzlich eine pendenz erstellen
((stammdatenReadRepository.getById(depotlieferungAboMapping, id) map { abo =>
DepotlieferungAboModify
@@ -590,7 +750,8 @@ trait StammdatenCommandHandler extends CommandHandler
}
}
- def createAboRechnungsPositionenAnzahlLieferungen(idFactory: IdFactory, meta: EventTransactionMetadata, aboRechnungCreate: AboRechnungsPositionBisAnzahlLieferungenCreate) = {
+ def createAboRechnungsPositionenAnzahlLieferungen(idFactory: IdFactory, meta: EventTransactionMetadata,
+ aboRechnungCreate: AboRechnungsPositionBisAnzahlLieferungenCreate) = {
DB readOnly { implicit session =>
// HauptAbos
val abos: List[Abo] = stammdatenReadRepository.getByIds(depotlieferungAboMapping, aboRechnungCreate.ids) :::
@@ -623,10 +784,11 @@ trait StammdatenCommandHandler extends CommandHandler
val repoType = abotyp match {
case a: ZusatzAbotyp => RechnungsPositionTyp.ZusatzAbo
- case _ => RechnungsPositionTyp.Abo
+ case _ => RechnungsPositionTyp.Abo
}
- val hauptRechnungPosition = createRechnungPositionEvent(abo, aboRechnungCreate.titel, anzahlLieferungen, hauptAboBetrag, aboRechnungCreate.waehrung, None, repoType)
+ val hauptRechnungPosition = createRechnungPositionEvent(abo, aboRechnungCreate.titel, anzahlLieferungen, hauptAboBetrag, aboRechnungCreate
+ .waehrung, None, repoType)
val parentRechnungPositionId = idFactory.newId(RechnungsPositionId.apply)
Success(List(EntityInsertEvent(parentRechnungPositionId, hauptRechnungPosition)))
@@ -673,7 +835,9 @@ trait StammdatenCommandHandler extends CommandHandler
Success(updateEvent +: (newPersonsEvents ++ newPendenzenEvents))
}
- private def createRechnungPositionEvent(abo: Abo, titel: String, anzahlLieferungen: Int, betrag: BigDecimal, waehrung: Waehrung, parentRechnungsPositionId: Option[RechnungsPositionId] = None, rechnungsPositionTyp: RechnungsPositionTyp.RechnungsPositionTyp = RechnungsPositionTyp.Abo): RechnungsPositionCreate = {
+ private def createRechnungPositionEvent(abo: Abo, titel: String, anzahlLieferungen: Int, betrag: BigDecimal, waehrung: Waehrung,
+ parentRechnungsPositionId: Option[RechnungsPositionId] = None, rechnungsPositionTyp: RechnungsPositionTyp
+ .RechnungsPositionTyp = RechnungsPositionTyp.Abo): RechnungsPositionCreate = {
RechnungsPositionCreate(
abo.kundeId,
Some(abo.id),
@@ -687,7 +851,8 @@ trait StammdatenCommandHandler extends CommandHandler
)
}
- def createAboRechnungsPositionenBisGuthaben(idFactory: IdFactory, meta: EventTransactionMetadata, aboRechnungCreate: AboRechnungsPositionBisGuthabenCreate) = {
+ def createAboRechnungsPositionenBisGuthaben(idFactory: IdFactory, meta: EventTransactionMetadata, aboRechnungCreate: AboRechnungsPositionBisGuthabenCreate)
+ = {
DB readOnly { implicit session =>
val abos: List[Abo] = stammdatenReadRepository.getByIds(depotlieferungAboMapping, aboRechnungCreate.ids) :::
stammdatenReadRepository.getByIds(postlieferungAboMapping, aboRechnungCreate.ids) :::
@@ -712,14 +877,15 @@ trait StammdatenCommandHandler extends CommandHandler
val hauptabo = stammdatenReadRepository.getHauptAbo(zusatzAbo.id)
hauptabo.get.guthaben
case abo: HauptAbo => abo.guthaben
- case abo => throw new InvalidStateException(s"Unexpected abo type found:$abo")
+ case abo => throw new InvalidStateException(s"Unexpected abo type found:$abo")
}
val anzahlLieferungen = math.max((aboRechnungCreate.bisGuthaben - guthaben), 0)
if (anzahlLieferungen > 0) {
val hauptAboBetrag = abo.price.getOrElse(abotyp.preis) * anzahlLieferungen
- val hauptRechnungPosition = createRechnungPositionEvent(abo, aboRechnungCreate.titel, anzahlLieferungen, hauptAboBetrag, aboRechnungCreate.waehrung)
+ val hauptRechnungPosition = createRechnungPositionEvent(abo, aboRechnungCreate.titel, anzahlLieferungen, hauptAboBetrag, aboRechnungCreate
+ .waehrung)
val parentRechnungPositionId = idFactory.newId(RechnungsPositionId.apply)
Success(List(EntityInsertEvent(parentRechnungPositionId, hauptRechnungPosition)))
@@ -817,8 +983,9 @@ trait StammdatenCommandHandler extends CommandHandler
//Konto daten creation
val kontoDaten = kunde.kontoDaten match {
- case Some(kd) => KontoDatenModify(kd.iban, kd.bic, None, None, kd.bankName, kd.nameAccountHolder, kd.addressAccountHolder, Some(kundeId), None, None, None)
- case None => KontoDatenModify(None, None, None, None, None, None, None, Some(kundeId), None, None, None)
+ case Some(kd) => KontoDatenModify(kd.iban, kd.bic, None, None, kd.bankName, kd.nameAccountHolder, kd.addressAccountHolder, Some(kundeId), None,
+ None, None)
+ case None => KontoDatenModify(None, None, None, None, None, None, None, Some(kundeId), None, None, None)
}
logger.debug(s"created => Insert entity:$kontoDaten")
val kontoDatenEvent = EntityInsertEvent(KontoDatenId(kundeId.id), kontoDaten)
@@ -863,14 +1030,18 @@ trait StammdatenCommandHandler extends CommandHandler
}
case _ => None
}
- } else { None }
+ } else {
+ None
+ }
case _ => None
}
}.flatten.isEmpty
}
}
- private def getCreateAuslieferungHeimEvent(idFactory: IdFactory, meta: EventTransactionMetadata, lieferplanung: Lieferplanung)(implicit personId: PersonId, session: DBSession): Seq[ResultingEvent] = {
+ private def getCreateAuslieferungHeimEvent(idFactory: IdFactory, meta: EventTransactionMetadata, lieferplanung: Lieferplanung)(implicit personId: PersonId,
+ session: DBSession)
+ : Seq[ResultingEvent] = {
val lieferungen = stammdatenReadRepository.getLieferungen(lieferplanung.id)
//handle Tourenlieferungen: Group all entries with the same TourId on the same Date
@@ -881,7 +1052,9 @@ trait StammdatenCommandHandler extends CommandHandler
(h.tourId, tour.name, lieferung.datum) -> h.id
}
}
- }).flatten.groupBy(_._1).view.mapValues(_ map { _._2 })
+ }).flatten.groupBy(_._1).view.mapValues(_ map {
+ _._2
+ })
(vertriebsartenDaten flatMap {
case ((tourId, tourName, lieferdatum), vertriebsartIds) => {
@@ -896,8 +1069,12 @@ trait StammdatenCommandHandler extends CommandHandler
EntityUpdateEvent(korb.id, KorbAuslieferungModify(tourAuslieferung.id, tourlieferungen find (_.id == korb.aboId) flatMap (_.sort)))
}
EntityInsertEvent(tourAuslieferung.id, tourAuslieferung) :: updates
- } else { Nil }
- } else { Nil }
+ } else {
+ Nil
+ }
+ } else {
+ Nil
+ }
}
}).toSeq
}
@@ -906,14 +1083,15 @@ trait StammdatenCommandHandler extends CommandHandler
val hauptAboKoerbe = koerbe map { korb =>
stammdatenReadRepository.getAbo(korb.aboId) match {
case Some(abo: ZusatzAbo) => None
- case None => None
- case _ => Some(korb)
+ case None => None
+ case _ => Some(korb)
}
}
hauptAboKoerbe.flatten.size
}
- private def getCreateDepotAuslieferungAndPostAusliferungEvent(idFactory: IdFactory, meta: EventTransactionMetadata, lieferplanung: Lieferplanung)(implicit personId: PersonId, session: DBSession): Seq[ResultingEvent] = {
+ private def getCreateDepotAuslieferungAndPostAusliferungEvent(idFactory: IdFactory, meta: EventTransactionMetadata, lieferplanung: Lieferplanung)(implicit
+ personId: PersonId, session: DBSession): Seq[ResultingEvent] = {
val lieferungen = stammdatenReadRepository.getLieferungen(lieferplanung.id)
val updates1 = handleLieferplanungAbgeschlossen(idFactory, meta, lieferungen)
@@ -923,14 +1101,18 @@ trait StammdatenCommandHandler extends CommandHandler
updates1 ::: updates2 ::: updates3
}
- private def handleLieferplanungAbgeschlossen(idFactory: IdFactory, meta: EventTransactionMetadata, lieferungen: List[Lieferung])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
+ private def handleLieferplanungAbgeschlossen(idFactory: IdFactory, meta: EventTransactionMetadata, lieferungen: List[Lieferung])(implicit
+ personId: PersonId,
+ session: DBSession)
+ : List[ResultingEvent] = {
//handle Depot- and Postlieferungen: Group all entries with the same VertriebId on the same Date
val vertriebeDaten = lieferungen.map(l => (l.vertriebId, l.datum)).distinct
getDepotAuslieferungEvents(idFactory, meta, getDepotAuslieferungAsAMapGrouped(vertriebeDaten)) :::
getPostAuslieferungEvents(idFactory, meta, getPostAuslieferungAsAMapGrouped(vertriebeDaten))
}
- private def getDepotAuslieferungAsAMapGrouped(vertriebeDaten: List[(VertriebId, DateTime)])(implicit personId: PersonId, session: DBSession): Map[(DepotId, DateTime), List[DepotlieferungDetail]] = {
+ private def getDepotAuslieferungAsAMapGrouped(vertriebeDaten: List[(VertriebId, DateTime)])(implicit personId: PersonId, session: DBSession): Map[(DepotId,
+ DateTime), List[DepotlieferungDetail]] = {
val depotAuslieferungMap = (vertriebeDaten map {
case (vertriebId, lieferungDatum) => {
logger.debug(s"handleLieferplanungAbgeschlossen Depot: ${vertriebId}:${lieferungDatum}.")
@@ -946,7 +1128,8 @@ trait StammdatenCommandHandler extends CommandHandler
}
}
- private def getDepotAuslieferungEvents(idFactory: IdFactory, meta: EventTransactionMetadata, depotAuslieferungGroupedMap: Map[(DepotId, DateTime), List[DepotlieferungDetail]])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
+ private def getDepotAuslieferungEvents(idFactory: IdFactory, meta: EventTransactionMetadata, depotAuslieferungGroupedMap: Map[(DepotId, DateTime),
+ List[DepotlieferungDetail]])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
val events = for {
((depotId, date), listDepotLieferungDetail) <- depotAuslieferungGroupedMap
} yield {
@@ -955,7 +1138,8 @@ trait StammdatenCommandHandler extends CommandHandler
events.flatten.toList
}
- private def getPostAuslieferungAsAMapGrouped(vertriebeDaten: List[(VertriebId, DateTime)])(implicit personId: PersonId, session: DBSession): Map[DateTime, List[PostlieferungDetail]] = {
+ private def getPostAuslieferungAsAMapGrouped(vertriebeDaten: List[(VertriebId, DateTime)])(implicit personId: PersonId, session: DBSession): Map[DateTime,
+ List[PostlieferungDetail]] = {
val postAuslieferungMap = (vertriebeDaten map {
case (vertriebId, lieferungDatum) => {
logger.debug(s"handleLieferplanungAbgeschlossen (Post): ${vertriebId}:${lieferungDatum}.")
@@ -972,7 +1156,8 @@ trait StammdatenCommandHandler extends CommandHandler
}
}
- private def getPostAuslieferungEvents(idFactory: IdFactory, meta: EventTransactionMetadata, postAuslieferungGroupedMap: Map[DateTime, List[PostlieferungDetail]])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
+ private def getPostAuslieferungEvents(idFactory: IdFactory, meta: EventTransactionMetadata, postAuslieferungGroupedMap: Map[DateTime,
+ List[PostlieferungDetail]])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
val events = for {
(date, listPostLieferungDetail) <- postAuslieferungGroupedMap
} yield {
@@ -981,7 +1166,9 @@ trait StammdatenCommandHandler extends CommandHandler
events.flatten.toList
}
- private def getPostAndDepotAuslieferungEvents(idFactory: IdFactory, meta: EventTransactionMetadata, date: DateTime, listVertriebsartDetail: List[VertriebsartDetail])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
+ private def getPostAndDepotAuslieferungEvents(idFactory: IdFactory, meta: EventTransactionMetadata, date: DateTime,
+ listVertriebsartDetail: List[VertriebsartDetail])(implicit personId: PersonId, session: DBSession)
+ : List[ResultingEvent] = {
val koerbe = getAllKoerbeForDepotOrPost(date, listVertriebsartDetail)
if (!koerbe.isEmpty) {
val newAuslieferung = createAuslieferungDepotPost(idFactory, meta, date, listVertriebsartDetail.head, countHauptAbos(koerbe)).get
@@ -994,14 +1181,16 @@ trait StammdatenCommandHandler extends CommandHandler
}
}
- private def getAllKoerbeForDepotOrPost(date: DateTime, vertriebsartDetailList: List[VertriebsartDetail])(implicit personId: PersonId, session: DBSession): List[Korb] = {
+ private def getAllKoerbeForDepotOrPost(date: DateTime, vertriebsartDetailList: List[VertriebsartDetail])(implicit personId: PersonId, session: DBSession)
+ : List[Korb] = {
val koerbe = vertriebsartDetailList map { vertriebsartDetail =>
stammdatenReadRepository.getKoerbe(date, vertriebsartDetail.id, WirdGeliefert)
}
koerbe.flatten
}
- private def recalculateValuesForLieferplanungAbgeschlossen(lieferungen: List[Lieferung])(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
+ private def recalculateValuesForLieferplanungAbgeschlossen(lieferungen: List[Lieferung])(implicit personId: PersonId, session: DBSession)
+ : List[ResultingEvent] = {
//calculate new values
lieferungen flatMap { lieferung =>
//calculate total of lieferung
@@ -1035,7 +1224,8 @@ trait StammdatenCommandHandler extends CommandHandler
}
}
- private def updateSammelbestellungStatus(lieferungen: List[Lieferung], lieferplanung: Lieferplanung)(implicit personId: PersonId, session: DBSession): List[ResultingEvent] = {
+ private def updateSammelbestellungStatus(lieferungen: List[Lieferung], lieferplanung: Lieferplanung)(implicit personId: PersonId, session: DBSession)
+ : List[ResultingEvent] = {
(stammdatenReadRepository.getSammelbestellungen(lieferplanung.id) map {
sammelbestellung =>
@@ -1044,11 +1234,14 @@ trait StammdatenCommandHandler extends CommandHandler
val sammelbestellungStatusModifyCopy = SammelbestellungStatusModify(sammelbestellungCopy.status)
Seq(EntityUpdateEvent(sammelbestellungCopy.id, sammelbestellungStatusModifyCopy))
- } else { Nil }
+ } else {
+ Nil
+ }
}).filter(_.nonEmpty).flatten
}
- private def createAuslieferungDepotPost(idFactory: IdFactory, meta: EventTransactionMetadata, lieferungDatum: DateTime, vertriebsart: VertriebsartDetail, anzahlKoerbe: Int)(implicit personId: PersonId): Option[Auslieferung] = {
+ private def createAuslieferungDepotPost(idFactory: IdFactory, meta: EventTransactionMetadata, lieferungDatum: DateTime, vertriebsart: VertriebsartDetail,
+ anzahlKoerbe: Int)(implicit personId: PersonId): Option[Auslieferung] = {
val auslieferungId = idFactory.newId(AuslieferungId.apply)
vertriebsart match {
@@ -1100,7 +1293,8 @@ trait StammdatenCommandHandler extends CommandHandler
stammdatenReadRepository.getTourAuslieferung(tourId, datum).isDefined
}
- private def createTourAuslieferungHeim(idFactory: IdFactory, meta: EventTransactionMetadata, lieferungDatum: DateTime, tourId: TourId, tourName: String, anzahlKoerbe: Int)(implicit personId: PersonId): TourAuslieferung = {
+ private def createTourAuslieferungHeim(idFactory: IdFactory, meta: EventTransactionMetadata, lieferungDatum: DateTime, tourId: TourId, tourName: String,
+ anzahlKoerbe: Int)(implicit personId: PersonId): TourAuslieferung = {
val auslieferungId = idFactory.newId(AuslieferungId.apply)
TourAuslieferung(
auslieferungId,
@@ -1129,15 +1323,15 @@ trait StammdatenCommandHandler extends CommandHandler
stammdatenReadRepository.getById(depotlieferungAboMapping, aboId) orElse
stammdatenReadRepository.getById(heimlieferungAboMapping, aboId) orElse
stammdatenReadRepository.getById(postlieferungAboMapping, aboId) map { abo =>
- stammdatenReadRepository.getPersonen(abo.kundeId) map { person =>
- val personEmailData = copyTo[Person, PersonEmailData](person)
- val mailContext = AboMailContext(personEmailData, abo)
- generateMail(subject, body, mailContext) match {
- case Success(mailPayload) => true
- case Failure(e) => false
- }
+ stammdatenReadRepository.getPersonen(abo.kundeId) map { person =>
+ val personEmailData = copyTo[Person, PersonEmailData](person)
+ val mailContext = AboMailContext(personEmailData, abo)
+ generateMail(subject, body, mailContext) match {
+ case Success(mailPayload) => true
+ case Failure(e) => false
}
}
+ }
}
templateCorrect.flatten.forall(x => x == true)
}
@@ -1151,7 +1345,7 @@ trait StammdatenCommandHandler extends CommandHandler
val mailContext = KundeMailContext(personEmailData, kunde)
generateMail(subject, body, mailContext) match {
case Success(mailPayload) => true
- case Failure(e) => false
+ case Failure(e) => false
}
}
}
@@ -1168,7 +1362,7 @@ trait StammdatenCommandHandler extends CommandHandler
val mailContext = AbotypMailContext(personEmailData, abotyp)
generateMail(subject, body, mailContext) match {
case Success(mailPayload) => true
- case Failure(e) => false
+ case Failure(e) => false
}
}
}
@@ -1185,7 +1379,7 @@ trait StammdatenCommandHandler extends CommandHandler
val mailContext = AbotypMailContext(personEmailData, abotyp)
generateMail(subject, body, mailContext) match {
case Success(mailPayload) => true
- case Failure(e) => false
+ case Failure(e) => false
}
}
}
@@ -1202,7 +1396,7 @@ trait StammdatenCommandHandler extends CommandHandler
val mailContext = TourMailContext(personEmailData, tour)
generateMail(subject, body, mailContext) match {
case Success(mailPayload) => true
- case Failure(e) => false
+ case Failure(e) => false
}
}
}
@@ -1219,7 +1413,7 @@ trait StammdatenCommandHandler extends CommandHandler
val mailContext = DepotMailContext(personEmailData, depot)
generateMail(subject, body, mailContext) match {
case Success(mailPayload) => true
- case Failure(e) => false
+ case Failure(e) => false
}
}
}
@@ -1234,7 +1428,7 @@ trait StammdatenCommandHandler extends CommandHandler
val mailContext = PersonMailContext(personEmailData)
generateMail(subject, body, mailContext) match {
case Success(mailPayload) => true
- case Failure(e) => false
+ case Failure(e) => false
}
}
}
@@ -1242,7 +1436,11 @@ trait StammdatenCommandHandler extends CommandHandler
}
}
-class DefaultStammdatenCommandHandler(override val sysConfig: SystemConfig, override val system: ActorSystem) extends StammdatenCommandHandler
- with DefaultStammdatenReadRepositorySyncComponent {
+class DefaultStammdatenCommandHandler(override val sysConfig: SystemConfig, override val system: ActorSystem, override val mailService: ActorRef) extends StammdatenCommandHandler
+ with DefaultStammdatenReadRepositorySyncComponent
+ with DefaultMailCommandForwarderComponent
+ with MailServiceReference {
override implicit protected val executionContext: ExecutionContext = system.dispatcher
+
+ override def projektReadRepository = stammdatenReadRepository
}
diff --git a/src/main/scala/ch/openolitor/stammdaten/StammdatenEntityStoreView.scala b/src/main/scala/ch/openolitor/stammdaten/StammdatenEntityStoreView.scala
index 41bbf383d..c5305dc3b 100644
--- a/src/main/scala/ch/openolitor/stammdaten/StammdatenEntityStoreView.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/StammdatenEntityStoreView.scala
@@ -50,7 +50,7 @@ trait StammdatenEntityStoreView extends EntityStoreView
/**
* Instanzieren der jeweiligen Insert, Update und Delete Child Actors
*/
-trait StammdatenEntityStoreViewComponent extends EntityStoreViewComponent with ActorSystemReference with MailServiceReference with SystemConfigReference {
+trait StammdatenEntityStoreViewComponent extends EntityStoreViewComponent with ActorSystemReference with SystemConfigReference with MailServiceReference {
override val insertService = StammdatenInsertService(sysConfig, system)
override val updateService = StammdatenUpdateService(sysConfig, system)
diff --git a/src/main/scala/ch/openolitor/stammdaten/StammdatenRoutes.scala b/src/main/scala/ch/openolitor/stammdaten/StammdatenRoutes.scala
index 91c4790eb..77488d8db 100644
--- a/src/main/scala/ch/openolitor/stammdaten/StammdatenRoutes.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/StammdatenRoutes.scala
@@ -44,7 +44,7 @@ import ch.openolitor.stammdaten.reporting._
import com.typesafe.scalalogging.LazyLogging
import ch.openolitor.core.filestore._
import akka.actor._
-import akka.http.scaladsl.model.headers.{ `Content-Disposition`, ContentDispositionTypes }
+import akka.http.scaladsl.model.headers.{`Content-Disposition`, ContentDispositionTypes}
import akka.http.scaladsl.server.Route
import ch.openolitor.buchhaltung.repositories.BuchhaltungReadRepositoryAsyncComponent
import ch.openolitor.buchhaltung.repositories.DefaultBuchhaltungReadRepositoryAsyncComponent
@@ -52,7 +52,8 @@ import ch.openolitor.buchhaltung.BuchhaltungJsonProtocol
import ch.openolitor.core.BaseJsonProtocol.IdResponse
import ch.openolitor.core.security.Subject
import ch.openolitor.stammdaten.repositories._
-import ch.openolitor.util.parsing.{ QueryFilter, GeschaeftsjahrFilter, FilterExpr, UriQueryParamFilterParser, UriQueryParamGeschaeftsjahrParser, UriQueryFilterParser }
+import ch.openolitor.util.parsing.{QueryFilter, GeschaeftsjahrFilter, FilterExpr, UriQueryParamFilterParser, UriQueryParamGeschaeftsjahrParser,
+ UriQueryFilterParser}
import scala.concurrent.ExecutionContext
@@ -102,7 +103,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("kontodaten" / kontoDatenIdPath) { id =>
get(detail(stammdatenReadRepository.getKontoDatenProjekt)) ~
- (put | post)(update[KontoDatenModify, KontoDatenId](id))
+ (put | post) (update[KontoDatenModify, KontoDatenId](id))
}
private def kundenRoute(implicit subject: Subject, filter: Option[FilterExpr], queryString: Option[QueryFilter]): Route =
@@ -124,7 +125,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("kunden" / kundeIdPath) { id =>
get(detail(stammdatenReadRepository.getKundeDetail(id))) ~
- (put | post)(
+ (put | post) (
entity(as[KundeModify]) { kunde =>
val allEmailAddresses = kunde.ansprechpersonen.map(_.email).flatten.filter(_.nonEmpty)
if (allEmailAddresses.distinct.length == allEmailAddresses.length) {
@@ -170,13 +171,13 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
delete(remove(aboId))
} ~
path("kunden" / kundeIdPath / "abos" / aboIdPath / "aktionen" / "guthabenanpassen") { (kundeId, aboId) =>
- (put | post)(update[AboGuthabenModify, AboId](aboId))
+ (put | post) (update[AboGuthabenModify, AboId](aboId))
} ~
path("kunden" / kundeIdPath / "abos" / aboIdPath / "aktionen" / "vertriebsartanpassen") { (kundeId, aboId) =>
- (put | post)(update[AboVertriebsartModify, AboId](aboId))
+ (put | post) (update[AboVertriebsartModify, AboId](aboId))
} ~
path("kunden" / kundeIdPath / "abos" / aboIdPath / "aktionen" / "priceanpassen") { (kundeId, aboId) =>
- (put | post)(update[AboPriceModify, AboId](aboId))
+ (put | post) (update[AboPriceModify, AboId](aboId))
} ~
path("kunden" / kundeIdPath / "abos" / aboIdPath / "koerbe") { (_, aboId) =>
get(list(stammdatenReadRepository.getKoerbe(aboId)))
@@ -199,7 +200,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("kunden" / kundeIdPath / "abos" / aboIdPath / "zusatzAbos" / aboIdPath) { (kundeId, hauptAboId, id) =>
get(detail(stammdatenReadRepository.getZusatzAboDetail(id))) ~
- (put | post)(update[ZusatzAboModify, AboId](id)) ~
+ (put | post) (update[ZusatzAboModify, AboId](id)) ~
delete(remove(id))
} ~
path("kunden" / kundeIdPath / "pendenzen") { kundeId =>
@@ -214,7 +215,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("kunden" / kundeIdPath / "pendenzen" / pendenzIdPath) { (kundeId, pendenzId) =>
get(detail(stammdatenReadRepository.getPendenzDetail(pendenzId))) ~
- (put | post)(update[PendenzModify, PendenzId](pendenzId)) ~
+ (put | post) (update[PendenzModify, PendenzId](pendenzId)) ~
delete(remove(pendenzId))
} ~
path("kunden" / kundeIdPath / "personen" / personIdPath) { (kundeId, personId) =>
@@ -257,7 +258,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
post(create[PersonCategoryCreate, PersonCategoryId](PersonCategoryId.apply _))
} ~
path("personCategories" / personCategoryIdPath) { (personCategoryId) =>
- (put | post)(update[PersonCategoryModify, PersonCategoryId](personCategoryId)) ~
+ (put | post) (update[PersonCategoryModify, PersonCategoryId](personCategoryId)) ~
delete(remove(personCategoryId))
}
@@ -267,7 +268,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
post(create[CustomKundentypCreate, CustomKundentypId](CustomKundentypId.apply _))
} ~
path("kundentypen" / kundentypIdPath) { (kundentypId) =>
- (put | post)(update[CustomKundentypModify, CustomKundentypId](kundentypId)) ~
+ (put | post) (update[CustomKundentypModify, CustomKundentypId](kundentypId)) ~
delete(remove(kundentypId))
}
@@ -289,7 +290,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("abotypen" / abotypIdPath) { id =>
get(detail(stammdatenReadRepository.getAbotypDetail(id))) ~
- (put | post)(update[AbotypModify, AbotypId](id)) ~
+ (put | post) (update[AbotypModify, AbotypId](id)) ~
delete(remove(id))
} ~
path("abotypen" / abotypIdPath / "vertriebe") { abotypId =>
@@ -298,7 +299,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("abotypen" / abotypIdPath / "vertriebe" / vertriebIdPath) { (abotypId, vertriebId) =>
get(detail(stammdatenReadRepository.getVertrieb(vertriebId))) ~
- (put | post)(update[VertriebModify, VertriebId](vertriebId)) ~
+ (put | post) (update[VertriebModify, VertriebId](vertriebId)) ~
delete(remove(vertriebId))
} ~
path("abotypen" / abotypIdPath / "vertriebe" / vertriebIdPath / "vertriebsarten") { (abotypId, vertriebId) =>
@@ -363,7 +364,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("zusatzAbotypen" / zusatzAbotypIdPath) { id =>
get(detail(stammdatenReadRepository.getZusatzAbotypDetail(id))) ~
- (put | post)(update[ZusatzAbotypModify, AbotypId](id)) ~
+ (put | post) (update[ZusatzAbotypModify, AbotypId](id)) ~
delete(remove(id))
}
@@ -385,7 +386,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("depots" / depotIdPath) { id =>
get(detail(stammdatenReadRepository.getDepotDetail(id))) ~
- (put | post)(update[DepotModify, DepotId](id)) ~
+ (put | post) (update[DepotModify, DepotId](id)) ~
delete(remove(id))
}
@@ -413,7 +414,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def zusatzaboRoute(implicit subject: Subject, filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter], queryString: Option[QueryFilter]): Route =
+ private def zusatzaboRoute(implicit subject: Subject, filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter], queryString: Option[QueryFilter])
+ : Route =
path("zusatzabos" ~ exportFormatPath.?) { exportFormat =>
parameter("x".as[AbosComplexFlags].?) { xFlags: Option[AbosComplexFlags] =>
get(list(stammdatenReadRepository.getZusatzAbos(xFlags), exportFormat))
@@ -432,7 +434,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
get(list(stammdatenReadRepository.getPendenzen, exportFormat))
} ~
path("pendenzen" / pendenzIdPath) { pendenzId =>
- (put | post)(update[PendenzModify, PendenzId](pendenzId))
+ (put | post) (update[PendenzModify, PendenzId](pendenzId))
}
private def produkteRoute(implicit subject: Subject): Route =
@@ -441,7 +443,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
post(create[ProduktModify, ProduktId](ProduktId.apply _))
} ~
path("produkte" / produktIdPath) { id =>
- (put | post)(update[ProduktModify, ProduktId](id)) ~
+ (put | post) (update[ProduktModify, ProduktId](id)) ~
delete(remove(id))
}
@@ -451,7 +453,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
post(create[ProduktekategorieModify, ProduktekategorieId](ProduktekategorieId.apply _))
} ~
path("produktekategorien" / produktekategorieIdPath) { id =>
- (put | post)(update[ProduktekategorieModify, ProduktekategorieId](id)) ~
+ (put | post) (update[ProduktekategorieModify, ProduktekategorieId](id)) ~
delete(remove(id))
}
@@ -462,7 +464,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("produzenten" / produzentIdPath) { id =>
get(detail(stammdatenReadRepository.getProduzentDetail(id))) ~
- (put | post)(update[ProduzentModify, ProduzentId](id)) ~
+ (put | post) (update[ProduzentModify, ProduzentId](id)) ~
delete(remove(id))
} ~
path("produzenten" / "berichte" / "produzentenbrief") {
@@ -486,7 +488,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
parameter("aktiveOrPlanned".as[Boolean].?) { aktiveOrPlanned: Option[Boolean] =>
get(detail(stammdatenReadRepository.getTourDetail(id, aktiveOrPlanned.getOrElse(false))))
} ~
- (put | post)(update[TourModify, TourId](id)) ~
+ (put | post) (update[TourModify, TourId](id)) ~
delete(remove(id))
}
@@ -497,24 +499,24 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("projekt" / projektIdPath) { id =>
get(detail(stammdatenReadRepository.getProjekt)) ~
- (put | post)(update[ProjektModify, ProjektId](id))
+ (put | post) (update[ProjektModify, ProjektId](id))
} ~
path("projekt" / projektIdPath / "logo") { id =>
get(download(ProjektStammdaten, "logo")) ~
- (put | post)(uploadStored(ProjektStammdaten, Some("logo")) { (id, metadata) =>
+ (put | post) (uploadStored(ProjektStammdaten, Some("logo")) { (id, metadata) =>
//TODO: update projekt stammdaten entity
complete("Logo uploaded")
})
} ~
path("projekt" / projektIdPath / "style-admin") { id =>
get(download(ProjektStammdaten, "style-admin")) ~
- (put | post)(uploadStored(ProjektStammdaten, Some("style-admin")) { (id, metadata) =>
+ (put | post) (uploadStored(ProjektStammdaten, Some("style-admin")) { (id, metadata) =>
complete("Style 'style-admin' uploaded")
})
} ~
path("projekt" / projektIdPath / "style-kundenportal") { id =>
get(download(ProjektStammdaten, "style-kundenportal")) ~
- (put | post)(uploadStored(ProjektStammdaten, Some("style-kundenportal")) { (id, metadata) =>
+ (put | post) (uploadStored(ProjektStammdaten, Some("style-kundenportal")) { (id, metadata) =>
complete("Style 'style-kundenportal' uploaded")
})
} ~
@@ -529,7 +531,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("lieferplanungen" / lieferplanungIdPath) { id =>
get(detail(stammdatenReadRepository.getLieferplanung(id))) ~
- (put | post)(update[LieferplanungModify, LieferplanungId](id)) ~
+ (put | post) (update[LieferplanungModify, LieferplanungId](id)) ~
delete(remove(id))
} ~
path("lieferplanungen" / lieferplanungIdPath / "lieferungen") { lieferplanungId =>
@@ -539,7 +541,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
get(list(stammdatenReadRepository.getVerfuegbareLieferungen(lieferplanungId)))
} ~
path("lieferplanungen" / lieferplanungIdPath / "lieferungen" / lieferungIdPath) { (lieferplanungId, lieferungId) =>
- (put | post)(create[LieferungPlanungAdd, LieferungId]((x: Long) => lieferungId)) ~
+ (put | post) (create[LieferungPlanungAdd, LieferungId]((x: Long) => lieferungId)) ~
delete(lieferplanungRemoveLieferung(lieferungId))
} ~
path("lieferplanungen" / lieferplanungIdPath / korbStatusPath / "aboIds") { (lieferplanungId, korbStatus) =>
@@ -548,14 +550,16 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
path("lieferplanungen" / lieferplanungIdPath / "auslieferungen") { (lieferplanungId) =>
get(list(stammdatenReadRepository.getAuslieferungen(lieferplanungId)))
} ~
- path("lieferplanungen" / lieferplanungIdPath / "lieferungen" / lieferungIdPath / korbStatusPath / "aboIds") { (lieferplanungId, lieferungId, korbStatus) =>
+ path("lieferplanungen" / lieferplanungIdPath / "lieferungen" / lieferungIdPath / korbStatusPath / "aboIds") { (lieferplanungId, lieferungId,
+ korbStatus) =>
get(list(stammdatenReadRepository.getAboIds(lieferungId, korbStatus)))
} ~
- path("lieferplanungen" / lieferplanungIdPath / "lieferungen" / lieferungIdPath / korbStatusPath / "hauptaboIds") { (lieferplanungId, lieferungId, korbStatus) =>
+ path("lieferplanungen" / lieferplanungIdPath / "lieferungen" / lieferungIdPath / korbStatusPath / "hauptaboIds") { (lieferplanungId, lieferungId,
+ korbStatus) =>
get(list(stammdatenReadRepository.getZusatzaboIds(lieferungId, korbStatus)))
} ~
path("lieferplanungen" / lieferplanungIdPath / "aktionen" / "abschliessen") { id =>
- (post)(lieferplanungAbschliessen(id))
+ (post) (lieferplanungAbschliessen(id))
} ~
path("lieferplanungen" / lieferplanungIdPath / "aktionen" / "modifizieren") { id =>
post {
@@ -567,16 +571,18 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
} ~
path("lieferplanungen" / lieferplanungIdPath / "aktionen" / "verrechnen") { id =>
- (post)(lieferplanungVerrechnen(id))
+ (post) (lieferplanungVerrechnen(id))
} ~
path("lieferplanungen" / lieferplanungIdPath / "sammelbestellungen") { lieferplanungId =>
get(list(stammdatenReadRepository.getSammelbestellungen(lieferplanungId)))
} ~
- path("lieferplanungen" / lieferplanungIdPath / "sammelbestellungen" / sammelbestellungIdPath / "bestellungen" / bestellungIdPath / "positionen") { (lieferplanungId, sammelbestellungId, bestellungId) =>
+ path("lieferplanungen" / lieferplanungIdPath / "sammelbestellungen" / sammelbestellungIdPath / "bestellungen" / bestellungIdPath / "positionen") {
+ (lieferplanungId, sammelbestellungId, bestellungId) =>
get(list(stammdatenReadRepository.getBestellpositionen(bestellungId)))
} ~
- path("lieferplanungen" / lieferplanungIdPath / "sammelbestellungen" / sammelbestellungIdPath / "aktionen" / "erneutBestellen") { (lieferplanungId, sammelbestellungId) =>
- (post)(sammelbestellungErneutVersenden(sammelbestellungId))
+ path("lieferplanungen" / lieferplanungIdPath / "sammelbestellungen" / sammelbestellungIdPath / "aktionen" / "erneutBestellen") { (lieferplanungId,
+ sammelbestellungId) =>
+ (post) (sammelbestellungErneutVersenden(sammelbestellungId))
} ~
path("lieferplanungen" / "berichte" / "lieferplanung") {
implicit val personId = subject.personId
@@ -589,7 +595,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
case UserCommandFailed =>
complete(StatusCodes.BadRequest, s"Could not transit Lieferplanung to status Abschliessen")
case _ =>
- // TODO OO-589
+ // TODO OO-589: SammelbestellungAnProduzentenVersendenCommand is not called on Abschliessen of Lieferplanung => Future task OO-589
if (false) {
stammdatenReadRepository.getSammelbestellungen(id) map {
_ map { sammelbestellung =>
@@ -618,7 +624,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def lieferplanungModifizieren(lieferplanungModify: LieferplanungPositionenModify)(implicit idPersister: Persister[LieferplanungId, _], subject: Subject): Route = {
+ private def lieferplanungModifizieren(lieferplanungModify: LieferplanungPositionenModify)(implicit idPersister: Persister[LieferplanungId, _],
+ subject: Subject): Route = {
implicit val timeout = Timeout(30.seconds)
onSuccess(entityStore ? StammdatenCommandHandler.LieferplanungModifyCommand(subject.personId, lieferplanungModify)) {
case UserCommandFailed =>
@@ -647,6 +654,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
complete("")
}
}
+
private def abwesenheitCreate(abw: AbwesenheitCreate)(implicit idPersister: Persister[AbwesenheitId, _], subject: Subject): Route = {
onSuccess(entityStore ? StammdatenCommandHandler.AbwesenheitCreateCommand(subject.personId, abw)) {
case UserCommandFailed =>
@@ -674,7 +682,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def lieferantenRoute(implicit subject: Subject, filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter], queryString: Option[QueryFilter]): Route =
+ private def lieferantenRoute(implicit subject: Subject, filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter],
+ queryString: Option[QueryFilter]): Route =
path("lieferanten" / "sammelbestellungen" ~ exportFormatPath.?) { exportFormat =>
get(list(stammdatenReadRepository.getSammelbestellungen, exportFormat))
} ~
@@ -695,7 +704,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
generateReport[SammelbestellungId](None, generateProduzentenabrechnungReports(VorlageProduzentenabrechnung) _)(SammelbestellungId.apply)
}
- private def sammelbestellungenAlsAbgerechnetMarkieren(datum: DateTime, ids: Seq[SammelbestellungId])(implicit idPersister: Persister[SammelbestellungId, _], subject: Subject): Route = {
+ private def sammelbestellungenAlsAbgerechnetMarkieren(datum: DateTime, ids: Seq[SammelbestellungId])(implicit idPersister: Persister[SammelbestellungId,
+ _], subject: Subject): Route = {
onSuccess(entityStore ? StammdatenCommandHandler.SammelbestellungenAlsAbgerechnetMarkierenCommand(subject.personId, datum, ids)) {
case UserCommandFailed =>
complete(StatusCodes.BadRequest, s"Die Bestellungen konnten nicht als abgerechnet markiert werden.")
@@ -704,7 +714,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def auslieferungenRoute(implicit subject: Subject, filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter], queryString: Option[QueryFilter]): Route =
+ private def auslieferungenRoute(implicit subject: Subject, filter: Option[FilterExpr], gjFilter: Option[GeschaeftsjahrFilter],
+ queryString: Option[QueryFilter]): Route =
path("depotauslieferungen" ~ exportFormatPath.?) { exportFormat =>
get(list(stammdatenReadRepository.getDepotAuslieferungen, exportFormat))
} ~
@@ -716,7 +727,7 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
} ~
path("tourauslieferungen" / auslieferungIdPath) { auslieferungId =>
get(detail(stammdatenReadRepository.getTourAuslieferungDetail(auslieferungId))) ~
- (put | post)(update[TourAuslieferungModify, AuslieferungId](auslieferungId))
+ (put | post) (update[TourAuslieferungModify, AuslieferungId](auslieferungId))
} ~
path("postauslieferungen" ~ exportFormatPath.?) { exportFormat =>
get(list(stammdatenReadRepository.getPostAuslieferungen, exportFormat))
@@ -824,7 +835,9 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def createAnzahlLieferungenRechnungsPositionen(rechnungCreate: AboRechnungsPositionBisAnzahlLieferungenCreate)(implicit idPersister: Persister[AboId, _], subject: Subject): Route = {
+ private def createAnzahlLieferungenRechnungsPositionen(rechnungCreate: AboRechnungsPositionBisAnzahlLieferungenCreate)(implicit
+ idPersister: Persister[AboId, _],
+ subject: Subject): Route = {
onSuccess(entityStore ? StammdatenCommandHandler.CreateAnzahlLieferungenRechnungsPositionenCommand(subject.personId, rechnungCreate)) {
case UserCommandFailed =>
complete(StatusCodes.BadRequest, s"Es konnten nicht alle Rechnungen für die gegebenen AboIds erstellt werden.")
@@ -833,7 +846,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def createBisGuthabenRechnungsPositionen(rechnungCreate: AboRechnungsPositionBisGuthabenCreate)(implicit idPersister: Persister[AboId, _], subject: Subject): Route = {
+ private def createBisGuthabenRechnungsPositionen(rechnungCreate: AboRechnungsPositionBisGuthabenCreate)(implicit idPersister: Persister[AboId, _],
+ subject: Subject): Route = {
onSuccess(entityStore ? StammdatenCommandHandler.CreateBisGuthabenRechnungsPositionenCommand(subject.personId, rechnungCreate)) {
case UserCommandFailed =>
complete(StatusCodes.BadRequest, s"Es konnten nicht alle Rechnungen für die gegebenen AboIds erstellt werden.")
@@ -910,13 +924,13 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
}) ~
- (put | post)(uploadStored(vorlageType, Some(defaultFileTypeId(vorlageType))) { (id, metadata) =>
+ (put | post) (uploadStored(vorlageType, Some(defaultFileTypeId(vorlageType))) { (id, metadata) =>
complete("Standardvorlage gespeichert")
})
} ~
//Projektvorlagen
path("vorlagen" / projektVorlageIdPath) { id =>
- (put | post)(update[ProjektVorlageModify, ProjektVorlageId](id)) ~
+ (put | post) (update[ProjektVorlageModify, ProjektVorlageId](id)) ~
//TODO: remove from filestore as well
delete(remove(id))
} ~
@@ -976,7 +990,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
post {
extractRequest { request =>
entity(as[ZusatzabotypMailRequest]) { zusatzabotypMailRequest =>
- sendEmailsToZuzatzabotypSubscribers(zusatzabotypMailRequest.subject, zusatzabotypMailRequest.body, zusatzabotypMailRequest.replyTo, zusatzabotypMailRequest.ids)
+ sendEmailsToZuzatzabotypSubscribers(zusatzabotypMailRequest.subject, zusatzabotypMailRequest.body, zusatzabotypMailRequest.replyTo,
+ zusatzabotypMailRequest.ids)
}
}
}
@@ -1036,7 +1051,8 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
}
- private def sendEmailsToZuzatzabotypSubscribers(emailSubject: String, body: String, replyTo: Option[String], ids: Seq[AbotypId])(implicit subject: Subject) = {
+ private def sendEmailsToZuzatzabotypSubscribers(emailSubject: String, body: String, replyTo: Option[String], ids: Seq[AbotypId])(implicit subject: Subject)
+ = {
onSuccess((entityStore ? StammdatenCommandHandler.SendEmailToZusatzabotypSubscribersCommand(subject.personId, emailSubject, body, replyTo, ids))) {
case UserCommandFailed =>
complete(StatusCodes.BadRequest, s"Something went wrong with the mail generation, please check the correctness of the template.")
@@ -1078,16 +1094,16 @@ trait StammdatenRoutes extends BaseRouteService with ActorReferences
}
class DefaultStammdatenRoutes(
- override val dbEvolutionActor: ActorRef,
- override val entityStore: ActorRef,
- override val eventStore: ActorRef,
- override val mailService: ActorRef,
- override val reportSystem: ActorRef,
- override val sysConfig: SystemConfig,
- override val system: ActorSystem,
- override val airbrakeNotifier: ActorRef,
- override val jobQueueService: ActorRef
-) extends StammdatenRoutes
+ override val dbEvolutionActor: ActorRef,
+ override val entityStore: ActorRef,
+ override val eventStore: ActorRef,
+ override val mailService: ActorRef,
+ override val reportSystem: ActorRef,
+ override val sysConfig: SystemConfig,
+ override val system: ActorSystem,
+ override val airbrakeNotifier: ActorRef,
+ override val jobQueueService: ActorRef
+ ) extends StammdatenRoutes
with DefaultStammdatenReadRepositoryAsyncComponent
with DefaultBuchhaltungReadRepositoryAsyncComponent
with DefaultFileStoreComponent {
diff --git a/src/main/scala/ch/openolitor/stammdaten/models/KontoDaten.scala b/src/main/scala/ch/openolitor/stammdaten/models/KontoDaten.scala
index 743258c26..6787ac1ff 100644
--- a/src/main/scala/ch/openolitor/stammdaten/models/KontoDaten.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/models/KontoDaten.scala
@@ -1,3 +1,26 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
+
package ch.openolitor.stammdaten.models
import ch.openolitor.core.models._
diff --git a/src/main/scala/ch/openolitor/stammdaten/repositories/ProjektReadRepositorySync.scala b/src/main/scala/ch/openolitor/stammdaten/repositories/ProjektReadRepositorySync.scala
new file mode 100644
index 000000000..cc52a54ee
--- /dev/null
+++ b/src/main/scala/ch/openolitor/stammdaten/repositories/ProjektReadRepositorySync.scala
@@ -0,0 +1,36 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
+package ch.openolitor.stammdaten.repositories
+
+import ch.openolitor.stammdaten.models.Projekt
+import scalikejdbc.DBSession
+
+trait ProjektReadRepositorySync {
+ def getProjekt(implicit session: DBSession): Option[Projekt]
+}
+
+trait ProjektReadRepositorySyncImpl extends ProjektReadRepositorySync with StammdatenProjektRepositoryQueries {
+ def getProjekt(implicit session: DBSession): Option[Projekt] = {
+ getProjektQuery.apply()
+ }
+}
diff --git a/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenProjektRepositoryQueries.scala b/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenProjektRepositoryQueries.scala
new file mode 100644
index 000000000..146dc80a2
--- /dev/null
+++ b/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenProjektRepositoryQueries.scala
@@ -0,0 +1,39 @@
+/* *\
+* ____ ____ ___ __ *
+* / __ \____ ___ ____ / __ \/ (_) /_____ _____ *
+* / / / / __ \/ _ \/ __ \/ / / / / / __/ __ \/ ___/ OpenOlitor *
+* / /_/ / /_/ / __/ / / / /_/ / / / /_/ /_/ / / contributed by tegonal *
+* \____/ .___/\___/_/ /_/\____/_/_/\__/\____/_/ http://openolitor.ch *
+* /_/ *
+* *
+* This program is free software: you can redistribute it and/or modify it *
+* under the terms of the GNU 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 General Public License for *
+* more details. *
+* *
+* You should have received a copy of the GNU General Public License along *
+* with this program. If not, see http://www.gnu.org/licenses/ *
+* *
+\* */
+
+package ch.openolitor.stammdaten.repositories
+
+import ch.openolitor.stammdaten.StammdatenDBMappings
+
+import scalikejdbc._
+
+trait StammdatenProjektRepositoryQueries extends StammdatenDBMappings {
+ lazy val projekt = projektMapping.syntax("projekt")
+
+ protected def getProjektQuery = {
+ withSQL {
+ select
+ .from(projektMapping as projekt)
+ }.map(projektMapping(projekt)).single
+ }
+}
diff --git a/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenReadRepositorySync.scala b/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenReadRepositorySync.scala
index b50337748..04bffb394 100644
--- a/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenReadRepositorySync.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenReadRepositorySync.scala
@@ -29,7 +29,7 @@ import org.joda.time.DateTime
import org.joda.time.LocalDate
import com.typesafe.scalalogging.LazyLogging
-trait StammdatenReadRepositorySync extends BaseReadRepositorySync {
+trait StammdatenReadRepositorySync extends BaseReadRepositorySync with ProjektReadRepositorySync {
def getAbotypDetail(id: AbotypId)(implicit session: DBSession): Option[Abotyp]
def getZusatzAbotypDetail(id: AbotypId)(implicit session: DBSession): Option[ZusatzAbotyp]
def getAboDetail(id: AboId)(implicit session: DBSession): Option[AboDetail]
@@ -45,8 +45,6 @@ trait StammdatenReadRepositorySync extends BaseReadRepositorySync {
def getHauptAbo(id: AboId)(implicit session: DBSession): Option[HauptAbo]
def getExistingZusatzAbotypen(lieferungId: LieferungId)(implicit session: DBSession): List[ZusatzAbotyp]
def getAbotypById(id: AbotypId)(implicit session: DBSession): Option[IAbotyp]
- def getProjekt(implicit session: DBSession): Option[Projekt]
-
@deprecated("Exists for compatibility purposes only", "OO 2.2 (Arbeitseinsatz)")
def getProjektV1(implicit session: DBSession): Option[ProjektV1]
def getKontoDatenProjekt(implicit session: DBSession): Option[KontoDaten]
@@ -144,7 +142,7 @@ trait StammdatenReadRepositorySync extends BaseReadRepositorySync {
def getAbo(id: AboId)(implicit session: DBSession): Option[Abo]
}
-trait StammdatenReadRepositorySyncImpl extends StammdatenReadRepositorySync with LazyLogging with StammdatenRepositoryQueries {
+trait StammdatenReadRepositorySyncImpl extends StammdatenReadRepositorySync with LazyLogging with StammdatenRepositoryQueries with ProjektReadRepositorySyncImpl {
def getAbotypById(id: AbotypId)(implicit session: DBSession): Option[IAbotyp] = {
getById(abotypMapping, id) orElse getById(zusatzAbotypMapping, id)
@@ -232,10 +230,6 @@ trait StammdatenReadRepositorySyncImpl extends StammdatenReadRepositorySync with
getExistingZusatzAbotypenQuery(lieferungId).apply()
}
- def getProjekt(implicit session: DBSession): Option[Projekt] = {
- getProjektQuery.apply()
- }
-
@deprecated("Exists for compatibility purposes only", "OO 2.2 (Arbeitseinsatz)")
def getProjektV1(implicit session: DBSession): Option[ProjektV1] = {
getProjektV1Query.apply()
diff --git a/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenRepositoryQueries.scala b/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenRepositoryQueries.scala
index eb246c641..840746097 100644
--- a/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenRepositoryQueries.scala
+++ b/src/main/scala/ch/openolitor/stammdaten/repositories/StammdatenRepositoryQueries.scala
@@ -38,7 +38,7 @@ import scalikejdbc.jodatime.JodaParameterBinderFactory
import scala.annotation.nowarn
-trait StammdatenRepositoryQueries extends LazyLogging with StammdatenDBMappings with ArbeitseinsatzDBMappings {
+trait StammdatenRepositoryQueries extends LazyLogging with StammdatenDBMappings with ArbeitseinsatzDBMappings with StammdatenProjektRepositoryQueries {
lazy val aboTyp = abotypMapping.syntax("atyp")
lazy val zusatzAboTyp = zusatzAbotypMapping.syntax("zatyp")
@@ -68,7 +68,6 @@ trait StammdatenRepositoryQueries extends LazyLogging with StammdatenDBMappings
lazy val produkt = produktMapping.syntax("produkt")
lazy val produktekategorie = produktekategorieMapping.syntax("produktekategorie")
lazy val produzent = produzentMapping.syntax("produzent")
- lazy val projekt = projektMapping.syntax("projekt")
@nowarn("cat=deprecation")
lazy val projektV1 = projektV1Mapping.syntax("projektV1")
lazy val kontoDaten = kontoDatenMapping.syntax("kontoDaten")
@@ -1295,13 +1294,6 @@ trait StammdatenRepositoryQueries extends LazyLogging with StammdatenDBMappings
}).list
}
- protected def getProjektQuery = {
- withSQL {
- select
- .from(projektMapping as projekt)
- }.map(projektMapping(projekt)).single
- }
-
@deprecated("Exists for compatibility purposes only", "OO 2.2 (Arbeitseinsatz)")
protected def getProjektV1Query = {
withSQL {
diff --git a/src/test/scala/ch/openolitor/mailtemplates/MailTemplateServiceSpec.scala b/src/test/scala/ch/openolitor/mailtemplates/MailTemplateServiceSpec.scala
index 7e71feb12..22970a955 100644
--- a/src/test/scala/ch/openolitor/mailtemplates/MailTemplateServiceSpec.scala
+++ b/src/test/scala/ch/openolitor/mailtemplates/MailTemplateServiceSpec.scala
@@ -185,6 +185,4 @@ class MailTemplateServiceMock extends MailTemplateService with Mockito with Mail
val mailTemplateReadRepositoryAsync: MailTemplateReadRepositoryAsync = mock[MailTemplateReadRepositoryAsync]
val mailTemplateReadRepositorySync: MailTemplateReadRepositorySync = mock[MailTemplateReadRepositorySync]
val sysConfig: SystemConfig = mock[SystemConfig]
-
- override lazy val config = ConfigFactory.parseString("""mailtemplates.max-file-store-resolve-timeout=1.day""")
}