diff --git a/build.sbt b/build.sbt index a213b80..f2313c1 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ ThisBuild / organization := "app.softnetwork" name := "payment" -ThisBuild / version := "0.7.4" +ThisBuild / version := "0.8.0" ThisBuild / scalaVersion := "2.12.18" diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 89daa0d..1d11e4c 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -27,6 +27,7 @@ payment{ card-route = "card" payment-method-route = "method" bank-route = "bank" + account-route = "account" declaration-route = "declaration" kyc-route = "kyc" diff --git a/common/src/main/scala/app/softnetwork/payment/config/Payment.scala b/common/src/main/scala/app/softnetwork/payment/config/Payment.scala index 77aabdc..e46f6cb 100644 --- a/common/src/main/scala/app/softnetwork/payment/config/Payment.scala +++ b/common/src/main/scala/app/softnetwork/payment/config/Payment.scala @@ -15,6 +15,7 @@ object Payment { cardRoute: String, paymentMethodRoute: String, bankRoute: String, + accountRoute: String, declarationRoute: String, kycRoute: String, disableBankAccountDeletion: Boolean, diff --git a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala index 79b9e31..47edaba 100644 --- a/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala +++ b/common/src/main/scala/app/softnetwork/payment/message/PaymentMessages.scala @@ -639,41 +639,33 @@ object PaymentMessages { lazy val key: String = transactionId } - /** Commands related to the bank account */ + /** Commands related to the payment account */ - case class BankAccountCommand( - bankAccount: BankAccount, + case class UserPaymentAccountCommand( user: Either[NaturalUser, LegalUser], acceptedTermsOfPSP: Option[Boolean] = None, - tokenId: Option[String] = None, - bankTokenId: Option[String] = None + tokenId: Option[String] = None ) - object BankAccountCommand { + object UserPaymentAccountCommand { def apply( - bankAccount: BankAccount, naturalUser: NaturalUser, acceptedTermsOfPSP: Option[Boolean], - tokenId: Option[String], - bankTokenId: Option[String] - ): BankAccountCommand = - BankAccountCommand(bankAccount, Left(naturalUser), acceptedTermsOfPSP, tokenId, bankTokenId) + tokenId: Option[String] + ): UserPaymentAccountCommand = + UserPaymentAccountCommand(Left(naturalUser), acceptedTermsOfPSP, tokenId) def apply( - bankAccount: BankAccount, legalUser: LegalUser, acceptedTermsOfPSP: Option[Boolean], - tokenId: Option[String], - bankTokenId: Option[String] - ): BankAccountCommand = - BankAccountCommand(bankAccount, Right(legalUser), acceptedTermsOfPSP, tokenId, bankTokenId) + tokenId: Option[String] + ): UserPaymentAccountCommand = + UserPaymentAccountCommand(Right(legalUser), acceptedTermsOfPSP, tokenId) } /** @param creditedAccount * - account to credit - * @param bankAccount - * - bank account * @param user * - payment user * @param acceptedTermsOfPSP @@ -686,18 +678,38 @@ object PaymentMessages { * - optional client id * @param tokenId * - optional account token id - * @param bankTokenId - * - optional bank token id */ - case class CreateOrUpdateBankAccount( + case class CreateOrUpdateUserPaymentAccount( creditedAccount: String, - bankAccount: BankAccount, user: Option[PaymentAccount.User] = None, acceptedTermsOfPSP: Option[Boolean] = None, ipAddress: Option[String] = None, userAgent: Option[String], clientId: Option[String] = None, - tokenId: Option[String] = None, + tokenId: Option[String] = None + ) extends PaymentCommandWithKey + with PaymentAccountCommand { + val key: String = creditedAccount + } + + case class BankAccountCommand( + bankAccount: BankAccount, + bankTokenId: Option[String] = None + ) + + /** @param creditedAccount + * - account to credit + * @param bankAccount + * - bank account + * @param clientId + * - optional client id + * @param bankTokenId + * - optional bank token id + */ + case class CreateOrUpdateBankAccount( + creditedAccount: String, + bankAccount: BankAccount, + clientId: Option[String] = None, bankTokenId: Option[String] = None ) extends PaymentCommandWithKey with PaymentAccountCommand { @@ -1029,14 +1041,18 @@ object PaymentMessages { case class PaymentAccountLoaded(paymentAccount: PaymentAccount) extends PaymentResult case class BankAccountCreatedOrUpdated( + bankAccountCreated: Boolean, + bankAccountUpdated: Boolean, + mandateCanceled: Boolean, + paymentAccount: PaymentAccountView + ) extends PaymentResult + + case class UserPaymentAccountCreatedOrUpdated( userCreated: Boolean, userTypeUpdated: Boolean, kycUpdated: Boolean, userUpdated: Boolean, - bankAccountCreated: Boolean, - bankAccountUpdated: Boolean, documentsUpdated: Boolean, - mandateCanceled: Boolean, uboDeclarationCreated: Boolean, paymentAccount: PaymentAccountView ) extends PaymentResult @@ -1177,6 +1193,9 @@ object PaymentMessages { case object BankAccountNotCreatedOrUpdated extends PaymentError("BankAccountNotCreatedOrUpdated") + case object UserPaymentAccountNotCreatedOrUpdated + extends PaymentError("UserPaymentAccountNotCreatedOrUpdated") + case object KycDocumentNotAdded extends PaymentError("KycDocumentNotAdded") case object KycDocumentStatusNotUpdated extends PaymentError("KycDocumentStatusNotUpdated") diff --git a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala index 495154c..3d6dfb9 100644 --- a/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala +++ b/core/src/main/scala/app/softnetwork/payment/persistence/typed/PaymentBehavior.scala @@ -976,83 +976,16 @@ trait PaymentBehavior } else if (cmd.bankAccount.wrongBic) { Effect.none.thenRun(_ => WrongBic ~> replyTo) } -// else if(cmd.bankAccount.wrongOwnerName) { -// Effect.none.thenRun(_ => WrongOwnerName ~> replyTo) -// } + // else if(cmd.bankAccount.wrongOwnerName) { + // Effect.none.thenRun(_ => WrongOwnerName ~> replyTo) + // } else if (cmd.bankAccount.wrongOwnerAddress) { Effect.none.thenRun(_ => WrongOwnerAddress ~> replyTo) } else { - (state match { - case None => - cmd.user match { - case Some(user) => - loadPaymentAccount(entityId, None, user, cmd.clientId) - case _ => None - } - case some => some - }) match { - case Some(paymentAccount) => + state match { + case Some(paymentAccount) + if paymentAccount.userId.isDefined && paymentAccount.walletId.isDefined => import cmd._ - - val updatedUser: PaymentAccount.User = - user match { - case None => paymentAccount.user - case Some(updatedUser) => - if (paymentAccount.user.isLegalUser && updatedUser.isLegalUser) { - val previousLegalUser = paymentAccount.getLegalUser - val updatedLegalUser = updatedUser.legalUser.get - PaymentAccount.User.LegalUser( - updatedLegalUser.copy( - legalRepresentative = updatedLegalUser.legalRepresentative - .copy( - userId = previousLegalUser.legalRepresentative.userId, - walletId = previousLegalUser.legalRepresentative.walletId - ) - .withNaturalUserType( - updatedLegalUser.legalRepresentative.naturalUserType - .getOrElse(NaturalUserType.COLLECTOR) - ), - uboDeclaration = previousLegalUser.uboDeclaration, - lastAcceptedTermsOfPSP = previousLegalUser.lastAcceptedTermsOfPSP - ) - ) - } else if (updatedUser.isLegalUser) { - val updatedLegalUser = updatedUser.legalUser.get - PaymentAccount.User.LegalUser( - updatedLegalUser.copy( - legalRepresentative = - updatedLegalUser.legalRepresentative.withNaturalUserType( - updatedLegalUser.legalRepresentative.naturalUserType.getOrElse( - NaturalUserType.COLLECTOR - ) - ) - ) - ) - } else if (paymentAccount.user.isNaturalUser && updatedUser.isNaturalUser) { - val previousNaturalUser = paymentAccount.getNaturalUser - val updatedNaturalUser = updatedUser.naturalUser.get - PaymentAccount.User.NaturalUser( - updatedNaturalUser - .copy( - userId = previousNaturalUser.userId, - walletId = previousNaturalUser.walletId - ) - .withNaturalUserType( - updatedNaturalUser.naturalUserType.getOrElse(NaturalUserType.COLLECTOR) - ) - ) - } else if (updatedUser.isNaturalUser) { - val updatedNaturalUser = updatedUser.naturalUser.get - PaymentAccount.User.NaturalUser( - updatedNaturalUser.withNaturalUserType( - updatedNaturalUser.naturalUserType.getOrElse(NaturalUserType.COLLECTOR) - ) - ) - } else { - updatedUser - } - } - val lastUpdated = now() val shouldUpdateIban = @@ -1065,11 +998,16 @@ trait PaymentBehavior _.checkIfSameBic(bankAccount.bic) ) - val bic = bankAccount.bic + val bic = + if (!shouldUpdateBic) + paymentAccount.bankAccount.map(_.bic).getOrElse(bankAccount.bic) + else bankAccount.bic + + val shouldCreateBankAccount = paymentAccount.bankAccount.isEmpty || + paymentAccount.bankAccount.flatMap(_.id).isEmpty var updatedPaymentAccount = paymentAccount - .withUser(updatedUser) .withBankAccount( bankAccount .copy( @@ -1081,102 +1019,299 @@ trait PaymentBehavior ) .withLastUpdated(lastUpdated) - updatedPaymentAccount.user.legalUser match { - case Some(legalUser) if legalUser.wrongSiret => - Effect.none.thenRun(_ => WrongSiret ~> replyTo) - case Some(legalUser) if legalUser.legalName.trim.isEmpty => - Effect.none.thenRun(_ => LegalNameRequired ~> replyTo) - case Some(legalUser) if legalUser.wrongLegalRepresentativeAddress => - Effect.none.thenRun(_ => WrongLegalRepresentativeAddress ~> replyTo) - case Some(legalUser) if legalUser.wrongHeadQuartersAddress => - Effect.none.thenRun(_ => WrongHeadQuartersAddress ~> replyTo) - case Some(legalUser) - if legalUser.lastAcceptedTermsOfPSP.isEmpty && !acceptedTermsOfPSP.getOrElse( - false - ) => - Effect.none.thenRun(_ => AcceptedTermsOfPSPRequired ~> replyTo) - case None if paymentAccount.emptyUser => - Effect.none.thenRun(_ => UserRequired ~> replyTo) - case _ => - val shouldCreateUser = paymentAccount.userId.isEmpty - - val shouldUpdateUserType = !shouldCreateUser && { - if (paymentAccount.legalUser) { // previous user is a legal user - !updatedPaymentAccount.legalUser || // update to natural user - !paymentAccount.checkIfSameLegalUserType( - updatedPaymentAccount.legalUserType - ) // update legal user type - } else { // previous user is a natural user - updatedPaymentAccount.legalUser // update to legal user - } + val shouldUpdateBankAccount = !shouldCreateBankAccount && ( + paymentAccount.bankAccount + .map(_.ownerName) + .getOrElse("") != bankAccount.ownerName || + !paymentAccount.getBankAccount.ownerAddress.equals(bankAccount.ownerAddress) || + shouldUpdateIban || + shouldUpdateBic /*|| + shouldUpdateUser*/ + ) + + val shouldCreateOrUpdateBankAccount = + shouldCreateBankAccount || shouldUpdateBankAccount + + val shouldCancelMandate = shouldUpdateBankAccount && + paymentAccount.bankAccount.flatMap(_.mandateId).isDefined + + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) + import paymentProvider._ + + (paymentAccount.bankAccount.flatMap(_.id) match { + case None => + createOrUpdateBankAccount( + updatedPaymentAccount.resetBankAccountId().bankAccount, + bankTokenId + ) + case Some(_) if shouldCreateOrUpdateBankAccount => + createOrUpdateBankAccount( + updatedPaymentAccount.resetBankAccountId().bankAccount, + bankTokenId + ) + case some => some + }) match { + case Some(bankAccountId) => + keyValueDao.addKeyValue(bankAccountId, entityId) + updatedPaymentAccount = + updatedPaymentAccount.resetBankAccountId(Some(bankAccountId)) + var events: List[ExternalSchedulerEvent] = List.empty + + if (shouldCreateBankAccount) { + updatedPaymentAccount = updatedPaymentAccount + .withBankAccount( + updatedPaymentAccount.getBankAccount + .withCreatedDate(lastUpdated) + .withLastUpdated(lastUpdated) + ) + } else if (shouldUpdateBankAccount) { + updatedPaymentAccount = updatedPaymentAccount + .withBankAccount( + updatedPaymentAccount.getBankAccount + .withLastUpdated(lastUpdated) + ) + } + + // BankAccountUpdatedEvent + events = events ++ + List( + BankAccountUpdatedEvent.defaultInstance + .withExternalUuid(updatedPaymentAccount.externalUuid) + .withLastUpdated(lastUpdated) + .withUserId(paymentAccount.userId.get) + .withWalletId(paymentAccount.walletId.get) + .withBankAccountId(bankAccountId) + ) + + if (shouldCancelMandate) { + updatedPaymentAccount = updatedPaymentAccount.copy( + bankAccount = updatedPaymentAccount.bankAccount.map( + _.copy( + mandateId = None, + mandateStatus = None + ) + ) + ) + + // MandateUpdatedEvent + events = events ++ + List( + MandateUpdatedEvent.defaultInstance + .withExternalUuid(updatedPaymentAccount.externalUuid) + .withLastUpdated(lastUpdated) + .withBankAccountId(bankAccountId) + .copy( + mandateId = None, + mandateStatus = None + ) + ) } - val shouldUpdateKYC = - shouldUpdateUserType || - paymentAccount.maybeUser.map(_.firstName).getOrElse("") != - updatedPaymentAccount.maybeUser.map(_.firstName).getOrElse("") || - paymentAccount.maybeUser.map(_.lastName).getOrElse("") != - updatedPaymentAccount.maybeUser.map(_.lastName).getOrElse("") || - paymentAccount.maybeUser.map(_.birthday).getOrElse("") != - updatedPaymentAccount.maybeUser.map(_.birthday).getOrElse("") - - val shouldUpdateUser = shouldUpdateKYC || - (updatedPaymentAccount.legalUser && - (updatedPaymentAccount.getLegalUser.legalName != paymentAccount.getLegalUser.legalName || - updatedPaymentAccount.getLegalUser.siret != paymentAccount.getLegalUser.siret || - !updatedPaymentAccount.getLegalUser.legalRepresentativeAddress.equals( - paymentAccount.getLegalUser.legalRepresentativeAddress - ) || - !updatedPaymentAccount.getLegalUser.headQuartersAddress.equals( - paymentAccount.getLegalUser.headQuartersAddress - ) || - updatedPaymentAccount.getLegalUser.legalRepresentative.email - != paymentAccount.getLegalUser.legalRepresentative.email || - updatedPaymentAccount.getLegalUser.legalRepresentative.nationality - != paymentAccount.getLegalUser.legalRepresentative.nationality || - updatedPaymentAccount.getLegalUser.legalRepresentative.countryOfResidence - != paymentAccount.getLegalUser.legalRepresentative.countryOfResidence)) || - (!updatedPaymentAccount.legalUser && (updatedPaymentAccount.getNaturalUser.email != paymentAccount.getNaturalUser.email || - updatedPaymentAccount.getNaturalUser.nationality != paymentAccount.getNaturalUser.nationality || - updatedPaymentAccount.getNaturalUser.countryOfResidence - != paymentAccount.getNaturalUser.countryOfResidence)) - - //val shouldCreateOrUpdateUser = shouldCreateUser || shouldUpdateUser - - val shouldCreateBankAccount = paymentAccount.bankAccount.isEmpty || - paymentAccount.bankAccount.flatMap(_.id).isEmpty - - val shouldUpdateBankAccount = !shouldCreateBankAccount && ( - paymentAccount.bankAccount - .map(_.ownerName) - .getOrElse("") != bankAccount.ownerName || - !paymentAccount.getBankAccount.ownerAddress.equals(bankAccount.ownerAddress) || - shouldUpdateIban || - shouldUpdateBic /*|| - shouldUpdateUser*/ + val encodedPaymentAccount = + updatedPaymentAccount.copy( + bankAccount = updatedPaymentAccount.bankAccount.map( + _.encode(shouldUpdateBic, shouldUpdateIban) + ) + ) + + Effect.persist( + events :+ + PaymentAccountUpsertedEvent.defaultInstance + .withDocument(encodedPaymentAccount) + .withLastUpdated(lastUpdated) + ) thenRun (_ => + BankAccountCreatedOrUpdated( + shouldCreateBankAccount, + shouldUpdateBankAccount, + shouldCancelMandate, + encodedPaymentAccount.view + ) ~> replyTo ) - val shouldCreateOrUpdateBankAccount = - shouldCreateBankAccount || shouldUpdateBankAccount + case _ => + Effect.none.thenRun(_ => BankAccountNotCreatedOrUpdated ~> replyTo) + } + + case _ => Effect.none.thenRun(_ => PaymentAccountNotFound ~> replyTo) + } + } - val documents: List[KycDocument] = initDocuments(updatedPaymentAccount) + case cmd: CreateOrUpdateUserPaymentAccount => + (state match { + case None => + cmd.user match { + case Some(user) => + loadPaymentAccount(entityId, None, user, cmd.clientId) + case _ => None + } + case some => some + }) match { + case Some(paymentAccount) => + import cmd._ - val shouldUpdateDocuments = shouldUpdateKYC + val updatedUser: PaymentAccount.User = + user match { + case None => paymentAccount.user + case Some(updatedUser) => + if (paymentAccount.user.isLegalUser && updatedUser.isLegalUser) { + val previousLegalUser = paymentAccount.getLegalUser + val updatedLegalUser = updatedUser.legalUser.get + PaymentAccount.User.LegalUser( + updatedLegalUser.copy( + legalRepresentative = updatedLegalUser.legalRepresentative + .copy( + userId = previousLegalUser.legalRepresentative.userId, + walletId = previousLegalUser.legalRepresentative.walletId + ) + .withNaturalUserType( + updatedLegalUser.legalRepresentative.naturalUserType + .getOrElse(NaturalUserType.COLLECTOR) + ), + uboDeclaration = previousLegalUser.uboDeclaration, + lastAcceptedTermsOfPSP = previousLegalUser.lastAcceptedTermsOfPSP + ) + ) + } else if (updatedUser.isLegalUser) { + val updatedLegalUser = updatedUser.legalUser.get + PaymentAccount.User.LegalUser( + updatedLegalUser.copy( + legalRepresentative = + updatedLegalUser.legalRepresentative.withNaturalUserType( + updatedLegalUser.legalRepresentative.naturalUserType.getOrElse( + NaturalUserType.COLLECTOR + ) + ) + ) + ) + } else if (paymentAccount.user.isNaturalUser && updatedUser.isNaturalUser) { + val previousNaturalUser = paymentAccount.getNaturalUser + val updatedNaturalUser = updatedUser.naturalUser.get + PaymentAccount.User.NaturalUser( + updatedNaturalUser + .copy( + userId = previousNaturalUser.userId, + walletId = previousNaturalUser.walletId + ) + .withNaturalUserType( + updatedNaturalUser.naturalUserType.getOrElse(NaturalUserType.COLLECTOR) + ) + ) + } else if (updatedUser.isNaturalUser) { + val updatedNaturalUser = updatedUser.naturalUser.get + PaymentAccount.User.NaturalUser( + updatedNaturalUser.withNaturalUserType( + updatedNaturalUser.naturalUserType.getOrElse(NaturalUserType.COLLECTOR) + ) + ) + } else { + updatedUser + } + } - val shouldCancelMandate = shouldUpdateBankAccount && - paymentAccount.bankAccount.flatMap(_.mandateId).isDefined + val lastUpdated = now() - val shouldCreateUboDeclaration = updatedPaymentAccount.legalUser && - updatedPaymentAccount.getLegalUser.uboDeclarationRequired && - updatedPaymentAccount.getLegalUser.uboDeclaration.isEmpty + var updatedPaymentAccount = + paymentAccount + .withUser(updatedUser) + .withLastUpdated(lastUpdated) - val clientId = paymentAccount.clientId.orElse( - internalClientId - ) - val paymentProvider = loadPaymentProvider(clientId) - import paymentProvider._ - (paymentAccount.userId match { - case None => + updatedPaymentAccount.user.legalUser match { + case Some(legalUser) if legalUser.wrongSiret => + Effect.none.thenRun(_ => WrongSiret ~> replyTo) + case Some(legalUser) if legalUser.legalName.trim.isEmpty => + Effect.none.thenRun(_ => LegalNameRequired ~> replyTo) + case Some(legalUser) if legalUser.wrongLegalRepresentativeAddress => + Effect.none.thenRun(_ => WrongLegalRepresentativeAddress ~> replyTo) + case Some(legalUser) if legalUser.wrongHeadQuartersAddress => + Effect.none.thenRun(_ => WrongHeadQuartersAddress ~> replyTo) + case Some(legalUser) + if legalUser.lastAcceptedTermsOfPSP.isEmpty && !acceptedTermsOfPSP.getOrElse( + false + ) => + Effect.none.thenRun(_ => AcceptedTermsOfPSPRequired ~> replyTo) + case None if paymentAccount.emptyUser => + Effect.none.thenRun(_ => UserRequired ~> replyTo) + case _ => + val shouldCreateUser = paymentAccount.userId.isEmpty + + val shouldUpdateUserType = !shouldCreateUser && { + if (paymentAccount.legalUser) { // previous user is a legal user + !updatedPaymentAccount.legalUser || // update to natural user + !paymentAccount.checkIfSameLegalUserType( + updatedPaymentAccount.legalUserType + ) // update legal user type + } else { // previous user is a natural user + updatedPaymentAccount.legalUser // update to legal user + } + } + + val shouldUpdateKYC = + shouldUpdateUserType || + paymentAccount.maybeUser.map(_.firstName).getOrElse("") != + updatedPaymentAccount.maybeUser.map(_.firstName).getOrElse("") || + paymentAccount.maybeUser.map(_.lastName).getOrElse("") != + updatedPaymentAccount.maybeUser.map(_.lastName).getOrElse("") || + paymentAccount.maybeUser.map(_.birthday).getOrElse("") != + updatedPaymentAccount.maybeUser.map(_.birthday).getOrElse("") + + val shouldUpdateUser = shouldUpdateKYC || + (updatedPaymentAccount.legalUser && + (updatedPaymentAccount.getLegalUser.legalName != paymentAccount.getLegalUser.legalName || + updatedPaymentAccount.getLegalUser.siret != paymentAccount.getLegalUser.siret || + !updatedPaymentAccount.getLegalUser.legalRepresentativeAddress.equals( + paymentAccount.getLegalUser.legalRepresentativeAddress + ) || + !updatedPaymentAccount.getLegalUser.headQuartersAddress.equals( + paymentAccount.getLegalUser.headQuartersAddress + ) || + updatedPaymentAccount.getLegalUser.legalRepresentative.email + != paymentAccount.getLegalUser.legalRepresentative.email || + updatedPaymentAccount.getLegalUser.legalRepresentative.nationality + != paymentAccount.getLegalUser.legalRepresentative.nationality || + updatedPaymentAccount.getLegalUser.legalRepresentative.countryOfResidence + != paymentAccount.getLegalUser.legalRepresentative.countryOfResidence)) || + (!updatedPaymentAccount.legalUser && (updatedPaymentAccount.getNaturalUser.email != paymentAccount.getNaturalUser.email || + updatedPaymentAccount.getNaturalUser.nationality != paymentAccount.getNaturalUser.nationality || + updatedPaymentAccount.getNaturalUser.countryOfResidence + != paymentAccount.getNaturalUser.countryOfResidence)) + + //val shouldCreateOrUpdateUser = shouldCreateUser || shouldUpdateUser + + val documents: List[KycDocument] = initDocuments(updatedPaymentAccount) + + val shouldUpdateDocuments = shouldUpdateKYC + + val shouldCreateUboDeclaration = updatedPaymentAccount.legalUser && + updatedPaymentAccount.getLegalUser.uboDeclarationRequired && + updatedPaymentAccount.getLegalUser.uboDeclaration.isEmpty + + val clientId = paymentAccount.clientId.orElse( + internalClientId + ) + val paymentProvider = loadPaymentProvider(clientId) + import paymentProvider._ + (paymentAccount.userId match { + case None => + createOrUpdatePaymentAccount( + Some(updatedPaymentAccount), + acceptedTermsOfPSP.getOrElse(false), + ipAddress, + userAgent, + tokenId + ) + case Some(_) if shouldUpdateUser => + if (shouldUpdateUserType) { + createOrUpdatePaymentAccount( + Some(updatedPaymentAccount.resetUserId(None)), + acceptedTermsOfPSP.getOrElse(false), + ipAddress, + userAgent, + tokenId + ) + } else { createOrUpdatePaymentAccount( Some(updatedPaymentAccount), acceptedTermsOfPSP.getOrElse(false), @@ -1184,242 +1319,143 @@ trait PaymentBehavior userAgent, tokenId ) - case Some(_) if shouldUpdateUser => - if (shouldUpdateUserType) { - createOrUpdatePaymentAccount( - Some(updatedPaymentAccount.resetUserId(None)), - acceptedTermsOfPSP.getOrElse(false), - ipAddress, - userAgent, - tokenId + } + case some => some + }) match { + case Some(userId) => + keyValueDao.addKeyValue(userId, entityId) + updatedPaymentAccount = updatedPaymentAccount.resetUserId(Some(userId)) + (paymentAccount.walletId match { + case None => + createOrUpdateWallet( + Some(userId), + "EUR", + updatedPaymentAccount.externalUuid, + None ) - } else { - createOrUpdatePaymentAccount( - Some(updatedPaymentAccount), - acceptedTermsOfPSP.getOrElse(false), - ipAddress, - userAgent, - tokenId + case Some(_) if shouldUpdateUserType => + createOrUpdateWallet( + Some(userId), + "EUR", + updatedPaymentAccount.externalUuid, + None ) - } - case some => some - }) match { - case Some(userId) => - keyValueDao.addKeyValue(userId, entityId) - updatedPaymentAccount = updatedPaymentAccount.resetUserId(Some(userId)) - (paymentAccount.walletId match { - case None => - createOrUpdateWallet( - Some(userId), - "EUR", - updatedPaymentAccount.externalUuid, - None + case some => some + }) match { + case Some(walletId) => + keyValueDao.addKeyValue(walletId, entityId) + updatedPaymentAccount = updatedPaymentAccount.resetWalletId(Some(walletId)) + + var events: List[ExternalSchedulerEvent] = List.empty + + if ( + updatedPaymentAccount.legalUser && acceptedTermsOfPSP.getOrElse( + false ) - case Some(_) if shouldUpdateUserType => - createOrUpdateWallet( - Some(userId), - "EUR", - updatedPaymentAccount.externalUuid, - None + ) { + updatedPaymentAccount = updatedPaymentAccount.withLegalUser( + updatedPaymentAccount.getLegalUser.withLastAcceptedTermsOfPSP( + lastUpdated + ) ) - case some => some - }) match { - case Some(walletId) => - keyValueDao.addKeyValue(walletId, entityId) - updatedPaymentAccount = - updatedPaymentAccount.resetWalletId(Some(walletId)) - (paymentAccount.bankAccount.flatMap(_.id) match { - case None => - createOrUpdateBankAccount( - updatedPaymentAccount.resetBankAccountId().bankAccount, - bankTokenId - ) - case Some(_) if shouldCreateOrUpdateBankAccount => - createOrUpdateBankAccount( - updatedPaymentAccount.resetBankAccountId().bankAccount, - bankTokenId - ) - case some => some - }) match { - case Some(bankAccountId) => - keyValueDao.addKeyValue(bankAccountId, entityId) - updatedPaymentAccount = - updatedPaymentAccount.resetBankAccountId(Some(bankAccountId)) - - var events: List[ExternalSchedulerEvent] = List.empty - - if (shouldCreateBankAccount) { - updatedPaymentAccount = updatedPaymentAccount - .withBankAccount( - updatedPaymentAccount.getBankAccount - .withCreatedDate(lastUpdated) - .withLastUpdated(lastUpdated) - ) - } else if (shouldUpdateBankAccount) { - updatedPaymentAccount = updatedPaymentAccount - .withBankAccount( - updatedPaymentAccount.getBankAccount - .withLastUpdated(lastUpdated) - ) - } + // TermsOfPSPAcceptedEvent + events = events ++ + List( + TermsOfPSPAcceptedEvent.defaultInstance + .withExternalUuid(updatedPaymentAccount.externalUuid) + .withLastUpdated(lastUpdated) + .withLastAcceptedTermsOfPSP(lastUpdated) + ) + } - // BankAccountUpdatedEvent + if (shouldCreateUboDeclaration) { + createDeclaration(userId) match { + case Some(uboDeclaration) => + keyValueDao.addKeyValue(uboDeclaration.id, entityId) + updatedPaymentAccount = updatedPaymentAccount.withLegalUser( + updatedPaymentAccount.getLegalUser.withUboDeclaration( + uboDeclaration + ) + ) + // UboDeclarationUpdatedEvent events = events ++ List( - BankAccountUpdatedEvent.defaultInstance + UboDeclarationUpdatedEvent.defaultInstance .withExternalUuid(updatedPaymentAccount.externalUuid) .withLastUpdated(lastUpdated) - .withUserId(userId) - .withWalletId(walletId) - .withBankAccountId(bankAccountId) - ) - - if ( - updatedPaymentAccount.legalUser && acceptedTermsOfPSP.getOrElse( - false - ) - ) { - updatedPaymentAccount = updatedPaymentAccount.withLegalUser( - updatedPaymentAccount.getLegalUser.withLastAcceptedTermsOfPSP( - lastUpdated - ) + .withUboDeclaration(uboDeclaration) ) - // TermsOfPSPAcceptedEvent - events = events ++ - List( - TermsOfPSPAcceptedEvent.defaultInstance - .withExternalUuid(updatedPaymentAccount.externalUuid) - .withLastUpdated(lastUpdated) - .withLastAcceptedTermsOfPSP(lastUpdated) - ) - } - - if (shouldCreateUboDeclaration) { - createDeclaration(userId) match { - case Some(uboDeclaration) => - keyValueDao.addKeyValue(uboDeclaration.id, entityId) - updatedPaymentAccount = updatedPaymentAccount.withLegalUser( - updatedPaymentAccount.getLegalUser.withUboDeclaration( - uboDeclaration - ) - ) - // UboDeclarationUpdatedEvent - events = events ++ - List( - UboDeclarationUpdatedEvent.defaultInstance - .withExternalUuid(updatedPaymentAccount.externalUuid) - .withLastUpdated(lastUpdated) - .withUboDeclaration(uboDeclaration) - ) - case _ => - log.warn(s"Could not create ubo declaration for user $userId") - } - } - - if (shouldUpdateDocuments) { // TODO we should rely on the payment provider to update document status - updatedPaymentAccount = updatedPaymentAccount - /*.withDocuments( - documents.map( - _.copy( - lastUpdated = Some(lastUpdated), - status = KycDocument.KycDocumentStatus.KYC_DOCUMENT_NOT_SPECIFIED, - refusedReasonType = None, - refusedReasonMessage = None - ) - ) - )*/ - .withDocuments(documents) - .withPaymentAccountStatus( - PaymentAccount.PaymentAccountStatus.DOCUMENTS_KO - ) + case _ => + log.warn(s"Could not create ubo declaration for user $userId") + } + } - // PaymentAccountStatusUpdatedEvent - events = events ++ - List( - PaymentAccountStatusUpdatedEvent.defaultInstance - .withExternalUuid(updatedPaymentAccount.externalUuid) - .withLastUpdated(lastUpdated) - .withPaymentAccountStatus( - updatedPaymentAccount.paymentAccountStatus + if (shouldUpdateDocuments) { // TODO we should rely on the payment provider to update document status + updatedPaymentAccount = updatedPaymentAccount + /*.withDocuments( + documents.map( + _.copy( + lastUpdated = Some(lastUpdated), + status = KycDocument.KycDocumentStatus.KYC_DOCUMENT_NOT_SPECIFIED, + refusedReasonType = None, + refusedReasonMessage = None ) - ) - } else { - updatedPaymentAccount = - updatedPaymentAccount.withDocuments(documents) - } - - if (shouldCancelMandate) { - updatedPaymentAccount = updatedPaymentAccount.copy( - bankAccount = updatedPaymentAccount.bankAccount.map( - _.copy( - mandateId = None, - mandateStatus = None ) - ) - ) - - // MandateUpdatedEvent - events = events ++ - List( - MandateUpdatedEvent.defaultInstance - .withExternalUuid(updatedPaymentAccount.externalUuid) - .withLastUpdated(lastUpdated) - .withBankAccountId(bankAccountId) - .copy( - mandateId = None, - mandateStatus = None - ) - ) - } + )*/ + .withDocuments(documents) + .withPaymentAccountStatus( + PaymentAccount.PaymentAccountStatus.DOCUMENTS_KO + ) - // DocumentsUpdatedEvent - events = events ++ - List( - DocumentsUpdatedEvent.defaultInstance - .withExternalUuid(updatedPaymentAccount.externalUuid) - .withLastUpdated(lastUpdated) - .withDocuments(updatedPaymentAccount.documents) + // PaymentAccountStatusUpdatedEvent + events = events ++ + List( + PaymentAccountStatusUpdatedEvent.defaultInstance + .withExternalUuid(updatedPaymentAccount.externalUuid) + .withLastUpdated(lastUpdated) + .withPaymentAccountStatus( + updatedPaymentAccount.paymentAccountStatus ) + ) + } else { + updatedPaymentAccount = updatedPaymentAccount.withDocuments(documents) + } - val encodedPaymentAccount = - updatedPaymentAccount.copy( - bankAccount = updatedPaymentAccount.bankAccount.map( - _.encode(shouldUpdateBic, shouldUpdateIban) - ) - ) + // DocumentsUpdatedEvent + events = events ++ + List( + DocumentsUpdatedEvent.defaultInstance + .withExternalUuid(updatedPaymentAccount.externalUuid) + .withLastUpdated(lastUpdated) + .withDocuments(updatedPaymentAccount.documents) + ) - Effect.persist( - events :+ - PaymentAccountUpsertedEvent.defaultInstance - .withDocument(encodedPaymentAccount) - .withLastUpdated(lastUpdated) - ) thenRun (_ => - BankAccountCreatedOrUpdated( - shouldCreateUser, - shouldUpdateUserType, - shouldUpdateKYC, - shouldUpdateUser, - shouldCreateBankAccount, - shouldUpdateBankAccount, - shouldUpdateDocuments, - shouldCancelMandate, - shouldCreateUboDeclaration, - encodedPaymentAccount.view - ) ~> replyTo - ) + Effect.persist( + events :+ + PaymentAccountUpsertedEvent.defaultInstance + .withDocument(updatedPaymentAccount) + .withLastUpdated(lastUpdated) + ) thenRun (_ => + UserPaymentAccountCreatedOrUpdated( + shouldCreateUser, + shouldUpdateUserType, + shouldUpdateKYC, + shouldUpdateUser, + shouldUpdateDocuments, + shouldCreateUboDeclaration, + updatedPaymentAccount.view + ) ~> replyTo + ) - case _ => - Effect.none.thenRun(_ => BankAccountNotCreatedOrUpdated ~> replyTo) - } - case _ => - Effect.none.thenRun(_ => BankAccountNotCreatedOrUpdated ~> replyTo) - } - case _ => Effect.none.thenRun(_ => BankAccountNotCreatedOrUpdated ~> replyTo) - } - } + case _ => + Effect.none.thenRun(_ => UserPaymentAccountNotCreatedOrUpdated ~> replyTo) + } + case _ => + Effect.none.thenRun(_ => UserPaymentAccountNotCreatedOrUpdated ~> replyTo) + } + } - case _ => Effect.none.thenRun(_ => PaymentAccountNotFound ~> replyTo) - } + case _ => Effect.none.thenRun(_ => PaymentAccountNotFound ~> replyTo) } case cmd: CreateOrUpdateKycDocument => diff --git a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala index 0ea1cc1..46618c5 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/BankAccountEndpoints.scala @@ -21,63 +21,26 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { val createOrUpdateBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = requiredSessionEndpoint.post .in(PaymentSettings.PaymentConfig.bankRoute) - .in(clientIp) - .in(header[Option[String]](HeaderNames.UserAgent)) - .in(jsonBody[BankAccountCommand].description("Legal or natural user bank account")) + .in(jsonBody[BankAccountCommand].description("Bank account to create or update")) .out( statusCode(StatusCode.Ok) .and(jsonBody[BankAccountCreatedOrUpdated].description("Bank account created or updated")) ) .serverLogic { - case (client, session) => { case (ipAddress, userAgent, bank) => - import bank._ - var externalUuid: String = "" - val updatedUser: Option[PaymentAccount.User] = { - user match { - case Left(naturalUser) => - var updatedNaturalUser = { - if (naturalUser.externalUuid.trim.isEmpty) { - naturalUser.withExternalUuid(session.id) - } else { - naturalUser - } - } - session.profile match { - case Some(profile) if updatedNaturalUser.profile.isEmpty => - updatedNaturalUser = updatedNaturalUser.withProfile(profile) - case _ => - } - externalUuid = updatedNaturalUser.externalUuid - Some(PaymentAccount.User.NaturalUser(updatedNaturalUser)) - case Right(legalUser) => - var updatedLegalRepresentative = legalUser.legalRepresentative - if (updatedLegalRepresentative.externalUuid.trim.isEmpty) { - updatedLegalRepresentative = - updatedLegalRepresentative.withExternalUuid(session.id) - } - session.profile match { - case Some(profile) if updatedLegalRepresentative.profile.isEmpty => - updatedLegalRepresentative = updatedLegalRepresentative.withProfile(profile) - case _ => - } - externalUuid = updatedLegalRepresentative.externalUuid - Some( - PaymentAccount.User.LegalUser( - legalUser.withLegalRepresentative(updatedLegalRepresentative) - ) - ) + case (client, session) => { bankAccountCommand => + import bankAccountCommand._ + val updatedBankAccount = + if (bankAccount.externalUuid.trim().isEmpty) { + bankAccount.withExternalUuid(session.id) + } else { + bankAccount } - } run( CreateOrUpdateBankAccount( externalUuidWithProfile(session), - bankAccount.withExternalUuid(externalUuid), - updatedUser, - acceptedTermsOfPSP, + updatedBankAccount, clientId = client.map(_.clientId).orElse(session.clientId), - ipAddress = ipAddress, - userAgent = userAgent, - tokenId = tokenId + bankTokenId = bankTokenId ) ).map { case r: BankAccountCreatedOrUpdated => Right(r) @@ -85,7 +48,7 @@ trait BankAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { } } } - .description("Create or update legal or natural user bank account") + .description("Create or update authenticated user bank account") val loadBankAccount: ServerEndpoint[Any with AkkaStreams, Future] = requiredSessionEndpoint.get diff --git a/core/src/main/scala/app/softnetwork/payment/service/PaymentAccountEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentAccountEndpoints.scala new file mode 100644 index 0000000..b9d5e3a --- /dev/null +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentAccountEndpoints.scala @@ -0,0 +1,118 @@ +package app.softnetwork.payment.service + +import app.softnetwork.payment.config.PaymentSettings +import app.softnetwork.payment.handlers.PaymentHandler +import app.softnetwork.payment.message.PaymentMessages._ +import app.softnetwork.payment.model.{PaymentAccount, PaymentAccountView} +import app.softnetwork.session.model.{SessionData, SessionDataDecorator} +import sttp.capabilities +import sttp.capabilities.akka.AkkaStreams +import sttp.model.{HeaderNames, StatusCode} +import sttp.tapir.json.json4s.jsonBody +import sttp.tapir.server.ServerEndpoint + +import scala.concurrent.Future + +trait PaymentAccountEndpoints[SD <: SessionData with SessionDataDecorator[SD]] { + _: RootPaymentEndpoints[SD] with PaymentHandler => + + import app.softnetwork.serialization._ + + lazy val createOrUpdatePaymentAccount: ServerEndpoint[Any with AkkaStreams, Future] = + requiredSessionEndpoint.post + .in(PaymentSettings.PaymentConfig.accountRoute) + .in(clientIp) + .in(header[Option[String]](HeaderNames.UserAgent)) + .in(jsonBody[UserPaymentAccountCommand].description("Legal or natural user payment account")) + .out( + statusCode(StatusCode.Ok) + .and( + jsonBody[UserPaymentAccountCreatedOrUpdated].description( + "User payment account created or updated" + ) + ) + ) + .serverLogic { + case (client, session) => { case (ipAddress, userAgent, userAccountCommand) => + import userAccountCommand._ + var externalUuid: String = "" + val updatedUser: Option[PaymentAccount.User] = { + user match { + case Left(naturalUser) => + var updatedNaturalUser = { + if (naturalUser.externalUuid.trim.isEmpty) { + naturalUser.withExternalUuid(session.id) + } else { + naturalUser + } + } + session.profile match { + case Some(profile) if updatedNaturalUser.profile.isEmpty => + updatedNaturalUser = updatedNaturalUser.withProfile(profile) + case _ => + } + externalUuid = updatedNaturalUser.externalUuid + Some(PaymentAccount.User.NaturalUser(updatedNaturalUser)) + case Right(legalUser) => + var updatedLegalRepresentative = legalUser.legalRepresentative + if (updatedLegalRepresentative.externalUuid.trim.isEmpty) { + updatedLegalRepresentative = + updatedLegalRepresentative.withExternalUuid(session.id) + } + session.profile match { + case Some(profile) if updatedLegalRepresentative.profile.isEmpty => + updatedLegalRepresentative = updatedLegalRepresentative.withProfile(profile) + case _ => + } + externalUuid = updatedLegalRepresentative.externalUuid + Some( + PaymentAccount.User.LegalUser( + legalUser.withLegalRepresentative(updatedLegalRepresentative) + ) + ) + } + } + run( + CreateOrUpdateUserPaymentAccount( + externalUuidWithProfile(session), + updatedUser, + acceptedTermsOfPSP, + clientId = client.map(_.clientId).orElse(session.clientId), + ipAddress = ipAddress, + userAgent = userAgent, + tokenId = tokenId + ) + ).map { + case r: UserPaymentAccountCreatedOrUpdated => Right(r) + case other => Left(error(other)) + } + } + } + .description("Create or update legal or natural user payment account") + + lazy val loadPaymentAccount: ServerEndpoint[Any with AkkaStreams, Future] = + requiredSessionEndpoint.get + .in(PaymentSettings.PaymentConfig.accountRoute) + .out(jsonBody[PaymentAccountView].description("Authenticated user payment account")) + .serverLogic { case (client, session) => + _ => { + run( + LoadPaymentAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ).map { + case r: PaymentAccountLoaded => Right(r.paymentAccount.view) + case other => Left(error(other)) + } + } + } + .description("Load authenticated user payment account") + + lazy val paymentAccountEndpoints + : List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = + List( + createOrUpdatePaymentAccount, + loadPaymentAccount + ) +} diff --git a/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala index ef29885..7943c19 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentService.scala @@ -57,6 +57,7 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] payInCallback ~ preAuthorizeCardCallback ~ firstRecurringPaymentCallback ~ + account ~ bank ~ declaration ~ kyc ~ @@ -196,20 +197,6 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] hmacTokenCsrfProtection(checkHeader) { // check if a session exists requiredClientSession { (client, session) => - get { - pathEnd { - run( - LoadPaymentAccount( - externalUuidWithProfile(session), - clientId = client.map(_.clientId).orElse(session.clientId) - ) - ) completeWith { - case r: PaymentAccountLoaded => - complete(HttpResponse(StatusCodes.OK, entity = r.paymentAccount.view)) - case other => error(other) - } - } - } ~ post { optionalHeaderValueByType[AcceptLanguage]((): Unit) { language => optionalHeaderValueByType[Accept]((): Unit) { acceptHeader => @@ -516,34 +503,30 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] concat(hooksRoutes: _*) } - lazy val bank: Route = pathPrefix(bankRoute) { + lazy val account: Route = pathPrefix(accountRoute) { // check anti CSRF token hmacTokenCsrfProtection(checkHeader) { // check if a session exists requiredClientSession { (client, session) => pathEnd { get { - run( - LoadBankAccount( - externalUuidWithProfile(session), - clientId = client.map(_.clientId).orElse(session.clientId) - ) - ) completeWith { - case r: BankAccountLoaded => - complete( - HttpResponse( - StatusCodes.OK, - entity = r.bankAccount.view - ) + pathEnd { + run( + LoadPaymentAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) ) - case other => error(other) + ) completeWith { + case r: PaymentAccountLoaded => + complete(HttpResponse(StatusCodes.OK, entity = r.paymentAccount.view)) + case other => error(other) + } } - } ~ - post { + } ~ post { optionalHeaderValueByType[UserAgent]((): Unit) { userAgent => extractClientIP { ipAddress => - entity(as[BankAccountCommand]) { bank => - import bank._ + entity(as[UserPaymentAccountCommand]) { userAccountCommand => + import userAccountCommand._ var externalUuid: String = "" val updatedUser: Option[PaymentAccount.User] = user match { @@ -582,24 +565,74 @@ trait PaymentService[SD <: SessionData with SessionDataDecorator[SD]] ) } run( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( externalUuidWithProfile(session), - bankAccount.withExternalUuid(externalUuid), updatedUser, acceptedTermsOfPSP, Some(ipAddress.value), userAgent.map(_.name()), - tokenId = tokenId, - bankTokenId = bankTokenId + clientId = client.map(_.clientId).orElse(session.clientId), + tokenId = tokenId ) ) completeWith { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => complete(HttpResponse(StatusCodes.OK, entity = r)) case other => error(other) } } } } + } + } + } + } + } + + lazy val bank: Route = pathPrefix(bankRoute) { + // check anti CSRF token + hmacTokenCsrfProtection(checkHeader) { + // check if a session exists + requiredClientSession { (client, session) => + pathEnd { + get { + run( + LoadBankAccount( + externalUuidWithProfile(session), + clientId = client.map(_.clientId).orElse(session.clientId) + ) + ) completeWith { + case r: BankAccountLoaded => + complete( + HttpResponse( + StatusCodes.OK, + entity = r.bankAccount.view + ) + ) + case other => error(other) + } + } ~ + post { + entity(as[BankAccountCommand]) { bank => + import bank._ + val updatedBankAccount = + if (bankAccount.externalUuid.trim().isEmpty) { + bankAccount.withExternalUuid(session.id) + } else { + bankAccount + } + run( + CreateOrUpdateBankAccount( + externalUuidWithProfile(session), + updatedBankAccount, + clientId = client.map(_.clientId).orElse(session.clientId), + bankTokenId = bankTokenId + ) + ) completeWith { + case r: BankAccountCreatedOrUpdated => + complete(HttpResponse(StatusCodes.OK, entity = r)) + case other => error(other) + } + } } ~ delete { run(DeleteBankAccount(externalUuidWithProfile(session), Some(false))) completeWith { diff --git a/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala b/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala index aaa940a..d5870cb 100644 --- a/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala +++ b/core/src/main/scala/app/softnetwork/payment/service/PaymentServiceEndpoints.scala @@ -2,15 +2,12 @@ package app.softnetwork.payment.service import app.softnetwork.payment.config.PaymentSettings import app.softnetwork.payment.handlers.PaymentHandler -import app.softnetwork.payment.message.PaymentMessages._ -import app.softnetwork.payment.model._ import app.softnetwork.payment.spi.PaymentProviders import app.softnetwork.session.model.{SessionData, SessionDataDecorator} import app.softnetwork.session.service.SessionMaterials import sttp.capabilities import sttp.capabilities.akka.AkkaStreams import sttp.model.Part -import sttp.tapir.json.json4s.jsonBody import sttp.tapir.server.ServerEndpoint import sttp.tapir.server.ServerEndpoint.Full @@ -21,6 +18,7 @@ trait PaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] extends RootPaymentEndpoints[SD] with PaymentMethodEndpoints[SD] with CheckoutEndpoints[SD] + with PaymentAccountEndpoints[SD] with BankAccountEndpoints[SD] with KycDocumentEndpoints[SD] with UboDeclarationEndpoints[SD] @@ -28,8 +26,6 @@ trait PaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] with MandateEndpoints[SD] { _: PaymentHandler with SessionMaterials[SD] => - import app.softnetwork.serialization._ - /** should be implemented by each payment provider */ def hooks: List[Full[Unit, Unit, _, Unit, Unit, Any, Future]] = { @@ -38,33 +34,16 @@ trait PaymentServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]] }.toList } - val loadPaymentAccount: ServerEndpoint[Any with AkkaStreams, Future] = - requiredSessionEndpoint.get - .out(jsonBody[PaymentAccountView].description("Authenticated user payment account")) - .serverLogic { case (client, session) => - _ => { - run( - LoadPaymentAccount( - externalUuidWithProfile(session), - clientId = client.map(_.clientId).orElse(session.clientId) - ) - ).map { - case r: PaymentAccountLoaded => Right(r.paymentAccount.view) - case other => Left(error(other)) - } - } - } - .description("Load authenticated user payment account") - override val endpoints: List[ServerEndpoint[AkkaStreams with capabilities.WebSockets, Future]] = cardEndpoints ++ cardPaymentEndpoints ++ + paymentAccountEndpoints ++ bankAccountEndpoints ++ kycDocumentEndpoints ++ uboDeclarationEndpoints ++ mandateEndpoints ++ recurringPaymentEndpoints ++ - hooks :+ loadPaymentAccount + hooks } diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteSpec.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteSpec.scala index de99040..910b84c 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteSpec.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteSpec.scala @@ -34,14 +34,23 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] "Payment service" must { "not create bank account with wrong iban" in { createNewSession(sellerSession()) + withHeaders( + Post( + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", + UserPaymentAccountCommand( + naturalUser.withExternalUuid(externalUserId), + Some(true), + None + ) + ) + ) ~> routes ~> check { + status shouldEqual StatusCodes.OK + } withHeaders( Post( s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", BankAccountCommand( BankAccount(None, ownerName, ownerAddress, "", bic), - naturalUser, - None, - None, None ) ) @@ -57,9 +66,6 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", BankAccountCommand( BankAccount(None, ownerName, ownerAddress, iban, "WRONG"), - naturalUser, - None, - None, None ) ) @@ -73,9 +79,6 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] val command = BankAccountCommand( BankAccount(None, ownerName, ownerAddress, iban, bic), - naturalUser.withExternalUuid(externalUserId), - Some(true), - None, None ) log.info(s"create bank account with natural user command: ${serialization.write(command)}") @@ -95,14 +98,23 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] } "update bank account with natural user" in { + withHeaders( + Post( + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", + UserPaymentAccountCommand( + naturalUser.withLastName("anotherLastName").withExternalUuid(externalUserId), + Some(true), + None + ) + ) + ) ~> routes ~> check { + status shouldEqual StatusCodes.OK + } withHeaders( Post( s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", BankAccountCommand( BankAccount(Option(sellerBankAccountId), ownerName, ownerAddress, iban, bic), - naturalUser.withLastName("anotherLastName").withExternalUuid(externalUserId), - None, - None, None ) ) @@ -115,21 +127,13 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] } } - "not update bank account with wrong siret" in { + "not update payment account with wrong siret" in { withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", - BankAccountCommand( - BankAccount( - Option(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", + UserPaymentAccountCommand( legalUser.withSiret(""), None, - None, None ) ) @@ -139,21 +143,13 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] } } - "not update bank account with empty legal name" in { + "not update payment account with empty legal name" in { withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", - BankAccountCommand( - BankAccount( - Option(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", + UserPaymentAccountCommand( legalUser.withLegalName(""), None, - None, None ) ) @@ -163,21 +159,13 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] } } - "not update bank account without accepted terms of PSP" in { + "not update payment account without accepted terms of PSP" in { withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", - BankAccountCommand( - BankAccount( - Option(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", + UserPaymentAccountCommand( legalUser, None, - None, None ) ) @@ -187,28 +175,20 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] } } - "update bank account with sole trader legal user" in { + "update payment account with sole trader legal user" in { externalUserId = "soleTrader" val command = - BankAccountCommand( - BankAccount( - Option(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), + UserPaymentAccountCommand( legalUser.withLegalRepresentative(naturalUser.withExternalUuid(externalUserId)), Some(true), - None, None ) log.info( - s"update bank account with sole trader legal user command: ${serialization.write(command)}" + s"update payment account with sole trader legal user command: ${serialization.write(command)}" ) withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", command ).withHeaders( `X-Forwarded-For`(RemoteAddress(InetAddress.getLocalHost)), @@ -216,6 +196,17 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] ) ) ~> routes ~> check { status shouldEqual StatusCodes.OK + withHeaders( + Post( + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", + BankAccountCommand( + BankAccount(Option(sellerBankAccountId), ownerName, ownerAddress, iban, bic), + None + ) + ) + ) ~> routes ~> check { + status shouldEqual StatusCodes.OK + } val bankAccount = loadBankAccount() // val previousBankAccountId = sellerBankAccountId sellerBankAccountId = bankAccount.bankAccountId @@ -223,31 +214,34 @@ trait PaymentRouteSpec[SD <: SessionData with SessionDataDecorator[SD]] } } - "update bank account with business legal user" in { + "update payment account with business legal user" in { externalUserId = "business" val command = - BankAccountCommand( - BankAccount( - Option(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), + UserPaymentAccountCommand( legalUser .withLegalUserType(LegalUser.LegalUserType.BUSINESS) .withLegalRepresentative(naturalUser.withExternalUuid(externalUserId)), Some(true), - None, None ) log.info( - s"update bank account with business legal user command: ${serialization.write(command)}" + s"update payment account with business legal user command: ${serialization.write(command)}" ) withHeaders( - Post(s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", command) + Post(s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", command) ) ~> routes ~> check { status shouldEqual StatusCodes.OK + withHeaders( + Post( + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", + BankAccountCommand( + BankAccount(Option(sellerBankAccountId), ownerName, ownerAddress, iban, bic), + None + ) + ) + ) ~> routes ~> check { + status shouldEqual StatusCodes.OK + } val bankAccount = loadBankAccount() // val previousBankAccountId = sellerBankAccountId sellerBankAccountId = bankAccount.bankAccountId diff --git a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala index c6216ee..66b87da 100644 --- a/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala +++ b/testkit/src/main/scala/app/softnetwork/payment/scalatest/PaymentRouteTestKit.scala @@ -50,7 +50,7 @@ trait PaymentRouteTestKit[SD <: SessionData with SessionDataDecorator[SD]] def loadPaymentAccount(): PaymentAccountView = { withHeaders( - Get(s"/$RootPath/${PaymentSettings.PaymentConfig.path}") + Get(s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute") ) ~> routes ~> check { status shouldEqual StatusCodes.OK responseAs[PaymentAccountView] diff --git a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala index 1221e7a..e5ce288 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/handlers/PaymentHandlerSpec.scala @@ -167,12 +167,20 @@ class PaymentHandlerSpec "not create bank account with wrong iban" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount(None, ownerName, ownerAddress, "", bic), + Some(User.NaturalUser(naturalUser.withExternalUuid(sellerUuid).withProfile("seller"))), ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") ) + ) await { case r: UserPaymentAccountCreatedOrUpdated => + assert(r.userCreated) + } + !?( + CreateOrUpdateBankAccount( + computeExternalUuidWithProfile(sellerUuid, Some("seller")), + BankAccount(None, ownerName, ownerAddress, "", bic) + ) ) await { case WrongIban => case other => fail(other.toString) @@ -183,9 +191,7 @@ class PaymentHandlerSpec !?( CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount(None, ownerName, ownerAddress, iban, "WRONG"), - ipAddress = Some("127.0.0.1"), - userAgent = Some("UserAgent") + BankAccount(None, ownerName, ownerAddress, iban, "WRONG") ) ) await { case WrongBic => @@ -198,14 +204,11 @@ class PaymentHandlerSpec CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), BankAccount(None, ownerName, ownerAddress, iban, ""), - Some(User.NaturalUser(naturalUser.withExternalUuid(sellerUuid).withProfile("seller"))), - clientId = Some(clientId), - ipAddress = Some("127.0.0.1"), - userAgent = Some("UserAgent") + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => - assert(r.userCreated) + assert(r.bankAccountCreated) !?(LoadPaymentAccount(computeExternalUuidWithProfile(sellerUuid, Some("seller")))) await { case result: PaymentAccountLoaded => val paymentAccount = result.paymentAccount @@ -228,18 +231,11 @@ class PaymentHandlerSpec } } - "update bank account with natural user" in { + "update payment account with natural user" in { // update first name !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.NaturalUser( naturalUser @@ -253,8 +249,25 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert(r.kycUpdated && r.userUpdated && r.documentsUpdated) + !?( + CreateOrUpdateBankAccount( + computeExternalUuidWithProfile(sellerUuid, Some("seller")), + BankAccount( + Some(sellerBankAccountId), + ownerName, + ownerAddress, + iban, + bic + ), + clientId = Some(clientId) + ) + ) await { + case r: BankAccountCreatedOrUpdated => + assert(r.bankAccountUpdated && !r.bankAccountCreated) + case other => fail(other.toString) + } !?(LoadPaymentAccount(computeExternalUuidWithProfile(sellerUuid, Some("seller")))) await { case result: PaymentAccountLoaded => val paymentAccount = result.paymentAccount @@ -279,15 +292,8 @@ class PaymentHandlerSpec } // update last name !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.NaturalUser( naturalUser @@ -302,21 +308,14 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert(r.kycUpdated && r.userUpdated && r.documentsUpdated) case other => fail(other.toString) } // update birthday !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.NaturalUser( naturalUser @@ -332,24 +331,17 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert(r.kycUpdated && r.userUpdated && r.documentsUpdated) case other => fail(other.toString) } } - "update bank account except kyc information with natural user" in { + "update payment account except kyc information with natural user" in { // update country of residence !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.NaturalUser( naturalUser @@ -365,20 +357,13 @@ class PaymentHandlerSpec ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") ) - ) await { case r: BankAccountCreatedOrUpdated => + ) await { case r: UserPaymentAccountCreatedOrUpdated => assert(!r.kycUpdated && !r.documentsUpdated && r.userUpdated) } // update nationality !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.NaturalUser( naturalUser @@ -395,22 +380,15 @@ class PaymentHandlerSpec ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") ) - ) await { case r: BankAccountCreatedOrUpdated => + ) await { case r: UserPaymentAccountCreatedOrUpdated => assert(!r.kycUpdated && !r.documentsUpdated && r.userUpdated) } } - "not update bank account with wrong siret" in { + "not update payment account with wrong siret" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some(User.LegalUser(legalUser.withSiret(""))), ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") @@ -421,17 +399,10 @@ class PaymentHandlerSpec } } - "not update bank account with empty legal name" in { + "not update payment account with empty legal name" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some(User.LegalUser(legalUser.withLegalName(""))), ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") @@ -442,17 +413,10 @@ class PaymentHandlerSpec } } - "not update bank account without accepted terms of PSP" in { + "not update payment account without accepted terms of PSP" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some(User.LegalUser(legalUser)), ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") @@ -463,17 +427,10 @@ class PaymentHandlerSpec } } - "update bank account with sole trader legal user" in { + "update payment account with sole trader legal user" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.LegalUser( legalUser.withLegalRepresentative(legalUser.legalRepresentative.withProfile("seller")) @@ -485,7 +442,7 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert(r.userTypeUpdated && r.kycUpdated && r.documentsUpdated && r.userUpdated) !?(LoadPaymentAccount(computeExternalUuidWithProfile(sellerUuid, Some("seller")))) await { case result: PaymentAccountLoaded => @@ -511,17 +468,10 @@ class PaymentHandlerSpec } } - "update bank account with business legal user" in { + "update payment account with business legal user" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - BankAccount( - Some(sellerBankAccountId), - ownerName, - ownerAddress, - iban, - bic - ), Some( User.LegalUser( legalUser @@ -538,7 +488,7 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert(r.userTypeUpdated && r.kycUpdated && r.documentsUpdated && r.userUpdated) !?(LoadPaymentAccount(computeExternalUuidWithProfile(sellerUuid, Some("seller")))) await { case result: PaymentAccountLoaded => @@ -588,7 +538,7 @@ class PaymentHandlerSpec } } - "update bank account except kyc information with business legal user" in { + "update payment account except kyc information with business legal user" in { var updatedBankAccount = BankAccount( Some(sellerBankAccountId), @@ -607,9 +557,8 @@ class PaymentHandlerSpec // update bank account owner name updatedBankAccount = updatedBankAccount.withOwnerName("anotherOwnerName") !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - updatedBankAccount, Some(User.LegalUser(updatedLegalUser)), Some(true), clientId = Some(clientId), @@ -617,10 +566,21 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert( - !r.userTypeUpdated && !r.kycUpdated && !r.documentsUpdated && !r.userUpdated && r.bankAccountUpdated + !r.userTypeUpdated && !r.kycUpdated && !r.documentsUpdated && !r.userUpdated ) + !?( + CreateOrUpdateBankAccount( + computeExternalUuidWithProfile(sellerUuid, Some("seller")), + updatedBankAccount, + clientId = Some(clientId) + ) + ) await { + case r: BankAccountCreatedOrUpdated => + assert(r.bankAccountUpdated && !r.bankAccountCreated) + case other => fail(other.toString) + } case other => fail(other.toString) } // update bank account owner address @@ -629,17 +589,11 @@ class PaymentHandlerSpec !?( CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - updatedBankAccount, - Some(User.LegalUser(updatedLegalUser)), - Some(true), - ipAddress = Some("127.0.0.1"), - userAgent = Some("UserAgent") + updatedBankAccount ) ) await { case r: BankAccountCreatedOrUpdated => - assert( - !r.userTypeUpdated && !r.kycUpdated && !r.documentsUpdated && !r.userUpdated && r.bankAccountUpdated - ) + assert(r.bankAccountUpdated && !r.bankAccountCreated) case other => fail(other.toString) } // update bank account iban @@ -647,17 +601,11 @@ class PaymentHandlerSpec !?( CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - updatedBankAccount, - Some(User.LegalUser(updatedLegalUser)), - Some(true), - ipAddress = Some("127.0.0.1"), - userAgent = Some("UserAgent") + updatedBankAccount ) ) await { case r: BankAccountCreatedOrUpdated => - assert( - !r.userTypeUpdated && !r.kycUpdated && !r.documentsUpdated && !r.userUpdated && r.bankAccountUpdated - ) + assert(r.bankAccountUpdated && !r.bankAccountCreated) case other => fail(other.toString) } // update bank account bic @@ -666,17 +614,11 @@ class PaymentHandlerSpec CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), updatedBankAccount, - Some(User.LegalUser(updatedLegalUser)), - Some(true), - clientId = Some(clientId), - ipAddress = Some("127.0.0.1"), - userAgent = Some("UserAgent") + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => - assert( - !r.userTypeUpdated && !r.kycUpdated && !r.documentsUpdated && !r.userUpdated && r.bankAccountUpdated - ) + assert(r.bankAccountUpdated && !r.bankAccountCreated) case other => fail(other.toString) } // update bank account with empty bic @@ -684,28 +626,23 @@ class PaymentHandlerSpec CreateOrUpdateBankAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), updatedBankAccount.withBic(""), - Some(User.LegalUser(updatedLegalUser)), - Some(true), - clientId = Some(clientId), - ipAddress = Some("127.0.0.1"), - userAgent = Some("UserAgent") + clientId = Some(clientId) ) ) await { case r: BankAccountCreatedOrUpdated => + /* + assert(!r.bankAccountUpdated) assert( - !r.userTypeUpdated && !r.kycUpdated && !r.documentsUpdated && !r.userUpdated /*&& !r.bankAccountUpdated FIXME*/ - ) - /*assert( - r.paymentAccount.bankAccount.map(_.bic).getOrElse("").nonEmpty - )FIXME*/ + r.paymentAccount.bankAccount.map(_.bic).getOrElse("").nonEmpty + ) FIXME + */ case other => fail(other.toString) } // update siret updatedLegalUser = updatedLegalUser.withSiret("12345678912345") !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(sellerUuid, Some("seller")), - updatedBankAccount, Some(User.LegalUser(updatedLegalUser)), Some(true), clientId = Some(clientId), @@ -713,9 +650,9 @@ class PaymentHandlerSpec userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert( - !r.userTypeUpdated && !r.documentsUpdated && r.userUpdated /*&& !r.bankAccountUpdated FIXME*/ + !r.userTypeUpdated && !r.documentsUpdated && r.userUpdated ) case other => fail(other.toString) } @@ -1162,17 +1099,27 @@ class PaymentHandlerSpec "transfer" in { !?( - CreateOrUpdateBankAccount( + CreateOrUpdateUserPaymentAccount( computeExternalUuidWithProfile(vendorUuid, Some("vendor")), - BankAccount(None, ownerName, ownerAddress, iban, bic), Some(User.NaturalUser(naturalUser.withExternalUuid(vendorUuid).withProfile("vendor"))), clientId = Some(clientId), ipAddress = Some("127.0.0.1"), userAgent = Some("UserAgent") ) ) await { - case r: BankAccountCreatedOrUpdated => + case r: UserPaymentAccountCreatedOrUpdated => assert(r.userCreated) + !?( + CreateOrUpdateBankAccount( + computeExternalUuidWithProfile(vendorUuid, Some("vendor")), + BankAccount(None, ownerName, ownerAddress, iban, bic), + clientId = Some(clientId) + ) + ) await { + case r: BankAccountCreatedOrUpdated => + assert(r.bankAccountCreated) + case other => fail(other.toString) + } !?(LoadPaymentAccount(computeExternalUuidWithProfile(vendorUuid, Some("vendor")))) await { case result: PaymentAccountLoaded => val paymentAccount = result.paymentAccount diff --git a/testkit/src/test/scala/app/softnetwork/payment/service/StripePaymentServiceSpec.scala b/testkit/src/test/scala/app/softnetwork/payment/service/StripePaymentServiceSpec.scala index a946f1e..332928c 100644 --- a/testkit/src/test/scala/app/softnetwork/payment/service/StripePaymentServiceSpec.scala +++ b/testkit/src/test/scala/app/softnetwork/payment/service/StripePaymentServiceSpec.scala @@ -41,7 +41,8 @@ import app.softnetwork.payment.message.PaymentMessages.{ PreRegisterPaymentMethod, RecurringPaymentRegistered, RegisterRecurringPayment, - Schedule4PaymentTriggered + Schedule4PaymentTriggered, + UserPaymentAccountCommand } import app.softnetwork.payment.model.{ computeExternalUuidWithProfile, @@ -98,18 +99,14 @@ trait StripePaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] externalUserId = "individual-production" val user = naturalUser.withExternalUuid(externalUserId) val token = createAccountToken(PaymentAccount.defaultInstance.withNaturalUser(user)) - val bankAccount = BankAccount(None, ownerName, ownerAddress, iban, bic) - val bankToken = createBankToken(bankAccount, individual = true) createNewSession(sellerSession(externalUserId)) withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", - BankAccountCommand( - bankAccount, + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", + UserPaymentAccountCommand( user, Some(true), - Some(token.getId), - Some(bankToken.getId) + Some(token.getId) ) ).withHeaders( `X-Forwarded-For`(RemoteAddress(InetAddress.getLocalHost)), @@ -117,6 +114,15 @@ trait StripePaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] ) ) ~> routes ~> check { status shouldEqual StatusCodes.OK + val bank = BankAccount(None, ownerName, ownerAddress, iban, bic) + val bankToken = createBankToken(bank, individual = true) + Post( + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", + BankAccountCommand( + bank, + Some(bankToken.getId) + ) + ) val bankAccount = loadBankAccount() sellerBankAccountId = bankAccount.bankAccountId } @@ -224,27 +230,25 @@ trait StripePaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] externalUserId = "soleTrader-production" val user = legalUser.withLegalRepresentative(naturalUser.withExternalUuid(externalUserId)) val token = createAccountToken(PaymentAccount.defaultInstance.withLegalUser(user)) - val bankAccount = BankAccount( + /*val bankAccount = BankAccount( Option(sellerBankAccountId), ownerName, ownerAddress, iban, bic ) - val bankToken = createBankToken(bankAccount, individual = false) + val bankToken = createBankToken(bankAccount, individual = false)*/ createNewSession(sellerSession(externalUserId)) val command = - BankAccountCommand( - bankAccount, + UserPaymentAccountCommand( user, Some(true), - Some(token.getId), - Some(bankToken.getId) + Some(token.getId) ) log.info(serialization.write(command)) withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", command ).withHeaders( `X-Forwarded-For`(RemoteAddress(InetAddress.getLocalHost)), @@ -265,7 +269,7 @@ trait StripePaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] .withLegalUserType(LegalUser.LegalUserType.BUSINESS) .withLegalRepresentative(naturalUser.withExternalUuid(externalUserId)) val token = createAccountToken(PaymentAccount.defaultInstance.withLegalUser(user)) - val bankAccount = + /*val bankAccount = BankAccount( Option(sellerBankAccountId), ownerName, @@ -273,20 +277,18 @@ trait StripePaymentServiceSpec[SD <: SessionData with SessionDataDecorator[SD]] iban, bic ) - val bankToken = createBankToken(bankAccount, individual = false) + val bankToken = createBankToken(bankAccount, individual = false)*/ createNewSession(sellerSession(externalUserId)) val bank = - BankAccountCommand( - bankAccount, + UserPaymentAccountCommand( user, Some(true), - Some(token.getId), - Some(bankToken.getId) + Some(token.getId) ) log.info(serialization.write(bank)) withHeaders( Post( - s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$bankRoute", + s"/$RootPath/${PaymentSettings.PaymentConfig.path}/$accountRoute", bank ).withHeaders( `X-Forwarded-For`(RemoteAddress(InetAddress.getLocalHost)),