Done ticket GEPAFINBE-6326 Ranking Management

This commit is contained in:
rajesh
2026-04-08 15:53:34 +05:30
parent 6ae1963c47
commit 8e0cffb61c
28 changed files with 834 additions and 8 deletions

View File

@@ -108,6 +108,12 @@ public class GepafinConstant {
public static final String INVALID_STATUS_CHANGE_FROM_PUBLISH_TO_DRAFT = "invalid.status.change.from.publish.to.draft";
public static final String STATUS_CANNOT_BE_CHANGED = "status.cannot.be.changed";
public static final String PUBLISHED_CALL_NOT_UPDATE = "published.call.not.update";
public static final String PUBLISHED_CALL_STEP1_ONLY_RANKING_TYPE_ALLOWED = "published.call.step1.only.ranking.type.allowed";
public static final String CALL_RANKING_TYPE_UPDATED_SUCCESSFULLY = "call.ranking.type.updated.successfully";
public static final String APPLICATION_RANKING_ACTION_UPDATED_SUCCESSFULLY = "application.ranking.action.updated.successfully";
public static final String APPLICATION_RANKING_FETCHED_SUCCESSFULLY = "application.ranking.fetched.successfully";
public static final String CALL_MUST_BE_CLOSED_FOR_RANKING_ACTION = "call.must.be.closed.for.ranking.action";
public static final String APPLICATION_RANKING_ACTION_INVALID = "application.ranking.action.invalid";
public static final String INVALID_USER = "invalid_user";
public static final String FLOW_CREATED_SUCCESSFULLY = "flow.created.successfully";
public static final String FLOW_FETCHED_SUCCESSFULLY = "flow.fetched.successfully";

View File

@@ -72,6 +72,7 @@ import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -215,6 +216,9 @@ public class ApplicationDao {
@Autowired
private ApplicationFormViewRepository applicationFormViewRepository;
@Autowired
private ApplicationRankingViewRepository applicationRankingViewRepository;
@Autowired
private FormRepository formRepository;
@@ -509,6 +513,11 @@ public class ApplicationDao {
responseBean.setDateAccepted(applicationEntity.getDateAccepted());
responseBean.setDateRejected(applicationEntity.getDateRejected());
responseBean.setNdg(applicationEntity.getNdg());
if (applicationEntity.getRankingActionType() != null && !applicationEntity.getRankingActionType().isBlank()) {
responseBean.setRankingActionType(
ApplicationRankingActionTypeEnum.valueOf(applicationEntity.getRankingActionType().trim()));
}
responseBean.setManualRanking(applicationEntity.getManualRanking());
return responseBean;
}
@@ -1152,6 +1161,114 @@ public class ApplicationDao {
return getApplicationResponse(applicationEntity);
}
public ApplicationResponse updateApplicationRankingAction(HttpServletRequest request, Long applicationId,
ApplicationRankingActionTypeEnum rankingActionType, Long manualRanking) {
ApplicationEntity applicationEntity = validateApplication(applicationId);
validator.validateRequest(request, RoleStatusEnum.ROLE_SUPER_ADMIN);
validateCallClosedForRankingAction(applicationEntity.getCall());
if (!ApplicationStatusTypeEnum.APPROVED.getValue().equals(applicationEntity.getStatus())) {
throw new CustomValidationException(Status.BAD_REQUEST,
Translator.toLocale(GepafinConstant.APPLICATION_RANKING_ACTION_INVALID));
}
validateRankingActionRequest(rankingActionType, manualRanking);
ApplicationEntity oldApplicationEntity = Utils.getClonedEntityForData(applicationEntity);
if (rankingActionType == null) {
applicationEntity.setRankingActionType(null);
applicationEntity.setManualRanking(null);
} else {
if (rankingActionType == ApplicationRankingActionTypeEnum.REPOSITION
&& applicationRepository.existsByCallIdAndManualRankingAndIsDeletedFalseAndIdNot(
applicationEntity.getCall().getId(), manualRanking, applicationEntity.getId())) {
throw new CustomValidationException(Status.BAD_REQUEST,
Translator.toLocale(GepafinConstant.APPLICATION_RANKING_ACTION_INVALID));
}
applicationEntity.setRankingActionType(rankingActionType.getValue());
applicationEntity.setManualRanking(
rankingActionType == ApplicationRankingActionTypeEnum.REPOSITION ? manualRanking : null);
}
applicationEntity = applicationRepository.save(applicationEntity);
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE)
.oldData(oldApplicationEntity).newData(applicationEntity).build());
return getApplicationResponse(applicationEntity);
}
public CallRankingSummaryResponse getApplicationRanking(Long callId,
List<ApplicationRankingActionTypeEnum> rankingActionTypes) {
CallEntity call = callRepository.findById(callId)
.orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND,
Translator.toLocale(GepafinConstant.CALL_NOT_FOUND)));
Specification<ApplicationRankingView> spec = (root, query, criteriaBuilder) -> {
List<jakarta.persistence.criteria.Predicate> predicates = new ArrayList<>();
predicates.add(criteriaBuilder.equal(root.get("callId"), callId));
if (rankingActionTypes != null && !rankingActionTypes.isEmpty()) {
List<String> types = rankingActionTypes.stream()
.filter(Objects::nonNull)
.map(ApplicationRankingActionTypeEnum::getValue)
.distinct()
.collect(Collectors.toList());
if (!types.isEmpty()) {
predicates.add(root.get("rankingActionType").in(types));
}
}
query.orderBy(criteriaBuilder.asc(root.get("rank")));
return criteriaBuilder.and(predicates.toArray(new jakarta.persistence.criteria.Predicate[0]));
};
List<ApplicationRankingView> rows = applicationRankingViewRepository.findAll(spec);
CallRankingSummaryResponse summary = new CallRankingSummaryResponse();
summary.setCallId(call.getId());
summary.setCallName(call.getName());
summary.setAmount(call.getAmount());
if (call.getRankingType() != null && !call.getRankingType().isBlank()) {
summary.setRankingType(CallRankingTypeEnum.valueOf(call.getRankingType().trim()));
}
summary.setApplications(rows.stream()
.map(this::convertToApplicationRankingResponse)
.collect(Collectors.toList()));
return summary;
}
private ApplicationRankingResponse convertToApplicationRankingResponse(ApplicationRankingView entity) {
ApplicationRankingResponse response = new ApplicationRankingResponse();
response.setApplicationId(entity.getApplicationId());
response.setCallId(entity.getCallId());
response.setUserId(entity.getUserId());
response.setStatus(entity.getStatus());
response.setSubmissionDate(entity.getSubmissionDate());
response.setProtocolDatetime(entity.getProtocolDatetime());
response.setProtocolNumber(entity.getProtocolNumber());
response.setNdg(entity.getNdg());
response.setAmountAccepted(entity.getAmountAccepted());
response.setPecEmail(entity.getPecEmail());
response.setManualRanking(entity.getManualRanking());
response.setRank(entity.getRank());
response.setTotalScore(entity.getTotalScore());
if (entity.getRankingActionType() != null && !entity.getRankingActionType().isBlank()) {
response.setRankingActionType(ApplicationRankingActionTypeEnum.valueOf(entity.getRankingActionType().trim()));
}
if (entity.getRankingType() != null && !entity.getRankingType().isBlank()) {
response.setRankingType(CallRankingTypeEnum.valueOf(entity.getRankingType().trim()));
}
return response;
}
private void validateCallClosedForRankingAction(CallEntity callEntity) {
if (!CallStatusEnum.EXPIRED.getValue().equals(callEntity.getStatus())) {
throw new CustomValidationException(Status.BAD_REQUEST,
Translator.toLocale(GepafinConstant.CALL_MUST_BE_CLOSED_FOR_RANKING_ACTION));
}
}
private void validateRankingActionRequest(ApplicationRankingActionTypeEnum rankingActionType, Long manualRanking) {
if (rankingActionType == ApplicationRankingActionTypeEnum.REPOSITION
&& (manualRanking == null || manualRanking <= 0)) {
throw new CustomValidationException(Status.BAD_REQUEST,
Translator.toLocale(GepafinConstant.APPLICATION_RANKING_ACTION_INVALID));
}
}
/**
* Sets all non-terminal amendments, the application evaluation (if any), and the assigned application row to CLOSE.
*/

View File

@@ -228,6 +228,9 @@ public class CallDao {
if (createCallRequest.getAllowMultipleApplications() != null) {
callEntity.setAllowMultipleApplications(createCallRequest.getAllowMultipleApplications());
}
if (createCallRequest.getRankingType() != null) {
callEntity.setRankingType(createCallRequest.getRankingType().getValue());
}
callEntity = callRepository.save(callEntity);
log.info("CallEntity saved with ID: {} for call name: '{}'", callEntity.getId(), callEntity.getName());
@@ -418,6 +421,9 @@ public class CallDao {
createCallResponseBean.setEmail(callEntity.getEmail());
createCallResponseBean.setCreatedDate(callEntity.getCreatedDate());
createCallResponseBean.setUpdatedDate(callEntity.getUpdatedDate());
if (callEntity.getRankingType() != null && !callEntity.getRankingType().isBlank()) {
createCallResponseBean.setRankingType(CallRankingTypeEnum.valueOf(callEntity.getRankingType().trim()));
}
return createCallResponseBean;
}
@@ -583,6 +589,41 @@ public class CallDao {
}
}
private boolean hasNonRankingStep1Field(UpdateCallRequestStep1 r) {
return r.getName() != null
|| r.getDescriptionShort() != null
|| r.getDescriptionLong() != null
|| r.getDates() != null
|| r.getAmount() != null
|| r.getAmountMax() != null
|| r.getAimedTo() != null
|| r.getDocumentationRequested() != null
|| r.getAmountMin() != null
|| r.getEmail() != null
|| r.getPhoneNumber() != null
|| r.getStartTime() != null
|| r.getEndTime() != null
|| r.getConfidi() != null
|| r.getAllowMultipleApplications() != null
|| r.getFaq() != null
|| r.getNumberOfCheck() != null
|| r.getAppointmentTemplateId() != null
|| r.getEvaluationVersion() != null;
}
private CallResponse updatePublishedCallStep1RankingTypeOnly(HttpServletRequest request, CallEntity callEntity,
CallEntity oldCallEntity, UpdateCallRequestStep1 updateCallRequest) {
setIfUpdated(callEntity::getRankingType, callEntity::setRankingType,
updateCallRequest.getRankingType() != null ? updateCallRequest.getRankingType().getValue() : null);
callEntity = callRepository.save(callEntity);
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallEntity).newData(callEntity).build());
CallResponse response = getCallResponseBean(callEntity);
response.setCurrentStep(GepafinConstant.STEP_1);
log.info("Published call step 1: ranking type only | callId={}", callEntity.getId());
return response;
}
public void isValidDateRange(UpdateCallRequestStep1 updateCallRequest, CallEntity callEntity) {
List<LocalDateTime> dates = updateCallRequest.getDates();
@@ -615,6 +656,18 @@ public class CallDao {
public CallResponse updateCallStep1(HttpServletRequest request,CallEntity callEntity, UpdateCallRequestStep1 updateCallRequest, UserEntity userEntity) {
log.info("Updating Call ID: {}, by User ID: {}", callEntity.getId(),userEntity.getId() );
CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity);
if (CallStatusEnum.PUBLISH.getValue().equals(callEntity.getStatus())) {
if (hasNonRankingStep1Field(updateCallRequest)) {
throw new CustomValidationException(Status.VALIDATION_ERROR,
Translator.toLocale(GepafinConstant.PUBLISHED_CALL_STEP1_ONLY_RANKING_TYPE_ALLOWED));
}
if (updateCallRequest.getRankingType() != null) {
return updatePublishedCallStep1RankingTypeOnly(request, callEntity, oldCallEntity, updateCallRequest);
}
CallResponse unchanged = getCallResponseBean(callEntity);
unchanged.setCurrentStep(GepafinConstant.STEP_1);
return unchanged;
}
isValidDateRange(updateCallRequest, callEntity);
setIfUpdated(callEntity::getName, callEntity::setName, updateCallRequest.getName());
setIfUpdated(callEntity::getDescriptionShort, callEntity::setDescriptionShort,
@@ -648,8 +701,6 @@ public class CallDao {
if (!requestEndTime.equals(storedEndTime)) {
setIfUpdated(callEntity::getEndTime, callEntity::setEndTime, DateTimeUtil.parseTime(updateCallRequest.getEndTime()));
// callEntity.setStatus(CallStatusEnum.PUBLISH.getValue());
// callRepository.save(callEntity);
isEndTimeUpdated = true;
}
}
@@ -708,10 +759,15 @@ public class CallDao {
setIfUpdated(callEntity::getPhoneNumber, callEntity::setPhoneNumber, updateCallRequest.getPhoneNumber());
setIfUpdated(callEntity::getStartTime, callEntity::setStartTime, DateTimeUtil.parseTime(updateCallRequest.getStartTime()));
setIfUpdated(callEntity::getConfidi, callEntity::setConfidi, updateCallRequest.getConfidi());
setIfUpdated(callEntity::getEvaluationVersion, callEntity::setEvaluationVersion, updateCallRequest.getEvaluationVersion().getValue());
if (updateCallRequest.getEvaluationVersion() != null) {
setIfUpdated(callEntity::getEvaluationVersion, callEntity::setEvaluationVersion,
updateCallRequest.getEvaluationVersion().getValue());
}
setIfUpdated(callEntity::getNumberOfCheck, callEntity::setNumberOfCheck, updateCallRequest.getNumberOfCheck());
setIfUpdated(callEntity::getAppointmentTemplateId, callEntity::setAppointmentTemplateId, updateCallRequest.getAppointmentTemplateId());
setIfUpdated(callEntity::getAllowMultipleApplications, callEntity::setAllowMultipleApplications, updateCallRequest.getAllowMultipleApplications());
setIfUpdated(callEntity::getRankingType, callEntity::setRankingType,
updateCallRequest.getRankingType() != null ? updateCallRequest.getRankingType().getValue() : null);
callEntity = callRepository.save(callEntity);
/** This code is responsible for adding a version history log for the "update call step 1" operation **/
@@ -725,6 +781,15 @@ public class CallDao {
return createCallResponseBean;
}
public CallResponse updateCallRankingType(HttpServletRequest request, CallEntity callEntity, CallRankingTypeEnum rankingType) {
CallEntity oldCallEntity = Utils.getClonedEntityForData(callEntity);
callEntity.setRankingType(rankingType != null ? rankingType.getValue() : null);
callEntity = callRepository.save(callEntity);
loggingUtil.addVersionHistory(
VersionHistoryRequest.builder().request(request).actionType(VersionActionTypeEnum.UPDATE).oldData(oldCallEntity).newData(callEntity).build());
return getCallResponseBean(callEntity);
}
private void softDeleteFaq(FaqEntity faqEntity) {
FaqEntity oldFaqEntity = Utils.getClonedEntityForData(faqEntity);

View File

@@ -90,4 +90,10 @@ public class ApplicationEntity extends BaseEntity {
@Column(name = "COMPANY_DOCUMENT")
private String companyDocument;
@Column(name = "ranking_action_type")
private String rankingActionType;
@Column(name = "manual_ranking")
private Long manualRanking;
}

View File

@@ -0,0 +1,68 @@
package net.gepafin.tendermanagement.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
import org.hibernate.annotations.Immutable;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* Maps {@code application_ranking_view} (read-only).
*/
@Data
@Entity
@Immutable
@Table(name = "application_ranking_view")
public class ApplicationRankingView implements Serializable {
@Id
@Column(name = "application_id")
private Long applicationId;
@Column(name = "listing_rank")
private Long rank;
@Column(name = "call_id")
private Long callId;
@Column(name = "ranking_action_type")
private String rankingActionType;
@Column(name = "total_score")
private BigDecimal totalScore;
@Column(name = "user_id")
private Long userId;
@Column(name = "status")
private String status;
@Column(name = "submission_date")
private LocalDateTime submissionDate;
@Column(name = "protocol_datetime")
private LocalDateTime protocolDatetime;
@Column(name = "protocol_number")
private Long protocolNumber;
@Column(name = "ndg")
private String ndg;
@Column(name = "amount_accepted")
private BigDecimal amountAccepted;
@Column(name = "pec_email")
private String pecEmail;
@Column(name = "manual_ranking")
private Long manualRanking;
@Column(name = "ranking_type")
private String rankingType;
}

View File

@@ -102,5 +102,8 @@ public class CallEntity extends BaseEntity {
@Column(name = "allow_multiple_applications")
private Boolean allowMultipleApplications;
@Column(name = "ranking_type")
private String rankingType;
}

View File

@@ -0,0 +1,20 @@
package net.gepafin.tendermanagement.enums;
import com.fasterxml.jackson.annotation.JsonValue;
public enum ApplicationRankingActionTypeEnum {
REMOVE("REMOVE"),
REPOSITION("REPOSITION");
private final String value;
ApplicationRankingActionTypeEnum(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
}

View File

@@ -0,0 +1,20 @@
package net.gepafin.tendermanagement.enums;
import com.fasterxml.jackson.annotation.JsonValue;
public enum CallRankingTypeEnum {
SCORE("SCORE"),
PROTOCOL_DATE_TIME("PROTOCOL_DATE_TIME");
private final String value;
CallRankingTypeEnum(String value) {
this.value = value;
}
@JsonValue
public String getValue() {
return value;
}
}

View File

@@ -236,7 +236,10 @@ public enum UserActionContextEnum {
REJECT_PEC_MAIL("REJECT_PEC_MAIL"),
FETCH_EMAIL_LOG("FETCH_EMAIL_LOG"),
FETCH_ALL_EMAIL_LOG("FETCH_ALL_EMAIL_LOG"),
UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION("UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION");
UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION("UPLOAD_COMPANY_DOCUMENT_TO_APPLICATION"),
UPDATE_CALL_RANKING_TYPE("UPDATE_CALL_RANKING_TYPE"),
UPDATE_APPLICATION_RANKING_ACTION("UPDATE_APPLICATION_RANKING_ACTION"),
GET_APPLICATION_RANKING("GET_APPLICATION_RANKING");
private final String value;

View File

@@ -0,0 +1,13 @@
package net.gepafin.tendermanagement.model.request;
import lombok.Data;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
@Data
public class ApplicationRankingActionRequest {
private ApplicationRankingActionTypeEnum rankingActionType;
/** Required when {@code rankingActionType} is {@link ApplicationRankingActionTypeEnum#REPOSITION}. */
private Long manualRanking;
}

View File

@@ -5,6 +5,7 @@ import java.time.LocalDateTime;
import java.util.List;
import lombok.Data;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
@Data
@@ -49,4 +50,6 @@ public class CreateCallRequestStep1 {
private List<FaqReq> faq;
private EvaluationVersionEnum evaluationVersion;
private CallRankingTypeEnum rankingType;
}

View File

@@ -5,6 +5,7 @@ import java.time.LocalDateTime;
import java.util.List;
import lombok.Data;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
@Data
@@ -46,6 +47,8 @@ public class UpdateCallRequestStep1 {
private Long appointmentTemplateId;
private EvaluationVersionEnum evaluationVersion;
private EvaluationVersionEnum evaluationVersion;
private CallRankingTypeEnum rankingType;
}

View File

@@ -0,0 +1,28 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class ApplicationRankingResponse {
private Long rank;
private Long applicationId;
private Long callId;
private ApplicationRankingActionTypeEnum rankingActionType;
private BigDecimal totalScore;
private Long userId;
private String status;
private LocalDateTime submissionDate;
private LocalDateTime protocolDatetime;
private Long protocolNumber;
private String ndg;
private BigDecimal amountAccepted;
private String pecEmail;
private Long manualRanking;
private CallRankingTypeEnum rankingType;
}

View File

@@ -1,6 +1,7 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
import net.gepafin.tendermanagement.model.response.ApplicationFormFieldResponseBean;
@@ -54,4 +55,8 @@ public class ApplicationResponse{
private String ndg;
private ApplicationRankingActionTypeEnum rankingActionType;
private Long manualRanking;
}

View File

@@ -0,0 +1,19 @@
package net.gepafin.tendermanagement.model.response;
import lombok.Data;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/** Call-level ranking payload: tender info plus ordered ranked applications. */
@Data
public class CallRankingSummaryResponse {
private Long callId;
private String callName;
private BigDecimal amount;
private CallRankingTypeEnum rankingType;
private List<ApplicationRankingResponse> applications;
}

View File

@@ -7,6 +7,7 @@ import java.util.List;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.enums.CallStatusEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
import net.gepafin.tendermanagement.util.DynamicLocalTimeSerializer;
@@ -83,6 +84,8 @@ public class CallResponse {
private Long preferredCallId;
private EvaluationVersionEnum evaluationVersion;
private CallRankingTypeEnum rankingType;
}

View File

@@ -0,0 +1,11 @@
package net.gepafin.tendermanagement.repositories;
import net.gepafin.tendermanagement.entities.ApplicationRankingView;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
public interface ApplicationRankingViewRepository extends JpaRepository<ApplicationRankingView, Long>,
JpaSpecificationExecutor<ApplicationRankingView> {
}

View File

@@ -183,5 +183,6 @@ public interface ApplicationRepository extends JpaRepository<ApplicationEntity,
public List<ApplicationEntity> findByCallIdAndIsDeletedFalseAndStatusIn(Long callId,List<String> status);
boolean existsByCallIdAndManualRankingAndIsDeletedFalseAndIdNot(Long callId, Long manualRanking, Long id);
}

View File

@@ -5,6 +5,7 @@ import jakarta.servlet.http.HttpServletResponse;
import net.gepafin.tendermanagement.entities.ApplicationEntity;
import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean;
import net.gepafin.tendermanagement.model.request.ApplicationRequest;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum;
import net.gepafin.tendermanagement.enums.FormActionEnum;
import net.gepafin.tendermanagement.model.request.ApplicationRequestBean;
@@ -57,4 +58,10 @@ public interface ApplicationService {
public byte[] downloadRankingCsv(HttpServletRequest request, Long callId);
public void uploadCompanyDocumentsToApplication(HttpServletRequest request, Long applicationId, List<Long> companyDocumentIds);
ApplicationResponse updateApplicationRankingAction(HttpServletRequest request, Long applicationId,
ApplicationRankingActionTypeEnum rankingActionType, Long manualRanking);
CallRankingSummaryResponse getApplicationRanking(HttpServletRequest request, Long callId,
List<ApplicationRankingActionTypeEnum> rankingActionTypes);
}

View File

@@ -4,6 +4,7 @@ import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.entities.CallEntity;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.enums.CallStatusEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
import net.gepafin.tendermanagement.model.request.*;
@@ -37,4 +38,6 @@ public interface CallService {
CallResponse createCallStep2EvaluationV2(HttpServletRequest request, Long callId, CreateCallRequestStep2EvaluationV2 createCallRequest);
CallResponse updateCallRankingType(HttpServletRequest request, Long callId, CallRankingTypeEnum rankingType);
}

View File

@@ -12,6 +12,7 @@ import net.gepafin.tendermanagement.entities.CompanyEntity;
import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.model.request.ApplicationPageableRequestBean;
import net.gepafin.tendermanagement.model.request.ApplicationRequest;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum;
import net.gepafin.tendermanagement.enums.FormActionEnum;
import net.gepafin.tendermanagement.model.request.ApplicationRequestBean;
@@ -195,4 +196,20 @@ public class ApplicationServiceImpl implements ApplicationService {
UserEntity userEntity = validator.validateUser(request);
applicationDao.uploadCompanyDocumentsToApplication(applicationId,companyDocumentIds,userEntity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApplicationResponse updateApplicationRankingAction(HttpServletRequest request, Long applicationId,
ApplicationRankingActionTypeEnum rankingActionType, Long manualRanking) {
return applicationDao.updateApplicationRankingAction(request, applicationId, rankingActionType, manualRanking);
}
@Override
@Transactional(readOnly = true)
public CallRankingSummaryResponse getApplicationRanking(HttpServletRequest request, Long callId,
List<ApplicationRankingActionTypeEnum> rankingActionTypes) {
validator.validateUser(request);
validator.validateSuperAdminOrDirector();
return applicationDao.getApplicationRanking(callId, rankingActionTypes);
}
}

View File

@@ -1,9 +1,12 @@
package net.gepafin.tendermanagement.service.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.dao.CallDao;
import net.gepafin.tendermanagement.entities.CallEntity;
import net.gepafin.tendermanagement.entities.UserEntity;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.enums.CallStatusEnum;
import net.gepafin.tendermanagement.enums.EvaluationVersionEnum;
import net.gepafin.tendermanagement.model.request.*;
@@ -12,6 +15,8 @@ import net.gepafin.tendermanagement.model.response.CallResponse;
import net.gepafin.tendermanagement.model.response.PageableResponseBean;
import net.gepafin.tendermanagement.service.CallService;
import net.gepafin.tendermanagement.util.Validator;
import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -116,4 +121,15 @@ public class CallServiceImpl implements CallService {
CallEntity call = validator.validateUserWithCall(user, callId);
return callDao.createCallStep2EvaluationV2(call, createCallRequest, user);
}
@Override
@Transactional(rollbackFor = Exception.class)
public CallResponse updateCallRankingType(HttpServletRequest request, Long callId, CallRankingTypeEnum rankingType) {
validator.validateUser(request);
if (Boolean.FALSE.equals(validator.checkIsSuperAdmin())) {
throw new ForbiddenAccessException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PERMISSION_DENIED));
}
CallEntity call = callDao.validateCall(callId);
return callDao.updateCallRankingType(request, call, rankingType);
}
}

View File

@@ -0,0 +1,84 @@
package net.gepafin.tendermanagement.web.rest.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.model.request.ApplicationRankingActionRequest;
import net.gepafin.tendermanagement.model.response.CallRankingSummaryResponse;
import net.gepafin.tendermanagement.model.response.ApplicationResponse;
import net.gepafin.tendermanagement.model.response.CallResponse;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Validated
public interface RankingApi {
@Operation(summary = "API to update call ranking type",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE)})),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE)})),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE)}))
})
@PutMapping(value = "/call/{callId}/type", produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN')")
ResponseEntity<Response<CallResponse>> updateCallRankingType(HttpServletRequest request,
@PathVariable("callId") Long callId,
@RequestParam("rankingType") CallRankingTypeEnum rankingType);
@Operation(summary = "API to update application ranking action type in application",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE)})),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE)})),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE)}))
})
@PatchMapping(value = "/application/{applicationId}/action", produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN')")
ResponseEntity<Response<ApplicationResponse>> updateApplicationRankingAction(HttpServletRequest request,
@PathVariable("applicationId") Long applicationId,
@Valid @RequestBody ApplicationRankingActionRequest rankingActionRequest);
@Operation(summary = "API to get ranking list with callId",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE)})),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@io.swagger.v3.oas.annotations.media.ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE)}))
})
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN') || hasRole('ROLE_DIRECTOR')")
ResponseEntity<Response<CallRankingSummaryResponse>> getApplicationRanking(HttpServletRequest request,
@Parameter(description = "Call id", required = true)
@RequestParam("callId") Long callId,
@Parameter(description = "ranking action types", required = false,
array = @ArraySchema(schema = @Schema(implementation = ApplicationRankingActionTypeEnum.class)))
@RequestParam(value = "rankingActionType", required = false) List<ApplicationRankingActionTypeEnum> rankingActionTypes);
}

View File

@@ -0,0 +1,74 @@
package net.gepafin.tendermanagement.web.rest.api.impl;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.enums.ApplicationRankingActionTypeEnum;
import net.gepafin.tendermanagement.enums.CallRankingTypeEnum;
import net.gepafin.tendermanagement.enums.UserActionContextEnum;
import net.gepafin.tendermanagement.enums.UserActionLogsEnum;
import net.gepafin.tendermanagement.model.request.ApplicationRankingActionRequest;
import net.gepafin.tendermanagement.model.request.UserActionRequest;
import net.gepafin.tendermanagement.model.response.CallRankingSummaryResponse;
import net.gepafin.tendermanagement.model.response.ApplicationResponse;
import net.gepafin.tendermanagement.model.response.CallResponse;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.ApplicationService;
import net.gepafin.tendermanagement.service.CallService;
import net.gepafin.tendermanagement.util.LoggingUtil;
import net.gepafin.tendermanagement.web.rest.api.RankingApi;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/v1/ranking")
public class RankingApiController implements RankingApi {
@Autowired
private CallService callService;
@Autowired
private ApplicationService applicationService;
@Autowired
private LoggingUtil loggingUtil;
@Override
public ResponseEntity<Response<CallResponse>> updateCallRankingType(HttpServletRequest request, Long callId,
CallRankingTypeEnum rankingType) {
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE)
.actionContext(UserActionContextEnum.UPDATE_CALL_RANKING_TYPE).build());
CallResponse updated = callService.updateCallRankingType(request, callId, rankingType);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(updated, Status.SUCCESS, Translator.toLocale(GepafinConstant.CALL_RANKING_TYPE_UPDATED_SUCCESSFULLY)));
}
@Override
public ResponseEntity<Response<ApplicationResponse>> updateApplicationRankingAction(HttpServletRequest request,
Long applicationId, @Valid @RequestBody ApplicationRankingActionRequest rankingActionRequest) {
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.UPDATE)
.actionContext(UserActionContextEnum.UPDATE_APPLICATION_RANKING_ACTION).build());
ApplicationResponse body = applicationService.updateApplicationRankingAction(request, applicationId,
rankingActionRequest.getRankingActionType(), rankingActionRequest.getManualRanking());
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(body, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_RANKING_ACTION_UPDATED_SUCCESSFULLY)));
}
@Override
public ResponseEntity<Response<CallRankingSummaryResponse>> getApplicationRanking(HttpServletRequest request,
Long callId, List<ApplicationRankingActionTypeEnum> rankingActionTypes) {
loggingUtil.logUserAction(UserActionRequest.builder().request(request).actionType(UserActionLogsEnum.VIEW)
.actionContext(UserActionContextEnum.GET_APPLICATION_RANKING).build());
CallRankingSummaryResponse ranking = applicationService.getApplicationRanking(request, callId, rankingActionTypes);
return ResponseEntity.status(HttpStatus.OK)
.body(new Response<>(ranking, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_RANKING_FETCHED_SUCCESSFULLY)));
}
}

View File

@@ -3223,4 +3223,22 @@
<changeSet id="25-03-2026_NK_170536" author="Rajesh Khore">
<sqlFile dbms="postgresql" path="db/dump/insert_form_field_25_03_2026.sql"/>
</changeSet>
<changeSet id="07-04-2026_ranking_columns" author="GEPAFIN">
<preConditions onFail="MARK_RAN">
<not>
<columnExists tableName="call" columnName="ranking_type"/>
</not>
</preConditions>
<addColumn tableName="call">
<column name="ranking_type" type="VARCHAR(64)"/>
</addColumn>
<addColumn tableName="application">
<column name="ranking_action_type" type="VARCHAR(64)"/>
<column name="manual_ranking" type="BIGINT"/>
</addColumn>
</changeSet>
<changeSet id="07-04-2026_RK_145623" author="Rajesh Khore">
<sqlFile path="db/dump/create_application_ranking_view_07_04_2026.sql"/>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,201 @@
DROP VIEW IF EXISTS application_ranking_view;
CREATE OR REPLACE VIEW application_ranking_view AS
WITH evaluation_scores AS (
SELECT
ae.application_id,
COALESCE(
SUM(
COALESCE(NULLIF(TRIM(score_item ->> 'score'), ''), '0')::numeric
),
0
) AS total_score
FROM application_evaluation ae
LEFT JOIN LATERAL jsonb_array_elements(
CASE
WHEN ae.criteria IS NULL OR BTRIM(ae.criteria) = '' THEN '[]'::jsonb
ELSE ae.criteria::jsonb
END
) score_item ON TRUE
WHERE ae.is_deleted = false
GROUP BY ae.application_id
),
approved_applications AS (
SELECT
a.id AS application_id,
a.call_id,
a.company_id,
a.user_id,
a.status AS status,
a.submission_date,
a.amount_requested,
a.amount_accepted,
a.manual_ranking,
a.ranking_action_type,
a.ndg,
a.pec_email,
c.ranking_type,
p.created_date AS protocol_datetime,
p.protocol_number AS protocol_number,
COALESCE(a.amount_accepted, a.amount_requested, 0) AS amount,
COALESCE(es.total_score, 0) AS total_score
FROM application a
JOIN call c ON c.id = a.call_id
AND (c.is_deleted = false OR c.is_deleted IS NULL)
AND NULLIF(BTRIM(c.ranking_type), '') IS NOT NULL
LEFT JOIN protocol p ON p.id = a.protocol_number
LEFT JOIN evaluation_scores es ON es.application_id = a.id
WHERE (a.is_deleted = false OR a.is_deleted IS NULL)
AND a.status = 'APPROVED'
AND COALESCE(a.ranking_action_type, '') <> 'EXCLUDE'
),
ranking_core AS (
SELECT *
FROM approved_applications
WHERE COALESCE(ranking_action_type, '') <> 'REMOVE'
),
remove_apps AS (
SELECT *
FROM approved_applications
WHERE COALESCE(ranking_action_type, '') = 'REMOVE'
),
natural_ranked AS (
SELECT
rc.*,
ROW_NUMBER() OVER (
PARTITION BY rc.call_id
ORDER BY
CASE WHEN rc.ranking_type = 'SCORE' THEN rc.total_score END DESC NULLS LAST,
CASE WHEN rc.ranking_type = 'PROTOCOL_DATE_TIME' THEN rc.protocol_datetime END ASC NULLS LAST,
rc.protocol_datetime ASC NULLS LAST,
rc.application_id ASC
) AS natural_rank
FROM ranking_core rc
),
manual_repositioned AS (
SELECT *
FROM natural_ranked
WHERE COALESCE(ranking_action_type, '') = 'REPOSITION'
AND manual_ranking IS NOT NULL
),
non_manual AS (
SELECT *
FROM natural_ranked
WHERE COALESCE(ranking_action_type, '') <> 'REPOSITION'
OR manual_ranking IS NULL
),
manual_slots AS (
SELECT
mr.call_id,
mr.application_id,
mr.company_id,
mr.user_id,
mr.status,
mr.submission_date,
mr.amount_requested,
mr.amount_accepted,
mr.amount,
mr.ranking_type,
mr.protocol_datetime,
mr.protocol_number,
mr.total_score,
mr.ranking_action_type,
mr.manual_ranking,
mr.ndg,
mr.pec_email,
mr.natural_rank,
mr.manual_ranking AS effective_rank_slot
FROM manual_repositioned mr
),
non_manual_shifted AS (
SELECT
nm.call_id,
nm.application_id,
nm.company_id,
nm.user_id,
nm.status,
nm.submission_date,
nm.amount_requested,
nm.amount_accepted,
nm.amount,
nm.ranking_type,
nm.protocol_datetime,
nm.protocol_number,
nm.total_score,
nm.ranking_action_type,
nm.manual_ranking,
nm.ndg,
nm.pec_email,
nm.natural_rank,
nm.natural_rank
+ COALESCE((
SELECT COUNT(*)::bigint
FROM manual_repositioned mr
WHERE mr.call_id = nm.call_id
AND mr.manual_ranking <= nm.natural_rank
), 0) AS effective_rank_slot
FROM non_manual nm
),
combined AS (
SELECT * FROM manual_slots
UNION ALL
SELECT * FROM non_manual_shifted
),
max_slot_by_call AS (
SELECT call_id, MAX(effective_rank_slot) AS max_slot
FROM combined
GROUP BY call_id
),
remove_placed AS (
SELECT
ra.call_id,
ra.application_id,
ra.company_id,
ra.user_id,
ra.status,
ra.submission_date,
ra.amount_requested,
ra.amount_accepted,
ra.amount,
ra.ranking_type,
ra.protocol_datetime,
ra.protocol_number,
ra.total_score,
ra.ranking_action_type,
ra.manual_ranking,
ra.ndg,
ra.pec_email,
NULL::bigint AS natural_rank,
COALESCE(ms.max_slot, 0)
+ ROW_NUMBER() OVER (
PARTITION BY ra.call_id
ORDER BY ra.protocol_datetime ASC NULLS LAST, ra.application_id
) AS effective_rank_slot
FROM remove_apps ra
LEFT JOIN max_slot_by_call ms ON ms.call_id = ra.call_id
),
final_rows AS (
SELECT * FROM combined
UNION ALL
SELECT * FROM remove_placed
)
SELECT
ROW_NUMBER() OVER (
PARTITION BY fr.call_id
ORDER BY fr.effective_rank_slot, fr.protocol_datetime ASC NULLS LAST, fr.application_id
) AS listing_rank,
fr.application_id,
fr.call_id,
fr.ranking_action_type,
fr.total_score,
fr.user_id,
fr.status,
fr.submission_date,
fr.protocol_datetime,
fr.protocol_number,
fr.ndg,
fr.amount_accepted,
fr.pec_email,
fr.manual_ranking,
fr.ranking_type
FROM final_rows fr;

View File

@@ -61,6 +61,12 @@ status.same.error=Status is already set.
invalid.status.change.from.draft=Status cannot be changed to READY_TO_PUBLISH or PUBLISH from DRAFT.
status.cannot.be.changed=Status cannot be changed.
published.call.not.update=Published call cannot be updated.
published.call.step1.only.ranking.type.allowed=For a published call, this step accepts only ranking type.
call.ranking.type.updated.successfully=Call ranking type updated successfully.
application.ranking.action.updated.successfully=Application ranking action updated successfully.
application.ranking.fetched.successfully=Application ranking fetched successfully.
call.must.be.closed.for.ranking.action=Ranking action is allowed only when the call is closed.
application.ranking.action.invalid=Invalid application ranking action request.
invalid.status.change.from.publish=Status cannot be changed to READY_TO_PUBLISH from PUBLISH.
invalid.status.change.from.publish.to.draft=Status cannot be changed to DRAFT from PUBLISH as Applications are already created for this CALL.
validation.table.message=Data for field {0} is not present.

View File

@@ -61,6 +61,12 @@ status.same.error=Lo stato ? gi? impostato.
invalid.status.change.from.draft=Lo stato non pu? essere cambiato in READY_TO_PUBLISH o PUBLISH da DRAFT.
status.cannot.be.changed=Lo stato non pu? essere cambiato.
published.call.not.update=Il bando pubblicato non pu? essere aggiornato.
published.call.step1.only.ranking.type.allowed=Per un bando pubblicato, questo passaggio accetta solo il tipo di graduatoria; omettere tutti gli altri campi.
call.ranking.type.updated.successfully=Tipo di graduatoria del bando aggiornato correttamente.
application.ranking.action.updated.successfully=Azione di graduatoria sulla domanda aggiornata correttamente.
application.ranking.fetched.successfully=Graduatoria recuperata correttamente.
call.must.be.closed.for.ranking.action=L'azione di graduatoria <20> consentita solo se il bando <20> chiuso (scaduto).
application.ranking.action.invalid=Richiesta di azione sulla graduatoria non valida.
invalid.status.change.from.publish=Lo stato non pu? essere modificato in READY_TO_PUBLISH da PUBLISH.
invalid.status.change.from.publish.to.draft=Lo stato non pu essere modificato da PUBLISH a DRAFT poich sono gi state create applicazioni per questa CALL.
@@ -71,7 +77,7 @@ email.already.exists=Esiste gi? un utente con questa email.
invalid_user=Validazione utente fallita. Controlla le informazioni, lo stato dell'account e la scadenza del token.
#Global messages
common_message=Qualcosa è andato storto. Riprova.
common_message=Qualcosa <EFBFBD> andato storto. Riprova.
invalid_signature=Gettone non valido.
invalid_login=Nome utente o password errati
req_validation_er=Errore di convalida
@@ -425,7 +431,7 @@ amendment.must.be.approved.first=L'emendamento deve essere approvato dal diretto
upload.company.document.to.application=Documento aziendale caricato correttamente nell'applicazione.
company.document.not.found.with.ids=Documento aziendale non trovato. ID mancanti: {0}
amount.field.not.provided= Si prega di fornire i campi obbligatori per l'importo.
vat.or.tax.code.required=È obbligatorio il numero di partita IVA o il codice fiscale.
vat.or.tax.code.required=<EFBFBD> obbligatorio il numero di partita IVA o il codice fiscale.
provide.valid.vat.number=Inserisci un numero di partita IVA valido per procedere con NDG.
application.status.transition.restricted=Questa modifica di stato non è disponibile tramite questa operazione.
application.status.transition.restricted=Questa modifica di stato non <EFBFBD> disponibile tramite questa operazione.
application.registry.segment.invalid=Valore del segmento non valido.