diff --git a/helm/values-uat.yaml b/helm/values-uat.yaml index 86e7a6b..daf911e 100644 --- a/helm/values-uat.yaml +++ b/helm/values-uat.yaml @@ -52,8 +52,8 @@ microservice-chart: cpu: "300m" autoscaling: enable: true - minReplica: 10 - maxReplica: 10 + minReplica: 1 + maxReplica: 1 pollingInterval: 10 # seconds cooldownPeriod: 50 # seconds triggers: diff --git a/src/main/java/it/gov/pagopa/gpd/payments/pull/entity/PaymentPosition.java b/src/main/java/it/gov/pagopa/gpd/payments/pull/entity/PaymentPosition.java index cedde0c..c875911 100644 --- a/src/main/java/it/gov/pagopa/gpd/payments/pull/entity/PaymentPosition.java +++ b/src/main/java/it/gov/pagopa/gpd/payments/pull/entity/PaymentPosition.java @@ -3,7 +3,9 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; + import it.gov.pagopa.gpd.payments.pull.models.enums.DebtPositionStatus; +import it.gov.pagopa.gpd.payments.pull.models.enums.ServiceType; import it.gov.pagopa.gpd.payments.pull.models.enums.Type; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -26,7 +28,6 @@ import lombok.Setter; import java.io.Serializable; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -107,7 +108,7 @@ public class PaymentPosition implements Serializable { private DebtPositionStatus status; @NotNull @Column(name = "last_updated_date") - private LocalDate lastUpdatedDate; + private LocalDateTime lastUpdatedDate; @Column(name = "payment_date") private LocalDateTime paymentDate; @@ -118,6 +119,11 @@ public class PaymentPosition implements Serializable { @Builder.Default @Column(name = "pull", columnDefinition = "boolean DEFAULT true") private Boolean pull = true; + + @NotNull + @Enumerated(EnumType.STRING) + @Column(name = "service_type") + private ServiceType serviceType; @Builder.Default @NotNull diff --git a/src/main/java/it/gov/pagopa/gpd/payments/pull/models/PaymentNotice.java b/src/main/java/it/gov/pagopa/gpd/payments/pull/models/PaymentNotice.java index 0808829..c981c52 100644 --- a/src/main/java/it/gov/pagopa/gpd/payments/pull/models/PaymentNotice.java +++ b/src/main/java/it/gov/pagopa/gpd/payments/pull/models/PaymentNotice.java @@ -7,7 +7,6 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema; import java.io.Serializable; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; @@ -20,7 +19,12 @@ @ToString public class PaymentNotice implements Serializable { - @Schema(description = "Unique ID of the Debt Position (for positions originating from ACA the IUPD starts with ACA_)", + /** + * + */ + private static final long serialVersionUID = -5951473285697199137L; + + @Schema(description = "Unique ID of the Debt Position", required = true) private String iupd; @Schema(description = "Tax code of the person to whom the Debt Position is registered", required = true) @@ -53,7 +57,7 @@ public class PaymentNotice implements Serializable { required = true) private PaymentNoticeStatus status; @Schema(description = "Date of update of the Debt Position", required = true) - private LocalDate lastUpdateDate; + private LocalDateTime lastUpdateDate; @Schema(description = "Array structure containing any payment options (there always exists at least 1)", required = true) private List paymentOptions; diff --git a/src/main/java/it/gov/pagopa/gpd/payments/pull/models/enums/ServiceType.java b/src/main/java/it/gov/pagopa/gpd/payments/pull/models/enums/ServiceType.java new file mode 100644 index 0000000..12a2547 --- /dev/null +++ b/src/main/java/it/gov/pagopa/gpd/payments/pull/models/enums/ServiceType.java @@ -0,0 +1,5 @@ +package it.gov.pagopa.gpd.payments.pull.models.enums; + +public enum ServiceType { + ACA, WISP, GPD +} diff --git a/src/main/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepository.java b/src/main/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepository.java index ca9b6a0..5c17879 100644 --- a/src/main/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepository.java +++ b/src/main/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepository.java @@ -8,17 +8,28 @@ import java.time.LocalDate; import java.util.List; +import org.eclipse.microprofile.config.inject.ConfigProperty; + @ApplicationScoped public class PaymentPositionRepository implements PanacheRepository { - public static final String GET_VALID_POSITIONS_BY_TAXCODE_BASE = - "from PaymentPosition AS ppos Where ppos.fiscalCode = ?1 " + - "AND ppos.status IN ('VALID', 'PARTIALLY_PAID') AND ppos.pull = true"; - public static final String GET_VALID_POSITIONS_BY_TAXCODE_AND_DUE_DATE = + @ConfigProperty(name = "app.payment_pull.keep_aca", defaultValue = "true") + public boolean keepAca; + + // the pull flag has no business value -> for future needs + private static final String BASE_QUERY = "from PaymentPosition AS ppos Where ppos.fiscalCode = ?1 " + - "AND ppos.status IN ('VALID', 'PARTIALLY_PAID') AND ppos.pull = true " + - "AND EXISTS (from ppos.paymentOption AS po WHERE po.dueDate >= ?2)"; + "AND ppos.status IN ('VALID', 'PARTIALLY_PAID') AND ppos.pull = true"; + private static final String DUE_DATE_QUERY = + BASE_QUERY + " AND EXISTS (from ppos.paymentOption AS po WHERE po.dueDate >= ?2)"; + + public String buildQuery(String query) { + return keepAca + ? query + " AND ppos.serviceType IN ('ACA', 'GPD')" + : query + " AND ppos.serviceType = 'GPD'"; + } + /** * Recovers a reactive stream of payment positions, using the debtor taxCode, and optionally the dueDate for which at least one * Payment Option must be valid. Uses limit and page to limit result size @@ -30,15 +41,16 @@ public class PaymentPositionRepository implements PanacheRepository findPaymentPositionsByTaxCodeAndDueDate( - String taxCode, LocalDate dueDate, Integer limit, Integer page - ) { - if (dueDate == null) { - return find(GET_VALID_POSITIONS_BY_TAXCODE_BASE, taxCode) - .page(Page.of(page, limit)) - .list(); - } - return find(GET_VALID_POSITIONS_BY_TAXCODE_AND_DUE_DATE, taxCode, dueDate.atStartOfDay()) - .page(Page.of(page, limit)) - .list(); + String taxCode, LocalDate dueDate, Integer limit, Integer page) { + + String query = (dueDate == null) ? buildQuery(BASE_QUERY) : buildQuery(DUE_DATE_QUERY); + + return dueDate == null + ? find(query, taxCode) + .page(Page.of(page, limit)) + .list() + : find(query, taxCode, dueDate.atStartOfDay()) + .page(Page.of(page, limit)) + .list(); } } diff --git a/src/main/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImpl.java b/src/main/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImpl.java index 1d4c057..1d9e2fc 100644 --- a/src/main/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImpl.java +++ b/src/main/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImpl.java @@ -9,7 +9,6 @@ import it.gov.pagopa.gpd.payments.pull.service.PaymentNoticesService; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import org.eclipse.microprofile.config.inject.ConfigProperty; import java.time.LocalDate; import java.util.List; @@ -20,14 +19,10 @@ public class PaymentNoticesServiceImpl implements PaymentNoticesService { @Inject PaymentPositionRepository paymentPositionRepository; - @ConfigProperty(name = "app.payment_pull.keep_aca", defaultValue = "true") - Boolean keepAca; - @Override public List getPaymentNotices(String taxCode, LocalDate dueDate, Integer limit, Integer page) { try { return getPositions(taxCode, dueDate, limit, page).parallelStream() - .filter(item -> keepAca || !item.getIupd().contains("ACA")) .map(PaymentNoticeMapper::manNotice) .toList(); } catch (PaymentNoticeException e) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 5c1e028..f7b3027 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -11,6 +11,7 @@ app.environment=${ENV:local} quarkus.default-locale=it-IT quarkus.locales=it-IT quarkus.native.additional-build-args=-H:ResourceConfigurationFiles=resources-config.json +quarkus.hibernate-orm.database.generation=none ################### ## LOG @@ -53,6 +54,9 @@ quarkus.datasource.db-kind=postgresql %test.quarkus.datasource.db-kind=h2 %test.quarkus.datasource.username=admin %test.quarkus.datasource.jdbc.url=jdbc:h2:mem:apd +%dev.quarkus.datasource.username=${GPD_DB_USERNAME} +%dev.quarkus.datasource.password=${GPD_DB_PASSWORD} +%dev.quarkus.datasource.jdbc.url=${GPD_DB_URL} ################ ## CUSTOM ## diff --git a/src/test/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepositoryTest.java b/src/test/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepositoryTest.java index 8a0e80f..29237df 100644 --- a/src/test/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepositoryTest.java +++ b/src/test/java/it/gov/pagopa/gpd/payments/pull/repository/PaymentPositionRepositoryTest.java @@ -5,7 +5,9 @@ import io.quarkus.test.junit.mockito.InjectSpy; import it.gov.pagopa.gpd.payments.pull.entity.PaymentPosition; import it.gov.pagopa.gpd.payments.pull.models.enums.DebtPositionStatus; +import it.gov.pagopa.gpd.payments.pull.models.enums.ServiceType; import it.gov.pagopa.gpd.payments.pull.models.enums.Type; + import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -14,8 +16,6 @@ import static it.gov.pagopa.gpd.payments.pull.Constants.DUE_DATE; import static it.gov.pagopa.gpd.payments.pull.Constants.FISCAL_CODE; -import static it.gov.pagopa.gpd.payments.pull.repository.PaymentPositionRepository.GET_VALID_POSITIONS_BY_TAXCODE_AND_DUE_DATE; -import static it.gov.pagopa.gpd.payments.pull.repository.PaymentPositionRepository.GET_VALID_POSITIONS_BY_TAXCODE_BASE; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -27,17 +27,21 @@ class PaymentPositionRepositoryTest { @InjectSpy PaymentPositionRepository paymentPositionRepository; + @Test void findNoticesOnRepositoryWithoutDueDate() { + // force keepAca to true + paymentPositionRepository.keepAca = true; PanacheQuery panacheQuery = Mockito.mock(PanacheQuery.class); - when(paymentPositionRepository.find(GET_VALID_POSITIONS_BY_TAXCODE_BASE, FISCAL_CODE)).thenReturn(panacheQuery); + when(paymentPositionRepository.find(paymentPositionRepository.buildQueryBase(), FISCAL_CODE)).thenReturn(panacheQuery); when(panacheQuery.page(any())).thenReturn(panacheQuery); when(panacheQuery.list()).thenReturn(Collections.singletonList( PaymentPosition.builder() .iupd("iupd") .status(DebtPositionStatus.VALID) .type(Type.F) + .serviceType(ServiceType.GPD) .build())); List result = assertDoesNotThrow(() -> paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate( @@ -50,8 +54,10 @@ void findNoticesOnRepositoryWithoutDueDate() { @Test void findNoticesOnRepositoryWithDueDate() { + // force keepAca to true + paymentPositionRepository.keepAca = true; PanacheQuery panacheQuery = Mockito.mock(PanacheQuery.class); - when(paymentPositionRepository.find(GET_VALID_POSITIONS_BY_TAXCODE_AND_DUE_DATE, FISCAL_CODE, DUE_DATE.atStartOfDay())) + when(paymentPositionRepository.find(paymentPositionRepository.buildQueryWithDueDate(), FISCAL_CODE, DUE_DATE.atStartOfDay())) .thenReturn(panacheQuery); when(panacheQuery.page(any())).thenReturn(panacheQuery); when(panacheQuery.list()).thenReturn(Collections.singletonList( @@ -59,6 +65,7 @@ void findNoticesOnRepositoryWithDueDate() { .iupd("iupd") .status(DebtPositionStatus.VALID) .type(Type.F) + .serviceType(ServiceType.GPD) .build())); List result = assertDoesNotThrow(() -> paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate( @@ -67,4 +74,26 @@ void findNoticesOnRepositoryWithDueDate() { assertNotNull(result); assertEquals(1, result.size()); } + + @Test + void findNoticesOnRepositoryForKeepACAFalse() { + // force keepAca to false + paymentPositionRepository.keepAca = false; + PanacheQuery panacheQuery = Mockito.mock(PanacheQuery.class); + when(paymentPositionRepository.find(paymentPositionRepository.buildQueryBase(), FISCAL_CODE)).thenReturn(panacheQuery); + when(panacheQuery.page(any())).thenReturn(panacheQuery); + when(panacheQuery.list()).thenReturn(Collections.singletonList( + PaymentPosition.builder() + .iupd("iupd") + .status(DebtPositionStatus.VALID) + .type(Type.F) + .serviceType(ServiceType.GPD) + .build())); + + List result = assertDoesNotThrow(() -> paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate( + FISCAL_CODE, null, 50, 0)); + + assertNotNull(result); + assertEquals(1, result.size()); + } } \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImplTest.java b/src/test/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImplTest.java index f27a9b1..36b4c86 100644 --- a/src/test/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImplTest.java +++ b/src/test/java/it/gov/pagopa/gpd/payments/pull/service/impl/PaymentNoticesServiceImplTest.java @@ -8,6 +8,7 @@ import it.gov.pagopa.gpd.payments.pull.models.PaymentNotice; import it.gov.pagopa.gpd.payments.pull.models.enums.AppErrorCodeEnum; import it.gov.pagopa.gpd.payments.pull.models.enums.DebtPositionStatus; +import it.gov.pagopa.gpd.payments.pull.models.enums.ServiceType; import it.gov.pagopa.gpd.payments.pull.models.enums.Type; import it.gov.pagopa.gpd.payments.pull.repository.PaymentPositionRepository; import jakarta.inject.Inject; @@ -40,19 +41,19 @@ class PaymentNoticesServiceImplTest { @Test void getPaymentNoticesShouldReturnOK() { when(paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate(FISCAL_CODE, DUE_DATE, 50, 0)) - .thenReturn(Arrays.asList(createPaymentPosition("", false), - createPaymentPosition("ACA_", false), - createPaymentPosition("PARTIAL_", true))); + .thenReturn(Arrays.asList(createPaymentPosition("", false, ServiceType.GPD), + createPaymentPosition("ACA_", false, ServiceType.ACA), + createPaymentPosition("PARTIAL_", true, ServiceType.GPD))); List response = assertDoesNotThrow(() -> paymentNoticesService.getPaymentNotices(FISCAL_CODE, DUE_DATE, 50, 0)); assertNotNull(response); - assertEquals(2, response.size()); + assertEquals(3, response.size()); assertEquals("iupd", response.get(0).getIupd()); assertEquals(1, response.get(0).getPaymentOptions().size()); assertEquals(1, response.get(1).getPaymentOptions().size()); - assertEquals(2, response.get(1).getPaymentOptions().get(0).getInstallments().size()); + assertEquals(2, response.get(2).getPaymentOptions().get(0).getInstallments().size()); verify(paymentPositionRepository).findPaymentPositionsByTaxCodeAndDueDate( FISCAL_CODE, DUE_DATE, 50, 0); } @@ -70,7 +71,7 @@ void getPaymentNoticesShouldReturnExceptionOnRepositoryError() { @Test void getPaymentNoticesShouldReturnExceptionOnMappingError() { - PaymentPosition paymentPosition = createPaymentPosition("", true); + PaymentPosition paymentPosition = createPaymentPosition("", true, ServiceType.GPD); paymentPosition.setPaymentOption(null); when(paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate(FISCAL_CODE, DUE_DATE, 50, 0)) .thenReturn(Collections.singletonList(paymentPosition)); @@ -81,11 +82,12 @@ void getPaymentNoticesShouldReturnExceptionOnMappingError() { assertEquals(AppErrorCodeEnum.PPL_800, e.getErrorCode()); } - private PaymentPosition createPaymentPosition(String prefix, Boolean isPartialPayment) { + private PaymentPosition createPaymentPosition(String prefix, Boolean isPartialPayment, ServiceType serviceType) { PaymentPosition paymentPosition = PaymentPosition.builder() .iupd(prefix + "iupd") .status(DebtPositionStatus.VALID) .type(Type.F) + .serviceType(serviceType) .build(); List paymentOption = new ArrayList<>(