Add scripts folder

This commit is contained in:
Ramon Ramirez 2026-01-09 18:37:46 -04:00
parent 066b002aa3
commit 7371422ac5
13 changed files with 193 additions and 80 deletions

31
scripts/native/Dockerfile Normal file
View File

@ -0,0 +1,31 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
# It uses a micro base image, tuned for Quarkus native executables.
# It reduces the size of the resulting container image.
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/rec-legal-customer-product-directory .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/rec-legal-customer-product-directory
#
###
FROM quay.io/quarkus/quarkus-micro-image:2.0
RUN mkdir -p /work
ENV TZ="America/Caracas"
ENV LANGUAGE='en_US:en'
VOLUME /tmp
COPY /file/*-runner /work/app
RUN chmod -R 775 /work
RUN ls -ltra /work/
EXPOSE 8080
WORKDIR /work/
ENTRYPOINT ["./app", "-Dquarkus.http.host=0.0.0.0"]

View File

@ -5,7 +5,7 @@ import com.banesco.common.domain.exception.InternalServerException;
import com.banesco.common.domain.model.ApiResponse;
import com.banesco.common.domain.model.ErrorMapping;
import com.banesco.common.domain.model.StatusResponse;
import com.banesco.common.infrastructure.config.ErrorMessagesConfig;
import com.banesco.common.infrastructure.config.MessagesConfig;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.runtime.annotations.RegisterForReflection;
@ -22,9 +22,9 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@ApplicationScoped
@RegisterForReflection
public class ErrorResponseHelper {
public class MessageResponseHelper {
private final ErrorMessagesConfig errorMessagesConfig;
private final MessagesConfig messagesConfig;
private final Map<String, ErrorMapping> errorMappings;
private static final String ERROR_DEFAULT = "default";
private static final String SUCCESS_DEFAULT = "200";
@ -32,19 +32,15 @@ public class ErrorResponseHelper {
private final ObjectMapper objectMapper;
@Inject
public ErrorResponseHelper(
public MessageResponseHelper(
ObjectMapper objectMapper,
ErrorMessagesConfig errorMessagesConfig
MessagesConfig messagesConfig
) {
this.objectMapper = objectMapper;
this.errorMessagesConfig = errorMessagesConfig;
this.messagesConfig = messagesConfig;
this.errorMappings = initializeErrorMappings();
}
// Ya no es una clase interna, ahora usa la clase del dominio
// Solo necesitas mantener la referencia al tipo
// Si ErrorMapping está en otro paquete, asegúrate de importarlo
public Response handleException(BaseApiException exception) {
return buildErrorResponse(exception);
}
@ -115,7 +111,7 @@ public class ErrorResponseHelper {
String json;
if (isReadingFromProps()) {
json = errorMessagesConfig.getErrorMessagesJson();
json = messagesConfig.getErrorMessagesJson();
log.info("Cargando mensajes de errores desde properties");
} else {
json = loadFromJsonFile();
@ -151,7 +147,7 @@ public class ErrorResponseHelper {
}
private String loadFromJsonFile() {
try (InputStream is = ErrorResponseHelper.class.getClassLoader().getResourceAsStream(ERROR_FILE_PATH)) {
try (InputStream is = MessageResponseHelper.class.getClassLoader().getResourceAsStream(ERROR_FILE_PATH)) {
if (is == null) {
log.warn("No se encontró el archivo de errores: {}", ERROR_FILE_PATH);
return "";
@ -189,6 +185,6 @@ public class ErrorResponseHelper {
}
public boolean isReadingFromProps() {
return errorMessagesConfig.isReadFromProps();
return messagesConfig.isReadFromProps();
}
}

View File

@ -5,16 +5,64 @@ import jakarta.inject.Inject;
import lombok.Getter;
import org.eclipse.microprofile.config.Config;
import java.util.Arrays;
import java.util.List;
@ApplicationScoped
@Getter
public class DataSourceConfig {
private final String spName;
private final String spIbsError;
private final List<String> spAccountStatusEnable;
private final List<String> spAccountStatusDisabled;
private final List<String> spAccountTypeSaving;
private final List<String> spAccountTypeCurrent;
private final List<String> spAccountTypeInterestArrangement;
private final List<String> spAccountParent;
private final List<String> spCurrencyBase;
@Inject
public DataSourceConfig(Config config) {
this.spName = config.getValue("datasource.sp.name", String.class);
this.spIbsError = config.getValue("datasource.sp.errors.ibs", String.class).toUpperCase();
this.spAccountStatusEnable = Arrays.stream(config.getValue(
"datasource.sp.allowed.account-status.enable",
String.class
).toUpperCase().split(",")).toList();
this.spAccountStatusDisabled = Arrays.stream(config.getValue(
"datasource.sp.allowed.account-status.disable",
String.class
).toUpperCase().split(",")).toList();
this.spAccountTypeSaving = Arrays.stream(config.getValue(
"datasource.sp.allowed.account-type.saving",
String.class
).toUpperCase().split(",")).toList();
this.spAccountTypeCurrent = Arrays.stream(config.getValue(
"datasource.sp.allowed.account-type.current",
String.class
).toUpperCase().split(",")).toList();
this.spAccountTypeInterestArrangement = Arrays.stream(config.getValue(
"datasource.sp.allowed.account-type.interest-arrangement",
String.class
).toUpperCase().split(",")).toList();
this.spAccountParent = Arrays.stream(config.getValue(
"datasource.sp.allowed.account-relationship-type.parent",
String.class
).toUpperCase().split(",")).toList();
this.spCurrencyBase = Arrays.stream(config.getValue(
"datasource.sp.allowed.currency.base",
String.class
).toUpperCase().split(",")).toList();
}
}

View File

@ -7,7 +7,7 @@ import org.eclipse.microprofile.config.Config;
@ApplicationScoped
@Getter
public class ErrorMessagesConfig {
public class MessagesConfig {
private final boolean readFromProps;
private final String errorMessagesJson;
@ -16,7 +16,7 @@ public class ErrorMessagesConfig {
private static final String KEY = "domLogalCustomerProductDirectory";
@Inject
public ErrorMessagesConfig(Config config) {
public MessagesConfig(Config config) {
this.readFromProps = config.getValue("api.read-messages.from-props", Boolean.class);
this.errorMessagesJson = config.getValue("api." + KEY + ".messages.content", String.class);
this.messagesKey = config.getValue("api." + KEY + ".messages.key", String.class);

View File

@ -3,6 +3,7 @@ package com.banesco.module.account.domain.model;
import com.banesco.module.party.domain.model.Party;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.*;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Getter
@ToString
@ -12,5 +13,6 @@ import lombok.*;
@RegisterForReflection
public class AccountInvolvement {
private AccountInvolvementType accountInvolvementType;
@Schema(description = "Información del cliente")
private Party partyReference;
}

View File

@ -1,8 +1,7 @@
package com.banesco.module.legal_customer_product_directory.application.service;
import com.banesco.common.domain.exception.BadRequestException;
import com.banesco.common.domain.exception.BaseApiException;
import com.banesco.common.domain.exception.ServiceUnavailableException;
import com.banesco.common.application.helper.MessageResponseHelper;
import com.banesco.common.domain.exception.*;
import com.banesco.common.domain.model.*;
import com.banesco.module.account.domain.model.*;
import com.banesco.module.legal_customer_product_directory.application.repository.PersistenceRepository;
@ -18,12 +17,15 @@ import lombok.extern.slf4j.Slf4j;
@ApplicationScoped
public class LegalCustomerProductDirectoryService implements LegalCustomerProductDirectoryUseCase {
private final MessageResponseHelper messageResponseHelper;
private final PersistenceRepository persistenceRepository;
@Inject
public LegalCustomerProductDirectoryService(
MessageResponseHelper messageResponseHelper,
PersistenceRepository persistenceRepository
) {
this.messageResponseHelper = messageResponseHelper;
this.persistenceRepository = persistenceRepository;
}
@ -38,6 +40,9 @@ public class LegalCustomerProductDirectoryService implements LegalCustomerProduc
} catch (BaseApiException e) {
log.warn("Excepción controlada del sp: {} -> {}", e.getErrorCode(), e.getMessage());
throw e;
} catch (PersistenceException e) {
log.warn("Excepción de la persistencia del sp: {} -> {}", e.getErrorCode(), e.getMessage());
throw new BadRequestException(e.getErrorCode(), null);
} catch (Exception e) {
log.warn("Excepción generica del sp: {}", e.getMessage());
throw new ServiceUnavailableException("503", e.getMessage(), null);
@ -52,17 +57,14 @@ public class LegalCustomerProductDirectoryService implements LegalCustomerProduc
CustomerProductAndServiceDirectory response = persistenceRepository.execute(request);
if(response == null) {
throw new BadRequestException("503", null);
throw new BadRequestException("400", null);
}
return new ApiResponse<>(
LegalCustomerProductDirectoryResponse.builder()
.customerProductAndServiceDirectory(response)
.build(),
StatusResponse.builder()
.statusCode("200")
.message("Operación exitosa")
.build()
messageResponseHelper.createSuccessResponse("200")
);
}
}

View File

@ -1,7 +1,6 @@
package com.banesco.module.legal_customer_product_directory.domain.model;
import com.banesco.module.account.domain.model.Account;
import com.banesco.module.party.domain.model.Party;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.*;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

View File

@ -1,5 +1,6 @@
package com.banesco.module.legal_customer_product_directory.infrastructure.adapter;
import com.banesco.common.infrastructure.config.DataSourceConfig;
import com.banesco.module.legal_customer_product_directory.application.repository.PersistenceRepository;
import com.banesco.module.legal_customer_product_directory.domain.dto.request.LegalCustomerProductDirectoryRequest;
import com.banesco.module.legal_customer_product_directory.domain.dto.response.SPAccountResponse;
@ -16,12 +17,15 @@ import java.util.List;
@ApplicationScoped
public class PersistenceAdapter implements PersistenceRepository {
private final DataSourceConfig dataSourceConfig;
private final AccountRepository accountRepository;
@Inject
public PersistenceAdapter(
DataSourceConfig dataSourceConfig,
AccountRepository accountRepository
) {
this.dataSourceConfig = dataSourceConfig;
this.accountRepository = accountRepository;
}
@ -29,7 +33,9 @@ public class PersistenceAdapter implements PersistenceRepository {
public CustomerProductAndServiceDirectory execute(
LegalCustomerProductDirectoryRequest request
) {
List<SPAccountResponse> accountsFromSP = accountRepository.execute(request);
List<SPAccountResponse> accountsFromSP = accountRepository.execute(
dataSourceConfig, request
);
log.info("Cuentas obtenidas por el SP: {}", accountsFromSP.size());
@ -38,7 +44,9 @@ public class PersistenceAdapter implements PersistenceRepository {
}
return CustomerProductAndServiceDirectory.builder()
.accounts(accountsFromSP.stream().map(AccountMapper::toAccount).toList())
.accounts(accountsFromSP.stream().map(spAccount ->
AccountMapper.toAccount(dataSourceConfig, spAccount)
).toList())
.build();
}
}

View File

@ -1,6 +1,7 @@
package com.banesco.module.legal_customer_product_directory.infrastructure.persistence.mapper;
import com.banesco.common.domain.model.*;
import com.banesco.common.infrastructure.config.DataSourceConfig;
import com.banesco.module.account.domain.model.*;
import com.banesco.module.legal_customer_product_directory.domain.dto.response.SPAccountResponse;
import com.banesco.module.party.domain.model.Party;
@ -14,29 +15,31 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class AccountMapper {
private AccountMapper() {}
public static Account toAccount(
SPAccountResponse spAccountResponse
DataSourceConfig dataSourceConfig,
SPAccountResponse response
) {
String accountType = response.getTipoCta().toUpperCase();
String currency = response.getMoneda().toUpperCase();
String parent = response.getParentChild().toUpperCase();
AccountStatus status = AccountStatus.builder()
.status(spAccountResponse.getEstatus())
.statusType((Objects.equals(spAccountResponse.getEstatus(), "A")) ?
AccountStatusType.ENABLED :
AccountStatusType.DISABLED
)
.status(response.getEstatus())
.statusType(getAccountStatusType(dataSourceConfig, response))
.build();
AccountType type = (Objects.equals(spAccountResponse.getTipoCta().toUpperCase(), "SAV"))
AccountType type = (dataSourceConfig.getSpAccountTypeSaving().contains(accountType))
? AccountType.SAVING_ACCOUNT
: AccountType.CURRENT_ACCOUNT;
List<AccountCurrency> currencies = List.of(
AccountCurrency.builder()
.currencyCode(spAccountResponse.getMoneda().toUpperCase())
.currencyType((Objects.equals(spAccountResponse.getMoneda().toUpperCase(), "BS"))
.currencyCode(currency)
.currencyType((dataSourceConfig.getSpCurrencyBase().contains(currency))
? CurrencyType.BASE
: CurrencyType.SECONDARY
)
@ -44,13 +47,13 @@ public class AccountMapper {
);
List<AccountRelationship> relationships = List.of(
AccountRelationship.builder()
.accountRelationshipType((Objects.equals(spAccountResponse.getParentChild().toUpperCase(), "PADRE"))
.accountRelationshipType((dataSourceConfig.getSpAccountParent().contains(parent))
? AccountRelationshipType.ACCOUNT_IS_PARENT_ACCOUNT_FOR_ACCOUNT
: AccountRelationshipType.ACCOUNT_IS_SUB_ACCOUNT_FOR_ACCOUNT
)
.build()
);
List<Agreement> agreements = (Objects.equals(spAccountResponse.getTipoCta().toUpperCase(), "MMK")) ? List.of(
List<Agreement> agreements = (dataSourceConfig.getSpAccountTypeInterestArrangement().contains(accountType)) ? List.of(
Agreement.builder()
.arrangement(List.of(
Arrangement.builder()
@ -66,7 +69,7 @@ public class AccountMapper {
Party.builder()
.partyName(List.of(
Name.builder()
.fullName(spAccountResponse.getNombre())
.fullName(response.getNombre())
.build()
))
.partyType(PartyType.ORGANISATION)
@ -74,19 +77,19 @@ public class AccountMapper {
PartyIdentification.builder()
.partyIdentificationType(PartyIdentificationType.TAX_IDENTIFICATION_NUMBER)
.partyIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getRif())
.identifierValue(response.getRif())
.build())
.build(),
PartyIdentification.builder()
.partyIdentificationType(PartyIdentificationType.TELEPHONE_NUMBER)
.partyIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getCelular())
.identifierValue(response.getCelular())
.build())
.build(),
PartyIdentification.builder()
.partyIdentificationType(PartyIdentificationType.TELEPHONE_OPERATOR)
.partyIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getOperadora())
.identifierValue(response.getOperadora())
.build())
.build()
))
@ -99,8 +102,8 @@ public class AccountMapper {
return Account.builder()
.accountStatus(status)
.accountType(type)
.accountIdentification(getAccountIdentifications(spAccountResponse))
.accountBalance(getAccountBalances(spAccountResponse))
.accountIdentification(getAccountIdentifications(response))
.accountBalance(getAccountBalances(response))
.accountCurrency(currencies)
.accountInvolvement(involvements)
.accountRelationship(relationships)
@ -108,59 +111,70 @@ public class AccountMapper {
.build();
}
private static AccountStatusType getAccountStatusType(
DataSourceConfig dataSourceConfig,
SPAccountResponse response
) {
String accountStatus = response.getEstatus().toUpperCase();
if (dataSourceConfig.getSpAccountStatusEnable().contains(accountStatus)) return AccountStatusType.ENABLED;
if (dataSourceConfig.getSpAccountStatusDisabled().contains(accountStatus)) return AccountStatusType.DISABLED;
return AccountStatusType.PENDING;
}
private static List<AccountIdentification> getAccountIdentifications(
SPAccountResponse spAccountResponse
SPAccountResponse response
) {
return List.of(
AccountIdentification.builder()
.accountIdentificationType(AccountIdentificationType.ACCOUNT_NUMBER)
.accountIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getCuenta())
.identifierValue(response.getCuenta())
.build())
.build(),
AccountIdentification.builder()
.accountIdentificationType(AccountIdentificationType.BANK_NUMBER)
.accountIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getBanco())
.identifierValue(response.getBanco())
.build())
.build(),
AccountIdentification.builder()
.accountIdentificationType(AccountIdentificationType.PRODUCT_CODE)
.accountIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getProducto())
.identifierValue(response.getProducto())
.build())
.build(),
AccountIdentification.builder()
.accountIdentificationType(AccountIdentificationType.ACCOUNT_CLASS)
.accountIdentification(Identifier.builder()
.identifierValue(spAccountResponse.getClaseCta())
.identifierValue(response.getClaseCta())
.build())
.build()
);
}
private static List<AccountBalance> getAccountBalances(
SPAccountResponse spAccountResponse
SPAccountResponse response
) {
return List.of(
AccountBalance.builder()
.balanceAmount(spAccountResponse.getSaldoDisponible())
.balanceAmount(response.getSaldoDisponible())
.balanceType(BalanceType.AVAILABLE_BALANCE)
.build(),
AccountBalance.builder()
.balanceAmount(spAccountResponse.getMaxDia())
.balanceAmount(response.getMaxDia())
.balanceType(BalanceType.DAILY_MAXIMUM)
.build(),
AccountBalance.builder()
.balanceAmount(spAccountResponse.getMaxMens())
.balanceAmount(response.getMaxMens())
.balanceType(BalanceType.MONTHLY_MAXIMUM)
.build(),
AccountBalance.builder()
.balanceAmount(spAccountResponse.getMinTran())
.balanceAmount(response.getMinTran())
.balanceType(BalanceType.TRANSACTION_MINIMUM)
.build(),
AccountBalance.builder()
.balanceAmount(spAccountResponse.getMaxTran())
.balanceAmount(response.getMaxTran())
.balanceType(BalanceType.TRANSACTION_MAXIMUM)
.build()
);

View File

@ -1,6 +1,5 @@
package com.banesco.module.legal_customer_product_directory.infrastructure.persistence.repository;
import com.banesco.common.domain.exception.BadRequestException;
import com.banesco.common.domain.exception.PersistenceException;
import com.banesco.common.infrastructure.config.DataSourceConfig;
import com.banesco.module.legal_customer_product_directory.domain.dto.request.LegalCustomerProductDirectoryRequest;
@ -23,33 +22,34 @@ import java.util.List;
@ApplicationScoped
public class AccountRepository {
private final DataSourceConfig dataSourceConfig;
private final AgroalDataSource dataSource;
@Inject
public AccountRepository(
DataSourceConfig dataSourceConfig,
AgroalDataSource dataSource
) {
this.dataSourceConfig = dataSourceConfig;
this.dataSource = dataSource;
}
public List<SPAccountResponse> execute(
DataSourceConfig dataSourceConfig,
LegalCustomerProductDirectoryRequest request
) {
try {
return callSp(request);
} catch (SQLException e) {
throw new PersistenceException("SP_ERROR", e.getMessage());
return callSp(dataSourceConfig, request);
} catch (PersistenceException e) {
throw e;
} catch (Exception e) {
throw new PersistenceException("ERROR", e.getMessage());
}
}
private List<SPAccountResponse> callSp(
DataSourceConfig dataSourceConfig,
LegalCustomerProductDirectoryRequest request
) throws SQLException {
) {
List<SPAccountResponse> results;
String spCall = buildSpCall(request);
String spCall = buildSpCall(dataSourceConfig, request);
log.info("Iniciando llamada SP: {}", spCall);
@ -63,15 +63,14 @@ public class AccountRepository {
!StringUtil.isNullOrEmpty(results.get(0).getDscError()) &&
results.get(0).getDscError().toUpperCase().equals(dataSourceConfig.getSpIbsError())
) {
throw new BadRequestException(
"SP_ERROR",
results.get(0).getDscError(),
null
);
throw new PersistenceException("ERROR", results.get(0).getDscError());
}
} catch (SQLException e) {
log.error("Error en conexión o ejecución SP {}: {}", spCall, e.getMessage());
throw e;
log.error("Error en conexión o ejecución del SP {}: {}", spCall, e.getMessage());
throw new PersistenceException("ERROR", e.getMessage());
} catch (Exception e) {
log.error("Error genérico en la ejecución del SP {}: {}", spCall, e.getMessage());
throw new PersistenceException("ERROR", e.getMessage());
} finally {
log.info("SP conexión finalizada");
}
@ -122,6 +121,7 @@ public class AccountRepository {
}
private String buildSpCall(
DataSourceConfig dataSourceConfig,
LegalCustomerProductDirectoryRequest request
) {
return "call " + dataSourceConfig.getSpName() +

View File

@ -1,6 +1,6 @@
package com.banesco.module.legal_customer_product_directory.infrastructure.resource;
import com.banesco.common.application.helper.ErrorResponseHelper;
import com.banesco.common.application.helper.MessageResponseHelper;
import com.banesco.common.domain.exception.BaseApiException;
import com.banesco.common.domain.model.ApiResponse;
import com.banesco.common.domain.model.StatusResponse;
@ -28,16 +28,17 @@ import java.util.Objects;
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class LegalCustomerProductDirectoryResource {
private final LegalCustomerProductDirectoryUseCase useCase;
private final ErrorResponseHelper errorResponseHelper;
private final MessageResponseHelper messageResponseHelper;
@Inject
public LegalCustomerProductDirectoryResource(
LegalCustomerProductDirectoryUseCase useCase,
ErrorResponseHelper errorResponseHelper
MessageResponseHelper messageResponseHelper,
LegalCustomerProductDirectoryUseCase useCase
) {
this.messageResponseHelper = messageResponseHelper;
this.useCase = useCase;
this.errorResponseHelper = errorResponseHelper;
}
@GET
@ -393,9 +394,9 @@ public class LegalCustomerProductDirectoryResource {
.build()
)).build();
} catch (BaseApiException e) {
return errorResponseHelper.handleException(e);
return messageResponseHelper.handleException(e);
} catch (Exception e) {
return errorResponseHelper.handleGenericException(e);
return messageResponseHelper.handleGenericException(e);
}
}
}

View File

@ -14,7 +14,7 @@ api:
allowed:
request-validation:
customer-ibs-number: '\d+'
account-status: '^(A|O|ACTBSUSD)$'
account-status: '^(A|D|ACTBSUSD)$'
product-cv-code: '^(CV|CVFL)$'
limit-type: '^(PAG|REC)$'
cachea-indicator: '^(SI|NO)$'
@ -28,5 +28,17 @@ api:
datasource:
sp:
name: BANCYFIL2.CONCTABOLE
allowed:
account-status:
enable: A
disable: D
account-type:
saving: SAV
current: DDA,MMK
interest-arrangement: MMK
account-relationship-type:
parent: PADRE
currency:
base: BS
errors:
ibs: "DEBE ESPECIFICAR EL NRO DE CLIENTE"