Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [PAGOPA-2359] - serviceType field #29

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions helm/values-uat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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;
alessio-acitelli marked this conversation as resolved.
Show resolved Hide resolved
@Schema(description = "Array structure containing any payment options (there always exists at least 1)",
required = true)
private List<PaymentOption> paymentOptions;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package it.gov.pagopa.gpd.payments.pull.models.enums;

public enum ServiceType {
ACA, WISP, GPD
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<PaymentPosition> {

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
Expand All @@ -30,15 +41,16 @@ public class PaymentPositionRepository implements PanacheRepository<PaymentPosit
* @return
*/
public List<PaymentPosition> 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<PaymentNotice> 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) {
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ##
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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<PaymentPosition> result = assertDoesNotThrow(() -> paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate(
Expand All @@ -50,15 +54,18 @@ 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(
PaymentPosition.builder()
.iupd("iupd")
.status(DebtPositionStatus.VALID)
.type(Type.F)
.serviceType(ServiceType.GPD)
.build()));

List<PaymentPosition> result = assertDoesNotThrow(() -> paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate(
Expand All @@ -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<PaymentPosition> result = assertDoesNotThrow(() -> paymentPositionRepository.findPaymentPositionsByTaxCodeAndDueDate(
FISCAL_CODE, null, 50, 0));

assertNotNull(result);
assertEquals(1, result.size());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<PaymentNotice> 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);
}
Expand All @@ -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));
Expand All @@ -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> paymentOption = new ArrayList<>(
Expand Down
Loading