Skip to content

Commit

Permalink
Merge branch 'main' into PPABV-32-update-pm-service
Browse files Browse the repository at this point in the history
  • Loading branch information
a-mannia authored Nov 4, 2024
2 parents cd0ad16 + 0915062 commit 353aa27
Show file tree
Hide file tree
Showing 7 changed files with 687 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package it.pagopa.ecommerce.helpdesk.dataproviders.repositories.history

import it.pagopa.ecommerce.helpdesk.documents.PmTransactionHistory
import org.springframework.data.mongodb.repository.Aggregation
import org.springframework.data.mongodb.repository.Query
import org.springframework.data.repository.reactive.ReactiveCrudRepository
import org.springframework.stereotype.Repository
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono

@Repository
interface PmTransactionsRepository : ReactiveCrudRepository<PmTransactionHistory, String> {

@Query("{'userInfo.notificationEmail': '?0'}", count = true)
fun countTransactionsWithEmail(email: String): Mono<Long>

@Query("{'userInfo.userFiscalCode': '?0'}", count = true)
fun countTransactionsWithUserFiscalCode(userFiscalCode: String): Mono<Long>

@Aggregation(
"{\$match: {'userInfo.notificationEmail': '?0'}}",
"{\$sort: {'transactionInfo.creationDate': -1}}",
"{\$skip: ?1}",
"{\$limit: ?2}",
)
fun findTransactionsWithEmailPaginatedOrderByCreationDateDesc(
email: String,
skip: Int,
limit: Int
): Flux<PmTransactionHistory>

@Aggregation(
"{\$match: {'userInfo.userFiscalCode': '?0'}}",
"{\$sort: {'transactionInfo.creationDate': -1}}",
"{\$skip: ?1}",
"{\$limit: ?2}",
)
fun findTransactionsWithUserFiscalCodePaginatedOrderByCreationDateDesc(
userFiscalCode: String,
skip: Int,
limit: Int
): Flux<PmTransactionHistory>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package it.pagopa.ecommerce.helpdesk.dataproviders.v2.mongo

import it.pagopa.ecommerce.helpdesk.dataproviders.repositories.history.PmTransactionsRepository
import it.pagopa.ecommerce.helpdesk.dataproviders.v2.TransactionDataProvider
import it.pagopa.ecommerce.helpdesk.documents.PmTransactionHistory
import it.pagopa.ecommerce.helpdesk.exceptions.InvalidSearchCriteriaException
import it.pagopa.ecommerce.helpdesk.utils.v2.SearchParamDecoderV2
import it.pagopa.ecommerce.helpdesk.utils.v2.pmTransactionToTransactionInfoDtoV2
import it.pagopa.generated.ecommerce.helpdesk.v2.model.*
import it.pagopa.generated.ecommerce.helpdesk.v2.model.HelpDeskSearchTransactionRequestDto
import it.pagopa.generated.ecommerce.helpdesk.v2.model.TransactionResultDto
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono

@Component("PmTransactionHistoryDataProviderV2")
class PmTransactionHistoryDataProvider(
@Autowired private val pmTransactionsRepository: PmTransactionsRepository
) : TransactionDataProvider {
override fun totalRecordCount(
searchParams: SearchParamDecoderV2<HelpDeskSearchTransactionRequestDto>
): Mono<Int> {
val decodedSearchParam = searchParams.decode()
val invalidSearchCriteriaError =
decodedSearchParam.flatMap {
Mono.error<Int>(InvalidSearchCriteriaException(it.type, ProductDto.PM))
}
return decodedSearchParam
.flatMap {
when (it) {
is SearchTransactionRequestPaymentTokenDto -> invalidSearchCriteriaError
is SearchTransactionRequestRptIdDto -> invalidSearchCriteriaError
is SearchTransactionRequestTransactionIdDto -> invalidSearchCriteriaError
is SearchTransactionRequestEmailDto ->
pmTransactionsRepository.countTransactionsWithEmail(it.userEmail)
is SearchTransactionRequestFiscalCodeDto ->
pmTransactionsRepository.countTransactionsWithUserFiscalCode(
it.userFiscalCode
)
else -> invalidSearchCriteriaError
}
}
.map { it.toInt() }
}

override fun findResult(
searchParams: SearchParamDecoderV2<HelpDeskSearchTransactionRequestDto>,
skip: Int,
limit: Int
): Mono<List<TransactionResultDto>> {
val decodedSearchParam = searchParams.decode()
val invalidSearchCriteriaError =
decodedSearchParam.flatMapMany {
Flux.error<PmTransactionHistory>(
InvalidSearchCriteriaException(it.type, ProductDto.PM)
)
}
val transactions: Flux<PmTransactionHistory> =
decodedSearchParam.flatMapMany {
when (it) {
is SearchTransactionRequestPaymentTokenDto -> invalidSearchCriteriaError
is SearchTransactionRequestRptIdDto -> invalidSearchCriteriaError
is SearchTransactionRequestTransactionIdDto -> invalidSearchCriteriaError
is SearchTransactionRequestEmailDto ->
pmTransactionsRepository
.findTransactionsWithEmailPaginatedOrderByCreationDateDesc(
email = it.userEmail,
skip = skip,
limit = limit
)
is SearchTransactionRequestFiscalCodeDto ->
pmTransactionsRepository
.findTransactionsWithUserFiscalCodePaginatedOrderByCreationDateDesc(
userFiscalCode = it.userFiscalCode,
skip = skip,
limit = limit
)
else -> invalidSearchCriteriaError
}
}
return transactions.map { pmTransactionToTransactionInfoDtoV2(it) }.collectList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package it.pagopa.ecommerce.helpdesk.documents

import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document

@Document(collection = "pm-transactions-history")
data class PmTransactionHistory(
@Id val id: String,
val userInfo: UserInfo,
val transactionInfo: TransactionInfo,
val paymentInfo: PaymentInfo,
val pspInfo: PspInfo,
val product: String
)

data class UserInfo(
val userFiscalCode: String,
val notificationEmail: String,
val authenticationType: Int
)

data class TransactionInfo(
val creationDate: String,
val status: Int,
val statusDetails: Int,
val amount: Int,
val fee: Int,
val grandTotal: Int,
val rrn: String,
val authorizationCode: String,
val paymentMethodName: String
)

data class PaymentInfo(val origin: String, val details: List<PaymentDetailInfo>)

data class PaymentDetailInfo(
val subject: String,
val iuv: String,
val idTransaction: String,
val creditorInstitution: String,
val paFiscalCode: String,
val amount: Int
)

data class PspInfo(val pspId: String, val businessName: String, val idChannel: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package it.pagopa.ecommerce.helpdesk.documents

enum class UserStatus(val code: Int, val description: String) {
UNREGISTERED(0, "Utente non registrato"),
REGISTERED_NO_SPID(1, "Utente registrato non SPID"),
PENDING_OTP_VERIFICATION(2, "Utente in attesa di verifica OTP"),
PASSWORD_TO_SET(3, "Password da impostare"),
PASSWORD_RESET(4, "Password da impostare - cambio password"),
USER_DELETED(5, "Utente cancellato"),
REGISTERED_SPID(11, "Utente registrato SPID"),
REGISTERED_WITH_CIE(12, "Utente registrato su IO con CIE");

companion object {
fun fromCode(code: Int): String {
return UserStatus.values().find { it.code == code }?.name ?: code.toString()
}
}
}

enum class PaymentStatus(val code: Int, val description: String) {
TO_AUTHORIZE(0, "Da autorizzare"),
PENDING(1, "In attesa"),
PENDING_MOD1(2, "In attesa mod1"),
CONFIRMED(3, "Confermato"),
REJECTED(4, "Rifiutato"),
PENDING_XPAY(6, "In attesa di XPAY"),
ERROR(7, "In errore"),
CONFIRMED_MOD1(8, "Confermato mod1"),
CONFIRMED_MOD2(9, "Confermato mod2"),
REJECTED_AGAIN(10, "Rifiutato"),
MISSING_CALLBACK_PSP(11, "Missing callback from PSP"),
PAYMENT_TAKEN(12, "Pagamento preso in carico"),
EXPIRED_3DS(13, "3DS Scaduto"),
AUTHORIZED_NODE_TIMEOUT(14, "Authorized with nodo timeout"),
AWAITING_3DS2_METHOD(15, "In attesa del metodo 3ds2"),
AWAITING_3DS2_CHALLENGE(16, "In attesa della challenge 3ds2"),
RETURNING_3DS2_METHOD(17, "Ritornando dal metodo 3ds2"),
RETURNING_3DS2_CHALLENGE(18, "Ritornando dalla challenge 3ds2"),
XPAY_PPAL_BPAY_TO_BE_REVERSED(19, "Transazione XPAY / PPAL / BPAY da stornare"),
XPAY_REVERSED_BATCH(20, "Transazione XPAY stornata da batch"),
PAYMENT_AUTHORIZED_BY_GATEWAY(21, "Pagamento Autorizzato dal Payment Gateway");

companion object {
fun fromCode(code: Int): String {
return PaymentStatus.values().find { it.code == code }?.name ?: code.toString()
}
}
}

enum class AccountingStatus(val code: Int, val description: String) {
NOT_MANAGED(0, "Non gestito"),
ACCOUNTED(1, "Contabilizzato"),
ACCOUNTING_ERROR(2, "Errore di contabilizzazione"),
REVERSED(3, "Stornato"),
REVERSAL_ERROR(4, "Errore Storno"),
RECEIPT_CREATED(5, "Ricevuta creata");

companion object {
fun fromCode(code: Int): String {
return AccountingStatus.values().find { it.code == code }?.name ?: code.toString()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ import it.pagopa.ecommerce.commons.domain.v1.TransactionWithClosureError
import it.pagopa.ecommerce.commons.domain.v1.pojos.*
import it.pagopa.ecommerce.commons.generated.server.model.AuthorizationResultDto
import it.pagopa.ecommerce.commons.utils.v1.TransactionUtils.getTransactionFee
import it.pagopa.ecommerce.helpdesk.documents.AccountingStatus
import it.pagopa.ecommerce.helpdesk.documents.PaymentStatus
import it.pagopa.ecommerce.helpdesk.documents.PmTransactionHistory
import it.pagopa.ecommerce.helpdesk.documents.UserStatus
import it.pagopa.generated.ecommerce.helpdesk.v2.model.*
import it.pagopa.generated.ecommerce.nodo.v2.model.UserDto
import java.math.BigDecimal
import java.time.LocalDateTime
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.util.*
Expand Down Expand Up @@ -99,6 +104,73 @@ fun resultToTransactionInfoDto(
.product(it.pagopa.generated.ecommerce.helpdesk.v2.model.ProductDto.PM)
}

fun pmTransactionToTransactionInfoDtoV2(
pmTransactionHistory: PmTransactionHistory
): TransactionResultDto {
val amount = pmTransactionHistory.transactionInfo.amount
val fee = pmTransactionHistory.transactionInfo.fee
val grandTotal = pmTransactionHistory.transactionInfo.grandTotal
val email = pmTransactionHistory.userInfo.notificationEmail
// Build user info

val userInfo =
UserInfoDto()
.notificationEmail(email)
.userFiscalCode(pmTransactionHistory.userInfo.userFiscalCode)
.authenticationType(
UserStatus.fromCode(pmTransactionHistory.userInfo.authenticationType)
)
// build transaction info
val transactionInfo =
TransactionInfoDto()
.creationDate(OffsetDateTime.parse(pmTransactionHistory.transactionInfo.creationDate))
.status(PaymentStatus.fromCode(pmTransactionHistory.transactionInfo.status))
.statusDetails(
AccountingStatus.fromCode(pmTransactionHistory.transactionInfo.statusDetails)
)
.eventStatus(null)
.amount(amount)
.fee(fee)
.grandTotal(grandTotal)
.rrn(pmTransactionHistory.transactionInfo.rrn)
.authorizationCode(pmTransactionHistory.transactionInfo.authorizationCode)
.paymentMethodName(pmTransactionHistory.transactionInfo.paymentMethodName)
.brand(null)
.authorizationRequestId(null)
.paymentGateway(null)
.authorizationOperationId(null)
.refundOperationId(null)
// build payment info
val paymentInfo =
PaymentInfoDto()
.origin(pmTransactionHistory.paymentInfo.origin)
.idTransaction(pmTransactionHistory.paymentInfo.details[0].idTransaction)
.details(
pmTransactionHistory.paymentInfo.details.map {
PaymentDetailInfoDto()
.subject(it.subject)
.iuv(it.iuv)
.rptId(null)
.paymentToken(null)
.paFiscalCode(it.paFiscalCode)
.amount(it.amount)
.creditorInstitution(it.creditorInstitution)
}
)
// build psp info
val pspInfo =
PspInfoDto()
.pspId(pmTransactionHistory.pspInfo.pspId)
.idChannel(pmTransactionHistory.pspInfo.idChannel)
.businessName(pmTransactionHistory.pspInfo.businessName)
return TransactionResultDto()
.product(ProductDto.PM)
.userInfo(userInfo)
.transactionInfo(transactionInfo)
.paymentInfo(paymentInfo)
.pspInfo(pspInfo)
}

fun baseTransactionToTransactionInfoDtoV1(
baseTransaction: BaseTransaction,
email: Optional<Email>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package it.pagopa.ecommerce.helpdesk

import it.pagopa.ecommerce.commons.documents.v2.TransactionEvent
import it.pagopa.ecommerce.commons.v1.TransactionTestUtils
import it.pagopa.ecommerce.helpdesk.documents.PmTransactionHistory
import it.pagopa.generated.ecommerce.helpdesk.v2.model.*
import java.time.OffsetDateTime
import java.time.ZonedDateTime
Expand Down Expand Up @@ -93,4 +94,52 @@ object HelpdeskTestUtilsV2 {
.idChannel(TransactionTestUtils.PSP_CHANNEL_CODE)
)
.product(product)

fun buildPmTransactionHisotryResultDto(
creationDate: OffsetDateTime,
product: ProductDto
): PmTransactionHistory =
PmTransactionHistory(
id = UUID.randomUUID().toString(),
userInfo =
it.pagopa.ecommerce.helpdesk.documents.UserInfo(
userFiscalCode = "user fiscal code",
notificationEmail = TransactionTestUtils.EMAIL_STRING,
authenticationType = 0
),
transactionInfo =
it.pagopa.ecommerce.helpdesk.documents.TransactionInfo(
creationDate = creationDate.toString(),
status = 0,
statusDetails = 0,
amount = 500,
fee = 200,
grandTotal = 700,
rrn = "rrn",
authorizationCode = "authorization code",
paymentMethodName = "payment method name"
),
paymentInfo =
it.pagopa.ecommerce.helpdesk.documents.PaymentInfo(
origin = "origin",
details =
listOf(
it.pagopa.ecommerce.helpdesk.documents.PaymentDetailInfo(
subject = "subject name",
iuv = "IUV",
idTransaction = TransactionTestUtils.TRANSACTION_ID,
creditorInstitution = "creditor institution",
paFiscalCode = TransactionTestUtils.PA_FISCAL_CODE,
amount = 500
)
)
),
pspInfo =
it.pagopa.ecommerce.helpdesk.documents.PspInfo(
pspId = TransactionTestUtils.PSP_ID,
businessName = TransactionTestUtils.PSP_BUSINESS_NAME,
idChannel = TransactionTestUtils.PSP_CHANNEL_CODE
),
product = product.name
)
}
Loading

0 comments on commit 353aa27

Please sign in to comment.