From 93acfe29807c023b5fdf29aead087b01ddd2ddf6 Mon Sep 17 00:00:00 2001 From: rajesh Date: Mon, 16 Jun 2025 15:35:29 +0530 Subject: [PATCH] Refactor NDG code --- .../constants/AppointmentApiConstant.java | 5 +- .../tendermanagement/dao/AppointmentDao.java | 318 +++++++++++------- .../tendermanagement/enums/NdgStatusEnum.java | 22 ++ 3 files changed, 229 insertions(+), 116 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/NdgStatusEnum.java diff --git a/src/main/java/net/gepafin/tendermanagement/constants/AppointmentApiConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/AppointmentApiConstant.java index 6e5ed97c..799421fd 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/AppointmentApiConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/AppointmentApiConstant.java @@ -18,7 +18,7 @@ public class AppointmentApiConstant { public static final boolean CREA_ANAGRAFICA = Boolean.TRUE; public static final boolean SALVA_DOCUMENTI = Boolean.TRUE; public static final String VISURA_PROVIDER = "cerved"; - public static final String VISURA_TYPE = "StandardReport"; + public static final String VISURA_TYPE = "FullReport"; public static final String VISURA_MODE = "visure"; public static final String COD_AGENTE = "UtenzaAPIPortal"; public static final boolean IS_FROM_RATING = Boolean.FALSE; @@ -38,4 +38,7 @@ public class AppointmentApiConstant { public static final String COD_OPERAZIONE = "codOperazione"; public static final String MOTIVAZIONE_ID = "id"; public static final String PRODOTTO_CODE = "code"; + + public static final String WS_ANAGRAFICA_URL= "/WSAnagrafica.getList"; + } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java index f0fd43cb..66bf44d7 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/AppointmentDao.java @@ -12,12 +12,7 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.constants.AppointmentApiConstant; import net.gepafin.tendermanagement.constants.GepafinConstant; -import net.gepafin.tendermanagement.entities.ApplicationAmendmentRequestEntity; -import net.gepafin.tendermanagement.entities.ApplicationEntity; -import net.gepafin.tendermanagement.entities.ApplicationEvaluationEntity; -import net.gepafin.tendermanagement.entities.CompanyEntity; -import net.gepafin.tendermanagement.entities.DocumentEntity; -import net.gepafin.tendermanagement.entities.HubEntity; +import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.*; import net.gepafin.tendermanagement.model.request.AppointmentCreationRequest; import net.gepafin.tendermanagement.model.request.AppointmentNdgRequest; @@ -30,11 +25,7 @@ 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.repositories.UserRepository; +import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.AmazonS3Service; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.service.CompanyService; @@ -62,13 +53,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.ScheduledExecutorService; @Slf4j @Component @@ -154,7 +140,7 @@ public class AppointmentDao { private final Map executorMap = new ConcurrentHashMap<>(); - + private final ConcurrentHashMap threadForDocumentMap = new ConcurrentHashMap<>(); private static final ThreadLocal threadLocalHubId = new ThreadLocal<>(); @@ -177,7 +163,7 @@ public class AppointmentDao { // Update application status log.info("Updating NDG status to IN_PROGRESS. applicationId: {}", applicationId); - application.setNdgStatus(GepafinConstant.NDG_IN_PROGRESS); + application.setNdgStatus(NdgStatusEnum.NDG_INITITATED.getValue()); applicationRepository.save(application); loggingUtil.addVersionHistory( @@ -401,6 +387,7 @@ public class AppointmentDao { } throw new RuntimeException("Max retries exceeded. Failed to login to Odessa."); } + private void CheckPasswordExpiredOrErrorInResponse(ApplicationEntity application, FeignException.Forbidden forbiddenException) { String responseBody = forbiddenException.contentUTF8(); @@ -436,89 +423,89 @@ public class AppointmentDao { } } } catch (IOException e) { - log.error("Unexpected exception during Odessa login.Error: {}",e.getMessage(), e); + log.error("Unexpected exception during Odessa login.Error: {}", e.getMessage(), e); } } - private void startAsyncNdgProcessing(Long applicationId) { - // If already polling for this applicationId, do nothing: - if (executorMap.containsKey(applicationId)) { - log.warn("Async processing already running for applicationId: {}", applicationId); - return; - } - ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); - - ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> { - Thread t = new Thread(runnable); - t.setName("AsyncNdgProcessing-" + applicationId); - return t; - }); - executorMap.put(applicationId, scheduler); - - // Record the start time so we can stop after 2 hours: - long startTime = System.currentTimeMillis(); - long twoHoursMs = TimeUnit.HOURS.toMillis(2); - long fifteenMin = 15; // in MINUTES - - // We need a reference to cancel the scheduled task from inside itself when we're done: - AtomicReference> futureRef = new AtomicReference<>(); - - Runnable pollingTask = () -> { - RequestContextHolder.setRequestAttributes(requestAttributes, true); - Utils.setHttpServletRequestForThread(request,HttpMethodEnum.POST.getValue(),GepafinConstant.CREATE_NDG, (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID)); - try { - // 1) If 2 hours have already passed, mark as FAILED and shut down: - if (System.currentTimeMillis() - startTime > twoHoursMs) { - ApplicationEntity app = applicationService.validateApplication(applicationId); - log.warn("2-hour timeout reached for applicationId {}. Marking NDG_FAILED.", applicationId); - app.setNdgStatus(GepafinConstant.NDG_FAILED); - applicationRepository.save(app); - - futureRef.get().cancel(false); - shutdownScheduler(applicationId); - return; - } - - // 2) Otherwise, call processNdgGeneration once: - processNdgGeneration(applicationId); - - // 3) After return, check if NDG is now set or timed out. If so, cancel & shut down: - ApplicationEntity updated = applicationService.validateApplication(applicationId); - if (isNdgValid(updated.getNdg())) { - log.info("NDG found for applicationId {}. Shutting down scheduler.", applicationId); - futureRef.get().cancel(false); - shutdownScheduler(applicationId); - } else if (updated.getNdgStatus() != null && updated.getNdgStatus().equals(GepafinConstant.NDG_FAILED)) { - log.info("NDG status is NDG_FAILED for applicationId {}. Shutting down scheduler.", applicationId); - futureRef.get().cancel(false); - shutdownScheduler(applicationId); - } - // Otherwise: no NDG yet, not timed out → next run happens in 15 minutes automatically. - } catch (Exception ex) { - log.error("Unexpected error during scheduled polling for applicationId {}: {}", applicationId, ex.getMessage(), ex); - try { - ApplicationEntity checkApp = applicationService.validateApplication(applicationId); - if (System.currentTimeMillis() - startTime > twoHoursMs) { - log.warn("After exception, 2-hour window passed for applicationId {}. Marking NDG_FAILED.", applicationId); - checkApp.setNdgStatus(GepafinConstant.NDG_FAILED); - applicationRepository.save(checkApp); - - futureRef.get().cancel(false); - shutdownScheduler(applicationId); - } - } catch (Exception ignore) { - futureRef.get().cancel(false); - shutdownScheduler(applicationId); - } - } - }; - - // Schedule pollingTask: run now (delay=0), then every fifteen minutes: - ScheduledFuture future = scheduler.scheduleWithFixedDelay(pollingTask, 0, // initial delay = 0 min → run immediately - fifteenMin, // subsequent runs every 15 minutes - TimeUnit.MINUTES); - futureRef.set(future); - } +// private void startAsyncNdgProcessing(Long applicationId) { +// // If already polling for this applicationId, do nothing: +// if (executorMap.containsKey(applicationId)) { +// log.warn("Async processing already running for applicationId: {}", applicationId); +// return; +// } +// ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); +// +// ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> { +// Thread t = new Thread(runnable); +// t.setName("AsyncNdgProcessing-" + applicationId); +// return t; +// }); +// executorMap.put(applicationId, scheduler); +// +// // Record the start time so we can stop after 2 hours: +// long startTime = System.currentTimeMillis(); +// long twoHoursMs = TimeUnit.HOURS.toMillis(2); +// long fifteenMin = 15; // in MINUTES +// +// // We need a reference to cancel the scheduled task from inside itself when we're done: +// AtomicReference> futureRef = new AtomicReference<>(); +// +// Runnable pollingTask = () -> { +// RequestContextHolder.setRequestAttributes(requestAttributes, true); +// Utils.setHttpServletRequestForThread(request,HttpMethodEnum.POST.getValue(),GepafinConstant.CREATE_NDG, (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID)); +// try { +// // 1) If 2 hours have already passed, mark as FAILED and shut down: +// if (System.currentTimeMillis() - startTime > twoHoursMs) { +// ApplicationEntity app = applicationService.validateApplication(applicationId); +// log.warn("2-hour timeout reached for applicationId {}. Marking NDG_FAILED.", applicationId); +// app.setNdgStatus(GepafinConstant.NDG_FAILED); +// applicationRepository.save(app); +// +// futureRef.get().cancel(false); +// shutdownScheduler(applicationId); +// return; +// } +// +// // 2) Otherwise, call processNdgGeneration once: +// processNdgGeneration(applicationId); +// +// // 3) After return, check if NDG is now set or timed out. If so, cancel & shut down: +// ApplicationEntity updated = applicationService.validateApplication(applicationId); +// if (isNdgValid(updated.getNdg())) { +// log.info("NDG found for applicationId {}. Shutting down scheduler.", applicationId); +// futureRef.get().cancel(false); +// shutdownScheduler(applicationId); +// } else if (updated.getNdgStatus() != null && updated.getNdgStatus().equals(GepafinConstant.NDG_FAILED)) { +// log.info("NDG status is NDG_FAILED for applicationId {}. Shutting down scheduler.", applicationId); +// futureRef.get().cancel(false); +// shutdownScheduler(applicationId); +// } +// // Otherwise: no NDG yet, not timed out → next run happens in 15 minutes automatically. +// } catch (Exception ex) { +// log.error("Unexpected error during scheduled polling for applicationId {}: {}", applicationId, ex.getMessage(), ex); +// try { +// ApplicationEntity checkApp = applicationService.validateApplication(applicationId); +// if (System.currentTimeMillis() - startTime > twoHoursMs) { +// log.warn("After exception, 2-hour window passed for applicationId {}. Marking NDG_FAILED.", applicationId); +// checkApp.setNdgStatus(GepafinConstant.NDG_FAILED); +// applicationRepository.save(checkApp); +// +// futureRef.get().cancel(false); +// shutdownScheduler(applicationId); +// } +// } catch (Exception ignore) { +// futureRef.get().cancel(false); +// shutdownScheduler(applicationId); +// } +// } +// }; +// +// // Schedule pollingTask: run now (delay=0), then every fifteen minutes: +// ScheduledFuture future = scheduler.scheduleWithFixedDelay(pollingTask, 0, // initial delay = 0 min → run immediately +// fifteenMin, // subsequent runs every 15 minutes +// TimeUnit.MINUTES); +// futureRef.set(future); +// } private void shutdownScheduler(Long applicationId) { @@ -529,12 +516,10 @@ public class AppointmentDao { log.info("Scheduler shut down for applicationId: {}", applicationId); } - private void processNdgGeneration(Long applicationId) { + private void processNdgGeneration(ApplicationEntity application, CompanyEntity company, HubEntity hub) { // Validate application, company, and hub + Long applicationId = application.getId(); log.info("Starting NDG generation process for applicationId: {}", applicationId); - ApplicationEntity application = applicationService.validateApplication(applicationId); - 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."); @@ -552,7 +537,7 @@ public class AppointmentDao { // Try retrieving NDG by VAT number AppointmentLoginResponse ndgResponse = retrieveNdgByVatNumber(company.getVatNumber(), authorizationToken, hub, application); if (isNdgValid(ndgResponse.getNdg())) { - saveNdgAndIdVisura(application, company, ndgResponse.getNdg()); + saveNdg(application, company, ndgResponse.getNdg()); log.info("NDG successfully generated for applicationId: {}", applicationId); } else { log.info("Polling for NDG for applicationId: {}", applicationId); @@ -568,7 +553,7 @@ public class AppointmentDao { log.info("Starting single‐shot NDG polling attempt for applicationId: {}, CompanyId: {}, HubId: {}", application.getId(), company.getId(), hub.getId()); ApplicationEntity oldApplication = Utils.getClonedEntityForData(application); - CompanyEntity oldCompanyEntity=Utils.getClonedEntityForData(company); + CompanyEntity oldCompanyEntity = Utils.getClonedEntityForData(company); long startTime = System.currentTimeMillis(); long twoHoursMs = TimeUnit.HOURS.toMillis(2); @@ -589,7 +574,7 @@ public class AppointmentDao { company.setNdg(fetchedNdg); application.setNdg(fetchedNdg); - application.setNdgStatus(GepafinConstant.NDG_GENERATED); + application.setNdgStatus(NdgStatusEnum.NDG_GENERATED.getValue()); application.setStatus(ApplicationStatusTypeEnum.NDG.getValue()); application.setIdVisura(visuraResponse.getIdVisura()); @@ -678,10 +663,10 @@ public class AppointmentDao { return ndg != null && !ndg.isEmpty(); } - private void saveNdgAndIdVisura(ApplicationEntity application, CompanyEntity company, String ndg) { + private void saveNdg(ApplicationEntity application, CompanyEntity company, String ndg) { ApplicationEntity oldApplication = Utils.getClonedEntityForData(application); - CompanyEntity oldCompanyEntity=Utils.getClonedEntityForData(company); + CompanyEntity oldCompanyEntity = Utils.getClonedEntityForData(company); application.setNdg(ndg); application.setNdgStatus(GepafinConstant.NDG_GENERATED); application.setStatus(ApplicationStatusTypeEnum.NDG.getValue()); @@ -738,13 +723,13 @@ public class AppointmentDao { // Parse and return the NDG response return parseNdgResponse(responseJson); } catch (FeignException.Forbidden forbiddenException) { - log.error("403 Forbidden during NDG retrieval | ApplicationId: {}, HubId: {}", application.getId(), hub.getId()); + log.error("403 Forbidden during NDG retrieval | ApplicationId: {}, HubId: {}", application.getId(), hub.getId()); logForbiddenError(); // Regenerate the token and retry String newAuthorizationToken = regenerateTokenAndSave(hub, application); return retrieveNdgByVatNumber(vatNumber, newAuthorizationToken, hub, application); } catch (Exception e) { - log.error("Error during NDG retrieval | ApplicationId: {}, HubId: {}, Message: {}", application.getId(), hub.getId(), e.getMessage(), e); + log.error("Error during NDG retrieval | ApplicationId: {}, HubId: {}, Message: {}", application.getId(), hub.getId(), e.getMessage(), e); throw new RuntimeException("NDG retrieval failed.", e); } } @@ -993,7 +978,7 @@ public class AppointmentDao { return appointmentCreationResponse; } catch (FeignException.Forbidden forbiddenException) { - log.error("403 Forbidden received while retrieving template. Attempting to regenerate token and retry. Application ID: {}", applicationId); + log.error("403 Forbidden received while retrieving template. Attempting to regenerate token and retry. Application ID: {}", applicationId); regenerateTokenAndSave(hub, application); return createAppointment(applicationId, createAppointmentRequest); } @@ -1094,7 +1079,7 @@ public class AppointmentDao { } public AppointmentCreationRequest buildAppointmentCreationRequest(Long applicationId, CreateAppointmentRequest createAppointmentRequest, Long areaCode, - AppointmentCreationRequest templateRichiestaData) { + AppointmentCreationRequest templateRichiestaData) { ApplicationEntity application = applicationService.validateApplication(applicationId); CreateAppointmentRequest.Nota nota = createAppointmentRequest.getNota(); @@ -1207,7 +1192,7 @@ public class AppointmentDao { } private void uploadDocumentToExternalSystemSync(Long documentId, UploadDocToExternalSystemRequest docToExternalSystemRequest, ApplicationEntity application) { - log.info("Starting sync document upload for documentId: {}", documentId); + log.info("Starting sync document upload for documentId: {}", documentId); // Synchronous upload logic DocumentEntity systemDoc = documentDao.validateDocument(documentId); @@ -1248,7 +1233,7 @@ public class AppointmentDao { log.info("Document uploaded successfully to external system: {}", parsedResponse); } catch (FeignException.Forbidden forbiddenException) { - log.error("403 Forbidden from external system during upload for documentId: {}. Retrying with new token...", documentId); + log.error("403 Forbidden from external system during upload for documentId: {}. Retrying with new token...", documentId); regenerateTokenAndSave(hub, application); uploadDocumentToExternalSystemSync(documentId, docToExternalSystemRequest, application); } catch (Exception e) { @@ -1328,4 +1313,107 @@ public class AppointmentDao { throw new RuntimeException("Failed to parse response: " + e.getMessage(), e); } } -} \ No newline at end of file + + private void startAsyncNdgProcessing(Long applicationId) { + if (executorMap.containsKey(applicationId)) { + log.warn("Async processing already running for applicationId: {}", applicationId); + return; + } + ApplicationEntity application = applicationService.validateApplication(applicationId); + CompanyEntity company = companyService.validateCompany(application.getCompanyId()); + ApplicationEntity oldApplication = Utils.getClonedEntityForData(application); + CompanyEntity oldCompanyEntity = Utils.getClonedEntityForData(company); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r); + t.setName("AsyncNdgPolling-" + applicationId); + return t; + }); + + executorMap.put(applicationId, scheduler); + application.setNdgStatus(NdgStatusEnum.NDG_IN_PROGRESS.getValue()); + applicationRepository.save(application); + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(application).build()); + + long startTime = System.currentTimeMillis(); + long twoHoursMs = TimeUnit.HOURS.toMillis(2); + long fifteenMin = 15; + + HubEntity hub = hubRepository.findByHubId(application.getHubId()); + + // 1. Run full NDG generation logic once upfront + processNdgGeneration(application, company, hub); + + AtomicReference> futureRef = new AtomicReference<>(); + + // 2. Now define the polling logic ONLY + Runnable pollingTask = () -> { + RequestContextHolder.setRequestAttributes(requestAttributes, true); + Utils.setHttpServletRequestForThread(request, HttpMethodEnum.POST.getValue(), + GepafinConstant.CREATE_NDG, (Long) request.getAttribute(GepafinConstant.USER_ACTION_ID)); + try { + + // Stop if timeout + if (System.currentTimeMillis() - startTime > twoHoursMs) { + log.warn("Polling timed out for applicationId {}. Marking NDG_FAILED.", applicationId); + application.setNdgStatus(GepafinConstant.NDG_FAILED); + applicationRepository.save(application); + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(application).build()); + + futureRef.get().cancel(false); + shutdownScheduler(applicationId); + return; + } + + // If NDG already present or marked failed + if (isNdgValid(application.getNdg()) || GepafinConstant.NDG_FAILED.equals(application.getNdgStatus())) { + log.info("NDG already present or failed for applicationId {}. Stopping polling.", applicationId); + futureRef.get().cancel(false); + shutdownScheduler(applicationId); + return; + } + + // Only Visura polling here: + String visuraListJson = getVisuraList(application.getIdVisura(), hub.getAppointmentAuthTokenId(), application, hub); + String parsedNdg = parseNdgFromVisuraListResponse(visuraListJson); + + if (isNdgValid(parsedNdg)) { + log.info("Valid NDG parsed from VisuraList: {} | applicationId: {}", parsedNdg, application.getId()); + + company.setNdg(parsedNdg); + application.setNdg(parsedNdg); + application.setNdgStatus(GepafinConstant.NDG_GENERATED); + application.setStatus(ApplicationStatusTypeEnum.NDG.getValue()); +// application.setIdVisura(visuraResponse.getIdVisura()); + + companyRepository.save(company); + applicationRepository.save(application); + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldApplication).newData(application).build()); + loggingUtil.addVersionHistory( + VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCompanyEntity).newData(company).build()); + + ApplicationEvaluationEntity eval = applicationEvaluationService.validateApplicationEvaluation(application.getApplicationEvaluationId()); + Map placeholders = new HashMap<>(); + placeholders.put("{{call_name}}", application.getCall().getName()); + placeholders.put("{{protocol_number}}", String.valueOf(application.getProtocol().getProtocolNumber())); + notificationDao.sendNotificationToInstructor(placeholders, eval, NotificationTypeEnum.NDG_GENERATION); + notificationDao.sendNotificationToSuperUser(application, placeholders, NotificationTypeEnum.NDG_GENERATION); + + log.info("NDG saved successfully for applicationId: {}", application.getId()); + return; + } + + } catch (Exception ex) { + log.error("Error during NDG polling: {}", ex.getMessage(), ex); + } + }; + + ScheduledFuture future = scheduler.scheduleWithFixedDelay(pollingTask, fifteenMin, fifteenMin, TimeUnit.MINUTES); + futureRef.set(future); + } + +} + diff --git a/src/main/java/net/gepafin/tendermanagement/enums/NdgStatusEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/NdgStatusEnum.java new file mode 100644 index 00000000..2d16a7bd --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/NdgStatusEnum.java @@ -0,0 +1,22 @@ +package net.gepafin.tendermanagement.enums; + + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum NdgStatusEnum { + + NDG_INITITATED("NDG_INITITATED"), + NDG_GENERATED("NDG_GENERATED"), + NDG_IN_PROGRESS("NDG_IN_PROGRESS"); + + private String value; + + NdgStatusEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } +}