Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4ceb6eb
Report Generation API Creation
martameligarziera Feb 6, 2026
be7bdb2
Report Generation API Creation- rename generateMerchantTransactionsRe…
martameligarziera Feb 6, 2026
2cf54fe
Report Generation API Creation- rename generateMerchantTransactionsRe…
martameligarziera Feb 10, 2026
0c6779a
Merge branch 'develop' of https://github.com/pagopa/idpay-transaction…
martameligarziera Feb 10, 2026
d1bd263
Merge remote-tracking branch 'refs/remotes/origin/UPBE-591-be-creazio…
v1tt0ri0Alt Feb 10, 2026
f3f7814
Report Generation API Creation - implementation
martameligarziera Feb 10, 2026
661c15b
Merge remote-tracking branch 'refs/remotes/origin/UPBE-591-be-creazio…
v1tt0ri0Alt Feb 11, 2026
fc87d0e
added getReportList in ReportController
v1tt0ri0Alt Feb 11, 2026
4f8ece0
Report Generation API Creation - implementation
martameligarziera Feb 11, 2026
228312c
Report Generation API Creation - collection name reports
martameligarziera Feb 11, 2026
dc2a8b3
added unit test for ReportController, ReportMapper, ReportServiceImpl…
v1tt0ri0Alt Feb 11, 2026
05e8d1f
Log injection
martameligarziera Feb 11, 2026
e3ba038
removed unused import
v1tt0ri0Alt Feb 11, 2026
72d118c
Log injection
martameligarziera Feb 11, 2026
0de0022
Log injection
martameligarziera Feb 11, 2026
7df2851
Merge branch 'UPBE-601-be-creazione-api-lista-report' of https://gith…
martameligarziera Feb 11, 2026
4bcf279
fix tests
martameligarziera Feb 12, 2026
2b82c19
coverage
martameligarziera Feb 12, 2026
79a4ec8
coverage
martameligarziera Feb 12, 2026
c8646aa
log injection
martameligarziera Feb 12, 2026
250a8ea
Merge branch 'develop' of https://github.com/pagopa/idpay-transaction…
martameligarziera Feb 12, 2026
52f3f98
deleting parameter operatorlevel
martameligarziera Feb 12, 2026
a746933
fix tests
martameligarziera Feb 12, 2026
5219cd5
modified getTransactionsReports
v1tt0ri0Alt Feb 12, 2026
ed5c06e
Merge branch 'UPBE-601-be-creazione-api-lista-report' of https://gith…
martameligarziera Feb 12, 2026
7355316
chaged endPoints
martameligarziera Feb 12, 2026
62b91cf
modified ReportServiceImpl and adjusted ReportControllerImplTest
v1tt0ri0Alt Feb 12, 2026
ce700d7
chaged endPoints
martameligarziera Feb 12, 2026
bdec236
patchReport - status
martameligarziera Feb 12, 2026
2c2e837
COMMENT
martameligarziera Feb 12, 2026
f201a60
coverage
martameligarziera Feb 12, 2026
cb504d0
handling merchant not found
martameligarziera Feb 12, 2026
a111da5
fix tests
martameligarziera Feb 12, 2026
11d55f0
log injection
martameligarziera Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ microservice-chart:

rest-client:
PDV_BASE_URL: pdv_decrypt_base_url
MERCHANT_BASE_URL: idpay_merchant_host

envSecret:
MONGODB_URI: mongodb-connection-string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package it.gov.pagopa.idpay.transactions.connector.rest;

import it.gov.pagopa.idpay.transactions.connector.rest.dto.MerchantDetailDTO;
import it.gov.pagopa.idpay.transactions.connector.rest.dto.PointOfSaleDTO;
import reactor.core.publisher.Mono;

public interface MerchantRestClient {

Mono<PointOfSaleDTO> getPointOfSale(String merchantId, String pointOfSaleId);

Mono<MerchantDetailDTO> getMerchantDetail(String merchantId, String initiativeId);


}
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
package it.gov.pagopa.idpay.transactions.connector.rest;

import it.gov.pagopa.common.reactive.utils.PerformanceLogger;
import it.gov.pagopa.common.web.exception.ClientExceptionWithBody;
import it.gov.pagopa.idpay.transactions.connector.rest.dto.MerchantDetailDTO;
import it.gov.pagopa.idpay.transactions.connector.rest.dto.PointOfSaleDTO;
import java.time.Duration;
import java.util.Map;

import it.gov.pagopa.idpay.transactions.utils.Utilities;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;

import static it.gov.pagopa.idpay.transactions.utils.ExceptionConstants.ExceptionCode.MERCHANT_NOT_FOUND;
import static it.gov.pagopa.idpay.transactions.utils.ExceptionConstants.ExceptionMessage.ERROR_MESSAGE_MERCHANT_NOT_FOUND;

@Service
@Slf4j
@CacheConfig
public class MerchantRestClientImpl implements MerchantRestClient {

private static final String URI_POS_DETAIL = "/idpay/merchant/portal/{merchantId}/point-of-sales/{pointOfSaleId}";
private static final String URI_MERCHANT_DETAIL = "/idpay/merchant/portal/initiatives/{initiativeId}";
private final WebClient webClient;
private final int retryDelay;
private final long maxAttempts;
Expand Down Expand Up @@ -81,4 +90,41 @@ public Mono<PointOfSaleDTO> getPointOfSale(String merchantId, String pointOfSale
return Mono.empty();
});
}

@Override
public Mono<MerchantDetailDTO> getMerchantDetail(String merchantId, String initiativeId) {
log.info("Sending request to merchant {} to get merchant details", Utilities.sanitizeString(merchantId));

return webClient
.get()
.uri(URI_MERCHANT_DETAIL, Map.of("initiativeId", initiativeId))
.header("x-merchant-id", merchantId)
.retrieve()
.onStatus(HttpStatus.NOT_FOUND::equals, response ->
response.bodyToMono(String.class)
.flatMap(body -> {
log.warn("Merchant not found for merchantId {}", Utilities.sanitizeString(merchantId));
return Mono.error(new ClientExceptionWithBody(
HttpStatus.NOT_FOUND,
MERCHANT_NOT_FOUND,
ERROR_MESSAGE_MERCHANT_NOT_FOUND.formatted(merchantId, initiativeId)
));
})
)
.bodyToMono(MerchantDetailDTO.class)
.retryWhen(
Retry.fixedDelay(maxAttempts, Duration.ofMillis(retryDelay))
.filter(ex ->
ex instanceof WebClientResponseException.TooManyRequests ||
ex.getMessage().startsWith("Connection refused")
)
)
.onErrorResume(WebClientResponseException.BadRequest.class, ex -> {
log.warn("Invalid request for merchant {}", Utilities.sanitizeString(merchantId));
return Mono.empty();
});
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package it.gov.pagopa.idpay.transactions.connector.rest.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MerchantDetailDTO {

private String businessName;

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ Mono<MerchantTransactionsListDTO> getMerchantTransactions(@RequestHeader("x-merc
Mono<List<String>> getProcessedTransactionStatuses(
@RequestHeader(value = "x-organization-role", required = false) String organizationRole);




}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ public Mono<List<String>> getProcessedTransactionStatuses(
return merchantTransactionService.getProcessedTransactionStatuses(
organizationRole);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package it.gov.pagopa.idpay.transactions.controller;

import it.gov.pagopa.idpay.transactions.dto.PatchReportRequest;
import it.gov.pagopa.idpay.transactions.dto.ReportDTO;
import it.gov.pagopa.idpay.transactions.dto.ReportListDTO;
import it.gov.pagopa.idpay.transactions.dto.ReportRequest;
import jakarta.validation.Valid;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

@RequestMapping("/idpay/merchant/portal")
public interface ReportController {

@GetMapping("/initiatives/{initiativeId}/reports")
Mono<ReportListDTO> getTransactionsReports(
@RequestHeader(value = "x-merchant-id", required = false) String merchantId,
@RequestHeader(value = "x-organization-role", required = false) String organizationRole,
@PathVariable("initiativeId") String initiativeId,
@PageableDefault Pageable pageable
);

@PostMapping("/initiatives/{initiativeId}/reports")
Mono<ReportDTO> generateReport(@RequestHeader("x-merchant-id") String merchantId,
@RequestHeader(value = "x-organization-role", required = false) String organizationRole,
@PathVariable("initiativeId") String initiativeId,
@RequestBody @Valid ReportRequest request);


@PatchMapping("/initiatives/{initiativeId}/reports/{reportId}")
Mono<ReportDTO> patchReport(@PathVariable("initiativeId") String initiativeId,
@PathVariable("reportId") String reportId,
@RequestBody PatchReportRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package it.gov.pagopa.idpay.transactions.controller;

import it.gov.pagopa.idpay.transactions.dto.PatchReportRequest;
import it.gov.pagopa.idpay.transactions.dto.ReportDTO;
import it.gov.pagopa.idpay.transactions.dto.ReportListDTO;
import it.gov.pagopa.idpay.transactions.dto.ReportRequest;
import it.gov.pagopa.idpay.transactions.service.ReportService;
import it.gov.pagopa.idpay.transactions.dto.mapper.ReportMapper;
import it.gov.pagopa.idpay.transactions.utils.Utilities;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
@Slf4j
public class ReportControllerImpl implements ReportController {

private final ReportService reportService;
private final ReportMapper reportMapper;

public ReportControllerImpl(ReportService reportService, ReportMapper reportMapper) {
this.reportService = reportService;
this.reportMapper = reportMapper;
}

@Override
public Mono<ReportListDTO> getTransactionsReports(
String merchantId,
String organizationRole,
String initiativeId,
Pageable pageable
) {
log.info("[GET_TRANSACTIONS_REPORTS] Request received for initiative: {}", Utilities.sanitizeString(initiativeId));

return reportService.getTransactionsReports(merchantId, organizationRole, initiativeId, pageable)
.flatMap(page -> Mono.just(reportMapper.toListDTO(page)));
}


@Override
public Mono<ReportDTO> generateReport(String merchantId,
String organizationRole,
String initiativeId,
ReportRequest request
) {
return reportService.generateReport(merchantId, organizationRole, initiativeId, request);
}


@Override
public Mono<ReportDTO> patchReport(String initiativeId,
String reportId,
PatchReportRequest request
) {
return reportService.patchReport(initiativeId, reportId, request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package it.gov.pagopa.idpay.transactions.dto;

import it.gov.pagopa.idpay.transactions.enums.ReportStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class PatchReportRequest {

private ReportStatus reportStatus;

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package it.gov.pagopa.idpay.transactions.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import it.gov.pagopa.idpay.transactions.enums.ReportStatus;
import it.gov.pagopa.idpay.transactions.enums.ReportType;
import it.gov.pagopa.idpay.transactions.enums.RewardBatchAssignee;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@AllArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ReportDTO {

String id;
String initiativeId;
ReportStatus reportStatus;
LocalDateTime startPeriod;
LocalDateTime endPeriod;
String merchantId;
String businessName;
LocalDateTime requestDate;
LocalDateTime elaborationDate;
RewardBatchAssignee operatorLevel;
String fileName;
ReportType reportType;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package it.gov.pagopa.idpay.transactions.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReportListDTO {
private List<ReportDTO> reports;
private int page;
private int size;
private int totalElements;
private int totalPages;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package it.gov.pagopa.idpay.transactions.dto;

import it.gov.pagopa.idpay.transactions.enums.ReportType;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReportRequest {

@NotNull
private LocalDateTime startPeriod;
@NotNull
private LocalDateTime endPeriod;
@NotNull
private ReportType reportType;

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package it.gov.pagopa.idpay.transactions.dto.mapper;

import it.gov.pagopa.idpay.transactions.dto.ReportDTO;
import it.gov.pagopa.idpay.transactions.dto.ReportListDTO;
import it.gov.pagopa.idpay.transactions.model.Report;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class ReportMapper {

public ReportDTO toDTO(Report report) {
if (report == null) {
return null;
}

return ReportDTO.builder()
.id(report.getId())
.initiativeId(report.getInitiativeId())
.reportStatus(report.getReportStatus())
.startPeriod(report.getStartPeriod())
.endPeriod(report.getEndPeriod())
.merchantId(report.getMerchantId())
.businessName(report.getBusinessName())
.requestDate(report.getRequestDate())
.elaborationDate(report.getElaborationDate())
.operatorLevel(report.getOperatorLevel())
.fileName(report.getFileName())
.reportType(report.getReportType())
.build();
}

public ReportListDTO toListDTO(Page<Report> page) {
List<ReportDTO> dtoList = page.getContent()
.stream()
.map(this::toDTO)
.collect(Collectors.toList());

return ReportListDTO.builder()
.reports(dtoList)
.page(page.getNumber())
.size(page.getSize())
.totalElements((int) page.getTotalElements())
.totalPages(page.getTotalPages())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package it.gov.pagopa.idpay.transactions.enums;

public enum ReportStatus {
INSERTED,
FAILED,
IN_PROGRESS,
GENERATED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package it.gov.pagopa.idpay.transactions.enums;

public enum ReportType {
MERCHANT_TRANSACTIONS
}
Loading
Loading