Created Appointment creation flow.
This commit is contained in:
@@ -0,0 +1,884 @@
|
||||
package net.gepafin.tendermanagement.dao;
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3Client;
|
||||
import com.amazonaws.services.s3.model.GetObjectRequest;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import feign.FeignException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.gepafin.tendermanagement.config.Translator;
|
||||
import net.gepafin.tendermanagement.constants.AppointmentApiConstant;
|
||||
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
||||
import net.gepafin.tendermanagement.entities.ApplicationEntity;
|
||||
import net.gepafin.tendermanagement.entities.CompanyEntity;
|
||||
import net.gepafin.tendermanagement.entities.DocumentEntity;
|
||||
import net.gepafin.tendermanagement.entities.HubEntity;
|
||||
import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum;
|
||||
import net.gepafin.tendermanagement.enums.VersionActionTypeEnum;
|
||||
import net.gepafin.tendermanagement.model.request.AppointmentCreationRequest;
|
||||
import net.gepafin.tendermanagement.model.request.AppointmentNdgRequest;
|
||||
import net.gepafin.tendermanagement.model.request.AppointmentVisuraListRequest;
|
||||
import net.gepafin.tendermanagement.model.request.AppointmentVisuraRequest;
|
||||
import net.gepafin.tendermanagement.model.request.CreateAppointmentRequest;
|
||||
import net.gepafin.tendermanagement.model.request.UploadDocToExternalSystemRequest;
|
||||
import net.gepafin.tendermanagement.model.request.VersionHistoryRequest;
|
||||
import net.gepafin.tendermanagement.model.response.AppointmentCreationResponse;
|
||||
import net.gepafin.tendermanagement.model.response.AppointmentLoginResponse;
|
||||
import net.gepafin.tendermanagement.model.response.DocumentUploadResponse;
|
||||
import net.gepafin.tendermanagement.model.response.NdgResponse;
|
||||
import net.gepafin.tendermanagement.repositories.ApplicationRepository;
|
||||
import net.gepafin.tendermanagement.repositories.CompanyRepository;
|
||||
import net.gepafin.tendermanagement.repositories.DocumentRepository;
|
||||
import net.gepafin.tendermanagement.repositories.HubRepository;
|
||||
import net.gepafin.tendermanagement.service.ApplicationService;
|
||||
import net.gepafin.tendermanagement.service.CompanyService;
|
||||
import net.gepafin.tendermanagement.service.feignClient.AppointmentApiService;
|
||||
import net.gepafin.tendermanagement.util.LoggingUtil;
|
||||
import net.gepafin.tendermanagement.util.Utils;
|
||||
import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
|
||||
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AppointmentDao {
|
||||
|
||||
@Value("${appointment.portal.user}")
|
||||
private String user;
|
||||
|
||||
@Value("${appointment.portal.password}")
|
||||
private String password;
|
||||
|
||||
@Value("${appointment.portal.source}")
|
||||
private String source;
|
||||
|
||||
@Value("${appointment.portal.context}")
|
||||
private String context;
|
||||
|
||||
@Value("${default.hub.uuid}")
|
||||
private String defaultHubUuid;
|
||||
|
||||
@Value("${aws.s3.url}")
|
||||
private String s3Url;
|
||||
|
||||
@Value("${aws.s3.bucket.name}")
|
||||
private String OLD_BUCKET;
|
||||
|
||||
@Value("${flagDaFirmare}")
|
||||
private Boolean flagDaFirmare;
|
||||
|
||||
@Autowired
|
||||
private HubRepository hubRepository;
|
||||
|
||||
@Autowired
|
||||
private AppointmentApiService appointmentApiService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationService applicationService;
|
||||
|
||||
@Autowired
|
||||
private CompanyService companyService;
|
||||
|
||||
@Autowired
|
||||
private ApplicationRepository applicationRepository;
|
||||
|
||||
@Autowired
|
||||
private CompanyRepository companyRepository;
|
||||
|
||||
@Autowired
|
||||
private DocumentDao documentDao;
|
||||
|
||||
@Autowired
|
||||
private AmazonS3Client s3Client;
|
||||
|
||||
@Autowired
|
||||
private DocumentRepository documentRepository;
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Autowired
|
||||
private LoggingUtil loggingUtil;
|
||||
|
||||
private final Map<Long, ExecutorService> executorMap = new ConcurrentHashMap<>();
|
||||
|
||||
public NdgResponse checkNdgForAppointment(Long applicationId) {
|
||||
|
||||
try {
|
||||
NdgResponse ndgResponseToReturn = new NdgResponse();
|
||||
// Validate application, company, and hub
|
||||
ApplicationEntity application = applicationService.validateApplication(applicationId);
|
||||
if (application.getNdgStatus() != null && application.getNdgStatus().equalsIgnoreCase(GepafinConstant.NDG_IN_PROGRESS)) {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_GENERATION_IS_IN_PROGRESS));
|
||||
}
|
||||
//cloned for old application data
|
||||
ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(application);
|
||||
|
||||
CompanyEntity company = companyService.validateCompany(application.getCompanyId());
|
||||
HubEntity hub = hubRepository.findByHubId(application.getHubId());
|
||||
|
||||
if (!hub.getUniqueUuid().equals(defaultHubUuid)) {
|
||||
log.info("Ndg cannot be created for another Hub, it is default for Gepafin.");
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NO_NDG_FOR_ANOTHER_HUB));
|
||||
}
|
||||
|
||||
// Check if NDG and idVisura are already present
|
||||
if (isNdgAndIdVisuraPresent(application)) {
|
||||
log.info("NDG already exist for applicationId: {}", applicationId);
|
||||
ndgResponseToReturn.setNdg(application.getNdg());
|
||||
return ndgResponseToReturn;
|
||||
}
|
||||
|
||||
// Authenticate and fetch token if required
|
||||
if (hub.getAppointmentAuthTokenId() == null && hub.getAreaCode() == null) {
|
||||
hub = authenticateAndSaveToken(hub);
|
||||
}
|
||||
|
||||
String authorizationToken = getBearerToken(hub);
|
||||
|
||||
// Try retrieving NDG by VAT number
|
||||
AppointmentLoginResponse ndgResponse = retrieveNdgByVatNumber(company.getVatNumber(), authorizationToken, hub, application);
|
||||
//For testing purpose Commenting it
|
||||
if (isNdgValid(ndgResponse.getNdg())) {
|
||||
saveNdgAndIdVisura(application, company, ndgResponse.getNdg(), null);
|
||||
ndgResponseToReturn.setNdg(application.getNdg());
|
||||
return ndgResponseToReturn;
|
||||
}
|
||||
|
||||
return getNdgResponse(company, authorizationToken, hub, application, ndgResponseToReturn, oldApplicationData);
|
||||
} catch (FeignException e) {
|
||||
log.error("Error in feign client call during NDG handling: {}", e.getMessage(), e);
|
||||
Utils.callException(e.status(), e);
|
||||
} catch (CustomValidationException e) {
|
||||
log.info("Custom validation exception: {}", e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("Error during NDG handling: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Error during fetching NDG.");
|
||||
}
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN));
|
||||
}
|
||||
|
||||
private NdgResponse getNdgResponse(CompanyEntity company, String authorizationToken, HubEntity hub, ApplicationEntity application, NdgResponse ndgResponseToReturn,
|
||||
ApplicationEntity oldApplicationData) {
|
||||
// Create Visura if NDG is not found
|
||||
AppointmentLoginResponse visuraResponse = createVisura(company, authorizationToken, hub);
|
||||
if (isNdgValid(visuraResponse.getNdg())) {
|
||||
saveNdgAndIdVisura(application, company, visuraResponse.getNdg(), visuraResponse.getIdVisura());
|
||||
ndgResponseToReturn.setNdg(application.getNdg());
|
||||
} else if (visuraResponse.getIdVisura() != null) {
|
||||
application.setNdgStatus(GepafinConstant.NDG_IN_PROGRESS);
|
||||
applicationRepository.save(application);
|
||||
|
||||
/** This code is responsible for adding a version history log for the "Updating ndg status in application" operation. **/
|
||||
loggingUtil.addVersionHistory(
|
||||
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(application).build());
|
||||
|
||||
startNdgPollingTask(application, company, hub);
|
||||
throw new CustomValidationException(Status.SUCCESS, Translator.toLocale(GepafinConstant.NDG_GENERATION_IS_IN_PROGRESS));
|
||||
}
|
||||
|
||||
return ndgResponseToReturn;
|
||||
}
|
||||
|
||||
private static String getBearerToken(HubEntity hub) {
|
||||
|
||||
return "Bearer " + hub.getAppointmentAuthTokenId();
|
||||
}
|
||||
|
||||
private void startNdgPollingTask(ApplicationEntity application, CompanyEntity company, HubEntity hub) {
|
||||
//cloned for all data
|
||||
ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(application);
|
||||
CompanyEntity oldCompanyData = Utils.getClonedEntityForData(company);
|
||||
|
||||
// Check if a thread is already running for this application
|
||||
if (executorMap.containsKey(application.getId())) {
|
||||
log.warn("Polling task already running for applicationId: {}", application.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a dedicated thread (single-threaded executor) for this application
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor(runnable -> {
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.setName(GepafinConstant.POLLING_THREAD_NAME + application.getId());
|
||||
return thread;
|
||||
});
|
||||
executorMap.put(application.getId(), executor);
|
||||
|
||||
// Submit polling task to this thread
|
||||
executor.submit(() -> {
|
||||
try {
|
||||
log.info("Polling task started for applicationId: {} on thread: {}", application.getId(), Thread.currentThread().getName());
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
while (true) {
|
||||
if (application.getNdg() != null)
|
||||
break;
|
||||
try {
|
||||
String visuraListJson = getVisuraList(application.getIdVisura(), hub.getAppointmentAuthTokenId(), application, hub);
|
||||
String ndg = parseNdgFromVisuraListResponse(visuraListJson);
|
||||
|
||||
if (isNdgValid(ndg)) {
|
||||
company.setNdg(ndg);
|
||||
application.setNdgStatus(GepafinConstant.NDG_GENERATED);
|
||||
application.setNdg(ndg);
|
||||
applicationRepository.save(application);
|
||||
companyRepository.save(company);
|
||||
|
||||
log.info("NDG obtained for applicationId: {} and saved successfully.", application.getId());
|
||||
break; // Exit the loop after successful NDG retrieval
|
||||
} else {
|
||||
log.warn("NDG not found for applicationId: {} in Visura List API response.", application.getId());
|
||||
}
|
||||
|
||||
// Check if polling time has exceeded the limit
|
||||
if (System.currentTimeMillis() - startTime > TimeUnit.HOURS.toMillis(2)) {
|
||||
log.warn("Polling timed out for applicationId: {}", application.getId());
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait before the next polling attempt
|
||||
Thread.sleep(TimeUnit.MINUTES.toMillis(1));
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Polling task interrupted for applicationId: {}", application.getId());
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
log.error("Error during NDG polling for applicationId: {}", application.getId(), e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Cleanup: Shut down the thread for this application
|
||||
executor.shutdown();
|
||||
executorMap.remove(application.getId());
|
||||
log.info("Polling task completed and thread shut down for applicationId: {}", application.getId());
|
||||
}
|
||||
});
|
||||
/** This code is responsible for adding a version history log for the "Update application ndgCode and ndgStatus" operation. **/
|
||||
loggingUtil.addVersionHistory(
|
||||
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(application).build());
|
||||
|
||||
/** This code is responsible for adding a version history log for the "Update company ndgCode" operation. **/
|
||||
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyData).newData(company).build());
|
||||
}
|
||||
|
||||
private boolean isNdgAndIdVisuraPresent(ApplicationEntity application) {
|
||||
|
||||
String ndg = application.getNdg();
|
||||
String idVisura = application.getIdVisura();
|
||||
|
||||
if (ndg != null && idVisura == null) {
|
||||
return true;
|
||||
} else if (ndg == null && idVisura != null) {
|
||||
return false;
|
||||
} else
|
||||
return ndg != null;
|
||||
}
|
||||
|
||||
private boolean isNdgValid(String ndg) {
|
||||
|
||||
return ndg != null && !ndg.isEmpty();
|
||||
}
|
||||
|
||||
private void saveNdgAndIdVisura(ApplicationEntity application, CompanyEntity company, String ndg, String idVisura) {
|
||||
|
||||
//cloned for old application and company data
|
||||
ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(application);
|
||||
CompanyEntity oldCompanyData = Utils.getClonedEntityForData(company);
|
||||
|
||||
application.setNdg(ndg);
|
||||
application.setIdVisura(idVisura);
|
||||
application.setNdgStatus(GepafinConstant.NDG_GENERATED);
|
||||
company.setNdg(ndg);
|
||||
companyRepository.save(company);
|
||||
applicationRepository.save(application);
|
||||
|
||||
/** This code is responsible for adding a version history log for the "update application ndg code, status, and Id visura" operation. **/
|
||||
loggingUtil.addVersionHistory(
|
||||
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(application).build());
|
||||
|
||||
/** This code is responsible for adding a version history log for the "update company ndg code" operation. **/
|
||||
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyData).newData(company).build());
|
||||
|
||||
log.info("NDG saved for applicationId: {}, {}", application.getId(), application.getNdg());
|
||||
}
|
||||
|
||||
private String getVisuraList(String idVisura, String authorizationToken, ApplicationEntity application, HubEntity hub) {
|
||||
|
||||
AppointmentVisuraListRequest visuraListRequest = new AppointmentVisuraListRequest();
|
||||
AppointmentVisuraListRequest.VisuraFilter filter = new AppointmentVisuraListRequest.VisuraFilter();
|
||||
filter.setIdVisura(idVisura);
|
||||
visuraListRequest.setFilter(filter);
|
||||
|
||||
try {
|
||||
String requestJson = Utils.convertObjectToJson(visuraListRequest);
|
||||
ResponseEntity<Object> response = appointmentApiService.getVisuraList(requestJson, authorizationToken);
|
||||
return Utils.convertObjectToJson(response.getBody());
|
||||
} catch (FeignException.Forbidden forbiddenException) {
|
||||
log.error("403 Forbidden received while getting visuraList for Ndg code. Regenerating token...");
|
||||
// Regenerate the token and retry
|
||||
String newAuthorizationToken = regenerateTokenAndSave(hub);
|
||||
return getVisuraList(idVisura, newAuthorizationToken, application, hub);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to fetch Ndg code: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Error fetching Ndg List", e);
|
||||
}
|
||||
}
|
||||
|
||||
private HubEntity authenticateAndSaveToken(HubEntity hub) {
|
||||
|
||||
HubEntity oldHubData = Utils.getClonedEntityForData(hub);
|
||||
try {
|
||||
//code to generate token with payload having "iat" epoch timestamp and secret key with no expiry and send in below method call
|
||||
String authJwtToken = Utils.generateAuthTokenForLoginToOdessa();
|
||||
log.info("Got the auth for login to odessa {}", authJwtToken);
|
||||
hub.setAuthToken(authJwtToken);
|
||||
hubRepository.save(hub);
|
||||
|
||||
/** This code is responsible for adding a version history log for the "Updating auth token for login api in hub" operation. **/
|
||||
loggingUtil.addVersionHistory(VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldHubData).newData(hub).build());
|
||||
|
||||
// Prepare the request body (adjust if necessary for login API)
|
||||
Map<String, Object> body = Collections.emptyMap();
|
||||
// Perform login API call
|
||||
ResponseEntity<Object> responseLogin = appointmentApiService.loginWithOdessa(authJwtToken, source, context, user, password, body);
|
||||
|
||||
// Handle successful login
|
||||
if (responseLogin.getStatusCode() == HttpStatus.OK) {
|
||||
log.info("Login successful to odessa. Parsing response.");
|
||||
String loginResponseJson = Utils.convertObjectToJson(responseLogin.getBody());
|
||||
AppointmentLoginResponse parsedResponse = parseLoginResponse(loginResponseJson);
|
||||
|
||||
// Validate and save token
|
||||
if (parsedResponse.getTokenId() != null) {
|
||||
hub.setAppointmentAuthTokenId(parsedResponse.getTokenId());
|
||||
hub.setAreaCode(parsedResponse.getAreaCode());
|
||||
hubRepository.save(hub);
|
||||
|
||||
/** This code is responsible for adding a version history log for the "inserting token and areaCode from login odessa response for appointment flow api's"
|
||||
* operation. **/
|
||||
loggingUtil.addVersionHistory(
|
||||
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldHubData).newData(hub).build());
|
||||
|
||||
log.info("Saved new authToken and areaCode for Hub.");
|
||||
return hub;
|
||||
} else {
|
||||
throw new RuntimeException("Login response is missing a valid tokenId for login to odessa system, please try again.");
|
||||
}
|
||||
}
|
||||
// Handle non-OK response
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_IN_GENERATING_NDG_TRY_AGAIN));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to authenticate user on Odessa : {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Authentication failed on Odessa. try again", e);
|
||||
}
|
||||
}
|
||||
|
||||
private AppointmentLoginResponse retrieveNdgByVatNumber(String vatNumber, String authorizationToken, HubEntity hub, ApplicationEntity application) {
|
||||
|
||||
try {
|
||||
// Prepare the NDG request
|
||||
AppointmentNdgRequest ndgRequest = getAppointmentNdgRequest(vatNumber);
|
||||
// Call the API to retrieve NDG
|
||||
ResponseEntity<Object> response = appointmentApiService.getNdgByVatNumber(ndgRequest, authorizationToken);
|
||||
String responseJson = Utils.convertObjectToJson(response.getBody());
|
||||
// Parse and return the NDG response
|
||||
return parseNdgResponse(responseJson);
|
||||
} catch (FeignException.Forbidden forbiddenException) {
|
||||
log.error("403 Forbidden received while retrieving NDG. Regenerating token...");
|
||||
// Regenerate the token and retry
|
||||
String newAuthorizationToken = regenerateTokenAndSave(hub);
|
||||
return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to retrieve NDG by VAT number: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("NDG retrieval failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String regenerateTokenAndSave(HubEntity hub) {
|
||||
|
||||
try {
|
||||
hub = authenticateAndSaveToken(hub);
|
||||
return "Bearer " + hub.getAppointmentAuthTokenId();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to regenerate token from Odessa: {}", e.getMessage());
|
||||
throw new RuntimeException("Token regeneration failed from Odessa.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private AppointmentLoginResponse createVisura(CompanyEntity company, String authorizationToken, HubEntity hub) {
|
||||
|
||||
try {
|
||||
String visuraRequest = getAppointmentVisuraRequest(company, hub.getAreaCode());
|
||||
ResponseEntity<Object> response = appointmentApiService.createVisura(visuraRequest, authorizationToken);
|
||||
String responseJson = Utils.convertObjectToJson(response.getBody());
|
||||
return parseVisuraResponse(responseJson);
|
||||
} catch (FeignException.Forbidden forbiddenException) {
|
||||
log.error("403 Forbidden received while retrieving NDG. Regenerating token...");
|
||||
// Regenerate the token and retry
|
||||
String newAuthorizationToken = regenerateTokenAndSave(hub);
|
||||
return createVisura(company, newAuthorizationToken, hub);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create Visura for Ndg : {}", e.getMessage());
|
||||
throw new RuntimeException("Visura creation failed for Ndg.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static AppointmentNdgRequest getAppointmentNdgRequest(String vatNumber) {
|
||||
|
||||
AppointmentNdgRequest request = new AppointmentNdgRequest();
|
||||
AppointmentNdgRequest.Filter filter = new AppointmentNdgRequest.Filter();
|
||||
filter.setPartitaIva(vatNumber);
|
||||
|
||||
AppointmentNdgRequest.Pagination pagination = new AppointmentNdgRequest.Pagination();
|
||||
pagination.setTargetPage(AppointmentApiConstant.TARGET_PAGE_SIZE);
|
||||
pagination.setRecordsPerPage(AppointmentApiConstant.RECORD_PER_PAGE_SIZE);
|
||||
|
||||
request.setFilter(filter);
|
||||
request.setPagination(pagination);
|
||||
return request;
|
||||
}
|
||||
|
||||
private static String getAppointmentVisuraRequest(CompanyEntity company, String areaCode) {
|
||||
|
||||
AppointmentVisuraRequest visuraRequest = new AppointmentVisuraRequest();
|
||||
AppointmentVisuraRequest.VisuraInput input = new AppointmentVisuraRequest.VisuraInput();
|
||||
input.setPartitaIva(company.getVatNumber());
|
||||
input.setCodiceFiscale(company.getCodiceFiscale());
|
||||
input.setCodArea(areaCode);
|
||||
input.setVisuraMode(AppointmentApiConstant.VISURA_MODE);
|
||||
input.setVisuraProvider(AppointmentApiConstant.VISURA_PROVIDER);
|
||||
input.setCodAgente(AppointmentApiConstant.COD_AGENTE);
|
||||
input.setAnagraficaLegame(AppointmentApiConstant.IS_ANAGRAFICA_LEGAME);
|
||||
input.setCreaAnagrafica(AppointmentApiConstant.CREA_ANAGRAFICA);
|
||||
input.setFromRating(AppointmentApiConstant.IS_FROM_RATING);
|
||||
input.setSalvaDocumenti(AppointmentApiConstant.SALVA_DOCUMENTI);
|
||||
input.setVisuraType(AppointmentApiConstant.VISURA_TYPE);
|
||||
visuraRequest.setInput(input);
|
||||
return Utils.convertObjectToJson(visuraRequest);
|
||||
}
|
||||
|
||||
private String parseNdgFromVisuraListResponse(String jsonResponse) {
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonResponse);
|
||||
JsonNode dataNode = rootNode.get(GepafinConstant.DATA_STRING);
|
||||
|
||||
if (dataNode != null && dataNode.isArray() && dataNode.size() > 0) {
|
||||
JsonNode firstEntry = dataNode.get(0);
|
||||
JsonNode ndgClienteNode = firstEntry.get("ndgCliente");
|
||||
if (ndgClienteNode != null && ndgClienteNode.get("code") != null) {
|
||||
String code = ndgClienteNode.get("code").asText();
|
||||
return normalizeNullValue(code);
|
||||
}
|
||||
}
|
||||
log.warn("NDG not found in Visura List API response.");
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to parse NDG from Visura List API response: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Error parsing NDG from Visura List API response", e);
|
||||
}
|
||||
}
|
||||
|
||||
public AppointmentLoginResponse parseLoginResponse(String jsonResponse) {
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonResponse);
|
||||
JsonNode dataNode = rootNode.get(GepafinConstant.DATA_STRING);
|
||||
|
||||
if (dataNode != null) {
|
||||
AppointmentLoginResponse response = new AppointmentLoginResponse();
|
||||
response.setTokenId(dataNode.get("tokenId").asText());
|
||||
JsonNode areasNode = dataNode.get("areas");
|
||||
if (areasNode != null && areasNode.isArray() && areasNode.size() > 0) {
|
||||
response.setAreaCode(areasNode.get(0).get("code").asText());
|
||||
}
|
||||
response.setCompanyId(dataNode.get("companyId").asLong());
|
||||
return response;
|
||||
} else {
|
||||
throw new RuntimeException("Invalid JSON structure: Missing 'data' node.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to parse response from loginApi for odessa: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public AppointmentLoginResponse parseVisuraResponse(String jsonResponse) {
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonResponse);
|
||||
JsonNode dataNode = rootNode.get(GepafinConstant.DATA_STRING);
|
||||
|
||||
if (dataNode != null) {
|
||||
AppointmentLoginResponse response = new AppointmentLoginResponse();
|
||||
response.setIdVisura(normalizeNullValue(dataNode.get(GepafinConstant.ID_VISURA_STRING).asText()));
|
||||
response.setNdg(normalizeNullValue(dataNode.get(GepafinConstant.NDG_STRING).asText()));
|
||||
return response;
|
||||
} else {
|
||||
throw new RuntimeException("Invalid JSON structure: Missing 'data' node.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to parse response: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public AppointmentLoginResponse parseNdgResponse(String jsonResponse) {
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonResponse);
|
||||
JsonNode dataArray = rootNode.get(GepafinConstant.DATA_STRING);
|
||||
if (dataArray == null || !dataArray.isArray() || dataArray.isEmpty()) {
|
||||
log.info("NDG data is empty or missing in the response.");
|
||||
AppointmentLoginResponse emptyResponse = new AppointmentLoginResponse();
|
||||
emptyResponse.setNdg(null);
|
||||
return emptyResponse;
|
||||
}
|
||||
JsonNode firstDataEntry = dataArray.get(0);
|
||||
AppointmentLoginResponse response = new AppointmentLoginResponse();
|
||||
if (firstDataEntry.has(GepafinConstant.NDG_STRING)) {
|
||||
response.setNdg(normalizeNullValue(firstDataEntry.get(GepafinConstant.NDG_STRING).asText()));
|
||||
}
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to parse response: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("Failed to parse NDG response.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeNullValue(String value) {
|
||||
|
||||
return (value == null || GepafinConstant.NULL_STRING.equalsIgnoreCase(value.trim())) ? null : value;
|
||||
}
|
||||
|
||||
public AppointmentCreationResponse createAppointment(Long applicationId, CreateAppointmentRequest createAppointmentRequest) {
|
||||
// Validate the application
|
||||
ApplicationEntity application = applicationService.validateApplication(applicationId);
|
||||
|
||||
AppointmentCreationResponse appointmentCreationResponse = new AppointmentCreationResponse();
|
||||
|
||||
ApplicationEntity oldApplicationData = Utils.getClonedEntityForData(application);
|
||||
HubEntity hub = hubRepository.findByHubId(application.getHubId());
|
||||
|
||||
// Check hub UUID and enforce constraints
|
||||
if (!hub.getUniqueUuid().equals(defaultHubUuid)) {
|
||||
log.info("Appointment cannot be created for another Hub; default is required for Gepafin.");
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NO_APPOINTMENT_FOR_ANOTHER_HUB));
|
||||
}
|
||||
|
||||
try {
|
||||
// Pre-check conditions for appointment creation
|
||||
if (application.getNdg() != null && !Objects.equals(application.getNdgStatus(), GepafinConstant.NDG_IN_PROGRESS) && application.getAppointmentId() != null) {
|
||||
appointmentCreationResponse.setAppointmentId(application.getAppointmentId());
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPOINTMENT_ALREADY_CREATED));
|
||||
// return appointmentCreationResponse;
|
||||
}
|
||||
|
||||
if (application.getNdg() == null && Objects.equals(application.getNdgStatus(), GepafinConstant.NDG_IN_PROGRESS)) {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_FOUND_FOR_APPLICATION));
|
||||
}
|
||||
|
||||
// Generate authorization token and fetch template data
|
||||
String authorizationToken = getBearerToken(hub);
|
||||
ResponseEntity<Object> response = appointmentApiService.getAppointmentTemplateForTemplateCreation(authorizationToken);
|
||||
|
||||
if (response.getStatusCode() != HttpStatus.OK) {
|
||||
log.error("Failed to retrieve appointment template for appointment creation. Status: {}", response.getStatusCode());
|
||||
throw new IllegalStateException("Failed to retrieve appointment template for appointment creation");
|
||||
}
|
||||
|
||||
// Parse template data
|
||||
String responseDataForTemplate = Utils.convertObjectToJson(response.getBody());
|
||||
AppointmentCreationRequest templateRichiestaData = parseTemplateResponseData(responseDataForTemplate);
|
||||
|
||||
// Build the appointment request body
|
||||
AppointmentCreationRequest appointmentCreationRequest = buildAppointmentCreationRequest(applicationId, createAppointmentRequest, hub.getAreaCode(),
|
||||
templateRichiestaData);
|
||||
String appointmentRequestBody = Utils.convertObjectToJson(appointmentCreationRequest);
|
||||
|
||||
// Make API call to create the appointment
|
||||
ResponseEntity<Object> appointmentResponse = appointmentApiService.createAppointment(authorizationToken, context, appointmentRequestBody);
|
||||
String appointmentId = extractAppointmentIdFromResponse(appointmentResponse);
|
||||
|
||||
if (appointmentId != null) {
|
||||
// Update application with the appointment ID
|
||||
application.setAppointmentId(appointmentId);
|
||||
applicationRepository.save(application);
|
||||
|
||||
// Log version history
|
||||
loggingUtil.addVersionHistory(
|
||||
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplicationData).newData(application).build());
|
||||
}
|
||||
|
||||
appointmentCreationResponse.setAppointmentId(appointmentId);
|
||||
return appointmentCreationResponse;
|
||||
|
||||
} catch (FeignException.Forbidden forbiddenException) {
|
||||
log.error("403 Forbidden received while retrieving template. Regenerating token...");
|
||||
regenerateTokenAndSave(hub);
|
||||
return createAppointment(applicationId, createAppointmentRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private String extractAppointmentIdFromResponse(ResponseEntity<Object> appointmentResponse) {
|
||||
|
||||
if (appointmentResponse.getBody() != null) {
|
||||
Map<String, Object> responseBody = (Map<String, Object>) appointmentResponse.getBody();
|
||||
if (responseBody.containsKey(GepafinConstant.DATA_STRING)) {
|
||||
Map<String, Object> data = (Map<String, Object>) responseBody.get(GepafinConstant.DATA_STRING);
|
||||
if (data != null && data.containsKey(GepafinConstant.ID_STRING)) {
|
||||
return data.get(GepafinConstant.ID_STRING).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public AppointmentCreationRequest parseTemplateResponseData(String jsonResponse) {
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonResponse);
|
||||
JsonNode richiestaClienteArray = rootNode.path(GepafinConstant.DATA_STRING).path(GepafinConstant.RICHIESTA_CLIENTE_STRING);
|
||||
|
||||
AppointmentCreationRequest appointmentCreationRequest = new AppointmentCreationRequest();
|
||||
AppointmentCreationRequest.Input input = new AppointmentCreationRequest.Input();
|
||||
|
||||
// Map `richiestaCliente` array
|
||||
List<AppointmentCreationRequest.RichiestaCliente> richiestaClienteList = new ArrayList<>();
|
||||
if (richiestaClienteArray.isArray()) {
|
||||
for (JsonNode richiestaNode : richiestaClienteArray) {
|
||||
richiestaClienteList.add(objectMapper.treeToValue(richiestaNode, AppointmentCreationRequest.RichiestaCliente.class));
|
||||
}
|
||||
}
|
||||
|
||||
input.setRichiestaCliente(richiestaClienteList);
|
||||
appointmentCreationRequest.setInput(input);
|
||||
return appointmentCreationRequest;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error parsing template response: {}", e.getMessage(), e);
|
||||
throw new IllegalStateException("Failed to parse template response", e);
|
||||
}
|
||||
}
|
||||
|
||||
public AppointmentCreationRequest buildAppointmentCreationRequest(Long applicationId, CreateAppointmentRequest createAppointmentRequest, String areaCode,
|
||||
AppointmentCreationRequest templateRichiestaData) {
|
||||
|
||||
ApplicationEntity application = applicationService.validateApplication(applicationId);
|
||||
CreateAppointmentRequest.Nota nota = createAppointmentRequest.getNota();
|
||||
|
||||
AppointmentCreationRequest appointmentCreationRequest = new AppointmentCreationRequest();
|
||||
AppointmentCreationRequest.Input input = new AppointmentCreationRequest.Input();
|
||||
|
||||
// Set Input Fields
|
||||
input.setId(areaCode);
|
||||
input.setNdg(application.getNdg());
|
||||
|
||||
// Populate richiestaCliente from template data
|
||||
List<AppointmentCreationRequest.RichiestaCliente> richiestaClienteList = new ArrayList<>();
|
||||
for (AppointmentCreationRequest.RichiestaCliente templateRichiesta : templateRichiestaData.getInput().getRichiestaCliente()) {
|
||||
AppointmentCreationRequest.RichiestaCliente richiestaCliente = new AppointmentCreationRequest.RichiestaCliente();
|
||||
BeanUtils.copyProperties(templateRichiesta, richiestaCliente);
|
||||
|
||||
// Add specific `nota`
|
||||
AppointmentCreationRequest.Nota requestNota = new AppointmentCreationRequest.Nota();
|
||||
requestNota.setTitolo(nota.getTitolo());
|
||||
requestNota.setTesto(nota.getTesto());
|
||||
richiestaCliente.setNota(requestNota);
|
||||
|
||||
richiestaClienteList.add(richiestaCliente);
|
||||
}
|
||||
|
||||
input.setRichiestaCliente(richiestaClienteList);
|
||||
appointmentCreationRequest.setInput(input);
|
||||
return appointmentCreationRequest;
|
||||
}
|
||||
|
||||
public DocumentUploadResponse uploadDocumentToExternalSystem(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest, Long applicationId) {
|
||||
|
||||
DocumentUploadResponse response = new DocumentUploadResponse();
|
||||
DocumentEntity systemDoc = documentDao.validateDocument(documentId);
|
||||
|
||||
ApplicationEntity application = getApplicationEntityForDocument(applicationId, systemDoc);
|
||||
|
||||
//cloned for old document data
|
||||
DocumentEntity oldDocumentEntity = Utils.getClonedEntityForData(systemDoc);
|
||||
|
||||
if (!docToExternalSystemRequest.getInput().getAttributes().getNdg().equalsIgnoreCase(application.getNdg())) {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NDG_NOT_MATCHED_OR_NOT_FOUND));
|
||||
}
|
||||
|
||||
Long hubId = application.getHubId();
|
||||
HubEntity hub = hubRepository.findByHubId(hubId);
|
||||
|
||||
if (!hub.getUniqueUuid().equals(defaultHubUuid)) {
|
||||
log.info("Document cannot be uploaded for another Hub, it is default for Gepafin.");
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.NO_DOCUMENT_UPLOAD_FOR_ANOTHER_HUB));
|
||||
}
|
||||
log.info("Got Document in system {}", systemDoc);
|
||||
|
||||
String oldUrl = systemDoc.getFilePath();
|
||||
log.info("Processing {}", oldUrl);
|
||||
|
||||
String authorizationToken = getBearerToken(hub);
|
||||
try {
|
||||
File localFile = downloadFileFromS3(oldUrl);
|
||||
MultipartFile multipartFile = convertFileToMultipartFile(localFile);
|
||||
|
||||
UploadDocToExternalSystemRequest externalSystemRequest = new UploadDocToExternalSystemRequest();
|
||||
|
||||
UploadDocToExternalSystemRequest.Input input = getUploadDocumentInput(docToExternalSystemRequest);
|
||||
externalSystemRequest.setInput(input);
|
||||
|
||||
String uploadDocRequest = Utils.convertObjectToJson(externalSystemRequest);
|
||||
ResponseEntity<Object> uploadedDocumentData = appointmentApiService.uploadDocumentToExternalSystemForAppointment(authorizationToken, context, uploadDocRequest,
|
||||
multipartFile);
|
||||
String responseData = Utils.convertObjectToJson(uploadedDocumentData.getBody());
|
||||
DocumentUploadResponse parsedDocumentUploadResponse = parseDocumentUploadResponse(responseData);
|
||||
|
||||
if (parsedDocumentUploadResponse == null) {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.ERROR_UPLOADING_DOCUMENT));
|
||||
}
|
||||
|
||||
systemDoc.setDocumentAttachmentId(parsedDocumentUploadResponse.getDocumentAttachmentId());
|
||||
documentRepository.save(systemDoc);
|
||||
|
||||
/** This code is responsible for adding a version history log for the "Update document with document attachment id" operation. **/
|
||||
loggingUtil.addVersionHistory(
|
||||
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldDocumentEntity).newData(systemDoc).build());
|
||||
|
||||
log.info("Document uploaded successfully to external system : {}", parsedDocumentUploadResponse);
|
||||
response.setDocumentAttachmentId(systemDoc.getDocumentAttachmentId());
|
||||
return response;
|
||||
} catch (FeignException.Forbidden forbiddenException) {
|
||||
log.error("403 Forbidden received while uploading document to external system. Regenerating token...");
|
||||
|
||||
regenerateTokenAndSave(hub);
|
||||
return uploadDocumentToExternalSystem(systemDoc.getSourceId(), docToExternalSystemRequest, applicationId);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception in uploading document to external system {}", e.getMessage());
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.EXTERNAL_DOCUMENT_UPLOAD_FAILURE_MSG));
|
||||
}
|
||||
}
|
||||
private ApplicationEntity getApplicationEntityForDocument(Long applicationId, DocumentEntity systemDoc) {
|
||||
|
||||
if (systemDoc.getDocumentAttachmentId() != null) {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.DOCUMENT_ALREADY_UPLOADED));
|
||||
}
|
||||
|
||||
ApplicationEntity application;
|
||||
|
||||
if (systemDoc.getSource().equalsIgnoreCase(DocumentSourceTypeEnum.APPLICATION.getValue()) && Objects.equals(systemDoc.getSourceId(), applicationId)) {
|
||||
application = applicationService.validateApplication(systemDoc.getSourceId());
|
||||
} else {
|
||||
throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.PROVIDE_VALID_APPLICATION_DOC_ID));
|
||||
}
|
||||
return application;
|
||||
}
|
||||
|
||||
private UploadDocToExternalSystemRequest.Input getUploadDocumentInput(UploadDocToExternalSystemRequest docToExternalSystemRequest) {
|
||||
|
||||
UploadDocToExternalSystemRequest.Input input = new UploadDocToExternalSystemRequest.Input();
|
||||
input.setIdTipoProtocollo(docToExternalSystemRequest.getInput().getIdTipoProtocollo());
|
||||
input.setIdClassificazione(docToExternalSystemRequest.getInput().getIdClassificazione());
|
||||
input.setFlagDaFirmare(flagDaFirmare);
|
||||
input.setDescrizione(docToExternalSystemRequest.getInput().getDescrizione());
|
||||
|
||||
UploadDocToExternalSystemRequest.Input.Attributes attributes = new UploadDocToExternalSystemRequest.Input.Attributes();
|
||||
attributes.setNdg(docToExternalSystemRequest.getInput().getAttributes().getNdg());
|
||||
attributes.setEmail(docToExternalSystemRequest.getInput().getAttributes().getEmail());
|
||||
|
||||
input.setAttributes(attributes);
|
||||
return input;
|
||||
}
|
||||
|
||||
public static MultipartFile convertFileToMultipartFile(File file) throws IOException {
|
||||
|
||||
FileInputStream input = new FileInputStream(file);
|
||||
return new MockMultipartFile(file.getName(), file.getName(), MediaType.APPLICATION_OCTET_STREAM_VALUE, input);
|
||||
}
|
||||
|
||||
private File downloadFileFromS3(String fileUrl) throws Exception {
|
||||
|
||||
String key = extractS3KeyFromUrl(fileUrl);
|
||||
File localFile = new File(GepafinConstant.TEMP_FILE_PATH + extractFileName(key));
|
||||
|
||||
GetObjectRequest getObjectRequest = new GetObjectRequest(OLD_BUCKET, key);
|
||||
|
||||
try (InputStream s3Stream = s3Client.getObject(getObjectRequest).getObjectContent(); FileOutputStream outputStream = new FileOutputStream(localFile)) {
|
||||
s3Stream.transferTo(outputStream);
|
||||
}
|
||||
|
||||
log.info("Downloaded file from old S3 bucket: {}", key);
|
||||
return localFile;
|
||||
}
|
||||
|
||||
private String extractS3KeyFromUrl(String url) {
|
||||
|
||||
return url.replace(s3Url, "");
|
||||
}
|
||||
|
||||
private String extractFileName(String filePath) {
|
||||
|
||||
String[] parts = filePath.split("/");
|
||||
return parts[parts.length - 1];
|
||||
|
||||
}
|
||||
|
||||
public DocumentUploadResponse parseDocumentUploadResponse(String jsonResponse) {
|
||||
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonResponse);
|
||||
|
||||
// Navigate to the "data" node
|
||||
JsonNode dataNode = rootNode.get(GepafinConstant.DATA_STRING);
|
||||
if (dataNode != null) {
|
||||
DocumentUploadResponse response = new DocumentUploadResponse();
|
||||
|
||||
// Extract "documentAttachmentId"
|
||||
JsonNode documentAttachmentIdNode = dataNode.get(GepafinConstant.DOCUMENT_ATTACHMENT_ID_STRING);
|
||||
if (documentAttachmentIdNode != null) {
|
||||
response.setDocumentAttachmentId(documentAttachmentIdNode.asText());
|
||||
} else {
|
||||
throw new RuntimeException("Invalid JSON structure: Missing 'documentAttachmentId' node.");
|
||||
}
|
||||
|
||||
return response;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to parse response: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user